Skip to content

Commit

Permalink
#3 added artist checks, small refactorings (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
tolik518 authored Jul 10, 2023
1 parent 8f11427 commit d089164
Show file tree
Hide file tree
Showing 15 changed files with 436 additions and 333 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/integration-deploy.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# /.github/workflows/integration-deploy.yml
# Warning: deletes all files on uberspace which are not in repo, use without --delete if unsure
name: Deploy integration
name: Deploy Integration
on:
push

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/swagger-deploy.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# /.github/workflows/integration-deploy.yml
# Warning: deletes all files on uberspace which are not in repo, use without --delete if unsure
name: Deploy integration
name: Deploy Swagger
on:
push

Expand Down
6 changes: 3 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
# IDE settings
.idea
# Vendor folder generated with 'make install'
/code/vendor
code/vendor
# Database created by docker
/database
database
# config for the production enviroment
code/config.prd.php
# Transpiled .js files from .ts files
Expand All @@ -12,4 +12,4 @@ code/config.prd.php
*.css
*.css.map
# PHPUnit reports
/code/tests/reports/
code/tests/reports/
3 changes: 2 additions & 1 deletion code/.env.local
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
MYSQL_ROOT_PASSWORD=kThisIsTheInitialDatabasePass
MYSQL_HOST=database
MYSQL_USER=root
MYSQL_DB=qg_song_data
MYSQL_DB=qg_song_data
API_JWT=
73 changes: 69 additions & 4 deletions code/src/ApiResponse.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,80 @@ public static function sucessful(Response $response, array $responseData = [], i
JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
)
);
return $response->withStatus($statusCode)->withHeader('Content-Type', 'application/json');
return $response->withStatus($statusCode)
->withHeader('Content-Type', 'application/json')
->withHeader('Access-Control-Allow-Origin', '*');
}

public static function noData(): Response
{
$response = new Response();
return $response->withStatus(204)->withHeader('Content-Type', 'application/json');
return $response->withStatus(204)
->withHeader('Content-Type', 'application/json')
->withHeader('Access-Control-Allow-Origin', '*');
}

public static function errorMissingData(Response $response, array $missingFields = []): Response
public static function errorNotAuthorized(): Response
{
$response = new Response();

$response->getBody()->write(
json_encode(
[
"code" => "ERROR_NOT_AUTHORIZED",
"message" => "You're not authorized to access that ressource"
],
JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
)
);

return $response->withStatus(403)
->withHeader('Content-Type', 'application/json')
->withHeader('Access-Control-Allow-Origin', '*');
}

public static function errorMissingAuthBearer(): Response
{
$response = new Response();

$response->getBody()->write(
json_encode(
[
"code" => "ERROR_MISSING_AUTH",
"message" => "Authorization Bearer is missing from header or is malformed"
],
JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
)
);

return $response->withStatus(401)
->withHeader('Content-Type', 'application/json')
->withHeader('Access-Control-Allow-Origin', '*');
}

public static function errorMissingAuth(): Response
{
$response = new Response();

$response->getBody()->write(
json_encode(
[
"code" => "ERROR_MISSING_AUTH",
"message" => "Authorization is missing from header"
],
JSON_UNESCAPED_UNICODE | JSON_THROW_ON_ERROR
)
);

return $response->withStatus(401)
->withHeader('Content-Type', 'application/json')
->withHeader('Access-Control-Allow-Origin', '*');
}

public static function errorMissingData(array $missingFields = []): Response
{
$response = new Response();

if (empty($missingFields))
{
$response->getBody()->write(
Expand All @@ -49,6 +112,8 @@ public static function errorMissingData(Response $response, array $missingFields
);
}

return $response->withStatus(400)->withHeader('Content-Type', 'application/json');
return $response->withStatus(400)
->withHeader('Content-Type', 'application/json')
->withHeader('Access-Control-Allow-Origin', '*');
}
}
40 changes: 40 additions & 0 deletions code/src/AuthMiddleware.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<?php

namespace QazaqGenius\LyricsApi;

