Change proof storage to have a settable folder
This commit is contained in:
parent
8c424c02d3
commit
4c5f27976c
8 changed files with 56 additions and 183 deletions
|
@ -3,9 +3,10 @@ package Pear::LocalLoop;
|
||||||
use Mojo::Base 'Mojolicious';
|
use Mojo::Base 'Mojolicious';
|
||||||
use Data::UUID;
|
use Data::UUID;
|
||||||
use Mojo::JSON;
|
use Mojo::JSON;
|
||||||
use Scalar::Util qw(looks_like_number);
|
|
||||||
use Pear::LocalLoop::Schema;
|
use Pear::LocalLoop::Schema;
|
||||||
use DateTime;
|
use DateTime;
|
||||||
|
use Mojo::Asset::File;
|
||||||
|
use Mojo::File qw/ path tempdir /;
|
||||||
|
|
||||||
has schema => sub {
|
has schema => sub {
|
||||||
my $c = shift;
|
my $c = shift;
|
||||||
|
@ -21,6 +22,7 @@ sub startup {
|
||||||
|
|
||||||
$self->plugin('Config', {
|
$self->plugin('Config', {
|
||||||
default => {
|
default => {
|
||||||
|
storage_path => tempdir,
|
||||||
sessionTimeSeconds => 60 * 60 * 24 * 7,
|
sessionTimeSeconds => 60 * 60 * 24 * 7,
|
||||||
sessionTokenJsonName => 'session_key',
|
sessionTokenJsonName => 'session_key',
|
||||||
sessionExpiresJsonName => 'sessionExpires',
|
sessionExpiresJsonName => 'sessionExpires',
|
||||||
|
@ -66,6 +68,29 @@ sub startup {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$self->helper( get_path_from_uuid => sub {
|
||||||
|
my $c = shift;
|
||||||
|
my $uuid = shift;
|
||||||
|
my ( $folder ) = $uuid =~ /(..)/;
|
||||||
|
return path($c->app->config->{storage_path}, $folder, $uuid);
|
||||||
|
});
|
||||||
|
|
||||||
|
$self->helper( store_file_from_upload => sub {
|
||||||
|
my $c = shift;
|
||||||
|
my $upload = shift;
|
||||||
|
my $uuid = Data::UUID->new->create_str;
|
||||||
|
my $path = $c->get_path_from_uuid( $uuid );
|
||||||
|
$path->dirname->make_path;
|
||||||
|
$upload->move_to( $path );
|
||||||
|
return $uuid;
|
||||||
|
});
|
||||||
|
|
||||||
|
$self->helper( get_file_from_uuid => sub {
|
||||||
|
my $c = shift;
|
||||||
|
my $uuid = shift;
|
||||||
|
return Mojo::Asset::File->new( path => $c->get_path_from_uuid( $uuid ) );
|
||||||
|
});
|
||||||
|
|
||||||
my $r = $self->routes;
|
my $r = $self->routes;
|
||||||
$r->get('/')->to('root#index');
|
$r->get('/')->to('root#index');
|
||||||
$r->post('/')->to('root#auth_login');
|
$r->post('/')->to('root#auth_login');
|
||||||
|
|
|
@ -92,7 +92,6 @@ sub post_admin_merge {
|
||||||
my $target_org = $valid_org_rs->find( $validation->param('target_organisation_id') );
|
my $target_org = $valid_org_rs->find( $validation->param('target_organisation_id') );
|
||||||
|
|
||||||
$c->copy_transactions_and_delete( $pending_org, $target_org );
|
$c->copy_transactions_and_delete( $pending_org, $target_org );
|
||||||
#FIXME This requires mutual exclusion.
|
|
||||||
|
|
||||||
return $c->render(
|
return $c->render(
|
||||||
json => {
|
json => {
|
||||||
|
@ -113,7 +112,7 @@ sub copy_transactions_and_delete {
|
||||||
'transactions', {
|
'transactions', {
|
||||||
buyeruserid_fk => $from_org_transaction->buyeruserid_fk,
|
buyeruserid_fk => $from_org_transaction->buyeruserid_fk,
|
||||||
valuemicrocurrency => $from_org_transaction->valuemicrocurrency,
|
valuemicrocurrency => $from_org_transaction->valuemicrocurrency,
|
||||||
proofimage => $from_org_transaction->proofimage,
|
proof_image => $from_org_transaction->proof_image,
|
||||||
timedatesubmitted => $from_org_transaction->timedatesubmitted,
|
timedatesubmitted => $from_org_transaction->timedatesubmitted,
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -113,12 +113,9 @@ sub post_upload {
|
||||||
return $c->api_validation_error if $validation->has_error;
|
return $c->api_validation_error if $validation->has_error;
|
||||||
|
|
||||||
my $transaction_value = $validation->param('transaction_value');
|
my $transaction_value = $validation->param('transaction_value');
|
||||||
|
my $upload = $validation->param('file');
|
||||||
|
|
||||||
my $file = $validation->param('file');
|
my $file = $c->store_file_from_upload( $upload );
|
||||||
|
|
||||||
my $ext = '.jpg';
|
|
||||||
my $uuid = Data::UUID->new->create_str;
|
|
||||||
my $filename = $uuid . $ext;
|
|
||||||
|
|
||||||
if ( $type == 1 ) {
|
if ( $type == 1 ) {
|
||||||
# Validated organisation
|
# Validated organisation
|
||||||
|
@ -126,44 +123,24 @@ sub post_upload {
|
||||||
buyeruserid_fk => $user->id,
|
buyeruserid_fk => $user->id,
|
||||||
sellerorganisationid_fk => $validation->param('organisation_id'),
|
sellerorganisationid_fk => $validation->param('organisation_id'),
|
||||||
valuemicrocurrency => $transaction_value,
|
valuemicrocurrency => $transaction_value,
|
||||||
proofimage => $filename,
|
proof_image => $file,
|
||||||
timedatesubmitted => DateTime->now,
|
timedatesubmitted => DateTime->now,
|
||||||
});
|
});
|
||||||
|
|
||||||
$file->move_to('images/' . $filename);
|
|
||||||
} elsif ( $type == 2 ) {
|
} elsif ( $type == 2 ) {
|
||||||
# Unvalidated Organisation
|
# Unvalidated Organisation
|
||||||
$c->schema->resultset('PendingTransaction')->create({
|
$c->schema->resultset('PendingTransaction')->create({
|
||||||
buyeruserid_fk => $user->id,
|
buyeruserid_fk => $user->id,
|
||||||
pendingsellerorganisationid_fk => $validation->param('organisation_id'),
|
pendingsellerorganisationid_fk => $validation->param('organisation_id'),
|
||||||
valuemicrocurrency => $transaction_value,
|
valuemicrocurrency => $transaction_value,
|
||||||
proofimage => $filename,
|
proof_image => $file,
|
||||||
timedatesubmitted => DateTime->now,
|
timedatesubmitted => DateTime->now,
|
||||||
});
|
});
|
||||||
|
|
||||||
$file->move_to('images/' . $filename);
|
|
||||||
} elsif ( $type == 3 ) {
|
} elsif ( $type == 3 ) {
|
||||||
my $organisation_name = $validation->param('organisation_name');
|
my $organisation_name = $validation->param('organisation_name');
|
||||||
my $street_name = $validation->param('street_name');
|
my $street_name = $validation->param('street_name');
|
||||||
my $town = $validation->param('town');
|
my $town = $validation->param('town');
|
||||||
my $postcode = $validation->param('postcode');
|
my $postcode = $validation->param('postcode');
|
||||||
|
|
||||||
my $fullAddress = "";
|
|
||||||
|
|
||||||
if ( defined $street_name && ! ($street_name =~ m/^\s*$/) ){
|
|
||||||
$fullAddress = $street_name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( defined $town && ! ($town =~ m/^\s*$/) ){
|
|
||||||
if ($fullAddress eq ""){
|
|
||||||
$fullAddress = $town;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
$fullAddress = $fullAddress . ", " . $town;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
my $pending_org = $c->schema->resultset('PendingOrganisation')->create({
|
my $pending_org = $c->schema->resultset('PendingOrganisation')->create({
|
||||||
submitted_by => $user,
|
submitted_by => $user,
|
||||||
submitted_at => DateTime->now,
|
submitted_at => DateTime->now,
|
||||||
|
@ -177,11 +154,9 @@ sub post_upload {
|
||||||
buyeruserid_fk => $user->id,
|
buyeruserid_fk => $user->id,
|
||||||
pendingsellerorganisationid_fk => $pending_org->id,
|
pendingsellerorganisationid_fk => $pending_org->id,
|
||||||
valuemicrocurrency => $transaction_value,
|
valuemicrocurrency => $transaction_value,
|
||||||
proofimage => $filename,
|
proof_image => $file,
|
||||||
timedatesubmitted => DateTime->now,
|
timedatesubmitted => DateTime->now,
|
||||||
});
|
});
|
||||||
|
|
||||||
$file->move_to('images/' . $filename);
|
|
||||||
}
|
}
|
||||||
return $self->render( json => {
|
return $self->render( json => {
|
||||||
success => Mojo::JSON->true,
|
success => Mojo::JSON->true,
|
||||||
|
|
|
@ -62,12 +62,9 @@ sub post_upload {
|
||||||
return $c->api_validation_error if $validation->has_error;
|
return $c->api_validation_error if $validation->has_error;
|
||||||
|
|
||||||
my $transaction_value = $validation->param('transaction_value');
|
my $transaction_value = $validation->param('transaction_value');
|
||||||
|
my $upload = $validation->param('file');
|
||||||
|
|
||||||
my $file = $validation->param('file');
|
my $file = $c->store_file_from_upload( $upload );
|
||||||
|
|
||||||
my $ext = '.jpg';
|
|
||||||
my $uuid = Data::UUID->new->create_str;
|
|
||||||
my $filename = $uuid . $ext;
|
|
||||||
|
|
||||||
if ( $type == 1 ) {
|
if ( $type == 1 ) {
|
||||||
# Validated organisation
|
# Validated organisation
|
||||||
|
@ -75,22 +72,18 @@ sub post_upload {
|
||||||
buyeruserid_fk => $user->id,
|
buyeruserid_fk => $user->id,
|
||||||
sellerorganisationid_fk => $validation->param('organisation_id'),
|
sellerorganisationid_fk => $validation->param('organisation_id'),
|
||||||
valuemicrocurrency => $transaction_value,
|
valuemicrocurrency => $transaction_value,
|
||||||
proofimage => $filename,
|
proof_image => $file,
|
||||||
timedatesubmitted => DateTime->now,
|
timedatesubmitted => DateTime->now,
|
||||||
});
|
});
|
||||||
|
|
||||||
$file->move_to('images/' . $filename);
|
|
||||||
} elsif ( $type == 2 ) {
|
} elsif ( $type == 2 ) {
|
||||||
# Unvalidated Organisation
|
# Unvalidated Organisation
|
||||||
$c->schema->resultset('PendingTransaction')->create({
|
$c->schema->resultset('PendingTransaction')->create({
|
||||||
buyeruserid_fk => $user->id,
|
buyeruserid_fk => $user->id,
|
||||||
pendingsellerorganisationid_fk => $validation->param('organisation_id'),
|
pendingsellerorganisationid_fk => $validation->param('organisation_id'),
|
||||||
valuemicrocurrency => $transaction_value,
|
valuemicrocurrency => $transaction_value,
|
||||||
proofimage => $filename,
|
proof_image => $file,
|
||||||
timedatesubmitted => DateTime->now,
|
timedatesubmitted => DateTime->now,
|
||||||
});
|
});
|
||||||
|
|
||||||
$file->move_to('images/' . $filename);
|
|
||||||
} elsif ( $type == 3 ) {
|
} elsif ( $type == 3 ) {
|
||||||
my $organisation_name = $validation->param('organisation_name');
|
my $organisation_name = $validation->param('organisation_name');
|
||||||
my $street_name = $validation->param('street_name');
|
my $street_name = $validation->param('street_name');
|
||||||
|
@ -110,11 +103,9 @@ sub post_upload {
|
||||||
buyeruserid_fk => $user->id,
|
buyeruserid_fk => $user->id,
|
||||||
pendingsellerorganisationid_fk => $pending_org->id,
|
pendingsellerorganisationid_fk => $pending_org->id,
|
||||||
valuemicrocurrency => $transaction_value,
|
valuemicrocurrency => $transaction_value,
|
||||||
proofimage => $filename,
|
proof_image => $file,
|
||||||
timedatesubmitted => DateTime->now,
|
timedatesubmitted => DateTime->now,
|
||||||
});
|
});
|
||||||
|
|
||||||
$file->move_to('images/' . $filename);
|
|
||||||
}
|
}
|
||||||
return $c->render( json => {
|
return $c->render( json => {
|
||||||
success => Mojo::JSON->true,
|
success => Mojo::JSON->true,
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
use utf8;
|
use utf8;
|
||||||
package Pear::LocalLoop::Schema;
|
package Pear::LocalLoop::Schema;
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader
|
|
||||||
# DO NOT MODIFY THE FIRST PART OF THIS FILE
|
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
|
@ -11,10 +8,4 @@ use base 'DBIx::Class::Schema';
|
||||||
|
|
||||||
__PACKAGE__->load_namespaces;
|
__PACKAGE__->load_namespaces;
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-02-24 17:32:21
|
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:JNwB+HEKyNyE5ZP1Br1pog
|
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom code or comments, and it will be preserved on regeneration
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -1,75 +1,18 @@
|
||||||
use utf8;
|
use utf8;
|
||||||
package Pear::LocalLoop::Schema::Result::PendingTransaction;
|
package Pear::LocalLoop::Schema::Result::PendingTransaction;
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader
|
|
||||||
# DO NOT MODIFY THE FIRST PART OF THIS FILE
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
Pear::LocalLoop::Schema::Result::PendingTransaction
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
use strict;
|
use strict;
|
||||||
use warnings;
|
use warnings;
|
||||||
|
|
||||||
use base 'DBIx::Class::Core';
|
use base 'DBIx::Class::Core';
|
||||||
|
|
||||||
=head1 COMPONENTS LOADED
|
__PACKAGE__->load_components( qw/
|
||||||
|
InflateColumn::DateTime
|
||||||
=over 4
|
InflateColumn::FS
|
||||||
|
/);
|
||||||
=item * L<DBIx::Class::InflateColumn::DateTime>
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
__PACKAGE__->load_components("InflateColumn::DateTime");
|
|
||||||
|
|
||||||
=head1 TABLE: C<PendingTransactions>
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
__PACKAGE__->table("PendingTransactions");
|
__PACKAGE__->table("PendingTransactions");
|
||||||
|
|
||||||
=head1 ACCESSORS
|
|
||||||
|
|
||||||
=head2 pendingtransactionid
|
|
||||||
|
|
||||||
data_type: 'integer'
|
|
||||||
is_auto_increment: 1
|
|
||||||
is_nullable: 0
|
|
||||||
|
|
||||||
=head2 buyeruserid_fk
|
|
||||||
|
|
||||||
data_type: 'integer'
|
|
||||||
is_foreign_key: 1
|
|
||||||
is_nullable: 0
|
|
||||||
|
|
||||||
=head2 pendingsellerorganisationid_fk
|
|
||||||
|
|
||||||
data_type: 'integer'
|
|
||||||
is_foreign_key: 1
|
|
||||||
is_nullable: 0
|
|
||||||
|
|
||||||
=head2 valuemicrocurrency
|
|
||||||
|
|
||||||
data_type: 'integer'
|
|
||||||
is_nullable: 0
|
|
||||||
|
|
||||||
=head2 proofimage
|
|
||||||
|
|
||||||
data_type: 'text'
|
|
||||||
is_nullable: 0
|
|
||||||
|
|
||||||
=head2 timedatesubmitted
|
|
||||||
|
|
||||||
data_type: 'integer'
|
|
||||||
is_nullable: 0
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
__PACKAGE__->add_columns(
|
__PACKAGE__->add_columns(
|
||||||
"pendingtransactionid",
|
"pendingtransactionid",
|
||||||
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
|
{ data_type => "integer", is_auto_increment => 1, is_nullable => 0 },
|
||||||
|
@ -79,48 +22,18 @@ __PACKAGE__->add_columns(
|
||||||
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
|
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
|
||||||
"valuemicrocurrency",
|
"valuemicrocurrency",
|
||||||
{ data_type => "integer", is_nullable => 0 },
|
{ data_type => "integer", is_nullable => 0 },
|
||||||
"proofimage",
|
"proof_image",
|
||||||
{ data_type => "text", is_nullable => 0 },
|
{
|
||||||
|
data_type => "text",
|
||||||
|
is_nullable => 0,
|
||||||
|
},
|
||||||
"timedatesubmitted",
|
"timedatesubmitted",
|
||||||
{ data_type => "datetime", is_nullable => 0 },
|
{ data_type => "datetime", is_nullable => 0 },
|
||||||
);
|
);
|
||||||
|
|
||||||
=head1 PRIMARY KEY
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item * L</pendingtransactionid>
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
__PACKAGE__->set_primary_key("pendingtransactionid");
|
__PACKAGE__->set_primary_key("pendingtransactionid");
|
||||||
|
|
||||||
=head1 UNIQUE CONSTRAINTS
|
|
||||||
|
|
||||||
=head2 C<proofimage_unique>
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item * L</proofimage>
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
__PACKAGE__->add_unique_constraint("proofimage_unique", ["proofimage"]);
|
|
||||||
|
|
||||||
=head1 RELATIONS
|
|
||||||
|
|
||||||
=head2 buyeruserid_fk
|
|
||||||
|
|
||||||
Type: belongs_to
|
|
||||||
|
|
||||||
Related object: L<Pear::LocalLoop::Schema::Result::User>
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
__PACKAGE__->belongs_to(
|
__PACKAGE__->belongs_to(
|
||||||
"buyeruserid_fk",
|
"buyeruserid_fk",
|
||||||
"Pear::LocalLoop::Schema::Result::User",
|
"Pear::LocalLoop::Schema::Result::User",
|
||||||
|
@ -128,14 +41,6 @@ __PACKAGE__->belongs_to(
|
||||||
{ is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
|
{ is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
|
||||||
);
|
);
|
||||||
|
|
||||||
=head2 pendingsellerorganisationid_fk
|
|
||||||
|
|
||||||
Type: belongs_to
|
|
||||||
|
|
||||||
Related object: L<Pear::LocalLoop::Schema::Result::PendingOrganisation>
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
__PACKAGE__->belongs_to(
|
__PACKAGE__->belongs_to(
|
||||||
"pendingsellerorganisationid_fk",
|
"pendingsellerorganisationid_fk",
|
||||||
"Pear::LocalLoop::Schema::Result::PendingOrganisation",
|
"Pear::LocalLoop::Schema::Result::PendingOrganisation",
|
||||||
|
@ -143,10 +48,4 @@ __PACKAGE__->belongs_to(
|
||||||
{ is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
|
{ is_deferrable => 0, on_delete => "NO ACTION", on_update => "NO ACTION" },
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
# Created by DBIx::Class::Schema::Loader v0.07046 @ 2017-02-24 17:32:21
|
|
||||||
# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:zwtxzfW5uB4FNA6mKdFOvg
|
|
||||||
|
|
||||||
|
|
||||||
# You can replace this text with custom code or comments, and it will be preserved on regeneration
|
|
||||||
1;
|
1;
|
||||||
|
|
|
@ -25,7 +25,10 @@ use base 'DBIx::Class::Core';
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
__PACKAGE__->load_components("InflateColumn::DateTime");
|
__PACKAGE__->load_components(qw/
|
||||||
|
InflateColumn::DateTime
|
||||||
|
InflateColumn::FS
|
||||||
|
/);
|
||||||
|
|
||||||
=head1 TABLE: C<Transactions>
|
=head1 TABLE: C<Transactions>
|
||||||
|
|
||||||
|
@ -79,8 +82,11 @@ __PACKAGE__->add_columns(
|
||||||
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
|
{ data_type => "integer", is_foreign_key => 1, is_nullable => 0 },
|
||||||
"valuemicrocurrency",
|
"valuemicrocurrency",
|
||||||
{ data_type => "integer", is_nullable => 0 },
|
{ data_type => "integer", is_nullable => 0 },
|
||||||
"proofimage",
|
"proof_image",
|
||||||
{ data_type => "text", is_nullable => 0 },
|
{
|
||||||
|
data_type => "text",
|
||||||
|
is_nullable => 0,
|
||||||
|
},
|
||||||
"timedatesubmitted",
|
"timedatesubmitted",
|
||||||
{ data_type => "datetime", is_nullable => 0 },
|
{ data_type => "datetime", is_nullable => 0 },
|
||||||
);
|
);
|
||||||
|
@ -97,20 +103,6 @@ __PACKAGE__->add_columns(
|
||||||
|
|
||||||
__PACKAGE__->set_primary_key("transactionid");
|
__PACKAGE__->set_primary_key("transactionid");
|
||||||
|
|
||||||
=head1 UNIQUE CONSTRAINTS
|
|
||||||
|
|
||||||
=head2 C<proofimage_unique>
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item * L</proofimage>
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
__PACKAGE__->add_unique_constraint("proofimage_unique", ["proofimage"]);
|
|
||||||
|
|
||||||
=head1 RELATIONS
|
=head1 RELATIONS
|
||||||
|
|
||||||
=head2 buyeruserid_fk
|
=head2 buyeruserid_fk
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
{
|
{
|
||||||
|
storage_path => 'images',
|
||||||
dsn => "dbi:SQLite:dbname=foodloop.db",
|
dsn => "dbi:SQLite:dbname=foodloop.db",
|
||||||
user => undef,
|
user => undef,
|
||||||
pass => undef,
|
pass => undef,
|
||||||
|
|
Reference in a new issue