Adding the first endpoint which allows to interact by http with the app.
The POST /developer endpoint is created using the openapi definition to validate the fields. This will allow a way to create endpoints and their doc automatically.
This commit is contained in:
parent
3d9724b144
commit
16ac140f9d
2
Build.PL
2
Build.PL
@ -21,6 +21,8 @@ my $build = Module::Build->new(
|
|||||||
'JSON' => 0,
|
'JSON' => 0,
|
||||||
'YAML' => 0,
|
'YAML' => 0,
|
||||||
'Capture::Tiny' => 0,
|
'Capture::Tiny' => 0,
|
||||||
|
'Email::Valid' => 0,
|
||||||
|
'Crypt::Bcrypt' => 0,
|
||||||
},
|
},
|
||||||
install_path => {
|
install_path => {
|
||||||
'templates' => "$HOME/.local/share/peace/template",
|
'templates' => "$HOME/.local/share/peace/template",
|
||||||
|
@ -16,16 +16,21 @@
|
|||||||
"prereqs" : {
|
"prereqs" : {
|
||||||
"runtime" : {
|
"runtime" : {
|
||||||
"requires" : {
|
"requires" : {
|
||||||
|
"Capture::Tiny" : "0",
|
||||||
|
"Crypt::Bcrypt" : "0",
|
||||||
"DBD::Mock" : "0",
|
"DBD::Mock" : "0",
|
||||||
"DBD::Pg" : "0",
|
"DBD::Pg" : "0",
|
||||||
"DBI" : "0",
|
"DBI" : "0",
|
||||||
"DateTime" : "0",
|
"DateTime" : "0",
|
||||||
"DateTime::Format::Pg" : "0",
|
"DateTime::Format::Pg" : "0",
|
||||||
|
"Email::Valid" : "0",
|
||||||
|
"JSON" : "0",
|
||||||
"Mojolicious" : "0",
|
"Mojolicious" : "0",
|
||||||
"Test::MockModule" : "0",
|
"Test::MockModule" : "0",
|
||||||
"Test::MockObject" : "0",
|
"Test::MockObject" : "0",
|
||||||
"Test::Most" : "0",
|
"Test::Most" : "0",
|
||||||
"Test::Pod::Coverage" : "0"
|
"Test::Pod::Coverage" : "0",
|
||||||
|
"YAML" : "0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -69,7 +69,7 @@ if ( !-e $config_path) {
|
|||||||
path ($config_path)->spew_utf8(encode_json $config);
|
path ($config_path)->spew_utf8(encode_json $config);
|
||||||
}
|
}
|
||||||
|
|
||||||
Peace::DB->dbh( config => Peace->new->config );
|
Peace::DB->dbh( config => Peace->new->peace_config );
|
||||||
@ARGV = ('daemon');
|
@ARGV = ('daemon');
|
||||||
|
|
||||||
# Start command line interface for application
|
# Start command line interface for application
|
||||||
|
@ -8,6 +8,9 @@
|
|||||||
<li>
|
<li>
|
||||||
<a href="lib/Peace.pm.html">Peace</a>
|
<a href="lib/Peace.pm.html">Peace</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="lib/Peace/Controller/Developer.pm.html">Peace::Controller::Developer</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="lib/Peace/Controller/User.pm.html">Peace::Controller::User</a>
|
<a href="lib/Peace/Controller/User.pm.html">Peace::Controller::User</a>
|
||||||
</li>
|
</li>
|
||||||
@ -44,6 +47,9 @@
|
|||||||
<li>
|
<li>
|
||||||
<a href="lib/Peace/Model/Release.pm.html">Peace::Model::Release</a>
|
<a href="lib/Peace/Model/Release.pm.html">Peace::Model::Release</a>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="lib/Peace/Swagger.pm.html">Peace::Swagger</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="lib/Peace/Test/Mock/Model/Application.pm.html">Peace::Test::Mock::Model::Application</a>
|
<a href="lib/Peace/Test/Mock/Model/Application.pm.html">Peace::Test::Mock::Model::Application</a>
|
||||||
</li>
|
</li>
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
<li><a href="#FUNCTIONS">FUNCTIONS</a>
|
<li><a href="#FUNCTIONS">FUNCTIONS</a>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="#startup">startup</a></li>
|
<li><a href="#startup">startup</a></li>
|
||||||
|
<li><a href="#peace_config">peace_config</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -42,6 +43,12 @@
|
|||||||
|
|
||||||
<p>For internal usage from Mojolicious.</p>
|
<p>For internal usage from Mojolicious.</p>
|
||||||
|
|
||||||
|
<h2 id="peace_config">peace_config</h2>
|
||||||
|
|
||||||
|
<pre><code>my $config = Peace->new->peace_config;</code></pre>
|
||||||
|
|
||||||
|
<p>Retrieves the config for the peace application.</p>
|
||||||
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
57
doc/lib/Peace/Controller/Developer.pm.html
Normal file
57
doc/lib/Peace/Controller/Developer.pm.html
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>Peace::Controller::Developer - Developer's http endpoint.</title>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
|
||||||
|
<link href="mailto:Alpine@build-edge-aarch64.nonet" rev="made" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul id="index">
|
||||||
|
<li><a href="#NAME">NAME</a></li>
|
||||||
|
<li><a href="#SYNOPSIS">SYNOPSIS</a></li>
|
||||||
|
<li><a href="#DESCRIPTION">DESCRIPTION</a></li>
|
||||||
|
<li><a href="#METHODS">METHODS</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#post">post</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="#SEE-ALSO">SEE ALSO</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h1 id="NAME">NAME</h1>
|
||||||
|
|
||||||
|
<p>Peace::Controller::Developer - Developer's http endpoint.</p>
|
||||||
|
|
||||||
|
<h1 id="SYNOPSIS">SYNOPSIS</h1>
|
||||||
|
|
||||||
|
<pre><code># This object is used by mojolicious.</code></pre>
|
||||||
|
|
||||||
|
<h1 id="DESCRIPTION">DESCRIPTION</h1>
|
||||||
|
|
||||||
|
<p>Peace::Controller::Developer allows to interact using a json http api with the <a href="../Model/Developer.pm.html">Peace::Model::Developer</a> objects in Peace.</p>
|
||||||
|
|
||||||
|
<h1 id="METHODS">METHODS</h1>
|
||||||
|
|
||||||
|
<p>Peace::Controller::Developer implements the following methods:</p>
|
||||||
|
|
||||||
|
<h2 id="post">post</h2>
|
||||||
|
|
||||||
|
<pre><code># To be used by mojolicious.</code></pre>
|
||||||
|
|
||||||
|
<p>Creates a Developer in db with the data given by the user.</p>
|
||||||
|
|
||||||
|
<h1 id="SEE-ALSO">SEE ALSO</h1>
|
||||||
|
|
||||||
|
<p><a href="../Model/Developer.pm.html">Peace::Model::Developer</a>, <a href="../DAO/Developer.pm.html">Peace::DAO::Developer</a></p>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
@ -22,6 +22,7 @@
|
|||||||
</li>
|
</li>
|
||||||
<li><a href="#METHODS">METHODS</a>
|
<li><a href="#METHODS">METHODS</a>
|
||||||
<ul>
|
<ul>
|
||||||
|
<li><a href="#to_json">to_json</a></li>
|
||||||
<li><a href="#applications">applications</a></li>
|
<li><a href="#applications">applications</a></li>
|
||||||
<li><a href="#uuid">uuid</a></li>
|
<li><a href="#uuid">uuid</a></li>
|
||||||
<li><a href="#date_creation">date_creation</a></li>
|
<li><a href="#date_creation">date_creation</a></li>
|
||||||
@ -79,6 +80,12 @@
|
|||||||
|
|
||||||
<p>Peace::Model::Developer implements the following methods:</p>
|
<p>Peace::Model::Developer implements the following methods:</p>
|
||||||
|
|
||||||
|
<h2 id="to_json">to_json</h2>
|
||||||
|
|
||||||
|
<pre><code>my $json = $developer->to_json;</code></pre>
|
||||||
|
|
||||||
|
<p>Renders the developer in a json like structure.</p>
|
||||||
|
|
||||||
<h2 id="applications">applications</h2>
|
<h2 id="applications">applications</h2>
|
||||||
|
|
||||||
<pre><code>my $applications = $developer->applications;</code></pre>
|
<pre><code>my $applications = $developer->applications;</code></pre>
|
||||||
|
90
doc/lib/Peace/Swagger.pm.html
Normal file
90
doc/lib/Peace/Swagger.pm.html
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
<?xml version="1.0" ?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<head>
|
||||||
|
<title>Peace::Swagger - OpenAPI definitions for the Peace API.</title>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type" />
|
||||||
|
<link href="mailto:Alpine@build-edge-aarch64.nonet" rev="made" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<ul id="index">
|
||||||
|
<li><a href="#NAME">NAME</a></li>
|
||||||
|
<li><a href="#SYNOPSIS">SYNOPSIS</a></li>
|
||||||
|
<li><a href="#DESCRIPTION">DESCRIPTION</a></li>
|
||||||
|
<li><a href="#INSTANCE-METHODS">INSTANCE METHODS</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#new">new</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<li><a href="#METHODS">METHODS</a>
|
||||||
|
<ul>
|
||||||
|
<li><a href="#schema">schema</a></li>
|
||||||
|
<li><a href="#validate_request">validate_request</a></li>
|
||||||
|
<li><a href="#developer">developer</a></li>
|
||||||
|
<li><a href="#developer_post">developer_post</a></li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h1 id="NAME">NAME</h1>
|
||||||
|
|
||||||
|
<p>Peace::Swagger - OpenAPI definitions for the Peace API.</p>
|
||||||
|
|
||||||
|
<h1 id="SYNOPSIS">SYNOPSIS</h1>
|
||||||
|
|
||||||
|
<p>my $swagger = Peace::Swagger->new;</p>
|
||||||
|
|
||||||
|
<p>my $spec = $swagger->schema;</p>
|
||||||
|
|
||||||
|
<h1 id="DESCRIPTION">DESCRIPTION</h1>
|
||||||
|
|
||||||
|
<p>This module aims to help in the programmatic description of all API endpoints in a way that makes possible to reuse those schemas in the code and in the documentation.</p>
|
||||||
|
|
||||||
|
<h1 id="INSTANCE-METHODS">INSTANCE METHODS</h1>
|
||||||
|
|
||||||
|
<p>Peace::Swagger implements the following instance methods:</p>
|
||||||
|
|
||||||
|
<h2 id="new">new</h2>
|
||||||
|
|
||||||
|
<p>my $swagger = Peace::Swagger->new;</p>
|
||||||
|
|
||||||
|
<p>Instances a Peace::Swagger.</p>
|
||||||
|
|
||||||
|
<h1 id="METHODS">METHODS</h1>
|
||||||
|
|
||||||
|
<p>Peace::Swagger implements the following methods:</p>
|
||||||
|
|
||||||
|
<h2 id="schema">schema</h2>
|
||||||
|
|
||||||
|
<pre><code>my $schema = $swagger->schema;</code></pre>
|
||||||
|
|
||||||
|
<p>Returns the complete openapi schema.</p>
|
||||||
|
|
||||||
|
<h2 id="validate_request">validate_request</h2>
|
||||||
|
|
||||||
|
<pre><code>$swagger->validate_request(json => $json, spec => $spec);</code></pre>
|
||||||
|
|
||||||
|
<p>Validates the spec for a specific endpoint say developer_post against the json got from the user and dies if the check is unsuccesful.</p>
|
||||||
|
|
||||||
|
<h2 id="developer">developer</h2>
|
||||||
|
|
||||||
|
<pre><code>my $developer_schema = $swagger->developer;</code></pre>
|
||||||
|
|
||||||
|
<p>Returns the schemas associated with the <a href="Model/Developer.pm.html">Peace::Model::Developer</a> object.</p>
|
||||||
|
|
||||||
|
<h2 id="developer_post">developer_post</h2>
|
||||||
|
|
||||||
|
<pre><code>my $developer_post = $swagger->developer_post</code></pre>
|
||||||
|
|
||||||
|
<p>Returns the schema of the post request to the /developer enpoint.</p>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
|
||||||
|
</html>
|
||||||
|
|
||||||
|
|
20
lib/Peace.pm
20
lib/Peace.pm
@ -8,18 +8,22 @@ use Mojo::Base 'Mojolicious';
|
|||||||
|
|
||||||
sub startup {
|
sub startup {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $home = $ENV{HOME};
|
|
||||||
|
|
||||||
# Load configuration from config file
|
my $config = $self->config;
|
||||||
my $config =
|
|
||||||
$self->plugin( JSONConfig => { file => "$home/.config/peace/peace.conf" } );
|
|
||||||
|
|
||||||
# Configure the application
|
# Configure the application
|
||||||
$self->secrets( $config->{secrets} );
|
$self->secrets( $config->{secrets} );
|
||||||
|
|
||||||
# Router
|
# Router
|
||||||
my $r = $self->routes;
|
my $r = $self->routes;
|
||||||
$r->post('/users')->to('user#post');
|
$r->post('/developer')->to('developer#post');
|
||||||
|
}
|
||||||
|
|
||||||
|
sub peace_config {
|
||||||
|
my $self = shift;
|
||||||
|
my $home = $ENV{HOME};
|
||||||
|
return $self->plugin(
|
||||||
|
JSONConfig => { file => "$home/.config/peace/peace.conf" } );
|
||||||
}
|
}
|
||||||
1;
|
1;
|
||||||
|
|
||||||
@ -46,4 +50,10 @@ Peace implements the following functions:
|
|||||||
|
|
||||||
For internal usage from Mojolicious.
|
For internal usage from Mojolicious.
|
||||||
|
|
||||||
|
=head2 peace_config
|
||||||
|
|
||||||
|
my $config = Peace->new->peace_config;
|
||||||
|
|
||||||
|
Retrieves the config for the peace application.
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
90
lib/Peace/Controller/Developer.pm
Normal file
90
lib/Peace/Controller/Developer.pm
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
package Peace::Controller::Developer;
|
||||||
|
|
||||||
|
use Mojo::Base 'Mojolicious::Controller';
|
||||||
|
|
||||||
|
use v5.30.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
use Const::Fast;
|
||||||
|
|
||||||
|
use Peace::Swagger;
|
||||||
|
use Crypt::Bcrypt qw/bcrypt/;
|
||||||
|
use Crypt::URandom qw/urandom/;
|
||||||
|
|
||||||
|
use Peace;
|
||||||
|
use Peace::DB;
|
||||||
|
|
||||||
|
use Peace::Model::Developer;
|
||||||
|
use Peace::DAO::Developer;
|
||||||
|
|
||||||
|
const my $swagger => Peace::Swagger->new;
|
||||||
|
|
||||||
|
sub post {
|
||||||
|
my $self = shift;
|
||||||
|
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 );
|
||||||
|
unless ( defined $json ) {
|
||||||
|
$self->render( text => 'body is not a json', status => '400' );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
my $spec = $swagger->developer_post;
|
||||||
|
eval { $swagger->validate_request( json => $json, spec => $spec, ); };
|
||||||
|
if ($@) {
|
||||||
|
$self->render( text => $@, status => '400' );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
my $secret = delete $json->{secret};
|
||||||
|
my $secret_bcrypt = bcrypt( $secret, '2b', 12, urandom(16) );
|
||||||
|
$json->{secret_bcrypt} = $secret_bcrypt;
|
||||||
|
$json->{verified} = 0;
|
||||||
|
my $developer = Peace::Model::Developer->new(%$json);
|
||||||
|
eval {
|
||||||
|
$developer_dao->create( developer => $developer );
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
|
$self->render( status => 400, text => $@ );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$self->render( json => $developer->to_json() );
|
||||||
|
}
|
||||||
|
1;
|
||||||
|
=encoding utf8
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Peace::Controller::Developer - Developer's http endpoint.
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
# This object is used by mojolicious.
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
Peace::Controller::Developer allows to interact using
|
||||||
|
a json http api with the L<Peace::Model::Developer> objects
|
||||||
|
in Peace.
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
Peace::Controller::Developer implements the following methods:
|
||||||
|
|
||||||
|
=head2 post
|
||||||
|
|
||||||
|
# To be used by mojolicious.
|
||||||
|
|
||||||
|
Creates a Developer in db with the data given by the user.
|
||||||
|
|
||||||
|
=head1 SEE ALSO
|
||||||
|
|
||||||
|
L<Peace::Model::Developer>, L<Peace::DAO::Developer>
|
||||||
|
|
||||||
|
=cut
|
@ -44,11 +44,20 @@ INSERT INTO developers (secret_bcrypt, name, surname, email, country, verified)
|
|||||||
VALUES (?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
RETURNING uuid;
|
RETURNING uuid;
|
||||||
EOF
|
EOF
|
||||||
my $result = $dbh->selectrow_hashref(
|
my $result;
|
||||||
|
eval {
|
||||||
|
$result = $dbh->selectrow_hashref(
|
||||||
$insert, undef, $developer->secret_bcrypt,
|
$insert, undef, $developer->secret_bcrypt,
|
||||||
$developer->name, $developer->surname, $developer->email,
|
$developer->name, $developer->surname, $developer->email,
|
||||||
$developer->country, $developer->verified
|
$developer->country, $developer->verified
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
if ($@) {
|
||||||
|
if ($@ =~ /duplicate key value/) {
|
||||||
|
die "Email already registered.";
|
||||||
|
}
|
||||||
|
die $@;
|
||||||
|
}
|
||||||
my $uuid = $result->{uuid};
|
my $uuid = $result->{uuid};
|
||||||
$developer->uuid($uuid);
|
$developer->uuid($uuid);
|
||||||
my $new_developer = $self->recover_by_uuid( uuid => $uuid );
|
my $new_developer = $self->recover_by_uuid( uuid => $uuid );
|
||||||
|
@ -30,7 +30,7 @@ my @migrations = (
|
|||||||
secret_bcrypt TEXT NOT NULL,
|
secret_bcrypt TEXT NOT NULL,
|
||||||
name TEXT NOT NULL,
|
name TEXT NOT NULL,
|
||||||
surname TEXT NOT NULL,
|
surname TEXT NOT NULL,
|
||||||
email TEXT NOT NULL,
|
email TEXT NOT NULL UNIQUE,
|
||||||
stripe_id TEXT,
|
stripe_id TEXT,
|
||||||
country TEXT NOT NULL,
|
country TEXT NOT NULL,
|
||||||
verified BOOL DEFAULT false,
|
verified BOOL DEFAULT false,
|
||||||
@ -93,7 +93,7 @@ my @migrations = (
|
|||||||
my %params = $validator->(@_);
|
my %params = $validator->(@_);
|
||||||
my $config = $params{config};
|
my $config = $params{config};
|
||||||
my $db_config = $config->{db_config};
|
my $db_config = $config->{db_config};
|
||||||
my $dbname = $db_config->{dbname} or die 'No dbnabe in db_config';
|
my $dbname = $db_config->{dbname} or die 'No dbname in db_config';
|
||||||
my $host = $db_config->{host} or die 'No host in db_config';
|
my $host = $db_config->{host} or die 'No host in db_config';
|
||||||
my $username = $db_config->{username} or die 'No username in db_config';
|
my $username = $db_config->{username} or die 'No username in db_config';
|
||||||
my $password = $db_config->{password} or die 'No password in db_config';
|
my $password = $db_config->{password} or die 'No password in db_config';
|
||||||
|
@ -35,15 +35,30 @@ use Peace::DAO::Application;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub to_json {
|
||||||
|
my $self = shift;
|
||||||
|
return {
|
||||||
|
uuid => $self->uuid,
|
||||||
|
date_creation => '' . $self->date_creation,
|
||||||
|
name => $self->name,
|
||||||
|
surname => $self->surname,
|
||||||
|
email => $self->email,
|
||||||
|
country => $self->country,
|
||||||
|
verified => $self->verified,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
sub applications {
|
sub applications {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
if ( !defined $self->{applications} ) {
|
if ( !defined $self->{applications} ) {
|
||||||
my $dbh = $self->_dbh;
|
my $dbh = $self->_dbh;
|
||||||
if ( !defined $dbh ) {
|
if ( !defined $dbh ) {
|
||||||
die "There is no database handle, so no chance to recover applications from the developer.";
|
die
|
||||||
|
"There is no database handle, so no chance to recover applications from the developer.";
|
||||||
}
|
}
|
||||||
my $application_dao = Peace::DAO::Application->new( dbh => $dbh );
|
my $application_dao = Peace::DAO::Application->new( dbh => $dbh );
|
||||||
$self->{applications} = $application_dao->recover_by_developer(developer => $self);
|
$self->{applications} =
|
||||||
|
$application_dao->recover_by_developer( developer => $self );
|
||||||
}
|
}
|
||||||
|
|
||||||
return $self->{applications};
|
return $self->{applications};
|
||||||
@ -181,6 +196,7 @@ sub _dbh {
|
|||||||
return $self->{dbh};
|
return $self->{dbh};
|
||||||
}
|
}
|
||||||
1;
|
1;
|
||||||
|
|
||||||
=encoding utf8
|
=encoding utf8
|
||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
@ -226,6 +242,12 @@ Peace::Model::Developer implements the following instance methods:
|
|||||||
|
|
||||||
Peace::Model::Developer implements the following methods:
|
Peace::Model::Developer implements the following methods:
|
||||||
|
|
||||||
|
=head2 to_json
|
||||||
|
|
||||||
|
my $json = $developer->to_json;
|
||||||
|
|
||||||
|
Renders the developer in a json like structure.
|
||||||
|
|
||||||
=head2 applications
|
=head2 applications
|
||||||
|
|
||||||
my $applications = $developer->applications;
|
my $applications = $developer->applications;
|
||||||
|
282
lib/Peace/Swagger.pm
Normal file
282
lib/Peace/Swagger.pm
Normal file
@ -0,0 +1,282 @@
|
|||||||
|
package Peace::Swagger;
|
||||||
|
|
||||||
|
use v5.30.0;
|
||||||
|
|
||||||
|
use strict;
|
||||||
|
use warnings;
|
||||||
|
|
||||||
|
use Params::ValidationCompiler qw/validation_for/;
|
||||||
|
use Types::Standard qw/ArrayRef Str HashRef/;
|
||||||
|
|
||||||
|
use Const::Fast;
|
||||||
|
use Email::Valid;
|
||||||
|
|
||||||
|
const my $EMAIL_VALIDATOR => Type::Tiny->new(
|
||||||
|
name => 'Email',
|
||||||
|
constraint => sub {
|
||||||
|
return Email::Valid->address($_);
|
||||||
|
},
|
||||||
|
message => sub { return "$_ is not an email address."; },
|
||||||
|
);
|
||||||
|
|
||||||
|
sub new {
|
||||||
|
my $class = shift;
|
||||||
|
my $self = bless {}, $class;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub schema {
|
||||||
|
return {
|
||||||
|
openapi => "3.1.0",
|
||||||
|
info => {
|
||||||
|
title => 'Peace API',
|
||||||
|
version => '0.0.1',
|
||||||
|
license => {
|
||||||
|
name => 'AGPLv3',
|
||||||
|
url => 'https://www.gnu.org/licenses/agpl-3.0.en.html',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
paths => { developer(), }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
type => { type => Str },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub _type_to_type_tiny {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my ($type) = $params{type};
|
||||||
|
return Str if $type eq 'string';
|
||||||
|
die 'No such type declared.';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
format => { type => Str },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub _format_to_type_tiny {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my ($format) = $params{format};
|
||||||
|
return $EMAIL_VALIDATOR if $format eq 'email';
|
||||||
|
die "No such format declared.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub developer {
|
||||||
|
return (
|
||||||
|
"/developer" => {
|
||||||
|
summary => "Allows to work with developers.",
|
||||||
|
post => developer_post(),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
json => { type => HashRef },
|
||||||
|
spec => { type => HashRef },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub validate_request {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my $json = $params{json};
|
||||||
|
my $spec = $params{spec};
|
||||||
|
my $spec_parameters = $spec->{parameters};
|
||||||
|
for my $parameter_spec (@$spec_parameters) {
|
||||||
|
$self->_validate_parameter(
|
||||||
|
parameter_spec => $parameter_spec,
|
||||||
|
json => $json,
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $validator = validation_for(
|
||||||
|
params => {
|
||||||
|
parameter_spec => { type => HashRef },
|
||||||
|
json => { type => HashRef },
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
sub _validate_parameter {
|
||||||
|
my $self = shift;
|
||||||
|
my %params = $validator->(@_);
|
||||||
|
my ( $parameter_spec, $json ) = @params{
|
||||||
|
qw/
|
||||||
|
parameter_spec json/
|
||||||
|
};
|
||||||
|
my $name = $parameter_spec->{name};
|
||||||
|
my $schema = $parameter_spec->{schema};
|
||||||
|
my $required = $parameter_spec->{required};
|
||||||
|
my $type = $schema->{type};
|
||||||
|
my $format = $schema->{format};
|
||||||
|
my $pattern = $schema->{pattern};
|
||||||
|
|
||||||
|
if ( !exists $json->{$name} ) {
|
||||||
|
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.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( defined $format ) {
|
||||||
|
my $type_format = $self->_format_to_type_tiny( format => $format );
|
||||||
|
unless ( $type_format->check( $json->{$name} ) ) {
|
||||||
|
die "$value is not $format.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( defined $pattern ) {
|
||||||
|
die "$value doesn\'t match $pattern." if $value !~ /^$pattern$/;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sub developer_post {
|
||||||
|
return {
|
||||||
|
summary => 'Creates a developer',
|
||||||
|
parameters => [
|
||||||
|
{
|
||||||
|
name => 'secret',
|
||||||
|
required => 1,
|
||||||
|
in => 'query',
|
||||||
|
description =>
|
||||||
|
'Access credential for Authenticate latter as the created developer.',
|
||||||
|
schema => {
|
||||||
|
type => "string",
|
||||||
|
|
||||||
|
# Bcrypt limit is 72 characters.
|
||||||
|
pattern => ".{10,72}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'name',
|
||||||
|
required => 1,
|
||||||
|
in => 'query',
|
||||||
|
description => 'Developer\'s real name',
|
||||||
|
schema => {
|
||||||
|
type => "string",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'surname',
|
||||||
|
required => 1,
|
||||||
|
in => 'query',
|
||||||
|
description => 'Developer\'s real surname',
|
||||||
|
schema => {
|
||||||
|
type => "string",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'surname',
|
||||||
|
required => 1,
|
||||||
|
in => 'query',
|
||||||
|
description => 'Developer\'s real surname',
|
||||||
|
schema => {
|
||||||
|
type => "string",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'email',
|
||||||
|
required => 1,
|
||||||
|
in => 'query',
|
||||||
|
description => 'Developer\'s email',
|
||||||
|
schema => {
|
||||||
|
type => "string",
|
||||||
|
format => 'email',
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name => 'country',
|
||||||
|
description => 'Developer\'s country in iso3166format',
|
||||||
|
required => 1,
|
||||||
|
in => 'query',
|
||||||
|
schema => {
|
||||||
|
type => "string",
|
||||||
|
pattern => '[A-Z]{2}',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
1;
|
||||||
|
|
||||||
|
=encoding utf8
|
||||||
|
|
||||||
|
=head1 NAME
|
||||||
|
|
||||||
|
Peace::Swagger - OpenAPI definitions for the Peace API.
|
||||||
|
|
||||||
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
|
my $swagger = Peace::Swagger->new;
|
||||||
|
|
||||||
|
my $spec = $swagger->schema;
|
||||||
|
|
||||||
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
|
This module aims to help in the programmatic description
|
||||||
|
of all API endpoints in a way that makes possible to
|
||||||
|
reuse those schemas in the code and in the documentation.
|
||||||
|
|
||||||
|
=head1 INSTANCE METHODS
|
||||||
|
|
||||||
|
Peace::Swagger implements the following instance methods:
|
||||||
|
|
||||||
|
=head2 new
|
||||||
|
|
||||||
|
my $swagger = Peace::Swagger->new;
|
||||||
|
|
||||||
|
Instances a Peace::Swagger.
|
||||||
|
|
||||||
|
=head1 METHODS
|
||||||
|
|
||||||
|
Peace::Swagger implements the following methods:
|
||||||
|
|
||||||
|
=head2 schema
|
||||||
|
|
||||||
|
my $schema = $swagger->schema;
|
||||||
|
|
||||||
|
Returns the complete openapi schema.
|
||||||
|
|
||||||
|
=head2 validate_request
|
||||||
|
|
||||||
|
$swagger->validate_request(json => $json, spec => $spec);
|
||||||
|
|
||||||
|
Validates the spec for a specific endpoint say
|
||||||
|
developer_post against the json got from the
|
||||||
|
user and dies if the check is unsuccesful.
|
||||||
|
|
||||||
|
=head2 developer
|
||||||
|
|
||||||
|
my $developer_schema = $swagger->developer;
|
||||||
|
|
||||||
|
Returns the schemas associated with the
|
||||||
|
L<Peace::Model::Developer> object.
|
||||||
|
|
||||||
|
=head2 developer_post
|
||||||
|
|
||||||
|
my $developer_post = $swagger->developer_post
|
||||||
|
|
||||||
|
Returns the schema of the post request
|
||||||
|
to the /developer enpoint.
|
||||||
|
|
||||||
|
=cut
|
Loading…
Reference in New Issue
Block a user