use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Psr\Http\Server\RequestHandlerInterface as RequestHandler;
use Psr\Http\Server\MiddlewareInterface;



class AuthMiddleware implements MiddlewareInterface
{
public function process(Request $request, RequestHandler $handler): Response
{
$authHeader = $request->getHeader("Authorization");

if (empty($authHeader)) {
return ApiResponse::errorMissingAuth();
}

$authParts = explode(" ", $authHeader[0]);

if (!isset($authParts[1]) || $authParts[0] !== "Bearer") {
return ApiResponse::errorMissingAuthBearer();
}

$jwt = $authParts[1];

//TODO: Check if JWT is valid
if ($jwt !== ENV['API_JWT'])
{
return ApiResponse::errorNotAuthorized();
}

$response = $handler->handle($request);

return $response;
}
}
5 changes: 5 additions & 0 deletions code/src/Factory.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ public function __construct(
) {
}

public function createAuthMiddleware(): AuthMiddleware
{
return new AuthMiddleware();
}

public function createSongIdReader(): SongIdReader
{
return new SongIdReader(
Expand Down
8 changes: 3 additions & 5 deletions code/src/Handler/SongWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,14 @@ public function __construct(
*/
public function handle(Request $request, Response $response): Response
{

$data = json_decode($request->getBody(), true);


if ($data == null){
return ApiResponse::errorMissingData($response);
if ($data === null) {
return ApiResponse::errorMissingData();
}

$artistIds = $this->mySQLSongWriter->insertArtists($data["artists"]);
$albumId = $this->mySQLSongWriter->insertAlbum($data["album"]);
$albumId = $this->mySQLSongWriter->insertAlbum($data["album"], $artistIds);
$songId = $this->mySQLSongWriter->insertSong($data);

$mediaIds = $this->mySQLSongWriter->insertMedia($data["media"], $songId);
Expand Down
102 changes: 74 additions & 28 deletions code/src/database/MySQLSongWriter.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ public function insertSong(array $song): int
');

$sql->bindValue(":title_cyr", $song["title_cyr"]);
$sql->bindValue(":title_lat", $song["title_lat"]);
$sql->bindValue(":title_lat", $song["title_lat"] ?? Transliterator::toLatin($song["title_lat"]));
$sql->bindValue(":release_date", $song["release_date"]);
$sql->bindValue(":cover_art", $song["cover_art"]);

Expand All @@ -119,30 +119,57 @@ public function insertSong(array $song): int
return $songId;
}

public function insertAlbum(array $album): ?int
public function insertAlbum(array $album, array $artistIds): ?int
{
if (!isset($album['id'])) {
if (isset($album['name_cyr']) || isset($album['name_lat']))
{
$sql = $this->mySqlConnection->prepare('
INSERT INTO Album (name_cyr, name_lat)
VALUES (:name_cyr, :name_lat)
');
if (isset($album['id'])) {
$albumId = (int)$album['id'];
} else if (isset($album['name_cyr']) || isset($album['name_lat'])) {

$name_lat = $album["name_lat"] ?? Transliterator::toLatin($album["name_cyr"]);
$sql->bindValue(":name_lat", $name_lat);
$sql->bindValue(":name_cyr", $album["name_cyr"]);
$sql->execute();
$albumId = (int) $this->mySqlConnection->lastInsertId();
}
else {
$albumId = null;
}
/*$albumId = $this->getAlbumIdIfExist($album, $artistIds);*/

$sql = $this->mySqlConnection->prepare('
INSERT INTO Album (name_cyr, name_lat)
VALUES (:name_cyr, :name_lat)
');

$name_lat = $album["name_lat"] ?? Transliterator::toLatin($album["name_cyr"]);
$sql->bindValue(":name_lat", $name_lat);
$sql->bindValue(":name_cyr", $album["name_cyr"]);
$sql->execute();
$albumId = (int)$this->mySqlConnection->lastInsertId();
} else {
$albumId = (int) $album['id'];
$albumId = null;
}

return $albumId;
}
/*
private function getAlbumIdIfExist(array $album, array $artistIds): ?int
{
$sql = $this->mySqlConnection->prepare('
SELECT Album.id
FROM Artist
INNER JOIN AlbumArtists
ON Artist.id = AlbumArtists.artist_id
INNER JOIN Album
ON Artist.id = Album.main_artist_id
WHERE (Artist.id IN (:artist_id) AND Album.name_cyr = :album_name_cyr)
OR (Artist.id IN (:artist_id) AND Album.name_lat = :album_name_lat)
');
$album_name_lat = $album["name_lat"] ?? Transliterator::toLatin($album["name_cyr"]);
$sql->bindValue(":artist_id", $artistIds);
$sql->bindValue(":album_name_cyr", $album["name_cyr"]);
$sql->bindValue(":album_name_lat", $album_name_lat);
$sql->execute();
$result = $sql->fetchAll(PDO::FETCH_ASSOC);
var_dump($result);
die();
return $result[0]["id"] ?? null;
}*/


public function insertArtists(array $artists): array
{
Expand All @@ -153,22 +180,41 @@ public function insertArtists(array $artists): array
return $artistIds;
}

private function insertArtistAndGetID(mixed $artist): int
private function insertArtistAndGetID(array $artist): int
{
if (!isset($artist['id'])) {
$sql = $this->mySqlConnection->prepare('
INSERT INTO Artist (name_cyr, name_lat)
VALUES (:name_cyr, :name_lat)
');
$artistId = $this->getArtistIdIfExist($artist);
if(!$artistId) {
$sql = $this->mySqlConnection->prepare('
INSERT INTO Artist (name_cyr, name_lat)
VALUES (:name_cyr, :name_lat)
');

$sql->bindValue(":name_lat", $artist["name_lat"]);
$sql->bindValue(":name_cyr", $artist["name_cyr"]);
$sql->execute();
$artistId = (int) $this->mySqlConnection->lastInsertId();
$sql->bindValue(":name_cyr", $artist["name_cyr"]);
$sql->bindValue(":name_lat", $artist["name_lat"] ?? Transliterator::toLatin($artist["name_cyr"]));
$sql->execute();
$artistId = (int) $this->mySqlConnection->lastInsertId();
}
} else {
$artistId = (int) $artist['id'];
}
return $artistId;
}

private function getArtistIdIfExist(array $artist): ?int
{
$sql = $this->mySqlConnection->prepare('
SELECT id
FROM Artist
WHERE Artist.name_cyr = :name_cyr OR Artist.name_lat = :name_lat
');

$sql->bindValue(":name_cyr", $artist["name_cyr"]);
$sql->bindValue(":name_lat", $artist["name_lat"] ?? Transliterator::toLatin($artist["name_cyr"]));
$sql->execute();
$result = $sql->fetchAll(PDO::FETCH_ASSOC);

return $result[0]["id"] ?? null;
}

}
11 changes: 9 additions & 2 deletions code/src/routes.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

$app->group('/api/v1', function (Group $v1) use ($factory) {

//TODO: implement /songs route
$v1->get('/songs', function (Request $request, Response $response) use ($factory) {
return $factory->createSongIdReader()->handle($request, $response);
})->setName('healtcheck');
Expand All @@ -31,10 +30,18 @@
})->setName('v1.GET.song');
});

//TODO: Implement
$v1->group('/artist', function (Group $song) use ($factory) {
$song->get('/{artist_id:\d+}', function (Request $request, Response $response) use ($factory) {
return $factory->createArtistHandler()->handle($request, $response);
})->setName('v1.GET.artist');
});
});

//TODO: Implement
$v1->group('/album', function (Group $song) use ($factory) {
$song->get('/{artist_id:\d+}', function (Request $request, Response $response) use ($factory) {
return $response;
})->setName('v1.GET.artist');
});
})->addMiddleware($factory->createAuthMiddleware());
};
Binary file removed documentation/database_dump/database_draft.png
Binary file not shown.
Binary file removed documentation/database_dump/lyrics_data_json.png
Binary file not shown.
Loading

0 comments on commit d089164

Please sign in to comment.