api_skeletton #3

Merged
remi.arnal merged 48 commits from api_skeletton into master 1 year ago

@ -0,0 +1,71 @@
kind: pipeline
type: docker
name: smartfit
trigger:
event:
- push
steps:
- name: build_api_image
image: plugins/docker
settings:
dockerfile: Dockerfile
context: .
registry: hub.codefirst.iut.uca.fr
repo: hub.codefirst.iut.uca.fr/remi.arnal/smartfit_api
username:
from_secret: cf_username
password:
from_secret: cf_password
- name: sonarqube
image: sonarsource/sonar-scanner-cli
environment:
SONAR_TOKEN:
from_secret: sonar_token
commands:
- sonar-scanner -Dsonar.projectKey=SmartFit_API
-Dsonar.sources=./app/
-Dsonar.inclusions=**/*.php
-Dsonar.login=$${SONAR_TOKEN}
-Dsonar.language=php
-Dsonar.host.url=https://codefirst.iut.uca.fr/sonar
depends_on: [build_api_image]
- name: deploy_api_image
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest
environment:
IMAGENAME: hub.codefirst.iut.uca.fr/remi.arnal/smartfit_api:latest
CONTAINERNAME: smartfit_api
COMMAND: create
OVERWRITE: true
CODEFIRST_CLIENTDRONE_ENV_SMDB_HOST: SmartFit-smartfit_db
CODEFIRST_CLIENTDRONE_ENV_SMDB_DATABASE:
from_secret: db_database
CODEFIRST_CLIENTDRONE_ENV_SMDB_USER:
from_secret: db_user
CODEFIRST_CLIENTDRONE_ENV_SMDB_PASSWORD:
from_secret: db_password
CODEFIRST_CLIENTDRONE_ENV_ROOT_PASSWORD:
from_secret: db_root_password
ADMINS: remiarnal,enzojolys,othmanebenjelloun
depends_on: [ build_api_image ]
- name: deploy_database_image
image: hub.codefirst.iut.uca.fr/thomas.bellembois/codefirst-dockerproxy-clientdrone:latest
environment:
IMAGENAME: mariadb:11.1.2
CONTAINERNAME: smartfit_db
PRIVATE : true
COMMAND: create
CODEFIRST_CLIENTDRONE_ENV_MARIADB_ROOT_PASSWORD:
from_secret: db_root_password
CODEFIRST_CLIENTDRONE_ENV_MARIADB_DATABASE:
from_secret: db_database
CODEFIRST_CLIENTDRONE_ENV_MARIADB_USER:
from_secret: db_user
CODEFIRST_CLIENTDRONE_ENV_MARIADB_PASSWORD:
from_secret: db_password
ADMINS: remiarnal,enzojolys,othmanebenjelloun
depends_on: [ deploy_api_image ]

@ -0,0 +1,13 @@
FROM php:8.1-apache
RUN apt-get update && apt-get install -y git zip
RUN docker-php-ext-install pdo pdo_mysql
COPY . /var/www/html/
WORKDIR /var/www/html/
RUN curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
RUN composer update && composer install
RUN echo "file_uploads = On\nmemory_limit = 64M\nupload_max_filesize = 64M\npost_max_size = 64M\nmax_execution_time = 600\n" > /usr/local/etc/php/conf.d/uploads.ini
RUN a2enmod rewrite
RUN a2enmod actions
RUN service apache2 restart
RUN mkdir -p /home/hel/smartfit_hdd
RUN chmod -R 777 /home/hel/smartfit_hdd

@ -0,0 +1,6 @@
#!/bin/sh
export SMDB_HOST=localhost
export SMDB_DATABASE=smartfit
export SMDB_USER=manager
export SMDB_PASSWORD=manager

@ -8,7 +8,7 @@ class DatabaseCon{
private string $login; private string $login;
private string $password; private string $password;
function __construct(){ public function __construct(){
if (getenv("SMDB_HOST") == null || getenv("SMDB_DATABASE") == null || getenv("SMDB_USER") == null || getenv("SMDB_PASSWORD") == null){ if (getenv("SMDB_HOST") == null || getenv("SMDB_DATABASE") == null || getenv("SMDB_USER") == null || getenv("SMDB_PASSWORD") == null){
throw new PDOException("ENV variables not found"); throw new PDOException("ENV variables not found");
} }
@ -17,7 +17,7 @@ class DatabaseCon{
$this->password = getenv("SMDB_PASSWORD"); $this->password = getenv("SMDB_PASSWORD");
} }
function connect(): int|Connection { public function connect(): int|Connection {
try { try {
$connection = new Connection($this->dsn,$this->login,$this->password); $connection = new Connection($this->dsn,$this->login,$this->password);
} catch (PDOException $e){ } catch (PDOException $e){

@ -0,0 +1,44 @@
<?php
namespace Config;
use Config\Connection;
use Config\DatabaseCon;
use PDOException;
class DatabaseInit {
private Connection $con;
public function __construct() {
if(getenv("IS_DB_INIT") === false) {
#try {
$this->con = (new DatabaseCon)->connect();
#} catch(PDOException $e) {
# throw new PDOException($e->getMessage(), $e->getCode(), $e);
$this->createUserTable();
$this->createFileTable();
putenv("IS_DB_INIT=true");
}
}
private function createUserTable() {
$query = 'CREATE TABLE IF NOT EXISTS user (
id UUID PRIMARY KEY,
email VARCHAR(100) UNIQUE,
hash VARCHAR(255),
username VARCHAR(20) DEFAULT \'Change Me!\',
creation_date DATE);';
$this->con->executeQuery($query);
}
private function createFileTable() {
$query = 'CREATE TABLE IF NOT EXISTS file (
id UUID PRIMARY KEY,
user_id UUID REFERENCES `user`(`id`) ON DELETE CASCADE,
filename VARCHAR(100) DEFAULT CURDATE(),
category VARCHAR(50),
creation_date DATETIME,
import_date DATE);';
$this->con->executeQuery($query);
}
}

@ -16,12 +16,14 @@ class FileGateway {
} }
} }
public function createFile(string $filename, string $user_uuid) { public function createFile(string $filename, string $user_uuid, string $category, string $creation_date) {
$query = "INSERT INTO file VALUES(UUID(), :user_uuid, :filename, CURDATE());"; $query = "INSERT INTO file VALUES(UUID(), :user_uuid, :filename, :category, :creation_date ,CURDATE());";
try { try {
$this->con->executeQuery($query, array( $this->con->executeQuery($query, array(
':user_uuid' => array($user_uuid, PDO::PARAM_STR),
':filename' => array($filename, PDO::PARAM_STR), ':filename' => array($filename, PDO::PARAM_STR),
':user_uuid' => array($user_uuid, PDO::PARAM_STR) ':category' => array($category, PDO::PARAM_STR),
':creation_date' => array($creation_date, PDO::PARAM_STR)
)); ));
} catch (PDOException $e) { } catch (PDOException $e) {
return -1; return -1;
@ -61,7 +63,7 @@ class FileGateway {
} }
public function listFiles(string $user_uuid) { public function listFiles(string $user_uuid) {
$query = "SELECT f.id, f.filename FROM file f, user u WHERE f.user_id=u.id and u.id=:user_uuid;"; $query = "SELECT f.id, f.filename, f.category, f.creation_date FROM file f, user u WHERE f.user_id=u.id and u.id=:user_uuid;";
try { try {
$this->con->executeQuery($query, array( $this->con->executeQuery($query, array(
':user_uuid' => array($user_uuid, PDO::PARAM_STR) ':user_uuid' => array($user_uuid, PDO::PARAM_STR)
@ -76,9 +78,11 @@ class FileGateway {
$rows[] = [ $rows[] = [
'uuid' => $row['id'], 'uuid' => $row['id'],
'filename' => $row['filename'], 'filename' => $row['filename'],
'category' => $row['category'],
'creation_date' => $row['creation_date']
]; ];
} }
return $rows; return $rows;
} }
} }

@ -6,8 +6,6 @@ use PDOException;
use PDO; use PDO;
use Config\Token; use Config\Token;
use function PHPUnit\Framework\isEmpty;
class UserGateway { class UserGateway {
private Connection $con; private Connection $con;
private Token $token; private Token $token;
@ -39,14 +37,16 @@ class UserGateway {
// Delete User: (1:OK, 2:Unauthorize, 3:No User) // Delete User: (1:OK, 2:Unauthorize, 3:No User)
public function deleteUser(string $uuid) : int { public function deleteUser(string $uuid) : int {
$query = "DELETE FROM user WHERE id=:uuid;"; $query = "DELETE FROM user WHERE id=:uuid RETURNING row_count();";
try { try {
$this->con->executeQuery($query, array( $this->con->executeQuery($query, array(
':uuid' => array($uuid, PDO::PARAM_STR) ':uuid' => array($uuid, PDO::PARAM_STR)
)); ));
$results = $this->con->getResults();
} catch (PDOException $e) { } catch (PDOException $e) {
return -1; return -2;
} }
if(count($results) === 0) return -1;
return 0; return 0;
} }
@ -69,6 +69,21 @@ class UserGateway {
return json_encode($this->token->getNewJsonToken($results[0]['id'])); return json_encode($this->token->getNewJsonToken($results[0]['id']));
} }
public function getInfo(string $uuid) {
$query = "SELECT email, username FROM user WHERE id=:uuid;";
try {
$this->con->executeQuery($query,array(
':uuid' => array($uuid, PDO::PARAM_STR)
));
$results = $this->con->getResults();
} catch(PDOException $e) {
return -2;
}
if(count($results) === 0) return -1;
return ["email" => $results[0]['email'], "username" => $results[0]['username']];
}
public function updateMail(string $uuid, string $new_email) { public function updateMail(string $uuid, string $new_email) {
$query = "UPDATE user SET email=:new_email WHERE id=:uuid;"; $query = "UPDATE user SET email=:new_email WHERE id=:uuid;";
try { try {
@ -96,4 +111,4 @@ class UserGateway {
return 0; return 0;
} }
} }

@ -1,19 +1,36 @@
<?php <?php
declare(strict_types=1); declare(strict_types=1);
require "gateway/user_gateway.php"; require_once "gateway/user_gateway.php";
require "gateway/file_gateway.php"; require_once "gateway/file_gateway.php";
require "database_con.php"; require_once "database_con.php";
require "token.php"; require_once "token.php";
header("Access-Control-Allow-Origin: *");
header("Access-Control-Allow-Headers: Access-Control-Allow-Origin, X-Requested-With, Content-Type, Accept, Origin, Authorization");
header("Access-Control-Allow-Methods: *");
header("Access-Control-Allow-Credentials: true");
use Psr\Http\Message\ResponseInterface as Response; use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request; use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\App; use Slim\App;
use SLim\Exception\HttpNotFoundException;
use gateway\UserGateway; use gateway\UserGateway;
use Config\Token; use Config\Token;
use Gateway\FileGateway; use Gateway\FileGateway;
return function (App $app) { return function (App $app) {
$app->options('/{routes:.+}', function ($request, $response, $args) {
return $response;
});
$app->add(function ($request, $handler) {
$response = $handler->handle($request);
return $response
->withHeader('Access-Control-Allow-Origin', '*')
->withHeader('Access-Control-Allow-Headers', 'X-Requested-With, Content-Type, Accept, Origin, Authorization')
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
});
$app->get('/', function (Request $req, Response $res) { $app->get('/', function (Request $req, Response $res) {
$res->getBody()->write('SmartFit-API is working!'); $res->getBody()->write('SmartFit-API is working!');
return $res; return $res;
@ -48,6 +65,8 @@ return function (App $app) {
return $res->withStatus(200); return $res->withStatus(200);
case -1: case -1:
return $res->withStatus(404); return $res->withStatus(404);
case -2:
return $res->withStatus(500);
} }
return $res->withStatus(500); return $res->withStatus(500);
}); });
@ -71,6 +90,25 @@ return function (App $app) {
return $res; return $res;
}); });
$app->get('/user/info', function(Request $req, Response $res) {
$token = $req->getHeader('Authorization')[0];
if(!(new Token)->verifyToken($token)) {
return $res->withStatus(401);
}
$uuid = (new Token)->getUuidFromToken($token);
$code = (new UserGateway)->getInfo($uuid);
switch($code) {
case -1:
return $res->withStatus(404);
case -2:
return $res->withStatus(500);
}
$res->getBody()->write(json_encode($code));
return $res;
});
// Update Mail // Update Mail
$app->put('/user/email', function(Request $req, Response $res) { $app->put('/user/email', function(Request $req, Response $res) {
$token = $req->getHeader('Authorization')[0]; $token = $req->getHeader('Authorization')[0];
@ -187,9 +225,12 @@ return function (App $app) {
$uuid = (new Token)->getUuidFromToken($token); $uuid = (new Token)->getUuidFromToken($token);
$file = $req->getUploadedFiles()['file']; $file = $req->getUploadedFiles()['file'];
$category = $req->getParsedBody()['SmartFit_Category'];
$creation_date = $req->getParsedBody()['SmartFit_Date'];
$filename = $file->getClientFilename(); $filename = $file->getClientFilename();
$code = (new FileGateway)->listFiles($uuid); $code = (new FileGateway)->listFiles($uuid);
if(in_array($filename, $code, false)) return $res->withStatus(409); if(array_search($filename, array_column($code, 'filename'), false) !== false) return $res->withStatus(409);
$file_save_folder = $save_folder.'/'.$uuid.'/'; $file_save_folder = $save_folder.'/'.$uuid.'/';
if(!is_dir($file_save_folder)) { if(!is_dir($file_save_folder)) {
@ -197,8 +238,13 @@ return function (App $app) {
} }
$file->moveTo($file_save_folder.'/'.$filename); $file->moveTo($file_save_folder.'/'.$filename);
$code = (new FileGateway)->createFile($filename, $uuid); $code = (new FileGateway)->createFile($filename, $uuid, $category, $creation_date);
if($code === -1) return $res->withStatus(500); if($code === -1) return $res->withStatus(500);
return $res->withStatus(200); return $res->withStatus(200);
}); });
};
$app->map(['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], '/{routes:.+}', function ($request, $response) {
throw new HttpNotFoundException($request);
});
};

@ -10,7 +10,7 @@ class Token {
// Need to be in a config file // Need to be in a config file
private string $path_to_key="../sym_keyfile.key"; private string $path_to_key="../sym_keyfile.key";
function __construct() public function __construct()
{ {
#$file = fopen($this->path_to_key, 'r'); #$file = fopen($this->path_to_key, 'r');
#$this->key = fread($file, filesize($this->path_to_key)); #$this->key = fread($file, filesize($this->path_to_key));
@ -18,7 +18,7 @@ class Token {
} }
// Return json containing JWT with uuid and exp // Return json containing JWT with uuid and exp
function getNewJsonToken(string $uuid) :array { public function getNewJsonToken(string $uuid) :array {
$payload = [ $payload = [
'uuid' => $uuid, 'uuid' => $uuid,
'exp' => strtotime("+2month", time()) 'exp' => strtotime("+2month", time())
@ -28,7 +28,7 @@ class Token {
} }
// Verify the JWT authenticity // Verify the JWT authenticity
function verifyToken(string $jwt) :bool { public function verifyToken(string $jwt) :bool {
try { try {
JWT::decode($jwt, new Key($this->key, 'HS256')); JWT::decode($jwt, new Key($this->key, 'HS256'));
} catch (Exception $e) { } catch (Exception $e) {
@ -39,7 +39,7 @@ class Token {
// Get uuid from JWT // Get uuid from JWT
// Missing error handling on bad JWT // Missing error handling on bad JWT
function getUuidFromToken(string $jwt) :string { public function getUuidFromToken(string $jwt) :string {
$decoded = (array) JWT::decode($jwt, new Key($this->key, 'HS256')); $decoded = (array) JWT::decode($jwt, new Key($this->key, 'HS256'));
return $decoded['uuid']; return $decoded['uuid'];
} }

@ -0,0 +1,35 @@
CREATE TABLE user (
`id` UUID PRIMARY KEY,
email VARCHAR(100) UNIQUE,
hash VARCHAR(255),
username VARCHAR(20) DEFAULT 'Change Me!',
creation_date DATE
);
CREATE TABLE file (
id UUID PRIMARY KEY,
`user_id` UUID REFERENCES `user`(`id`) ON DELETE CASCADE,
filename VARCHAR(100) DEFAULT CURDATE(),
import_date DATE,
);
-- CREATE USER
INSERT INTO user VALUES (UUID(), MAIL, HASH, USERNAME, CURDATE());
-- DELETE USER
DELETE FROM user WHERE id=USER_ID;
-- GET FILE LIST
SELECT id, import_date, title FROM file WHERE user_id=USER_ID;
-- UPLOAD FILE
INSERT INTO file VALUES (UUID(), USER_ID, TITLE, CURDATE(), DATA);
-- DELETE FILE
DELETE FROM file WHERE id=ID and USER_ID=USER_ID;
-- UPDATE MAIL
UPDATE user SET mail=MAIL WHERE id=ID;
-- UPDATE USERNAME
UPDATE user SET username=USERNAME WHERE id=ID;

@ -9,6 +9,9 @@ use App\Application\Settings\SettingsInterface;
use DI\ContainerBuilder; use DI\ContainerBuilder;
use Slim\Factory\AppFactory; use Slim\Factory\AppFactory;
use Slim\Factory\ServerRequestCreatorFactory; use Slim\Factory\ServerRequestCreatorFactory;
use Config\DatabaseInit;
require '../app/connection.php';
require '../app/database_init.php';
require __DIR__ . '/../vendor/autoload.php'; require __DIR__ . '/../vendor/autoload.php';
@ -76,6 +79,9 @@ $app->addBodyParsingMiddleware();
$errorMiddleware = $app->addErrorMiddleware($displayErrorDetails, $logError, $logErrorDetails); $errorMiddleware = $app->addErrorMiddleware($displayErrorDetails, $logError, $logErrorDetails);
$errorMiddleware->setDefaultErrorHandler($errorHandler); $errorMiddleware->setDefaultErrorHandler($errorHandler);
// Create DB
(new DatabaseInit);
// Run App & Emit Response // Run App & Emit Response
$response = $app->handle($request); $response = $app->handle($request);
$responseEmitter = new ResponseEmitter(); $responseEmitter = new ResponseEmitter();

@ -0,0 +1 @@
½µÆk,'Á<77>×þU<C3BE>çvž—„ƒ:uçý“„vTç"€Ûz^ª¹‡×ó&©þ<f+)ð0¨œúyYýB%& ÔÌ!hyžñ¯×­ÂÆ{C(5<>D#!G|"{ùBðO`§SÙê:Ep‰}d󓜈Q'ïSÿò•
Loading…
Cancel
Save