Add PostgreSQL support
This commit is contained in:
parent
d5395f4296
commit
18499a1106
|
@ -2,6 +2,7 @@ Revision history for Lufi
|
|||
|
||||
0.02 2017-?
|
||||
- Database abstraction layer
|
||||
- PostgreSQL support
|
||||
- IE 11 and Edge support
|
||||
- Fix encoding error (#83)
|
||||
- Htpassword authentication support
|
||||
|
|
|
@ -106,9 +106,9 @@ sub new {
|
|||
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(@_);
|
||||
} elsif ($dbtype eq 'postgresql') {
|
||||
use Lufi::DB::File::Pg;
|
||||
$c = Lufi::DB::File::Pg->new(@_);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,177 @@
|
|||
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
|
||||
package Lufi::DB::File::Pg;
|
||||
use Mojo::Base 'Lufi::DB::File';
|
||||
use Mojo::File;
|
||||
use Mojo::Collection 'c';
|
||||
use Lufi::DB::Slice;
|
||||
|
||||
has 'record' => 0;
|
||||
|
||||
sub new {
|
||||
my $c = shift;
|
||||
|
||||
$c = $c->SUPER::new(@_);
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
sub write {
|
||||
my $c = shift;
|
||||
|
||||
if ($c->record) {
|
||||
$c->app->pg->db->query('UPDATE files SET short = ?, deleted = ?, mediatype = ?, filename = ?, filesize = ?, counter = ?, delete_at_first_view = ?, delete_at_day = ?, created_at = ?, created_by = ?, last_access_at = ?, mod_token = ?, nbslices = ?, complete = ?, passwd = ? WHERE short = ?', $c->short, $c->deleted, $c->mediatype, $c->filename, $c->filesize, $c->counter, $c->delete_at_first_view, $c->delete_at_day, $c->created_at, $c->created_by, $c->last_access_at, $c->mod_token, $c->nbslices, $c->complete, $c->passwd, $c->short);
|
||||
} else {
|
||||
$c->app->pg->db->query('INSERT INTO files (short, deleted, mediatype, filename, filesize, counter, delete_at_first_view, delete_at_day, created_at, created_by, last_access_at, mod_token, nbslices, complete, passwd) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)', $c->short, $c->deleted, $c->mediatype, $c->filename, $c->filesize, $c->counter, $c->delete_at_first_view, $c->delete_at_day, $c->created_at, $c->created_by, $c->last_access_at, $c->mod_token, $c->nbslices, $c->complete, $c->passwd);
|
||||
$c->record(1);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
sub count_empty {
|
||||
my $c = shift;
|
||||
|
||||
return $c->app->pg->db->query('SELECT count(short) FROM files WHERE created_at IS NULL')->hashes->first->{count};
|
||||
}
|
||||
|
||||
sub already_exists {
|
||||
my $c = shift;
|
||||
my $short = shift;
|
||||
|
||||
return $c->app->pg->db->query('SELECT count(short) FROM files WHERE short = ?', $short)->hashes->first->{count};
|
||||
}
|
||||
|
||||
sub get_empty {
|
||||
my $c = shift;
|
||||
|
||||
my $r = $c->app->pg->db->query('SELECT * FROM files WHERE created_at IS NULL')->hashes->shuffle->first;
|
||||
|
||||
return $c->_slurp($r)->created_at(time)->write;
|
||||
}
|
||||
|
||||
sub get_stats {
|
||||
my $c = shift;
|
||||
|
||||
my $files = $c->app->pg->db->query('SELECT count(short) FROM files WHERE created_at IS NOT null AND deleted = 0')->hashes->first->{count};
|
||||
my $deleted = $c->app->pg->db->query('SELECT count(short) FROM files WHERE created_at IS NOT null AND deleted = 1')->hashes->first->{count};
|
||||
my $empty = $c->app->pg->db->query('SELECT count(short) FROM files WHERE created_at IS null')->hashes->first->{count};
|
||||
|
||||
return { files => $files, deleted => $deleted, empty => $empty };
|
||||
}
|
||||
|
||||
sub from_short {
|
||||
my $c = shift;
|
||||
my $short = shift;
|
||||
|
||||
my $r = $c->app->pg->db->query('SELECT * FROM files WHERE short = ?', $short)->hashes;
|
||||
|
||||
if ($r->size) {
|
||||
return $c->_slurp($r->first)->record(1);
|
||||
} else {
|
||||
return undef;
|
||||
}
|
||||
}
|
||||
|
||||
sub get_oldest_undeleted_files {
|
||||
my $c = shift;
|
||||
my $num = shift;
|
||||
|
||||
my @files;
|
||||
my $records = $c->app->pg->db->query('SELECT * FROM files WHERE deleted = 0 ORDER BY created_at ASC LIMIT ?', $num)->hashes;
|
||||
$records->each(
|
||||
sub {
|
||||
my ($e, $num) = @_;
|
||||
my $i = Lufi::DB::File->new(app => $c->app);
|
||||
|
||||
push @files, $i->_slurp($e);
|
||||
}
|
||||
);
|
||||
|
||||
return c(@files);
|
||||
}
|
||||
|
||||
sub get_expired {
|
||||
my $c = shift;
|
||||
my $time = shift;
|
||||
|
||||
my @files;
|
||||
## Select only files expired since two days, to be sure that nobody is still downloading it
|
||||
my $records = $c->app->pg->db->query('SELECT * FROM files WHERE deleted = 0 AND ((delete_at_day + 2) * 86400) < (? - created_at) AND delete_at_day != 0', $time)->hashes;
|
||||
$records->each(
|
||||
sub {
|
||||
my ($e, $num) = @_;
|
||||
my $i = Lufi::DB::File->new(app => $c->app);
|
||||
|
||||
push @files, $i->_slurp($e);
|
||||
}
|
||||
);
|
||||
|
||||
return c(@files);
|
||||
}
|
||||
|
||||
sub get_no_longer_viewed {
|
||||
my $c = shift;
|
||||
my $time = shift;
|
||||
|
||||
my @files;
|
||||
my $records = $c->app->pg->db->query('SELECT * FROM files WHERE deleted = 0 AND last_access_at < ?', $time)->hashes;
|
||||
$records->each(
|
||||
sub {
|
||||
my ($e, $num) = @_;
|
||||
my $i = Lufi::DB::File->new(app => $c->app);
|
||||
|
||||
push @files, $i->_slurp($e);
|
||||
}
|
||||
);
|
||||
|
||||
return c(@files);
|
||||
}
|
||||
|
||||
sub delete_creator_before {
|
||||
my $c = shift;
|
||||
my $separation = shift;
|
||||
|
||||
$c->app->pg->db->query('UPDATE files SET created_by = NULL WHERE created_by IS NOT NULL AND created_at < ?', $separation);
|
||||
}
|
||||
|
||||
sub _slurp {
|
||||
my $c = shift;
|
||||
my $r = shift;
|
||||
|
||||
my $file;
|
||||
if (defined $r) {
|
||||
$file = $r;
|
||||
} else {
|
||||
my $files = $c->app->pg->db->query('SELECT * FROM files WHERE short = ?', $c->short)->hashes;
|
||||
|
||||
if ($files->size) {
|
||||
$file = $files->first;
|
||||
}
|
||||
}
|
||||
|
||||
if ($file) {
|
||||
$c->short($file->{short});
|
||||
$c->deleted($file->{deleted});
|
||||
$c->mediatype($file->{mediatype});
|
||||
$c->filename($file->{filename});
|
||||
$c->filesize($file->{filesize});
|
||||
$c->counter($file->{counter});
|
||||
$c->delete_at_first_view($file->{delete_at_first_view});
|
||||
$c->delete_at_day($file->{delete_at_day});
|
||||
$c->created_at($file->{created_at});
|
||||
$c->created_by($file->{created_by});
|
||||
$c->last_access_at($file->{last_access_at});
|
||||
$c->mod_token($file->{mod_token});
|
||||
$c->nbslices($file->{nbslices});
|
||||
$c->complete($file->{complete});
|
||||
$c->passwd($file->{passwd});
|
||||
|
||||
$c->record(1) unless $c->record;
|
||||
}
|
||||
|
||||
$c->slices(Lufi::DB::Slice->new(app => $c->app)->get_slices_of_file($c->short));
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
1;
|
|
@ -90,7 +90,7 @@ sub get_stats {
|
|||
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};
|
||||
return { files => $files, deleted => $deleted, empty => $empty };
|
||||
}
|
||||
|
||||
sub from_short {
|
||||
|
|
|
@ -62,9 +62,9 @@ sub new {
|
|||
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(@_);
|
||||
} elsif ($dbtype eq 'postgresql') {
|
||||
use Lufi::DB::Slice::Pg;
|
||||
$c = Lufi::DB::Slice::Pg->new(@_);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,73 @@
|
|||
# vim:set sw=4 ts=4 sts=4 ft=perl expandtab:
|
||||
package Lufi::DB::Slice::Pg;
|
||||
use Mojo::Base 'Lufi::DB::Slice';
|
||||
use Mojo::Collection 'c';
|
||||
|
||||
has 'record' => 0;
|
||||
|
||||
sub new {
|
||||
my $c = shift;
|
||||
|
||||
$c = $c->SUPER::new(@_);
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
sub write {
|
||||
my $c = shift;
|
||||
|
||||
if ($c->record) {
|
||||
$c->app->pg->db->query('UPDATE slices SET short = ?, j = ?, path = ? WHERE short = ? AND j = ?', $c->short, $c->j, $c->path, $c->short, $c->j);
|
||||
} else {
|
||||
$c->app->pg->db->query('INSERT INTO slices (short, j, path) VALUES (?, ?, ?)', $c->short, $c->j, $c->path);
|
||||
$c->record(1);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
sub get_slices_of_file {
|
||||
my $c = shift;
|
||||
my $short = shift;
|
||||
|
||||
my @slices;
|
||||
my $records = $c->app->pg->db->query('SELECT * FROM slices WHERE short = ? ORDER BY j ASC', $short)->hashes;
|
||||
$records->each(
|
||||
sub {
|
||||
my ($e, $num) = @_;
|
||||
my $i = Lufi::DB::Slice->new(app => $c->app);
|
||||
|
||||
push @slices, $i->_slurp($e);
|
||||
}
|
||||
);
|
||||
|
||||
return c(@slices);
|
||||
}
|
||||
|
||||
sub _slurp {
|
||||
my $c = shift;
|
||||
my $r = shift;
|
||||
|
||||
my $slice;
|
||||
if (defined $r) {
|
||||
$slice = $r;
|
||||
} else {
|
||||
my $slices = $c->app->pg->db->query('SELECT * FROM slices WHERE short = ? AND j = ?', $c->short, $c->j)->hashes;
|
||||
|
||||
if ($slices->size) {
|
||||
$slice = $slices->first;
|
||||
}
|
||||
}
|
||||
|
||||
if ($slice) {
|
||||
$c->short($slice->{short});
|
||||
$c->j($slice->{j});
|
||||
$c->path($slice->{path});
|
||||
|
||||
$c->record(1);
|
||||
}
|
||||
|
||||
return $c;
|
||||
}
|
||||
|
||||
1;
|
|
@ -8,20 +8,19 @@ sub register {
|
|||
my ($self, $app) = @_;
|
||||
|
||||
$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') {
|
||||
|
||||
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}) {
|
||||
$migrations->from_file('utilities/migrations_pg.sql')->migrate(0)->migrate(1);
|
||||
} else {
|
||||
$migrations->from_file('utilities/migrations_pg.sql')->migrate(1);
|
||||
}
|
||||
} elsif ($app->config('dbtype') eq 'sqlite') {
|
||||
# SQLite database migration if needed
|
||||
use Lufi::DB::SQLite;
|
||||
my $columns = Lufi::DB::SQLite::Files->table_info;
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
# 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 Lutim user
|
||||
# remember that it has to be in a directory writable by Lufi user
|
||||
# optional, default is lufi.db
|
||||
#db_path => 'lufi.db',
|
||||
|
||||
|
|
|
@ -18,9 +18,10 @@ CREATE TABLE IF NOT EXISTS files (
|
|||
);
|
||||
|
||||
CREATE TABLE IF NOT EXISTS slices (
|
||||
short text REFERENCES files(short) ON DELETE CASCADE,
|
||||
short text NOT NULL REFERENCES files(short) ON DELETE CASCADE,
|
||||
j integer NOT NULL,
|
||||
path text unique NOT NULL,
|
||||
constraint slice_short_j UNIQUE (short, j)
|
||||
);
|
||||
-- 1 down
|
||||
DROP TABLE slices;
|
||||
|
|
Loading…
Reference in New Issue