Fix #150 — ✉️ Implement invitations to other people when using LDAP auth
This commit is contained in:
parent
e8ff0e467d
commit
8b68d7e821
|
@ -4,6 +4,7 @@ Revision history for Lufi
|
|||
- Allow to zip the files before upload
|
||||
- Allow to see what's in zip file on download page
|
||||
- Allow to individually download files from zip file (only if zip created by Lufi)
|
||||
- Allow to invite people to send you files on Lufi when using LDAP auth (See #150)
|
||||
|
||||
0.03.7 2019-08-01
|
||||
- Fix missing default values for some settings (mildis)
|
||||
|
|
41
lib/Lufi.pm
41
lib/Lufi.pm
|
@ -110,6 +110,47 @@ sub startup {
|
|||
$r->post('/logout')
|
||||
->to('Auth#log_out')
|
||||
->name('logout');
|
||||
|
||||
if (defined $self->config('ldap') && defined $self->config('invitations')) {
|
||||
# Invitation creation page
|
||||
$r->get('/invite')
|
||||
->name('invite')
|
||||
->to('Invitation#new_invite');
|
||||
|
||||
# Send invitation
|
||||
$r->post('/invite')
|
||||
->to('Invitation#send_invite');
|
||||
|
||||
# Get my invitations
|
||||
$r->get('/invite/list')
|
||||
->name('invite_list')
|
||||
->to('Invitation#my_invitations');
|
||||
|
||||
# Delete invitations
|
||||
$r->post('/invite/list/delete')
|
||||
->name('invite_list_delete')
|
||||
->to('Invitation#delete_invitations');
|
||||
|
||||
# Resend invitation mail
|
||||
$r->post('/invite/list/resend')
|
||||
->name('invite_list_resend')
|
||||
->to('Invitation#resend_invitations');
|
||||
|
||||
# Toggle invitations visibility
|
||||
$r->post('/invite/list/visibility')
|
||||
->name('invite_list_visibility')
|
||||
->to('Invitation#toggle_invitations_visibility');
|
||||
|
||||
# I’m a guest
|
||||
$r->get('/guest/:token')
|
||||
->name('guest')
|
||||
->to('Invitation#guest');
|
||||
|
||||
# I’m a guest and I sent all my files
|
||||
$r->post('/guest/:token/send_mail')
|
||||
->name('guest_send_mail')
|
||||
->to('Invitation#send_mail_to_ldap_user');
|
||||
}
|
||||
}
|
||||
|
||||
# About page
|
||||
|
|
|
@ -2,6 +2,7 @@ package Lufi::Command::sqliteToOtherDB;
|
|||
use Mojo::Base 'Mojolicious::Command';
|
||||
use Lufi::DB::File;
|
||||
use Lufi::DB::Slice;
|
||||
use Lufi::DB::Invitation;
|
||||
use Mojo::SQLite;
|
||||
use FindBin qw($Bin);
|
||||
use Term::ProgressBar;
|
||||
|
@ -31,11 +32,12 @@ sub run {
|
|||
exit 1;
|
||||
}
|
||||
|
||||
my $sqlite = Mojo::SQLite->new('sqlite:'.$config->{db_path});
|
||||
my $files = $sqlite->db->select('files', undef)->hashes;
|
||||
my $slices = $sqlite->db->select('slices', undef)->hashes;
|
||||
my $sqlite = Mojo::SQLite->new('sqlite:'.$config->{db_path});
|
||||
my $files = $sqlite->db->select('files', undef)->hashes;
|
||||
my $slices = $sqlite->db->select('slices', undef)->hashes;
|
||||
my $invitations = $sqlite->db->select('invitations', undef)->hashes;
|
||||
|
||||
my $progress = Term::ProgressBar->new({count => $files->size + $slices->size});
|
||||
my $progress = Term::ProgressBar->new({count => $files->size + $slices->size + $invitations->size});
|
||||
|
||||
$files->each(sub {
|
||||
my ($file, $num) = @_;
|
||||
|
@ -72,6 +74,24 @@ sub run {
|
|||
|
||||
$progress->update();
|
||||
});
|
||||
$invitations->each(sub {
|
||||
my ($invitation, $num) = @_;
|
||||
|
||||
Lufi::DB::Invitation->new(app => $c->app)
|
||||
->token($invitation->{token})
|
||||
->ldap_user($invitation->{ldap_user})
|
||||
->ldap_user_mail($invitation->{ldap_user_mail})
|
||||
->guest_mail($invitation->{guest_mail})
|
||||
->created_at($invitation->{created_at})
|
||||
->expire_at($invitation->{expire_at})
|
||||
->files_sent_at($invitation->{files_sent_at})
|
||||
->expend_expire_at($invitation->{expend_expire_at})
|
||||
->files($invitation->{files})
|
||||
->show_in_list($invitation->{show_in_list})
|
||||
->deleted($invitation->{deleted})
|
||||
->write();
|
||||
$progress->update();
|
||||
});
|
||||
}
|
||||
|
||||
=encoding utf8
|
||||
|
|
|
@ -4,26 +4,36 @@ use Mojo::Base 'Mojolicious::Controller';
|
|||
|
||||
sub login_page {
|
||||
my $c = shift;
|
||||
my $redirect = $c->param('redirect') // 'index';
|
||||
|
||||
if ($c->is_user_authenticated) {
|
||||
$c->redirect_to('index');
|
||||
} else {
|
||||
$c->render(template => 'login');
|
||||
$c->render(
|
||||
template => 'login',
|
||||
redirect => $redirect
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sub login {
|
||||
my $c = shift;
|
||||
|
||||
my $login = $c->param('login');
|
||||
my $pwd = $c->param('password');
|
||||
my $login = $c->param('login');
|
||||
my $pwd = $c->param('password');
|
||||
my $redirect = $c->param('redirect') // 'index';
|
||||
|
||||
if ($c->validation->csrf_protect->has_error('csrf_token')) {
|
||||
$c->stash(msg => $c->l('Bad CSRF token.'));
|
||||
$c->render(template => 'login');
|
||||
} else {
|
||||
if($c->authenticate($login, $pwd)) {
|
||||
$c->redirect_to('index');
|
||||
if ($redirect eq 'invite') {
|
||||
return $c->redirect_to('invite');
|
||||
} elsif ($redirect eq 'my_invitations') {
|
||||
return $c->redirect_to('invite_list');
|
||||
}
|
||||
return $c->redirect_to('index');
|
||||
} else {
|
||||
$c->stash(msg => $c->l('Please, check your credentials or your right to access this service: unable to authenticate.'));
|
||||
$c->render(template => 'login');
|
||||
|
|
|
@ -24,7 +24,10 @@ sub files {
|
|||
sub upload {
|
||||
my $c = shift;
|
||||
|
||||
if ((!defined($c->config('ldap')) && !defined($c->config('htpasswd'))) || $c->is_user_authenticated) {
|
||||
my $invitation;
|
||||
my $token = $c->session->{guest_token};
|
||||
$invitation = Lufi::DB::Invitation->new(app => $c->app)->from_token($token) if $token;
|
||||
if ((!defined($c->config('ldap')) && !defined($c->config('htpasswd'))) || $c->is_user_authenticated || $invitation) {
|
||||
$c->inactivity_timeout(30000000);
|
||||
|
||||
$c->app->log->debug('Client connected');
|
||||
|
@ -33,6 +36,8 @@ sub upload {
|
|||
message => sub {
|
||||
my ($ws, $text) = @_;
|
||||
|
||||
my $invit = Lufi::DB::Invitation->new(app => $c->app)->from_token($token) if $token;
|
||||
|
||||
my $begin = time;
|
||||
|
||||
my ($json) = split('XXMOJOXX', $text, 2);
|
||||
|
@ -81,7 +86,7 @@ sub upload {
|
|||
)));
|
||||
}
|
||||
# Check against max_size
|
||||
elsif (defined $c->config('max_file_size')) {
|
||||
if (defined $c->config('max_file_size')) {
|
||||
if ($json->{size} > $c->config('max_file_size')) {
|
||||
$stop = 1;
|
||||
return $ws->send(decode('UTF-8', encode_json(
|
||||
|
@ -95,7 +100,7 @@ sub upload {
|
|||
}
|
||||
}
|
||||
# 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}) {
|
||||
if ($json->{part} == 0 && ($json->{size} * 2) >= dfportable($c->config('upload_dir'))->{bavail}) {
|
||||
$stop = 1;
|
||||
return $ws->send(decode('UTF-8', encode_json(
|
||||
{
|
||||
|
@ -106,6 +111,18 @@ sub upload {
|
|||
}
|
||||
)));
|
||||
}
|
||||
# Check that the invitation is still valid, but only if it's the first chunk
|
||||
# (i.e. a new file, we don't want to stop a current uploading)
|
||||
if ($json->{part} == 0 && $invit && !$invit->is_valid()) {
|
||||
$stop = 1;
|
||||
$c->app->log->info(sprintf('Someone (%s) tried to use an expired or deleted invitation.', $invit->guest_mail));
|
||||
$ws->send(decode('UTF-8', encode_json(
|
||||
{
|
||||
success => false,
|
||||
msg => $c->l('Sorry, your invitation has expired or has been deleted. Please contact %1 to have another invitation.', $invit->ldap_user_mail),
|
||||
}
|
||||
)));
|
||||
}
|
||||
|
||||
unless ($stop) {
|
||||
my $f;
|
||||
|
@ -142,9 +159,15 @@ sub upload {
|
|||
}
|
||||
|
||||
my $creator = $c->ip;
|
||||
if (defined($c->config('ldap')) || defined($c->config('htpasswd'))) {
|
||||
$creator = 'User: '.$c->current_user->{username}.', IP: '.$creator;
|
||||
# Authenticated user logging
|
||||
if ((defined($c->config('ldap')) || defined($c->config('htpasswd'))) && !$invitation) {
|
||||
$creator = sprintf('User: %s, IP: %s', $c->current_user->{username}, $creator);
|
||||
}
|
||||
# Guest user logging
|
||||
if ($invitation) {
|
||||
$creator = sprintf('User: %s, IP: %s', $invitation->guest_mail, $creator);
|
||||
}
|
||||
|
||||
my $delete_at_first_view = ($json->{del_at_first_view}) ? 1 : 0;
|
||||
$delete_at_first_view = 1 if $c->app->config('force_burn_after_reading');
|
||||
$f = Lufi::DB::File->new(app => $c->app)->get_empty()
|
||||
|
@ -190,23 +213,22 @@ sub upload {
|
|||
}
|
||||
}
|
||||
|
||||
$ws->send(to_json(
|
||||
{
|
||||
success => true,
|
||||
i => $json->{i},
|
||||
j => $json->{part},
|
||||
parts => $json->{total},
|
||||
short => $f->short,
|
||||
name => $f->filename,
|
||||
size => $f->filesize,
|
||||
del_at_first_view => (($f->delete_at_first_view) ? true : false),
|
||||
created_at => $f->created_at,
|
||||
delay => $f->delete_at_day,
|
||||
token => $f->mod_token,
|
||||
sent_delay => $json->{delay},
|
||||
duration => time - $begin
|
||||
}
|
||||
));
|
||||
my $result = {
|
||||
success => true,
|
||||
i => $json->{i},
|
||||
j => $json->{part},
|
||||
parts => $json->{total},
|
||||
short => $f->short,
|
||||
name => $f->filename,
|
||||
size => $f->filesize,
|
||||
del_at_first_view => (($f->delete_at_first_view) ? true : false),
|
||||
created_at => $f->created_at,
|
||||
delay => $f->delete_at_day,
|
||||
token => $f->mod_token,
|
||||
sent_delay => $json->{delay},
|
||||
duration => time - $begin
|
||||
};
|
||||
$ws->send(to_json($result));
|
||||
} else {
|
||||
$ws->send(decode('UTF-8', encode_json(
|
||||
{
|
||||
|
|
|
@ -0,0 +1,283 @@
|
|||
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
|
||||
package Lufi::Controller::Invitation;
|
||||
use Mojo::Base 'Mojolicious::Controller';
|
||||
use Mojo::Collection 'c';
|
||||
use Mojo::File;
|
||||
use Mojo::JSON qw(true false decode_json encode_json);
|
||||
use Mojo::URL;
|
||||
use Email::Valid;
|
||||
use Lufi::DB::File;
|
||||
use Lufi::DB::Invitation;
|
||||
use Date::Format;
|
||||
|
||||
sub new_invite {
|
||||
my $c = shift;
|
||||
|
||||
# The `if (defined($c->config('ldap')))` is at the router level in lib/Lufi.pm
|
||||
if ($c->is_user_authenticated) {
|
||||
my $mail_attr = $c->config('invitations')->{'mail_attr'} // 'mail';
|
||||
my $max_expire_at = $c->config('invitations')->{'max_invitation_expiration_delay'} // 30;
|
||||
my $send_with_user_email = defined $c->config('invitations')->{'send_invitation_with_ldap_user_mail'};
|
||||
$c->render(
|
||||
template => 'invitations/invite',
|
||||
max_expire_at => $max_expire_at,
|
||||
send_with_user_email => $send_with_user_email,
|
||||
user_mail => ($send_with_user_email) ? $c->current_user->{$mail_attr} : '',
|
||||
fails => [],
|
||||
success => []
|
||||
);
|
||||
} else {
|
||||
$c->redirect_to($c->url_for('login')->query(redirect => 'invite'));
|
||||
}
|
||||
}
|
||||
|
||||
sub send_invite {
|
||||
my $c = shift;
|
||||
my $guest_mail = $c->param('guest_mail');
|
||||
my $expire_at = $c->param('expire_at');
|
||||
|
||||
my $mail_attr = $c->config('invitations')->{'mail_attr'} // 'mail';
|
||||
my $max_expire_at = $c->config('invitations')->{'max_invitation_expiration_delay'} // 30;
|
||||
my $send_with_user_email = defined $c->config('invitations')->{'send_invitation_with_ldap_user_mail'};
|
||||
|
||||
# The `if (defined($c->config('ldap')))` is at the router level in lib/Lufi.pm
|
||||
if ($c->is_user_authenticated) {
|
||||
my @fails = ();
|
||||
my @success = ();
|
||||
unless (Email::Valid->address($guest_mail)) {
|
||||
push @fails, $c->l('The guest email address (%1) is unvalid.', $guest_mail);
|
||||
}
|
||||
unless ($expire_at >= 1 && $expire_at <= $max_expire_at) {
|
||||
push @fails, $c->l('The expiration delay (%1) is not between 1 and %2 days.', $expire_at, $max_expire_at);
|
||||
}
|
||||
|
||||
unless (scalar(@fails)) {
|
||||
my $invitation = Lufi::DB::Invitation->new(app => $c->app);
|
||||
my $mail_attr = $c->config('invitations')->{'mail_attr'} // 'mail';
|
||||
my $expend_expire_at = $c->config('invitations')->{'expend_expire_at'} // 10;
|
||||
|
||||
my $token;
|
||||
do {
|
||||
$token = $c->create_invitation_token;
|
||||
} while ($invitation->is_token_used($token));
|
||||
|
||||
$invitation = $invitation->from_token($token);
|
||||
$invitation->ldap_user($c->current_user->{username});
|
||||
$invitation->ldap_user_mail($c->current_user->{$mail_attr});
|
||||
$invitation->created_at(time);
|
||||
$invitation->guest_mail($guest_mail);
|
||||
$invitation->expire_at($invitation->created_at + 86400 * $expire_at);
|
||||
$invitation->expend_expire_at($expend_expire_at);
|
||||
$invitation->show_in_list(1);
|
||||
$invitation = $invitation->write;
|
||||
|
||||
my $from = ($c->config('invitations')->{'send_invitation_with_ldap_user_mail'}) ? $invitation->ldap_user_mail : $c->config('mail_sender');
|
||||
my $url = $c->url_for('guest', token => $invitation->token)->to_abs;
|
||||
$c->mail(
|
||||
from => $from,
|
||||
to => $invitation->guest_mail,
|
||||
template => 'invitations/invite',
|
||||
format => 'mail',
|
||||
ldap_user => ucfirst($invitation->ldap_user),
|
||||
url => $url,
|
||||
invitation => $invitation,
|
||||
expires => time2str($c->l('%A %d %B %Y at %T'), $invitation->expire_at)
|
||||
);
|
||||
|
||||
push @success, $c->l('Invitation sent to %1.<br> URL: %2', $invitation->guest_mail, $url);
|
||||
}
|
||||
|
||||
$c->render(
|
||||
template => 'invitations/invite',
|
||||
max_expire_at => $max_expire_at,
|
||||
send_with_user_email => $send_with_user_email,
|
||||
user_mail => ($send_with_user_email) ? $c->current_user->{$mail_attr} : '',
|
||||
fails => \@fails,
|
||||
success => \@success
|
||||
);
|
||||
} else {
|
||||
$c->redirect_to('login');
|
||||
}
|
||||
}
|
||||
|
||||
sub my_invitations {
|
||||
my $c = shift;
|
||||
|
||||
# The `if (defined($c->config('ldap')))` is at the router level in lib/Lufi.pm
|
||||
if ($c->is_user_authenticated) {
|
||||
my $invitations = Lufi::DB::Invitation->new(app => $c->app)
|
||||
->from_user($c->current_user->{username});
|
||||
$invitations = c() unless $invitations;
|
||||
$c->render(
|
||||
template => 'invitations/my_invitations',
|
||||
invitations => $invitations
|
||||
);
|
||||
} else {
|
||||
$c->redirect_to($c->url_for('login')->query(redirect => 'my_invitations'));
|
||||
}
|
||||
}
|
||||
|
||||
sub delete_invitations {
|
||||
my $c = shift;
|
||||
my @tokens = @{$c->every_param('tokens[]')};
|
||||
|
||||
my @result = ();
|
||||
for my $token (@tokens) {
|
||||
my $i = Lufi::DB::Invitation->new(app => $c->app)
|
||||
->from_token($token)
|
||||
->deleted(1)
|
||||
->write;
|
||||
push @result, { msg => $c->l('The invitation %1 has been deleted.', $i->token), token => $i->token, deleted => $i->deleted };
|
||||
}
|
||||
|
||||
$c->render(json => {
|
||||
success => true,
|
||||
tokens => \@result
|
||||
});
|
||||
}
|
||||
|
||||
sub resend_invitations {
|
||||
my $c = shift;
|
||||
my @tokens = @{$c->every_param('tokens[]')};
|
||||
|
||||
my @success;
|
||||
my @failures;
|
||||
for my $token (@tokens) {
|
||||
my $i = Lufi::DB::Invitation->new(app => $c->app)
|
||||
->from_token($token);
|
||||
|
||||
if ($i->files_sent_at) {
|
||||
push @failures, $c->l('The invitation %1 can’t be resend: %2 has already sent files.<br>Please create a new invitation.', $i->token, $i->guest_mail);
|
||||
} else {
|
||||
if ($c->config('invitations')->{'extend_invitation_expiration_on_resend'}) {
|
||||
$i->expire_at(time + $i->expire_at - $i->created_at)
|
||||
->write;
|
||||
}
|
||||
|
||||
my $from = ($c->config('invitations')->{'send_invitation_with_ldap_user_mail'}) ? $i->ldap_user_mail : $c->config('mail_sender');
|
||||
my $url = $c->url_for('guest', token => $i->token)->to_abs;
|
||||
my $expire = time2str($c->l('%A %d %B %Y at %T'), $i->expire_at);
|
||||
$c->mail(
|
||||
from => $from,
|
||||
to => $i->guest_mail,
|
||||
template => 'invitations/invite',
|
||||
format => 'mail',
|
||||
ldap_user => ucfirst($i->ldap_user),
|
||||
url => $url,
|
||||
invitation => $i,
|
||||
expires => $expire
|
||||
);
|
||||
|
||||
push @success, { msg => $c->l('Invitation resent to %1.<br> URL: %2', $i->guest_mail, $url), expires => $expire, token => $i->token };
|
||||
}
|
||||
}
|
||||
|
||||
$c->render(json => {
|
||||
success => \@success,
|
||||
failures => \@failures
|
||||
});
|
||||
}
|
||||
|
||||
sub toggle_invitations_visibility {
|
||||
my $c = shift;
|
||||
my @tokens = @{$c->every_param('tokens[]')};
|
||||
|
||||
my @result = ();
|
||||
for my $token (@tokens) {
|
||||
my $i = Lufi::DB::Invitation->new(app => $c->app)
|
||||
->from_token($token)
|
||||
->toggle_visibility;
|
||||
push @result, { token => $i->token, show => ($i->show_in_list) ? true : false }
|
||||
}
|
||||
|
||||
$c->render(json => {
|
||||
success => true,
|
||||
tokens => \@result
|
||||
});
|
||||
}
|
||||
|
||||
sub guest {
|
||||
my $c = shift;
|
||||
my $token = $c->param('token');
|
||||
|
||||
my $invitation = Lufi::DB::Invitation->new(app => $c->app)->from_token($token);
|
||||
if ($invitation) {
|
||||
if ($invitation->is_valid) {
|
||||
$c->session->{guest_token} = $token;
|
||||
$c->session(expires => $invitation->expire_at);
|
||||
return $c->render(
|
||||
template => 'index',
|
||||
invitation => $invitation
|
||||
);
|
||||
} else {
|
||||
$c->stash('expired_or_deleted_invitation' => 1);
|
||||
}
|
||||
} else {
|
||||
$c->stash('invitation_not_found' => 1);
|
||||
}
|
||||
return $c->render(template => 'invitations/exception');
|
||||
}
|
||||
|
||||
sub send_mail_to_ldap_user {
|
||||
my $c = shift;
|
||||
my $token = $c->param('token');
|
||||
my $urls = c(@{$c->every_param('urls[]')});
|
||||
|
||||
my $invitation = Lufi::DB::Invitation->new(app => $c->app)->from_token($token);
|
||||
if ($invitation) {
|
||||
my @files = ();
|
||||
if ($c->config('invitations')->{'save_files_url_in_db'} && $urls->size) {
|
||||
my $guest_files = $invitation->files;
|
||||
if ($guest_files) {
|
||||
$guest_files = decode_json($guest_files);
|
||||
} else {
|
||||
$guest_files = [];
|
||||
}
|
||||
push @files, @{$guest_files};
|
||||
$urls->each(sub {
|
||||
my ($e, $num) = @_;
|
||||
$e = decode_json($e);
|
||||
push @{$guest_files}, $e;
|
||||
push @files, $e;
|
||||
});
|
||||
$invitation->files(encode_json($guest_files));
|
||||
$invitation->write;
|
||||
} else {
|
||||
$urls->each(sub {
|
||||
push @files, decode_json(shift);
|
||||
});
|
||||
}
|
||||
my $already_notified = 1;
|
||||
unless ($invitation->files_sent_at) {
|
||||
$invitation->files_sent_at(time);
|
||||
$invitation->write;
|
||||
$already_notified = 0;
|
||||
}
|
||||
$c->session(expires => $invitation->files_sent_at + 60 * $invitation->expend_expire_at);
|
||||
$c->mail(
|
||||
from => $c->config('mail_sender'),
|
||||
to => $invitation->ldap_user_mail,
|
||||
template => 'invitations/notification_files_sent',
|
||||
format => 'mail',
|
||||
files => c(@files),
|
||||
invitation => $invitation,
|
||||
already_notified => $already_notified
|
||||
);
|
||||
|
||||
return $c->render(
|
||||
json => {
|
||||
success => true,
|
||||
msg => $c->l('The URLs of your files have been sent by email to %1.', $invitation->ldap_user_mail)
|
||||
}
|
||||
);
|
||||
} else {
|
||||
return $c->render(
|
||||
json => {
|
||||
success => false,
|
||||
msg => $c->l('Sorry, the invitation doesn’t exist. Are you sure you are on the right URL?')
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
1;
|
|
@ -8,9 +8,7 @@ has 'token';
|
|||
has 'ldap_user';
|
||||
has 'ldap_user_mail';
|
||||
has 'guest_mail';
|
||||
has 'created_at' => sub {
|
||||
return time;
|
||||
};
|
||||
has 'created_at';
|
||||
has 'expire_at';
|
||||
has 'files_sent_at';
|
||||
has 'expend_expire_at';
|
||||
|
@ -199,6 +197,32 @@ sub show {
|
|||
return $c;
|
||||
}
|
||||
|
||||
=head2 toggle_visibility
|
||||
|
||||
=over 1
|
||||
|
||||
=item B<Usage> : C<$c-E<gt>toggle_visibility>
|
||||
|
||||
=item B<Arguments> : none
|
||||
|
||||
=item B<Purpose> : toggle the C<show_in_list> flag
|
||||
|
||||
=item B<Returns> : the db accessor object
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub toggle_visibility {
|
||||
my $c = shift;
|
||||
|
||||
if ($c->show_in_list) {
|
||||
return $c->hide;
|
||||
} else {
|
||||
return $c->show;
|
||||
}
|
||||
}
|
||||
|
||||
=head2 write
|
||||
|
||||
=over 1
|
||||
|
@ -236,7 +260,7 @@ sub write {
|
|||
|
||||
=item B<Arguments> : string
|
||||
|
||||
=item B<Purpose> : find an invitation in the database from its token attribute
|
||||
=item B<Purpose> : find an invitation in the database from its C<token> attribute
|
||||
|
||||
=item B<Returns> : a db accessor object
|
||||
|
||||
|
@ -257,11 +281,49 @@ sub from_token {
|
|||
}
|
||||
}
|
||||
|
||||
=head2 from_user
|
||||
|
||||
=over 1
|
||||
|
||||
=item B<Usage> : C<$c-E<gt>from_user($mail)>
|
||||
|
||||
=item B<Arguments> : string
|
||||
|
||||
=item B<Purpose> : find invitations in the database from their C<ldap_user_mail> attribute
|
||||
|
||||
=item B<Returns> : a Mojo::Collection of Lufi::DB::Invitation objects, sorted by creation date
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub from_user {
|
||||
my $c = shift;
|
||||
my $user = shift;
|
||||
|
||||
my $r = $c->app->dbi->db
|
||||
->select('invitations', undef, { ldap_user => $user })
|
||||
->hashes;
|
||||
|
||||
if ($r->size) {
|
||||
my @invitations;
|
||||
$r->each(sub {
|
||||
my ($e, $num) = @_;
|
||||
$e->{app} = $c->app;
|
||||
$e->{record} = 1;
|
||||
push @invitations, Lufi::DB::Invitation->new($e);
|
||||
});
|
||||
return c(@invitations);
|
||||
} else {
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
|
||||
=head2 is_token_used
|
||||
|
||||
=over 1
|
||||
|
||||
=item B<Usage> : C<$c-E<gt>does_token_exists($token)>
|
||||
=item B<Usage> : C<$c-E<gt>is_token_used($token)>
|
||||
|
||||
=item B<Arguments> : string
|
||||
|
||||
|
@ -287,6 +349,30 @@ sub is_token_used {
|
|||
}
|
||||
}
|
||||
|
||||
=head2 is_valid
|
||||
|
||||
=over 1
|
||||
|
||||
=item B<Usage> : C<$c-E<gt>is_valid()>
|
||||
|
||||
=item B<Arguments> : none
|
||||
|
||||
=item B<Purpose> : tells if an invitation is still valid
|
||||
|
||||
=item B<Returns> : a boolean
|
||||
|
||||
=back
|
||||
|
||||
=cut
|
||||
|
||||
sub is_valid {
|
||||
my $c = shift;
|
||||
|
||||
my $time = time;
|
||||
# Active After creation date Before expiration date Before files send date plus extension delay
|
||||
return (!$c->deleted && $time >= $c->created_at && $time < $c->expire_at && (!defined($c->files_sent_at) || $time < ($c->files_sent_at + $c->expend_expire_at * 60)));
|
||||
}
|
||||
|
||||
=head2 _slurp
|
||||
|
||||
=over 1
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
package Lufi::Plugin::Helpers;
|
||||
use Mojo::Base 'Mojolicious::Plugin';
|
||||
use Lufi::DB::File;
|
||||
use Lufi::DB::Invitation;
|
||||
|
||||
sub register {
|
||||
my ($self, $app) = @_;
|
||||
|
@ -11,7 +12,6 @@ sub register {
|
|||
$app->plugin('PgURLHelper');
|
||||
}
|
||||
|
||||
|
||||
if ($app->config('dbtype') eq 'postgresql') {
|
||||
require Mojo::Pg;
|
||||
$app->helper(dbi => \&_pg);
|
||||
|
@ -58,13 +58,15 @@ sub register {
|
|||
$app->dbi->db->query('ALTER TABLE files ADD COLUMN passwd TEXT') unless $pwd_col;
|
||||
}
|
||||
|
||||
$app->helper(provisioning => \&_provisioning);
|
||||
$app->helper(get_empty => \&_get_empty);
|
||||
$app->helper(ip => \&_ip);
|
||||
$app->helper(default_delay => \&_default_delay);
|
||||
$app->helper(max_delay => \&_max_delay);
|
||||
$app->helper(is_selected => \&_is_selected);
|
||||
$app->helper(stop_upload => \&_stop_upload);
|
||||
$app->helper(provisioning => \&_provisioning);
|
||||
$app->helper(get_empty => \&_get_empty);
|
||||
$app->helper(ip => \&_ip);
|
||||
$app->helper(default_delay => \&_default_delay);
|
||||
$app->helper(max_delay => \&_max_delay);
|
||||
$app->helper(is_selected => \&_is_selected);
|
||||
$app->helper(stop_upload => \&_stop_upload);
|
||||
$app->helper(create_invitation_token => \&_create_invitation_token);
|
||||
$app->helper(is_guest => \&_is_guest);
|
||||
}
|
||||
|
||||
sub _pg {
|
||||
|
@ -170,4 +172,19 @@ sub _stop_upload {
|
|||
return 0;
|
||||
}
|
||||
|
||||
sub _create_invitation_token {
|
||||
my $c = shift;
|
||||
|
||||
return $c->shortener(32);
|
||||
}
|
||||
|
||||
sub _is_guest {
|
||||
my $c = shift;
|
||||
my $token = shift;
|
||||
|
||||
my $invitation = Lufi::DB::Invitation->new(app => $c->app)->from_token($token);
|
||||
return $invitation if ($invitation && $invitation->is_valid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -17,10 +17,34 @@ msgstr ""
|
|||
|
||||
#. ($delay)
|
||||
#. (max_delay)
|
||||
#: themes/default/templates/index.html.ep:47 themes/default/templates/index.html.ep:56 themes/default/templates/index.html.ep:57
|
||||
#: themes/default/templates/index.html.ep:56 themes/default/templates/index.html.ep:65 themes/default/templates/index.html.ep:66
|
||||
msgid "%1 days"
|
||||
msgstr ""
|
||||
|
||||
#. (stash('invitation')
|
||||
#: themes/default/templates/invitations/notification_files_sent.mail.ep:4
|
||||
msgid "%1 have send you files"
|
||||
msgstr ""
|
||||
|
||||
#. (stash('ldap_user')
|
||||
#: themes/default/templates/invitations/invite.mail.ep:2
|
||||
msgid "%1 invites you to send him/her files"
|
||||
msgstr ""
|
||||
|
||||
#. (stash('ldap_user')
|
||||
#: themes/default/templates/invitations/invite.mail.ep:6
|
||||
msgid "%1 invites you to send him/her files through Lufi."
|
||||
msgstr ""
|
||||
|
||||
#. (stash('invitation')
|
||||
#: themes/default/templates/invitations/notification_files_sent.mail.ep:8
|
||||
msgid "%1 used your invitation to send you files:"
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Invitation.pm:159 lib/Lufi/Controller/Invitation.pm:84 themes/default/templates/invitations/my_invitations.html.ep:51 themes/default/templates/invitations/my_invitations.html.ep:52 themes/default/templates/invitations/my_invitations.html.ep:53 themes/default/templates/invitations/notification_files_sent.mail.ep:12
|
||||
msgid "%A %d %B %Y at %T"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/index.js.ep:26
|
||||
msgid "(max size: XXX)"
|
||||
msgstr ""
|
||||
|
@ -29,7 +53,7 @@ msgstr ""
|
|||
msgid "1 year"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:4 themes/default/templates/index.html.ep:56
|
||||
#: themes/default/templates/index.html.ep:4 themes/default/templates/index.html.ep:65
|
||||
msgid "24 hours"
|
||||
msgstr ""
|
||||
|
||||
|
@ -41,11 +65,11 @@ msgstr ""
|
|||
msgid "Abort"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/layouts/default.html.ep:49 themes/default/templates/layouts/default.html.ep:78
|
||||
#: themes/default/templates/layouts/default.html.ep:53 themes/default/templates/layouts/default.html.ep:82
|
||||
msgid "About"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:98
|
||||
#: themes/default/templates/index.html.ep:107
|
||||
msgid "Add a password to file(s)"
|
||||
msgstr ""
|
||||
|
||||
|
@ -53,6 +77,14 @@ msgstr ""
|
|||
msgid "Adding URLs not related to this Lufi instance to the mail body or subject is prohibited."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/invitations.js.ep:3
|
||||
msgid "Are you sure you want to delete the selected invitations?"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/invitations.js.ep:4
|
||||
msgid "Are you sure you want to resend the invitation mail for the selected invitations?"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/about.html.ep:17
|
||||
msgid "As Lufi is a free software licensed under of the terms of the <a href=\"https://gnu.org/licenses/agpl.html\" class=\"classic\">AGPLv3</a>, you can install it on you own server. Have a look on the <a href=\"https://framagit.org/luc/lufi/wikis/home\" class=\"classic\">Wiki</a> for the procedure."
|
||||
msgstr ""
|
||||
|
@ -70,7 +102,7 @@ msgstr ""
|
|||
msgid "Bad CSRF token!"
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Auth.pm:22 lib/Lufi/Controller/Auth.pm:39
|
||||
#: lib/Lufi/Controller/Auth.pm:27 lib/Lufi/Controller/Auth.pm:49
|
||||
msgid "Bad CSRF token."
|
||||
msgstr ""
|
||||
|
||||
|
@ -78,11 +110,15 @@ msgstr ""
|
|||
msgid "Click here to refresh the page and restart the download."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:119
|
||||
#: themes/default/templates/invitations/invite.mail.ep:8
|
||||
msgid "Click on the following URL to upload files on Lufi:"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:128
|
||||
msgid "Click to open the file browser"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/delays.html.ep:38
|
||||
#: themes/default/templates/delays.html.ep:38 themes/default/templates/invitations/my_invitations.html.ep:80
|
||||
msgid "Close"
|
||||
msgstr ""
|
||||
|
||||
|
@ -90,7 +126,7 @@ msgstr ""
|
|||
msgid "Comma-separated email addresses"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:133
|
||||
#: themes/default/templates/index.html.ep:142
|
||||
msgid "Compressing zip file…"
|
||||
msgstr ""
|
||||
|
||||
|
@ -102,15 +138,15 @@ msgstr ""
|
|||
msgid "Copy to clipboard"
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:485
|
||||
#: lib/Lufi/Controller/Files.pm:507
|
||||
msgid "Could not delete the file. You are not authenticated."
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:467
|
||||
#: lib/Lufi/Controller/Files.pm:489
|
||||
msgid "Could not find the file. Are you sure of the URL and the token?"
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:378
|
||||
#: lib/Lufi/Controller/Files.pm:400
|
||||
msgid "Could not find the file. Are you sure of the URL?"
|
||||
msgstr ""
|
||||
|
||||
|
@ -118,11 +154,19 @@ msgstr ""
|
|||
msgid "Counter"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:91
|
||||
#: themes/default/templates/index.html.ep:100
|
||||
msgid "Create a zip archive with the files before uploading?"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/files.html.ep:29 themes/default/templates/index.html.ep:81
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:26
|
||||
msgid "Created at"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:14
|
||||
msgid "Delete"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/files.html.ep:29 themes/default/templates/index.html.ep:90
|
||||
msgid "Delete at first download?"
|
||||
msgstr ""
|
||||
|
||||
|
@ -154,10 +198,14 @@ msgstr ""
|
|||
msgid "Drag and drop files in the appropriate area or use the traditional way to send files and the files will be chunked, encrypted and sent to the server. You will get two links per file: a download link, that you give to the people you want to share the file with and a deletion link, allowing you to delete the file whenever you want."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:115
|
||||
#: themes/default/templates/index.html.ep:124
|
||||
msgid "Drop files here"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/invite.html.ep:40
|
||||
msgid "Email address of your guest"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/mail.html.ep:39
|
||||
msgid "Email body"
|
||||
msgstr ""
|
||||
|
@ -174,15 +222,15 @@ msgstr ""
|
|||
msgid "Encrypting part XX1 of XX2"
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:267
|
||||
#: lib/Lufi/Controller/Files.pm:289
|
||||
msgid "Error: the file existed but was deleted."
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:347
|
||||
#: lib/Lufi/Controller/Files.pm:369
|
||||
msgid "Error: the file has not been sent entirely."
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:357
|
||||
#: lib/Lufi/Controller/Files.pm:379
|
||||
msgid "Error: unable to find the file. Are you sure of your URL?"
|
||||
msgstr ""
|
||||
|
||||
|
@ -190,6 +238,10 @@ msgstr ""
|
|||
msgid "Expiration:"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:27
|
||||
msgid "Expire at"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/files.html.ep:31
|
||||
msgid "Expires at"
|
||||
msgstr ""
|
||||
|
@ -198,7 +250,7 @@ msgstr ""
|
|||
msgid "Export localStorage data"
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:449
|
||||
#: lib/Lufi/Controller/Files.pm:471
|
||||
msgid "File deleted"
|
||||
msgstr ""
|
||||
|
||||
|
@ -206,10 +258,22 @@ msgstr ""
|
|||
msgid "File name"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:71
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:61
|
||||
msgid "Files"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:80
|
||||
msgid "Files deleted at first download"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:28
|
||||
msgid "Files sent at"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/invitations.js.ep:8
|
||||
msgid "Files sent in invitation XX1 by XX2"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/render.js.ep:8
|
||||
msgid "Get the file"
|
||||
msgstr ""
|
||||
|
@ -218,6 +282,19 @@ msgstr ""
|
|||
msgid "Get the source code on <a href=\"https://framagit.org/luc/lufi\" class=\"classic\">the official repository</a> or on its <a href=\"https://github.com/ldidry/lufi\" class=\"classic\">Github mirror</a>"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:24
|
||||
msgid "Guest mail"
|
||||
msgstr ""
|
||||
|
||||
#. (ucfirst(stash('invitation')
|
||||
#: themes/default/templates/invitations/notification_files_sent.mail.ep:6
|
||||
msgid "Hello %1,"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/invite.mail.ep:4
|
||||
msgid "Hello,"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/mail.js.ep:35
|
||||
msgid "Hello,\\n\\nHere's some files I want to share with you:\\n"
|
||||
msgstr ""
|
||||
|
@ -226,6 +303,10 @@ msgstr ""
|
|||
msgid "Here's some files"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/invitations.js.ep:7
|
||||
msgid "Hide hidden invitations"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/index.js.ep:24
|
||||
msgid "Hit Enter, then Ctrl+C to copy all the download links"
|
||||
msgstr ""
|
||||
|
@ -238,6 +319,10 @@ msgstr ""
|
|||
msgid "How does it work?"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/invite.html.ep:46
|
||||
msgid "How many days would you like the invitation to be valid?"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/about.html.ep:16
|
||||
msgid "How to install the software on my server?"
|
||||
msgstr ""
|
||||
|
@ -258,7 +343,7 @@ msgstr ""
|
|||
msgid "Import localStorage data"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:44
|
||||
#: themes/default/templates/index.html.ep:53
|
||||
msgid "Important: more information on delays"
|
||||
msgstr ""
|
||||
|
||||
|
@ -266,6 +351,24 @@ msgstr ""
|
|||
msgid "Information about delays"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:12
|
||||
msgid "Invert selection"
|
||||
msgstr ""
|
||||
|
||||
#. ($i->guest_mail, $url)
|
||||
#: lib/Lufi/Controller/Invitation.pm:171
|
||||
msgid "Invitation resent to %1.<br> URL: %2"
|
||||
msgstr ""
|
||||
|
||||
#. ($invitation->guest_mail, $url)
|
||||
#: lib/Lufi/Controller/Invitation.pm:87
|
||||
msgid "Invitation sent to %1.<br> URL: %2"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/invite.html.ep:27 themes/default/templates/layouts/default.html.ep:36
|
||||
msgid "Invite a guest"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/render.js.ep:6
|
||||
msgid "It seems that the key in your URL is incorrect. Please, verify your URL."
|
||||
msgstr ""
|
||||
|
@ -274,7 +377,7 @@ msgstr ""
|
|||
msgid "Javascript is disabled. You won't be able to use Lufi."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/layouts/default.html.ep:40 themes/default/templates/layouts/default.html.ep:42 themes/default/templates/layouts/default.html.ep:69 themes/default/templates/layouts/default.html.ep:71
|
||||
#: themes/default/templates/layouts/default.html.ep:44 themes/default/templates/layouts/default.html.ep:46 themes/default/templates/layouts/default.html.ep:73 themes/default/templates/layouts/default.html.ep:75
|
||||
msgid "Language"
|
||||
msgstr ""
|
||||
|
||||
|
@ -282,7 +385,7 @@ msgstr ""
|
|||
msgid "Login"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/layouts/default.html.ep:54 themes/default/templates/layouts/default.html.ep:80
|
||||
#: themes/default/templates/layouts/default.html.ep:58 themes/default/templates/layouts/default.html.ep:84
|
||||
msgid "Logout"
|
||||
msgstr ""
|
||||
|
||||
|
@ -294,16 +397,24 @@ msgstr ""
|
|||
msgid "Mail"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/files.html.ep:3 themes/default/templates/layouts/default.html.ep:34 themes/default/templates/layouts/default.html.ep:63
|
||||
#: themes/default/templates/files.html.ep:3 themes/default/templates/layouts/default.html.ep:34 themes/default/templates/layouts/default.html.ep:67
|
||||
msgid "My files"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:106
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:5 themes/default/templates/layouts/default.html.ep:37
|
||||
msgid "My invitations"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/notification_files_sent.mail.ep:17
|
||||
msgid "NB: this list includes the list of files that have already been sent to you."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:115
|
||||
msgid "Name of the zip file"
|
||||
msgstr ""
|
||||
|
||||
#. (format_bytes($json->{size})
|
||||
#: lib/Lufi/Controller/Files.pm:103
|
||||
#: lib/Lufi/Controller/Files.pm:108
|
||||
msgid "No enough space available on the server for this file (size: %1)."
|
||||
msgstr ""
|
||||
|
||||
|
@ -315,7 +426,7 @@ msgstr ""
|
|||
msgid "Only the files sent with this browser will be listed here. This list is stored in localStorage: if you delete your localStorage data, you'll lose this list."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:97 themes/default/templates/login.html.ep:21 themes/default/templates/render.html.ep:26
|
||||
#: themes/default/templates/index.html.ep:106 themes/default/templates/login.html.ep:21 themes/default/templates/render.html.ep:26
|
||||
msgid "Password"
|
||||
msgstr ""
|
||||
|
||||
|
@ -328,7 +439,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/Controller/Auth.pm:28
|
||||
#: lib/Lufi/Controller/Auth.pm:38
|
||||
msgid "Please, check your credentials or your right to access this service: unable to authenticate."
|
||||
msgstr ""
|
||||
|
||||
|
@ -340,10 +451,26 @@ msgstr ""
|
|||
msgid "Purge expired files from localStorage"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/layouts/default.html.ep:31 themes/default/templates/layouts/default.html.ep:60
|
||||
#: themes/default/templates/invitations/notification_files_sent.mail.ep:20
|
||||
msgid "Regards,"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/invite.mail.ep:15
|
||||
msgid "Regards."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/layouts/default.html.ep:31 themes/default/templates/layouts/default.html.ep:64
|
||||
msgid "Report file"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:15
|
||||
msgid "Resend invitation mail"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:9
|
||||
msgid "Rows in purple mean that the invitations have expired."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/files.html.ep:9
|
||||
msgid "Rows in red mean that the files have expired and are no longer available."
|
||||
msgstr ""
|
||||
|
@ -352,6 +479,10 @@ msgstr ""
|
|||
msgid "Send all links by email"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/invite.html.ep:50
|
||||
msgid "Send the invitation"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/mail.html.ep:46
|
||||
msgid "Send with this server"
|
||||
msgstr ""
|
||||
|
@ -369,22 +500,44 @@ msgstr ""
|
|||
msgid "Share your files in total privacy on %1"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:13 themes/default/templates/partial/invitations.js.ep:9
|
||||
msgid "Show hidden invitations"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/render.js.ep:11
|
||||
msgid "Show zip content"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/layouts/default.html.ep:36 themes/default/templates/layouts/default.html.ep:65 themes/default/templates/login.html.ep:27 themes/default/templates/logout.html.ep:17
|
||||
#: themes/default/templates/layouts/default.html.ep:40 themes/default/templates/layouts/default.html.ep:69 themes/default/templates/login.html.ep:28 themes/default/templates/logout.html.ep:17
|
||||
msgid "Signin"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:37
|
||||
#: lib/Lufi/Controller/Invitation.pm:277 themes/default/templates/invitations/exception.html.ep:16
|
||||
msgid "Sorry, the invitation doesn’t exist. Are you sure you are on the right URL?"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:46
|
||||
msgid "Sorry, the uploading is currently disabled. Please try again later."
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:77
|
||||
#: lib/Lufi/Controller/Files.pm:82
|
||||
msgid "Sorry, uploading is disabled."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/exception.html.ep:7
|
||||
msgid "Sorry, your invitation has expired or has been deleted."
|
||||
msgstr ""
|
||||
|
||||
#. ($invit->ldap_user_mail)
|
||||
#: lib/Lufi/Controller/Files.pm:122
|
||||
msgid "Sorry, your invitation has expired or has been deleted. Please contact %1 to have another invitation."
|
||||
msgstr ""
|
||||
|
||||
#. ($invitation->ldap_user_mail)
|
||||
#: lib/Lufi/Controller/Invitation.pm:270
|
||||
msgid "The URLs of your files have been sent by email to %1."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/about.html.ep:7
|
||||
msgid "The administrator can only see the file's name, its size and its mimetype (what kind of file it is: video, text, etc.)."
|
||||
msgstr ""
|
||||
|
@ -405,7 +558,12 @@ msgstr ""
|
|||
msgid "The email subject can't be empty."
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:446
|
||||
#. ($expire_at, $max_expire_at)
|
||||
#: lib/Lufi/Controller/Invitation.pm:51
|
||||
msgid "The expiration delay (%1) is not between 1 and %2 days."
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:468
|
||||
msgid "The file has already been deleted"
|
||||
msgstr ""
|
||||
|
||||
|
@ -418,10 +576,40 @@ msgstr ""
|
|||
msgid "The following email addresses are not valid: %1"
|
||||
msgstr ""
|
||||
|
||||
#. ($guest_mail)
|
||||
#: lib/Lufi/Controller/Invitation.pm:48
|
||||
msgid "The guest email address (%1) is unvalid."
|
||||
msgstr ""
|
||||
|
||||
#. ($i->token, $i->guest_mail)
|
||||
#: lib/Lufi/Controller/Invitation.pm:150
|
||||
msgid "The invitation %1 can’t be resend: %2 has already sent files.<br>Please create a new invitation."
|
||||
msgstr ""
|
||||
|
||||
#. ($i->token)
|
||||
#: lib/Lufi/Controller/Invitation.pm:130
|
||||
msgid "The invitation %1 has been deleted."
|
||||
msgstr ""
|
||||
|
||||
#. (stash('user_mail')
|
||||
#: themes/default/templates/invitations/invite.html.ep:34
|
||||
msgid "The invitation mail will be send from your email address (%1)."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/index.js.ep:15
|
||||
msgid "The link(s) has been copied to your clipboard"
|
||||
msgstr ""
|
||||
|
||||
#. (stash('invitation')
|
||||
#: themes/default/templates/index.html.ep:30
|
||||
msgid "The link(s) of your file(s) will automatically be sent by mail to %1 (%2)"
|
||||
msgstr ""
|
||||
|
||||
#. (stash('ldap_user')
|
||||
#: themes/default/templates/invitations/invite.mail.ep:11
|
||||
msgid "The links of your file(s) will automatically be send by mail to %1."
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Mail.pm:97
|
||||
msgid "The mail has been sent."
|
||||
msgstr ""
|
||||
|
@ -430,42 +618,59 @@ msgstr ""
|
|||
msgid "The original (and only for now) author is <a href=\"https://fiat-tux.fr\" class=\"classic\">Luc Didry</a>."
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:214
|
||||
#: lib/Lufi/Controller/Files.pm:236
|
||||
msgid "The server was unable to find the file record to add your file part to. Please, contact the administrator."
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:273
|
||||
#: lib/Lufi/Controller/Files.pm:295
|
||||
msgid "This file has been deactivated by the admins. Contact them to know why."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:46 themes/default/templates/partial/invitations.js.ep:6
|
||||
msgid "This invitation is normally hidden"
|
||||
msgstr ""
|
||||
|
||||
#. (stash('expires')
|
||||
#: themes/default/templates/invitations/invite.mail.ep:13
|
||||
msgid "This invitation is valid until %1."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/delays.html.ep:10
|
||||
msgid "This server sets limitations according to the file size. The expiration delay of your file will be the minimum between what you choose and the following limitations:"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:16
|
||||
msgid "Toggle visibility"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/my_invitations.html.ep:25
|
||||
msgid "URL"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/index.js.ep:16
|
||||
msgid "Unable to copy the link(s) to your clipboard"
|
||||
msgstr ""
|
||||
|
||||
#. ($short)
|
||||
#: lib/Lufi/Controller/Files.pm:417
|
||||
#: lib/Lufi/Controller/Files.pm:439
|
||||
msgid "Unable to get counter for %1. The file does not exists. It will be removed from your localStorage."
|
||||
msgstr ""
|
||||
|
||||
#. ($short)
|
||||
#: lib/Lufi/Controller/Files.pm:407
|
||||
#: lib/Lufi/Controller/Files.pm:429
|
||||
msgid "Unable to get counter for %1. The token is invalid."
|
||||
msgstr ""
|
||||
|
||||
#. ($short)
|
||||
#: lib/Lufi/Controller/Files.pm:427
|
||||
#: lib/Lufi/Controller/Files.pm:449
|
||||
msgid "Unable to get counter for %1. You are not authenticated."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/layouts/default.html.ep:33 themes/default/templates/layouts/default.html.ep:62
|
||||
#: themes/default/templates/layouts/default.html.ep:33 themes/default/templates/layouts/default.html.ep:66
|
||||
msgid "Upload files"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:110
|
||||
#: themes/default/templates/index.html.ep:119
|
||||
msgid "Upload generated zip file"
|
||||
msgstr ""
|
||||
|
||||
|
@ -473,7 +678,7 @@ msgstr ""
|
|||
msgid "Uploaded at"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:142
|
||||
#: themes/default/templates/index.html.ep:151
|
||||
msgid "Uploaded files"
|
||||
msgstr ""
|
||||
|
||||
|
@ -489,6 +694,10 @@ msgstr ""
|
|||
msgid "Who wrote this software?"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/invitations/invite.html.ep:30
|
||||
msgid "You can invite someone to send you files through this Lufi instance even if they don’t have an account on it."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/about.html.ep:11
|
||||
msgid "You can see the list of your files by clicking on the \"My files\" link at the top right of this page."
|
||||
msgstr ""
|
||||
|
@ -521,16 +730,16 @@ msgstr ""
|
|||
msgid "You must give email addresses."
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:29
|
||||
#: themes/default/templates/index.html.ep:38
|
||||
msgid "Your browser has not enough entropy to generate a strong encryption key. Please wait (it's better if you do things on your computer while waiting)."
|
||||
msgstr ""
|
||||
|
||||
#. (format_bytes($json->{size})
|
||||
#: lib/Lufi/Controller/Files.pm:90
|
||||
#: lib/Lufi/Controller/Files.pm:95
|
||||
msgid "Your file is too big: %1 (maximum size allowed: %2)"
|
||||
msgstr ""
|
||||
|
||||
#: lib/Lufi/Controller/Files.pm:329
|
||||
#: lib/Lufi/Controller/Files.pm:351
|
||||
msgid "Your password is not valid. Please refresh the page to retry."
|
||||
msgstr ""
|
||||
|
||||
|
@ -548,6 +757,10 @@ msgstr ""
|
|||
msgid "deadline: "
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/partial/invitations.js.ep:5
|
||||
msgid "expires on XXX"
|
||||
msgstr ""
|
||||
|
||||
#. (format_bytes($keys[$i])
|
||||
#: themes/default/templates/delays.html.ep:26
|
||||
msgid "for %1 and more, the file will be kept %2 day(s)"
|
||||
|
@ -562,6 +775,11 @@ msgstr ""
|
|||
msgid "no time limit"
|
||||
msgstr ""
|
||||
|
||||
#: themes/default/templates/index.html.ep:117
|
||||
#: themes/default/templates/index.html.ep:126
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
#. ($e->{name}, format_bytes($e->{size})
|
||||
#: themes/default/templates/invitations/notification_files_sent.mail.ep:12
|
||||
msgid "— %1 (%2), that will expire on %3"
|
||||
msgstr ""
|
||||
|
|
|
@ -203,6 +203,26 @@ button.pulse {
|
|||
transform: scale(1.5);
|
||||
}
|
||||
}
|
||||
.margin-bottom-35 {
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
.toast.teal.accent-3,
|
||||
.toast.red.accent-2 {
|
||||
color: black;
|
||||
}
|
||||
.offscreen {
|
||||
clip-path: inset(100%);
|
||||
clip: rect(1px 1px 1px 1px); /* IE 6/7 */
|
||||
clip: rect(1px, 1px, 1px, 1px);
|
||||
height: 1px;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
white-space: nowrap; /* added line */
|
||||
width: 1px;
|
||||
}
|
||||
.small-h1 {
|
||||
font-size: 2.2rem;
|
||||
}
|
||||
.white-background {
|
||||
background-color: #FFF;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
function invertSelection(e) {
|
||||
e.preventDefault();
|
||||
$('#myInvitations input[type="checkbox"]').each(function () {
|
||||
var el = $(this);
|
||||
var tr = el.parent().parent();
|
||||
if (!tr.hasClass('hide')) {
|
||||
el.click();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function toggleHidden(e) {
|
||||
e.preventDefault();
|
||||
if ($('#myInvitations').attr('data-visibility') === 'hidden') {
|
||||
$('#toggleHidden').text(i18n.hideText);
|
||||
$('tr[data-visibility="0"]').removeClass('hide');
|
||||
$('#myInvitations').attr('data-visibility', 'shown');
|
||||
} else {
|
||||
$('#toggleHidden').text(i18n.showText);
|
||||
$('tr[data-visibility="0"]').addClass('hide');
|
||||
$('tr[data-visibility="0"] input[type="checkbox"]').each(function() {
|
||||
var el = $(this);
|
||||
if (el.attr('data-checked') === 'data-checked') {
|
||||
$('tr[data-visibility="0"] input[type="checkbox"]').click();
|
||||
}
|
||||
});
|
||||
$('#myInvitations').attr('data-visibility', 'hidden');
|
||||
}
|
||||
}
|
||||
|
||||
function deleteInvit(e) {
|
||||
e.preventDefault();
|
||||
if (confirm(i18n.confirmDeleteInvit)) {
|
||||
var tokens = selectChecked();
|
||||
$.ajax({
|
||||
url: deleteURL,
|
||||
method: 'POST',
|
||||
data: {
|
||||
tokens: tokens
|
||||
},
|
||||
success: function(data, textStatus, jqXHR) {
|
||||
if (data.success) {
|
||||
data.tokens.forEach(function(t) {
|
||||
Materialize.toast(t.msg, 6000, 'teal accent-3');
|
||||
$('#row-' + t.token).remove();
|
||||
});
|
||||
disableButtons();
|
||||
} else {
|
||||
Materialize.toast(data.msg, 10000, 'red accent-2');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function resendMail(e) {
|
||||
e.preventDefault();
|
||||
if (confirm(i18n.confirmResendMail)) {
|
||||
var tokens = selectChecked();
|
||||
$.ajax({
|
||||
url: resendURL,
|
||||
method: 'POST',
|
||||
data: {
|
||||
tokens: tokens
|
||||
},
|
||||
success: function(data, textStatus, jqXHR) {
|
||||
data.success.forEach(function(s) {
|
||||
Materialize.toast(s.msg, 6000, 'teal accent-3');
|
||||
$('#expire-' + s.token).text(s.expires)
|
||||
$('#' + s.token).click();
|
||||
});
|
||||
data.failures.forEach(function(msg) {
|
||||
Materialize.toast(msg, 10000, 'red accent-2');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function toggleVisibility(e) {
|
||||
e.preventDefault();
|
||||
var tokens = selectChecked();
|
||||
$.ajax({
|
||||
url: toggleURL,
|
||||
method: 'POST',
|
||||
data: {
|
||||
tokens: tokens
|
||||
},
|
||||
success: function(data, textStatus, jqXHR) {
|
||||
if (data.success) {
|
||||
data.tokens.forEach(function(t) {
|
||||
var row = $('#row-' + t.token)
|
||||
if (t.show) {
|
||||
row.attr('data-visibility', 1);
|
||||
row.removeClass('hide');
|
||||
$('#row-' + t.token + ' > td:first i').remove();
|
||||
} else {
|
||||
row.attr('data-visibility', 0);
|
||||
if ($('#myInvitations').attr('data-visibility') === 'hidden') {
|
||||
row.addClass('hide');
|
||||
}
|
||||
$('#row-' + t.token + ' > td:first').append(i18n.hiddenMark);
|
||||
}
|
||||
$('#' + t.token).click();
|
||||
});
|
||||
disableButtons();
|
||||
} else {
|
||||
Materialize.toast(data.msg, 10000, 'red accent-2');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function selectChecked() {
|
||||
var tokens = [];
|
||||
$('#myInvitations input[type="checkbox"][data-checked="data-checked"]').each(function() {
|
||||
tokens.push($(this).attr('id'));
|
||||
});
|
||||
return tokens;
|
||||
}
|
||||
|
||||
function handleCheckboxClic() {
|
||||
var el = $(this);
|
||||
if (el.attr('data-checked') === 'data-checked') {
|
||||
el.attr('data-checked', null);
|
||||
} else {
|
||||
el.attr('data-checked', 'data-checked');
|
||||
}
|
||||
if ($('#myInvitations input[type="checkbox"][data-checked="data-checked"]').length !== 0) {
|
||||
$('#deleteInvit').removeClass('disabled');
|
||||
$('#deleteInvit').attr('disabled', null);
|
||||
$('#resendMail').removeClass('disabled');
|
||||
$('#resendMail').attr('disabled', null);
|
||||
$('#toggleVisibility').removeClass('disabled');
|
||||
$('#toggleVisibility').attr('disabled', null);
|
||||
} else {
|
||||
disableButtons();
|
||||
}
|
||||
}
|
||||
|
||||
function disableButtons() {
|
||||
$('#deleteInvit').addClass('disabled');
|
||||
$('#deleteInvit').attr('disabled', 'disabled');
|
||||
$('#resendMail').addClass('disabled');
|
||||
$('#resendMail').attr('disabled', 'disabled');
|
||||
$('#toggleVisibility').addClass('disabled');
|
||||
$('#toggleVisibility').attr('disabled', 'disabled');
|
||||
}
|
||||
|
||||
function fillModal() {
|
||||
var el = $(this);
|
||||
|
||||
$('#files-info h1').text('');
|
||||
$('#files-ul').html('');
|
||||
|
||||
var token = el.attr('data-token');
|
||||
var guest = el.attr('data-guest');
|
||||
$('#files-info h1').text(
|
||||
i18n.listFiles.replace('XX1', token)
|
||||
.replace('XX2', guest)
|
||||
);
|
||||
|
||||
var files = JSON.parse(el.attr('data-files'));
|
||||
var content = [];
|
||||
for (i = 0; i < files.length; i++) {
|
||||
var f = files[i];
|
||||
var expires = i18n.expiration.replace('XXX',
|
||||
moment.unix(f.delay * 86400 + f.created_at).locale(window.navigator.language).format('LLLL')
|
||||
);
|
||||
content.push(
|
||||
'<li>— ',
|
||||
'<a href="', f.url, '">',
|
||||
f.name,
|
||||
'</a> (',
|
||||
filesize(f.size),
|
||||
', ',
|
||||
expires,
|
||||
')',
|
||||
'</li>',
|
||||
);
|
||||
}
|
||||
$('#files-ul').html(content.join(''));
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$('.modal-trigger').leanModal();
|
||||
$('.modal-trigger').on('click', fillModal);
|
||||
$('#invertSelection').on('click', invertSelection);
|
||||
$('#toggleHidden').on('click', toggleHidden);
|
||||
$('#deleteInvit').on('click', deleteInvit);
|
||||
$('#resendMail').on('click', resendMail);
|
||||
$('#toggleVisibility').on('click', toggleVisibility);
|
||||
$('#myInvitations input[type="checkbox"]').on('click', handleCheckboxClic);
|
||||
});
|
|
@ -11,6 +11,8 @@ window.sliceLength = 2000000;
|
|||
// Global zip objects for currently created zip file
|
||||
window.zip = null;
|
||||
window.zipSize = 0;
|
||||
// Init the list of files (used by LDAP invitation feature)
|
||||
window.filesURLs = [];
|
||||
|
||||
// Copy a link to clipboard
|
||||
function copyToClipboard(txt) {
|
||||
|
@ -184,6 +186,28 @@ function updateMailLink() {
|
|||
$('#mailto').attr('href', u);
|
||||
}
|
||||
|
||||
// [Invitation feature] Send URLs of files to server
|
||||
function sendFilesURLs() {
|
||||
if (window.filesURLs.length > 0) {
|
||||
$.ajax({
|
||||
url: sendFilesURLsURL,
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
data: {
|
||||
urls: window.filesURLs
|
||||
},
|
||||
success: function(data, textStatus, jqXHR) {
|
||||
if (data.success) {
|
||||
Materialize.toast(data.msg, 6000, 'teal accent-3');
|
||||
} else {
|
||||
Materialize.toast(data.msg, 10000, 'red accent-2');
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Start uploading the files (called from <input> and from drop zone)
|
||||
function handleFiles(f) {
|
||||
var delay = $('#delete-day');
|
||||
|
@ -221,6 +245,7 @@ function handleFiles(f) {
|
|||
} else {
|
||||
if (window.fileList === undefined || window.fileList === null) {
|
||||
window.fileList = Array.prototype.slice.call(f);
|
||||
window.nbFiles = window.fileList.length;
|
||||
$('#results').show();
|
||||
uploadFile(0, delay.val(), del_at_first_view.is(':checked'));
|
||||
} else {
|
||||
|
@ -492,6 +517,10 @@ function updateProgressBar(data) {
|
|||
// Add the file to localStorage
|
||||
addItem(data.name, url, data.size, del_at_first_view, created_at, delay, data.short, data.token);
|
||||
|
||||
if (isGuest && short !== null) {
|
||||
window.filesURLs.push(JSON.stringify({ name: data.name, short: data.short, url: url, size: data.size, created_at: created_at, delay: delay, token: data.token }));
|
||||
}
|
||||
|
||||
// Upload next file
|
||||
window.fc++;
|
||||
i++;
|
||||
|
@ -506,6 +535,9 @@ function updateProgressBar(data) {
|
|||
if ($('#zip-files').is(':checked')) {
|
||||
$('label[for="zip-files"]').click();
|
||||
}
|
||||
if (isGuest) {
|
||||
sendFilesURLs();
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
|
@ -522,6 +554,9 @@ function updateProgressBar(data) {
|
|||
}
|
||||
} else {
|
||||
addAlertOnFile(data.msg, i, delay, del_at_first_view);
|
||||
if (isGuest) {
|
||||
sendFilesURLs();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,6 +22,15 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% }
|
||||
% if (stash('invitation')) {
|
||||
<div class="col s12">
|
||||
<div class="card blue">
|
||||
<div class="card-content white-text">
|
||||
<strong><%= l('The link(s) of your file(s) will automatically be sent by mail to %1 (%2)', stash('invitation')->ldap_user, stash('invitation')->ldap_user_mail) %></strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% }
|
||||
<div class="col s12 hiddendiv" id="not-enough-entropy">
|
||||
<div class="card pink">
|
||||
|
@ -71,12 +80,12 @@
|
|||
<%= l('Files deleted at first download') %>
|
||||
</p>
|
||||
% }
|
||||
<p class="col s12 m6 text-left<%= ' hiddendiv' if $self->config('force_burn_after_reading') %>">
|
||||
<p class="col s12 m6 text-left<%= ' hiddendiv' if (config('force_burn_after_reading') || stash('invitation')) %>">
|
||||
<input
|
||||
type="checkbox"
|
||||
id="first-view"
|
||||
data-checked="<%= 'data-checked' if $self->config('force_burn_after_reading') %>"
|
||||
<%= 'disabled="disabled"' if $self->config('force_burn_after_reading') %>
|
||||
data-checked="<%= 'data-checked' if config('force_burn_after_reading') %>"
|
||||
<%= 'disabled="disabled"' if config('force_burn_after_reading') %>
|
||||
>
|
||||
<label for="first-view"><%= l('Delete at first download?') %></label>
|
||||
</p>
|
||||
|
@ -91,7 +100,7 @@
|
|||
<label for="zip-files"><%= l('Create a zip archive with the files before uploading?') %></label>
|
||||
</p>
|
||||
</div>
|
||||
% if (config('allow_pwd_on_files')) {
|
||||
% if (config('allow_pwd_on_files') && (!stash('invitation'))) {
|
||||
<div class="col s12 m6">
|
||||
<div class="input-field">
|
||||
<input type="password" id="file_pwd" placeholder="<%= l('Password') %>" class="validate" autocomplete="off">
|
||||
|
@ -145,7 +154,11 @@
|
|||
</ul>
|
||||
</div>
|
||||
%= include 'delays'
|
||||
% if (defined stash('invitation')) {
|
||||
%= javascript '/partial/index.js?token=' . stash('invitation')->token
|
||||
% } else {
|
||||
%= javascript '/partial/index.js'
|
||||
% }
|
||||
%= javascript '/js/sjcl.js'
|
||||
%= javascript '/js/moment-with-locales.min.js'
|
||||
%= javascript '/js/filesize.min.js'
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:
|
||||
|
||||
% if (stash('expired_or_deleted_invitation')) {
|
||||
<div class="col s12">
|
||||
<div class="card pink">
|
||||
<div class="card-content white-text">
|
||||
<strong><%= l('Sorry, your invitation has expired or has been deleted.') %></strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% }
|
||||
% if (stash('invitation_not_found')) {
|
||||
<div class="col s12">
|
||||
<div class="card pink">
|
||||
<div class="card-content white-text">
|
||||
<strong><%= l('Sorry, the invitation doesn’t exist. Are you sure you are on the right URL?') %></strong>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% }
|
|
@ -0,0 +1,51 @@
|
|||
% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:
|
||||
|
||||
% if (scalar(@{$self->stash('fails')})) {
|
||||
<div class="col s12">
|
||||
<div class="card pink">
|
||||
<div class="card-content white-text">
|
||||
% for my $msg (@{$self->stash('fails')}) {
|
||||
<strong><%= $msg %></strong>
|
||||
% }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% }
|
||||
% if (scalar(@{$self->stash('success')})) {
|
||||
<div class="col s12">
|
||||
<div class="card blue">
|
||||
<div class="card-content white-text">
|
||||
% for my $msg (@{$self->stash('success')}) {
|
||||
<strong><%== $msg %></strong>
|
||||
% }
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
% }
|
||||
|
||||
<form class="row" method="post">
|
||||
<h1><%= l('Invite a guest') %></h1>
|
||||
<div class="margin-bottom-35">
|
||||
<p>
|
||||
<%= l('You can invite someone to send you files through this Lufi instance even if they don’t have an account on it.') %>
|
||||
</p>
|
||||
% if (stash('send_with_user_email')) {
|
||||
<p>
|
||||
<%= l('The invitation mail will be send from your email address (%1).', stash('user_mail')) %>
|
||||
</p>
|
||||
% }
|
||||
</div>
|
||||
<div class="input-field">
|
||||
<label for="guest_mail">
|
||||
<%= l('Email address of your guest') %>
|
||||
</label>
|
||||
<input id="guest_mail" name="guest_mail" type="email" placeholder="nami@example.org" required>
|
||||
</div>
|
||||
<div class="input-field">
|
||||
<label for="expire_at">
|
||||
<%= l('How many days would you like the invitation to be valid?') %>
|
||||
</label>
|
||||
<input id="expire_at" name="expire_at" type="number" min="1" max="<%= stash('max_expire_at') %>" step="1" value="<%= stash('max_expire_at') %>" required>
|
||||
</div>
|
||||
<button class="btn waves-effect waves-light" type="submit"><%= l('Send the invitation') %></button>
|
||||
</form>
|
|
@ -0,0 +1,15 @@
|
|||
% # vim:set sw=4 ts=4 sts=4 ft=mail.epl expandtab:
|
||||
% stash subject => l('%1 invites you to send him/her files', stash('ldap_user'));
|
||||
|
||||
%= l('Hello,')
|
||||
|
||||
%= l('%1 invites you to send him/her files through Lufi.', stash('ldap_user'))
|
||||
|
||||
%= l('Click on the following URL to upload files on Lufi:')
|
||||
%== stash('url')
|
||||
|
||||
%= l('The links of your file(s) will automatically be send by mail to %1.', stash('ldap_user'))
|
||||
|
||||
%= l('This invitation is valid until %1.', stash('expires'))
|
||||
|
||||
%= l('Regards.')
|
|
@ -0,0 +1,87 @@
|
|||
% # vim:set sw=4 ts=4 sts=4 ft=html.epl expandtab:
|
||||
% use Number::Bytes::Human qw(format_bytes);
|
||||
% use Date::Format;
|
||||
|
||||
<h2><%= l('My invitations') %></h2>
|
||||
<hr>
|
||||
|
||||
<p>
|
||||
<%= l('Rows in purple mean that the invitations have expired.') %>
|
||||
</p>
|
||||
<div class="invitations-buttons">
|
||||
<a href="#" id="invertSelection" class="btn left-mg cyan"><%= l('Invert selection') %></a>
|
||||
<a href="#" id="toggleHidden" class="btn left-mg cyan"><%= l('Show hidden invitations') %></a>
|
||||
<a href="#" id="deleteInvit" class="btn left-mg cyan disabled" disabled><%= l('Delete') %></a>
|
||||
<a href="#" id="resendMail" class="btn left-mg cyan disabled" disabled><%= l('Resend invitation mail') %></a>
|
||||
<a href="#" id="toggleVisibility" class="btn left-mg cyan disabled" disabled><%= l('Toggle visibility') %></a>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<table class="responsive-table highlight">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="center-align"> </th>
|
||||
<th class="center-align"><%= l('Guest mail') %></th>
|
||||
<th class="center-align"><%= l('URL') %></th>
|
||||
<th class="center-align"><%= l('Created at') %></th>
|
||||
<th class="center-align"><%= l('Expire at') %></th>
|
||||
<th class="center-align"><%= l('Files sent at') %></th>
|
||||
<th class="center-align"> </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="myInvitations" data-visibility="hidden">
|
||||
% my $time = time;
|
||||
% $invitations->each(sub {
|
||||
% my ($e, $num) = @_;
|
||||
% return if $e->deleted;
|
||||
% my $class = '';
|
||||
% $class = 'purple lighten-4' unless $e->is_valid;
|
||||
% $class .= ' hide' unless $e->show_in_list;
|
||||
<tr id="row-<%= $e->token %>" class="<%= $class %>" data-visibility="<%= ($e->show_in_list) ? 1 : 0 %>">
|
||||
<td>
|
||||
<input type="checkbox" id="<%= $e->token %>" data-checked="">
|
||||
<label for="<%= $e->token %>" hidden></label>
|
||||
|
||||
% unless ($e->show_in_list) {
|
||||
<i class="mdi-navigation-cancel" title="<%= l('This invitation is normally hidden') %>"></i>
|
||||
% }
|
||||
</td>
|
||||
<td><%= $e->guest_mail %></td>
|
||||
<td><%= url_for('guest', token => $e->token)->to_abs %></td>
|
||||
<td><%= time2str(l('%A %d %B %Y at %T'), $e->created_at) %></td>
|
||||
<td id="expire-<%= $e->token %>"><%= time2str(l('%A %d %B %Y at %T'), $e->expire_at) %></td>
|
||||
<td><%= time2str(l('%A %d %B %Y at %T'), $e->files_sent_at) if $e->files_sent_at %></td>
|
||||
<td>
|
||||
% if ($e->files) {
|
||||
<a href="#files-info"
|
||||
data-files="<%= $e->files %>"
|
||||
data-token="<%= $e->token %>"
|
||||
data-guest="<%= $e->guest_mail %>"
|
||||
class="btn left-mg cyan waves-effect waves-light modal-trigger prefix">
|
||||
<%= l('Files') %>
|
||||
</a>
|
||||
% }
|
||||
</td>
|
||||
</tr>
|
||||
% });
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div id="files-info" class="modal">
|
||||
<div class="modal-content">
|
||||
<h1 class="small-h1"></h1>
|
||||
<div class="text-left">
|
||||
<ul id="files-ul">
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<a href="#!" class="modal-action modal-close waves-effect waves-green btn-flat"><%= l('Close') %></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
%= javascript '/partial/invitations.js'
|
||||
%= javascript '/js/lufi-list-invitations.js'
|
||||
%= javascript '/js/moment-with-locales.min.js'
|
||||
%= javascript '/js/filesize.min.js'
|
|
@ -0,0 +1,22 @@
|
|||
% # vim:set sw=4 ts=4 sts=4 ft=mail.epl expandtab:
|
||||
% use Number::Bytes::Human qw(format_bytes);
|
||||
% use Date::Format;
|
||||
% stash subject => l('%1 have send you files', stash('invitation')->guest_mail);
|
||||
|
||||
%= l('Hello %1,', ucfirst(stash('invitation')->ldap_user))
|
||||
|
||||
%= l('%1 used your invitation to send you files:', stash('invitation')->guest_mail)
|
||||
|
||||
% stash('files')->each(sub {
|
||||
% my ($e, $num) = @_;
|
||||
%= l('— %1 (%2), that will expire on %3', $e->{name}, format_bytes($e->{size}), time2str(l('%A %d %B %Y at %T'), $e->{created_at} + $e->{delay} * 86400))
|
||||
%= ' '.$e->{url}
|
||||
% });
|
||||
|
||||
% if (config('invitations')->{'save_files_url_in_db'} && stash('already_notified')) {
|
||||
%= l('NB: this list includes the list of files that have already been sent to you.')
|
||||
|
||||
% }
|
||||
%= l('Regards,')
|
||||
--
|
||||
Lufi
|
|
@ -32,6 +32,10 @@
|
|||
% if ((!defined(config('ldap')) && !defined(config('htpasswd'))) || is_user_authenticated()) {
|
||||
<li<%== ' class="active"' if (current_route eq 'index') %>><a href="<%= url_for('/') %>"><%= l('Upload files') %></a></li>
|
||||
<li<%== ' class="active"' if (current_route eq 'files') %>><a href="<%= url_for('/files') %>"><%= l('My files') %></a></li>
|
||||
% if (defined $self->config('ldap') && defined $self->config('invitations')) {
|
||||
<li<%== ' class="active"' if (current_route eq 'invite') %>><a href="<%= url_for('/invite') %>"><%= l('Invite a guest') %></a></li>
|
||||
<li<%== ' class="active"' if (current_route eq 'invite/list') %>><a href="<%= url_for('/invite/list') %>"><%= l('My invitations') %></a></li>
|
||||
% }
|
||||
% } else {
|
||||
<li><a href="<%= url_for('/login') %>"><%= l('Signin') %></a></li>
|
||||
% }
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
</div>
|
||||
</div>
|
||||
%= csrf_field
|
||||
<input name="redirect" value="<%= stash('redirect') %>" type="hidden">
|
||||
<div class="col s8 m8 offset-s2 offset-m2">
|
||||
<button class="btn waves-effect waves-light" type="submit" name="action">
|
||||
<%= l('Signin') %>
|
||||
|
|
|
@ -29,3 +29,10 @@ var i18n = {
|
|||
wsProblem: '<%= l('Websocket communication error') %>',
|
||||
};
|
||||
var maxSize = <%= config('max_file_size') || 0 %>;
|
||||
|
||||
% if (stash('token')) {
|
||||
var isGuest = true;
|
||||
var sendFilesURLsURL = '<%= url_for('guest_send_mail', token => stash('token'))->to_abs() %>';
|
||||
% } else {
|
||||
var isGuest = false;
|
||||
% }
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
% # vim:set sts=4 sw=4 ts=4 ft=javascript expandtab:
|
||||
var i18n = {
|
||||
confirmDeleteInvit: '<%= l('Are you sure you want to delete the selected invitations?') %>',
|
||||
confirmResendMail: '<%= l('Are you sure you want to resend the invitation mail for the selected invitations?') %>',
|
||||
expiration: '<%= l('expires on XXX') %>',
|
||||
hiddenMark: '<i class="mdi-navigation-cancel" title="<%= l('This invitation is normally hidden') %>"></i>',
|
||||
hideText: '<%= l('Hide hidden invitations') %>',
|
||||
listFiles: '<%= l('Files sent in invitation XX1 by XX2') %>',
|
||||
showText: '<%= l('Show hidden invitations') %>'
|
||||
};
|
||||
|
||||
var deleteURL = '<%= url_for('invite_list_delete') %>';
|
||||
var resendURL = '<%= url_for('invite_list_resend') %>';
|
||||
var toggleURL = '<%= url_for('invite_list_visibility') %>';
|
Loading…
Reference in New Issue