Adding endpoint to create applications.
This commit is contained in:
parent
16ac140f9d
commit
85aea0378c
@ -17,6 +17,8 @@ sub startup {
|
||||
# Router
|
||||
my $r = $self->routes;
|
||||
$r->post('/developer')->to('developer#post');
|
||||
$r->post('/developer/#identifier/application')
|
||||
->to('application#developer_application_post');
|
||||
}
|
||||
|
||||
sub peace_config {
|
||||
|
97
lib/Peace/Controller/Application.pm
Normal file
97
lib/Peace/Controller/Application.pm
Normal file
@ -0,0 +1,97 @@
|
||||
package Peace::Controller::Application;
|
||||
|
||||
use Mojo::Base 'Mojolicious::Controller';
|
||||
|
||||
use v5.30.0;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Peace;
|
||||
use Peace::Swagger;
|
||||
use Peace::DB;
|
||||
use Peace::DAO::Developer;
|
||||
use Peace::Model::Application;
|
||||
use Peace::DAO::Application;
|
||||
|
||||
sub developer_application_post {
|
||||
my $self = shift;
|
||||
my $json = $self->req->json;
|
||||
my $peace = Peace->new;
|
||||
my $config = $peace->peace_config;
|
||||
my $dbh = Peace::DB->dbh( config => $config );
|
||||
my $swagger = Peace::Swagger->new;
|
||||
my $headers = $self->req->headers->to_hash;
|
||||
unless ( defined $json ) {
|
||||
$self->render( text => 'body is not a json', status => '400' );
|
||||
return;
|
||||
}
|
||||
my $spec = $swagger->developer_application_post;
|
||||
eval {
|
||||
$swagger->validate_request(
|
||||
json => $json,
|
||||
stash => $self->stash,
|
||||
headers => $headers,
|
||||
spec => $spec,
|
||||
);
|
||||
};
|
||||
if ($@) {
|
||||
$self->render( text => $@, status => '400' );
|
||||
return;
|
||||
}
|
||||
my $api_key = $headers->{api_key};
|
||||
my $identifier = $self->stash->{identifier};
|
||||
my $developer_dao = Peace::DAO::Developer->new( dbh => $dbh );
|
||||
my $developer = $developer_dao->recover_by_identifier( identifier => $identifier );
|
||||
unless (defined $developer || $developer->login($api_key)) {
|
||||
$self->render( text => 'Incorrect user or password', status => 401 );
|
||||
return;
|
||||
}
|
||||
|
||||
unless ($developer->verified) {
|
||||
$self->render( text => 'Developer is still not verified', status => 401 );
|
||||
return;
|
||||
}
|
||||
my $application = Peace::Model::Application->new(%$json, verified => 0, developer => $developer);
|
||||
my $application_dao = Peace::DAO::Application->new( dbh => $dbh );
|
||||
eval {
|
||||
$application_dao->create( application => $application );
|
||||
};
|
||||
if ($@) {
|
||||
$self->render( status => 400, text => $@ );
|
||||
return;
|
||||
}
|
||||
$self->render( json => $application->to_json() );
|
||||
}
|
||||
1;
|
||||
=encoding utf8
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Peace::Controller::Application - Application's http endpoint.
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
# This object is used by mojolicious.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Peace::Controller::Application allows to interact using
|
||||
a json http api with the L<Peace::Model::Application> objects
|
||||
in Peace.
|
||||
|
||||
=head1 METHODS
|
||||
|
||||
Peace::Controller::Developer implements the following methods:
|
||||
|
||||
=head2 developer_application_post
|
||||
|
||||
# To be used by mojolicious.
|
||||
|
||||
Creates a application in db with the data given by the user.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Peace::Model::Application>, L<Peace::DAO::Application>
|
||||
|
||||
=cut
|
@ -28,7 +28,6 @@ sub post {
|
||||
my $json = $self->req->json;
|
||||
my $peace = Peace->new;
|
||||
my $config = $peace->peace_config;
|
||||
print Data::Dumper::Dumper $config;
|
||||
|
||||
my $dbh = Peace::DB->dbh( config => $config );
|
||||
my $developer_dao = Peace::DAO::Developer->new( dbh => $dbh );
|
||||
@ -37,7 +36,7 @@ sub post {
|
||||
return;
|
||||
}
|
||||
my $spec = $swagger->developer_post;
|
||||
eval { $swagger->validate_request( json => $json, spec => $spec, ); };
|
||||
eval { $swagger->validate_request( json => $json, stash => $self->stash, headers=>$self->req->headers->to_hash, spec => $spec, ); };
|
||||
if ($@) {
|
||||
$self->render( text => $@, status => '400' );
|
||||
return;
|
||||
|
@ -84,6 +84,9 @@ SELECT uuid, date_creation, secret_bcrypt, name, surname, email, stripe_id, coun
|
||||
FROM developers
|
||||
WHERE uuid = ?;
|
||||
EOF
|
||||
if (!defined $result) {
|
||||
die "No such developer $uuid.";
|
||||
}
|
||||
for my $key (keys %$result) {
|
||||
delete $result->{$key} unless defined $result->{$key};
|
||||
}
|
||||
@ -99,6 +102,40 @@ EOF
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
my $validator = validation_for(
|
||||
params => {
|
||||
identifier => { type => Str },
|
||||
}
|
||||
);
|
||||
|
||||
sub recover_by_identifier {
|
||||
my $self = shift;
|
||||
my %params = $validator->(@_);
|
||||
my $identifier =$params{identifier};
|
||||
my $dbh = $self->_dbh;
|
||||
my $result = $dbh->selectrow_hashref( <<'EOF', undef, $identifier );
|
||||
SELECT uuid, date_creation, secret_bcrypt, name, surname, email, stripe_id, country, verified
|
||||
FROM developers
|
||||
WHERE email = $1 or uuid::text = $1;
|
||||
EOF
|
||||
if (!defined $result) {
|
||||
die "No such developer $identifier.";
|
||||
}
|
||||
for my $key (keys %$result) {
|
||||
delete $result->{$key} unless defined $result->{$key};
|
||||
}
|
||||
|
||||
if ( exists $result->{date_creation} ) {
|
||||
my $iso8601 = DateTime::Format::Pg->new;
|
||||
$result->{date_creation} =
|
||||
$iso8601->parse_datetime( $result->{date_creation} );
|
||||
}
|
||||
|
||||
my $developer = Peace::Model::Developer->new(%$result);
|
||||
return $developer;
|
||||
}
|
||||
}
|
||||
sub _dbh {
|
||||
my $self = shift;
|
||||
return $self->{dbh};
|
||||
@ -153,6 +190,12 @@ in the passed object.
|
||||
|
||||
Recovers the L<Peace::Model::Developer> associated from an uuid from database.
|
||||
|
||||
=head2 recover_by_identifier
|
||||
|
||||
my $developer = $developer_dao->recover_by_identifier( identifier => $identifier );
|
||||
|
||||
Recovers the L<Peace::Model::Developer> associated from an identifier from database.
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
L<Peace::DB>, L<Peace::Model::Developer>
|
||||
|
@ -44,6 +44,24 @@ use DateTime;
|
||||
}
|
||||
}
|
||||
|
||||
sub to_json {
|
||||
my $self = shift;
|
||||
return {
|
||||
uuid => $self->uuid,
|
||||
date_creation => $self->date_creation,
|
||||
name => $self->name,
|
||||
description => $self->description,
|
||||
url => $self->url,
|
||||
developer => $self->developer->uuid,
|
||||
app_id => $self->app_id,
|
||||
price => $self->price,
|
||||
git_repo => $self->git_repo,
|
||||
flatpak_builder_file => $self->flatpak_builder_file,
|
||||
flatpak_repo => $self->flatpak_repo,
|
||||
verified => $self->verified,
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
my $validator =
|
||||
validation_for( params => [ { type => Str, optional => 1 } ] );
|
||||
@ -282,6 +300,12 @@ Peace::Model::Application implements the following instance methods:
|
||||
|
||||
Peace::Model::Application implements the following methods:
|
||||
|
||||
=head2 to_json
|
||||
|
||||
my $json = $application->to_json;
|
||||
|
||||
Retrieves the json representation of the application.
|
||||
|
||||
=head2 uuid
|
||||
|
||||
my $uuid = $application->uuid;
|
||||
|
@ -8,6 +8,7 @@ use Params::ValidationCompiler qw/validation_for/;
|
||||
use Types::Standard qw/Str InstanceOf Bool HasMethods/;
|
||||
|
||||
use DateTime;
|
||||
use Crypt::Bcrypt qw/bcrypt_check/;
|
||||
|
||||
use Peace::DAO::Application;
|
||||
|
||||
@ -48,6 +49,21 @@ sub to_json {
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
my $validator = validation_for(
|
||||
params => {
|
||||
secret => { type => Str },
|
||||
}
|
||||
);
|
||||
sub login {
|
||||
my $self = shift;
|
||||
my %params = $validator->(@_);
|
||||
my $secret = $params{secret};
|
||||
my $secret_bcrypt = $self->secret_bcrypt;
|
||||
return bcrypt_check($secret, $secret_bcrypt);
|
||||
}
|
||||
}
|
||||
|
||||
sub applications {
|
||||
my $self = shift;
|
||||
if ( !defined $self->{applications} ) {
|
||||
@ -248,6 +264,13 @@ Peace::Model::Developer implements the following methods:
|
||||
|
||||
Renders the developer in a json like structure.
|
||||
|
||||
=head2 login
|
||||
|
||||
my $logged = $developer->login( secret => $secret );
|
||||
|
||||
Returns true if the login is successful, false
|
||||
otherwise.
|
||||
|
||||
=head2 applications
|
||||
|
||||
my $applications = $developer->applications;
|
||||
|
@ -5,8 +5,10 @@ use v5.30.0;
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
use Data::Dumper;
|
||||
|
||||
use Params::ValidationCompiler qw/validation_for/;
|
||||
use Types::Standard qw/ArrayRef Str HashRef/;
|
||||
use Types::Standard qw/ArrayRef Str HashRef Int/;
|
||||
|
||||
use Const::Fast;
|
||||
use Email::Valid;
|
||||
@ -14,11 +16,29 @@ use Email::Valid;
|
||||
const my $EMAIL_VALIDATOR => Type::Tiny->new(
|
||||
name => 'Email',
|
||||
constraint => sub {
|
||||
return Email::Valid->address($_);
|
||||
return Email::Valid->rfc822($_);
|
||||
},
|
||||
message => sub { return "$_ is not an email address."; },
|
||||
);
|
||||
|
||||
const my $UUID_VALIDATOR => Type::Tiny->new(
|
||||
name => 'Uuid',
|
||||
constraint => sub {
|
||||
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
||||
},
|
||||
message => sub { return "$_ is not an uuid."; },
|
||||
);
|
||||
|
||||
const my $DEVELOPER_IDENTIFIER_VALIDATOR => Type::Tiny->new(
|
||||
name => 'DeveloperIdentifier',
|
||||
constraint => sub {
|
||||
return 1 if $EMAIL_VALIDATOR->check($_);
|
||||
return 1 if $UUID_VALIDATOR->check($_);
|
||||
return 0;
|
||||
},
|
||||
message => sub { return "$_ is not a developer identifier."; },
|
||||
);
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
my $self = bless {}, $class;
|
||||
@ -51,6 +71,7 @@ sub schema {
|
||||
my %params = $validator->(@_);
|
||||
my ($type) = $params{type};
|
||||
return Str if $type eq 'string';
|
||||
return Int if $type eq 'integer';
|
||||
die 'No such type declared.';
|
||||
}
|
||||
}
|
||||
@ -67,6 +88,8 @@ sub schema {
|
||||
my %params = $validator->(@_);
|
||||
my ($format) = $params{format};
|
||||
return $EMAIL_VALIDATOR if $format eq 'email';
|
||||
return $DEVELOPER_IDENTIFIER_VALIDATOR
|
||||
if $format eq 'developer_identifier';
|
||||
die "No such format declared.";
|
||||
}
|
||||
}
|
||||
@ -76,6 +99,11 @@ sub developer {
|
||||
"/developer" => {
|
||||
summary => "Allows to work with developers.",
|
||||
post => developer_post(),
|
||||
},
|
||||
"/developer/{identifier}/application" => {
|
||||
summary =>
|
||||
"Allows to work with applications with developer's permissions.",
|
||||
post => developer_application_post(),
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -85,6 +113,8 @@ sub developer {
|
||||
params => {
|
||||
json => { type => HashRef },
|
||||
spec => { type => HashRef },
|
||||
headers => { type => HashRef },
|
||||
stash => { type => HashRef },
|
||||
}
|
||||
);
|
||||
|
||||
@ -93,13 +123,25 @@ sub developer {
|
||||
my %params = $validator->(@_);
|
||||
my $json = $params{json};
|
||||
my $spec = $params{spec};
|
||||
my $headers = $params{headers};
|
||||
my $stash = $params{stash};
|
||||
my $spec_parameters = $spec->{parameters};
|
||||
my $validated_json_keys = {};
|
||||
|
||||
for my $parameter_spec (@$spec_parameters) {
|
||||
$self->_validate_parameter(
|
||||
parameter_spec => $parameter_spec,
|
||||
json => $json,
|
||||
headers => $headers,
|
||||
stash => $stash,
|
||||
validated_json_keys => $validated_json_keys,
|
||||
);
|
||||
|
||||
}
|
||||
## Avoiding fancy exploits.
|
||||
my @keys_to_remove =
|
||||
grep { !defined $validated_json_keys->{$_} } keys %$json;
|
||||
for my $key (@keys_to_remove) {
|
||||
delete $json->{$key};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -109,28 +151,41 @@ sub developer {
|
||||
params => {
|
||||
parameter_spec => { type => HashRef },
|
||||
json => { type => HashRef },
|
||||
headers => { type => HashRef },
|
||||
stash => { type => HashRef },
|
||||
validated_json_keys => { type => HashRef },
|
||||
}
|
||||
);
|
||||
|
||||
sub _validate_parameter {
|
||||
my $self = shift;
|
||||
my %params = $validator->(@_);
|
||||
my ( $parameter_spec, $json ) = @params{
|
||||
my ( $parameter_spec, $json, $headers, $stash, $validated_json_keys ) =
|
||||
@params{
|
||||
qw/
|
||||
parameter_spec json/
|
||||
parameter_spec json headers stash validated_json_keys/
|
||||
};
|
||||
my $name = $parameter_spec->{name};
|
||||
my $schema = $parameter_spec->{schema};
|
||||
my $required = $parameter_spec->{required};
|
||||
my $in = $parameter_spec->{in};
|
||||
my $type = $schema->{type};
|
||||
my $format = $schema->{format};
|
||||
my $pattern = $schema->{pattern};
|
||||
|
||||
if ( !exists $json->{$name} ) {
|
||||
my $value;
|
||||
if ( $in eq 'query' ) {
|
||||
$value = $json->{$name};
|
||||
$validated_json_keys->{$name} = 1;
|
||||
}
|
||||
print Data::Dumper::Dumper $headers;
|
||||
$value = $headers->{$name} if $in eq 'header';
|
||||
$value = $stash->{$name} if $in eq 'path';
|
||||
|
||||
if ( !defined $value ) {
|
||||
die "$name is required." if $required;
|
||||
return;
|
||||
}
|
||||
my $value = $json->{$name};
|
||||
|
||||
unless ( $self->_type_to_type_tiny( type => $type )->check($value) ) {
|
||||
die "$value is not $type.";
|
||||
@ -138,7 +193,7 @@ sub developer {
|
||||
|
||||
if ( defined $format ) {
|
||||
my $type_format = $self->_format_to_type_tiny( format => $format );
|
||||
unless ( $type_format->check( $json->{$name} ) ) {
|
||||
unless ( $type_format->check($value) ) {
|
||||
die "$value is not $format.";
|
||||
}
|
||||
}
|
||||
@ -149,6 +204,108 @@ sub developer {
|
||||
}
|
||||
}
|
||||
|
||||
sub developer_application_post {
|
||||
return {
|
||||
summary => 'Creates a application.',
|
||||
parameters => [
|
||||
{
|
||||
name => 'identifier',
|
||||
description => 'Developer\'s email or uuid.',
|
||||
required => 1,
|
||||
in => 'path',
|
||||
schema => {
|
||||
type => "string",
|
||||
format => "developer_identifier",
|
||||
}
|
||||
},
|
||||
{
|
||||
name => 'api_key',
|
||||
description => '<secret>',
|
||||
required => 1,
|
||||
in => 'header',
|
||||
schema => {
|
||||
type => "string",
|
||||
}
|
||||
},
|
||||
{
|
||||
name => 'name',
|
||||
description => 'Project\'s name.',
|
||||
required => 1,
|
||||
in => 'query',
|
||||
schema => {
|
||||
type => "string",
|
||||
}
|
||||
},
|
||||
{
|
||||
name => 'description',
|
||||
required => 1,
|
||||
in => 'query',
|
||||
description => 'Application\'s description.',
|
||||
schema => {
|
||||
type => "string",
|
||||
}
|
||||
},
|
||||
{
|
||||
name => 'url',
|
||||
required => 1,
|
||||
in => 'query',
|
||||
description => 'Project\'s url.',
|
||||
pattern => '^https?://',
|
||||
schema => {
|
||||
type => "string",
|
||||
}
|
||||
},
|
||||
{
|
||||
name => 'price',
|
||||
required => 1,
|
||||
in => 'query',
|
||||
description => 'Price in dollar cents.',
|
||||
schema => {
|
||||
type => "integer",
|
||||
}
|
||||
},
|
||||
{
|
||||
name => 'git_repo',
|
||||
required => 1,
|
||||
in => 'query',
|
||||
description => 'Project\'s git repository.',
|
||||
schema => {
|
||||
type => "string",
|
||||
pattern => 'https?://.*'
|
||||
}
|
||||
},
|
||||
{
|
||||
name => 'app_id',
|
||||
required => 1,
|
||||
in => 'query',
|
||||
description => 'Project\'s application id in flatpak format.',
|
||||
schema => {
|
||||
type => "string",
|
||||
}
|
||||
},
|
||||
{
|
||||
name => 'flatpak_builder_file',
|
||||
required => 1,
|
||||
in => 'query',
|
||||
description => 'Project\'s path to the flatpak builder file.',
|
||||
schema => {
|
||||
type => "string",
|
||||
}
|
||||
},
|
||||
{
|
||||
name => 'flatpak_repo',
|
||||
required => 1,
|
||||
in => 'query',
|
||||
description =>
|
||||
'Flatpak repo to be attached to the .flatpak file.',
|
||||
schema => {
|
||||
type => "string",
|
||||
}
|
||||
}
|
||||
]
|
||||
};
|
||||
}
|
||||
|
||||
sub developer_post {
|
||||
return {
|
||||
summary => 'Creates a developer',
|
||||
@ -274,9 +431,16 @@ L<Peace::Model::Developer> object.
|
||||
|
||||
=head2 developer_post
|
||||
|
||||
my $developer_post = $swagger->developer_post
|
||||
my $developer_post = $swagger->developer_post;
|
||||
|
||||
Returns the schema of the post request
|
||||
to the /developer enpoint.
|
||||
|
||||
=head2 developer_application_post
|
||||
|
||||
my $developer_application_post = $swagger->developer_application_post;
|
||||
|
||||
Returns the schema of the post request
|
||||
to the /developer/:identifier/application endpoint.
|
||||
|
||||
=cut
|
||||
|
Loading…
Reference in New Issue
Block a user