Code cleanup

This commit is contained in:
kdeng00
2019-11-17 13:33:58 -05:00
parent ca1fcb801d
commit 69f5a37eb3
74 changed files with 4397 additions and 4717 deletions
+11 -12
View File
@@ -7,20 +7,19 @@
#include "oatpp/web/protocol/http/outgoing/ChunkedBody.hpp" #include "oatpp/web/protocol/http/outgoing/ChunkedBody.hpp"
namespace callback { namespace callback {
class StreamCallback : public oatpp::data::stream::ReadCallback class StreamCallback : public oatpp::data::stream::ReadCallback {
{ public:
public: StreamCallback();
StreamCallback(); StreamCallback(const std::string&);
StreamCallback(const std::string&);
oatpp::data::v_io_size read(void*, oatpp::data::v_io_size); oatpp::data::v_io_size read(void*, oatpp::data::v_io_size);
private: private:
std::string m_songPath; std::string m_songPath;
long m_bytesRead; long m_bytesRead;
long m_counter; long m_counter;
long m_fileSize; long m_fileSize;
}; };
} }
#endif #endif
+22 -19
View File
@@ -9,29 +9,32 @@
#include "oatpp/web/server/HttpConnectionHandler.hpp" #include "oatpp/web/server/HttpConnectionHandler.hpp"
namespace component { namespace component {
class AppComponent {
public:
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>,
serverConnectionProvider)([&] {
return oatpp::network::server::SimpleTCPConnectionProvider::
createShared(appPort());
}());
class AppComponent OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, httpRouter)([] {
{ return oatpp::web::server::HttpRouter::createShared();
public: }());
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>, serverConnectionProvider)([] {
return oatpp::network::server::SimpleTCPConnectionProvider::createShared(5002);
}());
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, httpRouter)([] { OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::server::ConnectionHandler>,
return oatpp::web::server::HttpRouter::createShared(); serverConnectionHandler)([] {
}()); OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router);
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::server::ConnectionHandler>, serverConnectionHandler)([] { return oatpp::web::server::HttpConnectionHandler::createShared(router);
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); }());
return oatpp::web::server::HttpConnectionHandler::createShared(router); OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::data::mapping::ObjectMapper>,
}()); apiObjectMapper)([] {
return oatpp::parser::json::mapping::ObjectMapper::createShared();
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::data::mapping::ObjectMapper>, apiObjectMapper)([] { }());
return oatpp::parser::json::mapping::ObjectMapper::createShared(); private:
}()); constexpr int appPort() noexcept { return 5002; }
private: };
};
} }
#endif #endif
+48 -51
View File
@@ -29,69 +29,66 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class AlbumController : public oatpp::web::server::api::ApiController class AlbumController : public oatpp::web::server::api::ApiController {
{ public:
public: AlbumController(const model::BinaryPath& bConf,
AlbumController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) : oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
{ }
AlbumController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) #include OATPP_CODEGEN_BEGIN(ApiController)
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf)
{ }
#include OATPP_CODEGEN_BEGIN(ApiController) // endpoint for retrieving all album records in json format
ENDPOINT("GET", "/api/v1/album", albumRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveAlbum), Status::CODE_403, "Not allowed");
// endpoint for retrieving all album records in json format std::cout << "starting process of retrieving album\n";
ENDPOINT("GET", "/api/v1/album", albumRecords, database::AlbumRepository albRepo(m_bConf);
REQUEST(std::shared_ptr<IncomingRequest>, request)) auto albsDb = albRepo.retrieveRecords();
{ auto albums = oatpp::data::mapping::type::
auto authHeader = request->getHeader("Authorization"); List<dto::AlbumDto::ObjectWrapper>::createShared();
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveAlbum), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving album" << std::endl; for (auto& albDb : albsDb) {
database::AlbumRepository albRepo(m_bConf); auto alb = dto::conversion::DtoConversions::toAlbumDto(albDb);
auto albsDb = albRepo.retrieveRecords();
auto albums = oatpp::data::mapping::type::List<dto::AlbumDto::ObjectWrapper>::createShared();
for (auto& albDb : albsDb) { albums->pushBack(alb);
auto alb = dto::conversion::DtoConversions::toAlbumDto(albDb); }
albums->pushBack(alb); return createDtoResponse(Status::CODE_200, albums);
} }
return createDtoResponse(Status::CODE_200, albums); // endpoint for retrieving single album record by the album id in json format
} ENDPOINT("GET", "/api/v1/album/{id}", albumRecord,
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveAlbum), Status::CODE_403, "Not allowed");
// endpoint for retrieving single album record by the album id in json format database::AlbumRepository albRepo(m_bConf);
ENDPOINT("GET", "/api/v1/album/{id}", albumRecord, model::Album albDb(id);
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveAlbum), Status::CODE_403, "Not allowed");
database::AlbumRepository albRepo(m_bConf); OATPP_ASSERT_HTTP(albRepo.doesAlbumExists(albDb,
model::Album albDb(id); type::AlbumFilter::id) , Status::CODE_403, "album does not exist");
OATPP_ASSERT_HTTP(albRepo.doesAlbumExists(albDb, type::AlbumFilter::id) , Status::CODE_403, "album does not exist"); std::cout << "album exists\n";
albDb = albRepo.retrieveRecord(albDb, type::AlbumFilter::id);
std::cout << "album exists" << std::endl; auto album = dto::conversion::DtoConversions::toAlbumDto(albDb);
albDb = albRepo.retrieveRecord(albDb, type::AlbumFilter::id);
auto album = dto::conversion::DtoConversions::toAlbumDto(albDb); return createDtoResponse(Status::CODE_200, album);
}
return createDtoResponse(Status::CODE_200, album); #include OATPP_CODEGEN_END(ApiController)
} private:
model::BinaryPath m_bConf;
#include OATPP_CODEGEN_END(ApiController) };
private:
std::string m_exe_path;
model::BinaryPath m_bConf;
};
} }
#endif #endif
+52 -55
View File
@@ -28,73 +28,70 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class ArtistController : public oatpp::web::server::api::ApiController class ArtistController : public oatpp::web::server::api::ApiController {
{ public:
public: ArtistController(const model::BinaryPath& bConf,
ArtistController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) : oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
{ }
ArtistController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) #include OATPP_CODEGEN_BEGIN(ApiController)
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf)
{ }
#include OATPP_CODEGEN_BEGIN(ApiController) // endpoint for retrieving all artist records in json format
ENDPOINT("GET", "/api/v1/artist", artistRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveArtist), Status::CODE_403, "Not allowed");
// endpoint for retrieving all artist records in json format std::cout << "starting process of retrieving artist\n";
ENDPOINT("GET", "/api/v1/artist", artistRecords, database::ArtistRepository artRepo(m_bConf);
REQUEST(std::shared_ptr<IncomingRequest>, request)) auto artsDb = artRepo.retrieveRecords();
{ auto artists = oatpp::data::mapping::type::
auto authHeader = request->getHeader("Authorization"); List<dto::ArtistDto::ObjectWrapper>::createShared();
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveArtist), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving artist" << std::endl; for (auto& artDb : artsDb) {
database::ArtistRepository artRepo(m_bConf); auto art = dto::ArtistDto::createShared();
auto artsDb = artRepo.retrieveRecords(); art->id = artDb.id;
auto artists = oatpp::data::mapping::type::List<dto::ArtistDto::ObjectWrapper>::createShared(); art->artist = artDb.artist.c_str();
for (auto& artDb : artsDb) { artists->pushBack(art);
auto art = dto::ArtistDto::createShared(); }
art->id = artDb.id;
art->artist = artDb.artist.c_str();
artists->pushBack(art); return createDtoResponse(Status::CODE_200, artists);
} }
return createDtoResponse(Status::CODE_200, artists); // endpoint for retrieving single artist record by the artist id in json format
} ENDPOINT("GET", "/api/v1/artist/{id}", artistRecord,
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveArtist), Status::CODE_403, "Not allowed");
// endpoint for retrieving single artist record by the artist id in json format database::ArtistRepository artRepo(m_bConf);
ENDPOINT("GET", "/api/v1/artist/{id}", artistRecord, model::Artist artDb(id);
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveArtist), Status::CODE_403, "Not allowed");
database::ArtistRepository artRepo(m_bConf); OATPP_ASSERT_HTTP(artRepo.doesArtistExist(artDb,
model::Artist artDb(id); type::ArtistFilter::id) , Status::CODE_403, "artist does not exist");
OATPP_ASSERT_HTTP(artRepo.doesArtistExist(artDb, type::ArtistFilter::id) , Status::CODE_403, "artist does not exist"); std::cout << "artist exist\n";
artDb = artRepo.retrieveRecord(artDb, type::ArtistFilter::id);
std::cout << "artist exist" << std::endl; auto artist = dto::ArtistDto::createShared();
artDb = artRepo.retrieveRecord(artDb, type::ArtistFilter::id); artist->id = artDb.id;
artist->artist = artDb.artist.c_str();
auto artist = dto::ArtistDto::createShared(); return createDtoResponse(Status::CODE_200, artist);
artist->id = artDb.id; }
artist->artist = artDb.artist.c_str();
return createDtoResponse(Status::CODE_200, artist); #include OATPP_CODEGEN_END(ApiController)
} private:
model::BinaryPath m_bConf;
#include OATPP_CODEGEN_END(ApiController) };
private:
std::string m_exe_path;
model::BinaryPath m_bConf;
};
} }
#endif #endif
+71 -73
View File
@@ -27,95 +27,93 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class CoverArtController : public oatpp::web::server::api::ApiController class CoverArtController : public oatpp::web::server::api::ApiController {
{ public:
public: CoverArtController(const model::BinaryPath& bConf,
CoverArtController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) : oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
{ }
CoverArtController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) #include OATPP_CODEGEN_BEGIN(ApiController)
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf)
{ }
#include OATPP_CODEGEN_BEGIN(ApiController) // endpoint for retrieving all cover art records in json format
ENDPOINT("GET", "/api/v1/coverart", coverArtRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed");
// endpoint for retrieving all cover art records in json format std::cout << "starting process of retrieving cover art\n";
ENDPOINT("GET", "/api/v1/coverart", coverArtRecords, database::CoverArtRepository covRepo(m_bConf);
REQUEST(std::shared_ptr<IncomingRequest>, request)) auto covsDb = covRepo.retrieveRecords();
{ auto coverArts = oatpp::data::mapping::type::
auto authHeader = request->getHeader("Authorization"); List<dto::CoverArtDto::ObjectWrapper>::createShared();
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving cover art" << std::endl; for (auto& covDb : covsDb) {
database::CoverArtRepository covRepo(m_bConf); auto cov = dto::CoverArtDto::createShared();
auto covsDb = covRepo.retrieveRecords(); cov->id = covDb.id;
auto coverArts = oatpp::data::mapping::type::List<dto::CoverArtDto::ObjectWrapper>::createShared(); cov->songTitle = covDb.songTitle.c_str();
for (auto& covDb : covsDb) { coverArts->pushBack(cov);
auto cov = dto::CoverArtDto::createShared(); }
cov->id = covDb.id;
cov->songTitle = covDb.songTitle.c_str();
coverArts->pushBack(cov); return createDtoResponse(Status::CODE_200, coverArts);
} }
return createDtoResponse(Status::CODE_200, coverArts); // endpoint for retrieving single cover art record by the cover art id in json format
} ENDPOINT("GET", "/api/v1/coverart/{id}", coverArtRecord,
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed");
// endpoint for retrieving single cover art record by the cover art id in json format database::CoverArtRepository covRepo(m_bConf);
ENDPOINT("GET", "/api/v1/coverart/{id}", coverArtRecord, model::Cover covDb;
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) { covDb.id = id;
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed");
database::CoverArtRepository covRepo(m_bConf); OATPP_ASSERT_HTTP(covRepo.doesCoverArtExist(covDb,
model::Cover covDb; type::CoverFilter::id) , Status::CODE_403, "song does not exist");
covDb.id = id;
OATPP_ASSERT_HTTP(covRepo.doesCoverArtExist(covDb, type::CoverFilter::id) , Status::CODE_403, "song does not exist"); std::cout << "cover art exists\n";
covDb = covRepo.retrieveRecord(covDb, type::CoverFilter::id);
std::cout << "cover art exists" << std::endl; auto coverArt = dto::CoverArtDto::createShared();
covDb = covRepo.retrieveRecord(covDb, type::CoverFilter::id); coverArt->id = covDb.id;
coverArt->songTitle = covDb.songTitle.c_str();
auto coverArt = dto::CoverArtDto::createShared(); return createDtoResponse(Status::CODE_200, coverArt);
coverArt->id = covDb.id; }
coverArt->songTitle = covDb.songTitle.c_str();
return createDtoResponse(Status::CODE_200, coverArt); ENDPOINT("GET", "/api/v1/coverart/download/{id}", downloadCoverArt,
} REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed");
ENDPOINT("GET", "/api/v1/coverart/download/{id}", downloadCoverArt, database::CoverArtRepository covRepo(m_bConf);
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) { model::Cover covDb;
auto authHeader = request->getHeader("Authorization"); covDb.id = id;
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); covDb = covRepo.retrieveRecord(covDb, type::CoverFilter::id);
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed");
database::CoverArtRepository covRepo(m_bConf); auto rawCover = oatpp::base::StrBuffer::loadFromFile(covDb.imagePath.c_str());
model::Cover covDb; auto response = createResponse(Status::CODE_200, rawCover);
covDb.id = id;
covDb = covRepo.retrieveRecord(covDb, type::CoverFilter::id); response->putHeader(Header::CONTENT_TYPE, "image/*");
auto rawCover = oatpp::base::StrBuffer::loadFromFile(covDb.imagePath.c_str()); return response;
auto response = createResponse(Status::CODE_200, rawCover); }
response->putHeader(Header::CONTENT_TYPE, "image/*");
return response; #include OATPP_CODEGEN_END(ApiController)
} private:
model::BinaryPath m_bConf;
#include OATPP_CODEGEN_END(ApiController) };
private:
std::string m_exe_path;
model::BinaryPath m_bConf;
};
} }
#endif #endif
+52 -55
View File
@@ -28,73 +28,70 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class GenreController : public oatpp::web::server::api::ApiController class GenreController : public oatpp::web::server::api::ApiController {
{ public:
public: GenreController(const model::BinaryPath& bConf,
GenreController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) : oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
{ }
GenreController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) #include OATPP_CODEGEN_BEGIN(ApiController)
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf)
{ }
#include OATPP_CODEGEN_BEGIN(ApiController) // endpoint for retrieving all genre records in json format
ENDPOINT("GET", "/api/v1/genre", genreRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveGenre), Status::CODE_403, "Not allowed");
// endpoint for retrieving all genre records in json format std::cout << "starting process of retrieving genre\n";
ENDPOINT("GET", "/api/v1/genre", genreRecords, database::GenreRepository gnrRepo(m_bConf);
REQUEST(std::shared_ptr<IncomingRequest>, request)) auto gnrsDb = gnrRepo.retrieveRecords();
{ auto genres = oatpp::data::mapping::type::
auto authHeader = request->getHeader("Authorization"); List<dto::GenreDto::ObjectWrapper>::createShared();
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveGenre), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving genre" << std::endl; for (auto& gnrDb : gnrsDb) {
database::GenreRepository gnrRepo(m_bConf); auto gnr = dto::GenreDto::createShared();
auto gnrsDb = gnrRepo.retrieveRecords(); gnr->id = gnrDb.id;
auto genres = oatpp::data::mapping::type::List<dto::GenreDto::ObjectWrapper>::createShared(); gnr->category = gnrDb.category.c_str();
for (auto& gnrDb : gnrsDb) { genres->pushBack(gnr);
auto gnr = dto::GenreDto::createShared(); }
gnr->id = gnrDb.id;
gnr->category = gnrDb.category.c_str();
genres->pushBack(gnr); return createDtoResponse(Status::CODE_200, genres);
} }
return createDtoResponse(Status::CODE_200, genres); // endpoint for retrieving single genre record by the genre id in json format
} ENDPOINT("GET", "/api/v1/genre/{id}", genreRecord,
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveGenre), Status::CODE_403, "Not allowed");
// endpoint for retrieving single genre record by the genre id in json format database::GenreRepository gnrRepo(m_bConf);
ENDPOINT("GET", "/api/v1/genre/{id}", genreRecord, model::Genre gnrDb(id);
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveGenre), Status::CODE_403, "Not allowed");
database::GenreRepository gnrRepo(m_bConf); OATPP_ASSERT_HTTP(gnrRepo.doesGenreExist(gnrDb,
model::Genre gnrDb(id); type::GenreFilter::id) , Status::CODE_403, "genre does not exist");
OATPP_ASSERT_HTTP(gnrRepo.doesGenreExist(gnrDb, type::GenreFilter::id) , Status::CODE_403, "genre does not exist"); std::cout << "genre exist\n";
gnrDb = gnrRepo.retrieveRecord(gnrDb, type::GenreFilter::id);
std::cout << "genre exist" << std::endl; auto genre = dto::GenreDto::createShared();
gnrDb = gnrRepo.retrieveRecord(gnrDb, type::GenreFilter::id); genre->id = gnrDb.id;
genre->category= gnrDb.category.c_str();
auto genre = dto::GenreDto::createShared(); return createDtoResponse(Status::CODE_200, genre);
genre->id = gnrDb.id; }
genre->category= gnrDb.category.c_str();
return createDtoResponse(Status::CODE_200, genre); #include OATPP_CODEGEN_END(ApiController)
} private:
model::BinaryPath m_bConf;
#include OATPP_CODEGEN_END(ApiController) };
private:
std::string m_exe_path;
model::BinaryPath m_bConf;
};
} }
#endif #endif
+27 -31
View File
@@ -16,46 +16,42 @@
#include "model/Models.h" #include "model/Models.h"
namespace controller { namespace controller {
class LoginController : public oatpp::web::server::api::ApiController { class LoginController : public oatpp::web::server::api::ApiController {
public: public:
LoginController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) LoginController(const model::BinaryPath& bConf,
: oatpp::web::server::api::ApiController(objectMapper), exe_path(p) OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
{ } :oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
LoginController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
:oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf)
{ }
#include OATPP_CODEGEN_BEGIN(ApiController) #include OATPP_CODEGEN_BEGIN(ApiController)
ENDPOINT("POST", "/api/v1/login", data, BODY_DTO(dto::UserDto::ObjectWrapper, usr)) { ENDPOINT("POST", "/api/v1/login", data, BODY_DTO(dto::UserDto::ObjectWrapper, usr)) {
OATPP_LOGI("icarus", "logging in"); OATPP_LOGI("icarus", "logging in");
manager::UserManager usrMgr(m_bConf); manager::UserManager usrMgr(m_bConf);
auto user = dto::conversion::DtoConversions::toUser(usr); auto user = dto::conversion::DtoConversions::toUser(usr);
if (!usrMgr.doesUserExist(user) || !usrMgr.validatePassword(user)) { if (!usrMgr.doesUserExist(user) || !usrMgr.validatePassword(user)) {
auto logRes = dto::LoginResultDto::createShared(); auto logRes = dto::LoginResultDto::createShared();
logRes->message = "invalid credentials"; logRes->message = "invalid credentials";
std::cout << "user does not exist" << std::endl; std::cout << "user does not exist\n";
return createDtoResponse(Status::CODE_401, logRes); return createDtoResponse(Status::CODE_401, logRes);
} }
std::cout << "user exists" << std::endl; std::cout << "user exists\n";
manager::TokenManager tok; manager::TokenManager tok;
auto token = tok.retrieveToken(m_bConf); auto token = tok.retrieveToken(m_bConf);
auto logRes = dto::conversion::DtoConversions::toLoginResultDto(user, token); auto logRes = dto::conversion::DtoConversions::toLoginResultDto(user, token);
logRes->message = "Successful"; logRes->message = "Successful";
return createDtoResponse(Status::CODE_200, logRes); return createDtoResponse(Status::CODE_200, logRes);
} }
#include OATPP_CODEGEN_END(ApiController) #include OATPP_CODEGEN_END(ApiController)
private: private:
std::string exe_path; model::BinaryPath m_bConf;
model::BinaryPath m_bConf; };
};
} }
#endif #endif
+5 -2
View File
@@ -17,8 +17,8 @@ namespace controller {
class RegisterController : public oatpp::web::server::api::ApiController { class RegisterController : public oatpp::web::server::api::ApiController {
public: public:
RegisterController(const model::BinaryPath& bConf, RegisterController(const model::BinaryPath& bConf,
OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) : OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) :
oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { } oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
#include OATPP_CODEGEN_BEGIN(ApiController) #include OATPP_CODEGEN_BEGIN(ApiController)
@@ -26,6 +26,9 @@ namespace controller {
BODY_DTO(dto::UserDto::ObjectWrapper, usr)) { BODY_DTO(dto::UserDto::ObjectWrapper, usr)) {
manager::UserManager usrMgr(m_bConf); manager::UserManager usrMgr(m_bConf);
auto user = dto::conversion::DtoConversions::toUser(usr); auto user = dto::conversion::DtoConversions::toUser(usr);
if (usrMgr.doesUserExist(user)) {
return createResponse(Status::CODE_401, "user already exists");
}
auto res = usrMgr.registerUser(user); auto res = usrMgr.registerUser(user);
auto registerResult = dto::conversion::DtoConversions::toRegisterResultDto(res); auto registerResult = dto::conversion::DtoConversions::toRegisterResultDto(res);
+166 -166
View File
@@ -32,219 +32,219 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class SongController : public oatpp::web::server::api::ApiController { class SongController : public oatpp::web::server::api::ApiController {
public: public:
SongController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) SongController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) : oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
{ }
SongController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) #include OATPP_CODEGEN_BEGIN(ApiController)
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf)
{ }
#include OATPP_CODEGEN_BEGIN(ApiController) // endpoint for uploading a song
ENDPOINT("POST", "/api/v1/song/data", songUpload,
REQUEST(std::shared_ptr<IncomingRequest>, request)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::upload), Status::CODE_403, "Not allowed");
// endpoint for uploading a song auto mp =
ENDPOINT("POST", "/api/v1/song/data", songUpload, std::make_shared<oatpp::web::mime::multipart::Multipart>
REQUEST(std::shared_ptr<IncomingRequest>, request)) (request->getHeaders());
{
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::upload), Status::CODE_403, "Not allowed");
auto mp = std::make_shared<oatpp::web::mime::multipart::Multipart>(request->getHeaders()); oatpp::web::mime::multipart::Reader mp_reader(mp.get());
oatpp::web::mime::multipart::Reader mp_reader(mp.get()); mp_reader.setPartReader("file",
oatpp::web::mime::multipart::createInMemoryPartReader(m_dataSize));
mp_reader.setPartReader("file", oatpp::web::mime::multipart::createInMemoryPartReader(m_dataSize)); request->transferBody(&mp_reader);
request->transferBody(&mp_reader); auto file = mp->getNamedPart("file");
auto file = mp->getNamedPart("file"); OATPP_ASSERT_HTTP(file, Status::CODE_400, "file is null");
OATPP_ASSERT_HTTP(file, Status::CODE_400, "file is null"); auto buff = std::unique_ptr<char>(new char[file->getKnownSize()]);
auto buffSize = file->getInputStream()->read(buff.get(), file->getKnownSize());
auto buff = std::unique_ptr<char>(new char[file->getKnownSize()]); std::vector<unsigned char> data(buff.get(), buff.get() + buffSize);
auto buffSize = file->getInputStream()->read(buff.get(), file->getKnownSize());
std::vector<unsigned char> data(buff.get(), buff.get() + buffSize); model::Song sng;
sng.data = std::move(data);
manager::SongManager songMgr(m_bConf);
const auto result = songMgr.saveSong(sng);
if (!result.first) {
switch (result.second) {
case type::SongUpload::AlreadyExist:
return createResponse(Status::CODE_400, "Song already exists");
default:
break;
}
}
model::Song sng; auto songDto = dto::conversion::DtoConversions::toSongDto(sng);
sng.data = std::move(data);
manager::SongManager songMgr(m_bConf);
const auto result = songMgr.saveSong(sng);
if (!result.first) {
switch (result.second) {
case type::SongUpload::AlreadyExist:
return createResponse(Status::CODE_400, "Song already exists");
default:
break;
}
}
auto songDto = dto::conversion::DtoConversions::toSongDto(sng); return createDtoResponse(Status::CODE_200, songDto);
}
return createDtoResponse(Status::CODE_200, songDto); // endpoint for retrieving all song records in json format
} ENDPOINT("GET", "/api/v1/song", songRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveSong), Status::CODE_403, "Not allowed");
// endpoint for retrieving all song records in json format std::cout << "starting process of retrieving songs\n";
ENDPOINT("GET", "/api/v1/song", songRecords, database::SongRepository songRepo(m_bConf);
REQUEST(std::shared_ptr<IncomingRequest>, request)) auto songsDb = songRepo.retrieveRecords();
{ auto songs = oatpp::data::mapping::type::List<dto::SongDto::ObjectWrapper>::createShared();
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveSong), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving songs" << std::endl; std::cout << "creating object to send\n";
database::SongRepository songRepo(m_bConf); for (auto& songDb : songsDb) {
auto songsDb = songRepo.retrieveRecords(); auto song = dto::conversion::DtoConversions::toSongDto(songDb);
auto songs = oatpp::data::mapping::type::List<dto::SongDto::ObjectWrapper>::createShared();
std::cout << "creating object to send" << std::endl; songs->pushBack(song);
for (auto& songDb : songsDb) { }
auto song = dto::conversion::DtoConversions::toSongDto(songDb);
songs->pushBack(song); return createDtoResponse(Status::CODE_200, songs);
} }
return createDtoResponse(Status::CODE_200, songs);
}
// endpoint for retrieving song record by the song id in json format // endpoint for retrieving song record by the song id in json format
ENDPOINT("GET", "/api/v1/song/{id}", songRecord, ENDPOINT("GET", "/api/v1/song/{id}", songRecord,
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) { REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveSong), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveSong), Status::CODE_403, "Not allowed");
database::SongRepository songRepo(m_bConf); database::SongRepository songRepo(m_bConf);
model::Song songDb(id); model::Song songDb(id);
if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) { if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) {
return songDoesNotExist(); return songDoesNotExist();
} }
std::cout << "song exists" << std::endl; std::cout << "song exists\n";
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id); songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
auto song = dto::conversion::DtoConversions::toSongDto(songDb); auto song = dto::conversion::DtoConversions::toSongDto(songDb);
return createDtoResponse(Status::CODE_200, song); return createDtoResponse(Status::CODE_200, song);
} }
ENDPOINT("GET", "/api/v1/song/data/{id}", downloadSong, ENDPOINT("GET", "/api/v1/song/data/{id}", downloadSong,
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) { REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::download), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::download), Status::CODE_403, "Not allowed");
database::SongRepository songRepo(m_bConf); database::SongRepository songRepo(m_bConf);
model::Song songDb(id); model::Song songDb(id);
if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) { if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) {
return songDoesNotExist(); return songDoesNotExist();
} }
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id); songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
auto rawSong = oatpp::base::StrBuffer::loadFromFile(songDb.songPath.c_str()); auto rawSong = oatpp::base::StrBuffer::loadFromFile(songDb.songPath.c_str());
auto response = createResponse(Status::CODE_200, rawSong); auto response = createResponse(Status::CODE_200, rawSong);
response->putHeader(Header::CONTENT_TYPE, "audio/mpeg"); response->putHeader(Header::CONTENT_TYPE, "audio/mpeg");
return response; return response;
} }
ENDPOINT("UPDATE", "/api/v1/song/{id}", songUpdate, ENDPOINT("UPDATE", "/api/v1/song/{id}", songUpdate,
REQUEST(std::shared_ptr<IncomingRequest>, request), REQUEST(std::shared_ptr<IncomingRequest>, request),
BODY_DTO(dto::SongDto::ObjectWrapper, songDto), PATH(Int32, id)) { BODY_DTO(dto::SongDto::ObjectWrapper, songDto), PATH(Int32, id)) {
songDto->id = id; songDto->id = id;
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::updateSong), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::updateSong), Status::CODE_403, "Not allowed");
auto updatedSong = dto::conversion::DtoConversions::toSong(songDto); auto updatedSong = dto::conversion::DtoConversions::toSong(songDto);
manager::SongManager songMgr(m_bConf); manager::SongManager songMgr(m_bConf);
auto result = songMgr.updateSong(updatedSong); auto result = songMgr.updateSong(updatedSong);
if (!result) { if (!result) {
return songDoesNotExist(); return songDoesNotExist();
} }
return createResponse(Status::CODE_200, "OK"); return createResponse(Status::CODE_200, "OK");
} }
// endpoint to delete a song // endpoint to delete a song
ENDPOINT("DELETE", "api/v1/song/data/{id}", songDelete, ENDPOINT("DELETE", "api/v1/song/data/{id}", songDelete,
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) { REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::deleteSong), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::deleteSong), Status::CODE_403, "Not allowed");
model::Song song(id); model::Song song(id);
manager::SongManager sngMgr(m_bConf); manager::SongManager sngMgr(m_bConf);
auto result = sngMgr.deleteSong(song); auto result = sngMgr.deleteSong(song);
if (!result) { if (!result) {
return songDoesNotExist(); return songDoesNotExist();
} }
return createResponse(Status::CODE_200, "OK"); return createResponse(Status::CODE_200, "OK");
} }
// endpoint for streaming a song // endpoint for streaming a song
ENDPOINT("GET", "/api/v1/song/stream/{id}", streamSong, ENDPOINT("GET", "/api/v1/song/stream/{id}", streamSong,
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) { REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::stream), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::stream), Status::CODE_403, "Not allowed");
database::SongRepository songRepo(m_bConf); database::SongRepository songRepo(m_bConf);
model::Song songDb(id); model::Song songDb(id);
if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) { if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) {
return songDoesNotExist(); return songDoesNotExist();
} }
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id); songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
oatpp::data::v_io_size dSize = 1024; oatpp::data::v_io_size dSize = 1024;
auto db = std::make_shared<oatpp::web::protocol::http::outgoing::ChunkedBody>( auto db = std::make_shared<oatpp::web::protocol::http::outgoing::ChunkedBody>(
std::make_shared<callback::StreamCallback>(songDb.songPath), nullptr, dSize); std::make_shared<callback::StreamCallback>(songDb.songPath),
nullptr, dSize);
auto response = OutgoingResponse::createShared(Status::CODE_200, db); auto response = OutgoingResponse::createShared(Status::CODE_200, db);
response->putHeader(Header::CONNECTION, Header::Value::CONNECTION_KEEP_ALIVE); response->putHeader(Header::CONNECTION, Header::Value::CONNECTION_KEEP_ALIVE);
response->putHeader(Header::CONTENT_TYPE, "audio/mpeg"); response->putHeader(Header::CONTENT_TYPE, "audio/mpeg");
return response; return response;
} }
#include OATPP_CODEGEN_END(ApiController) #include OATPP_CODEGEN_END(ApiController)
private: private:
std::shared_ptr<oatpp::web::protocol::http::outgoing::Response> std::shared_ptr<oatpp::web::protocol::http::outgoing::Response>
songDoesNotExist() { songDoesNotExist() {
return createResponse(Status::CODE_404, "Song not found"); return createResponse(Status::CODE_404, "Song not found");
} }
std::string m_exe_path; model::BinaryPath m_bConf;
model::BinaryPath m_bConf; const long m_dataSize = std::numeric_limits<long long int>::max();
};
const long m_dataSize = std::numeric_limits<long long int>::max();
};
} }
#endif #endif
+53 -55
View File
@@ -27,73 +27,71 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class YearController : public oatpp::web::server::api::ApiController class YearController : public oatpp::web::server::api::ApiController {
{ public:
public: YearController(const model::BinaryPath& bConf,
YearController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) : oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
{ }
YearController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) #include OATPP_CODEGEN_BEGIN(ApiController)
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf)
{ }
#include OATPP_CODEGEN_BEGIN(ApiController) // endpoint for retrieving all year records in json format
ENDPOINT("GET", "/api/v1/year", yearRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveYear), Status::CODE_403, "Not allowed");
// endpoint for retrieving all year records in json format std::cout << "starting process of retrieving year\n";
ENDPOINT("GET", "/api/v1/year", yearRecords, database::YearRepository yrRepo(m_bConf);
REQUEST(std::shared_ptr<IncomingRequest>, request)) auto yrsDb = yrRepo.retrieveRecords();
{ auto yearRecs = oatpp::data::mapping::type::
auto authHeader = request->getHeader("Authorization"); List<dto::YearDto::ObjectWrapper>::createShared();
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveYear), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving year" << std::endl; for (auto& yrDb : yrsDb) {
database::YearRepository yrRepo(m_bConf); auto yr = dto::YearDto::createShared();
auto yrsDb = yrRepo.retrieveRecords(); yr->id = yrDb.id;
auto yearRecs = oatpp::data::mapping::type::List<dto::YearDto::ObjectWrapper>::createShared(); yr->year = yrDb.year;
for (auto& yrDb : yrsDb) { yearRecs->pushBack(yr);
auto yr = dto::YearDto::createShared(); }
yr->id = yrDb.id;
yr->year = yrDb.year;
yearRecs->pushBack(yr); return createDtoResponse(Status::CODE_200, yearRecs);
} }
return createDtoResponse(Status::CODE_200, yearRecs); // endpoint for retrieving single year record by the year id in json format
} ENDPOINT("GET", "/api/v1/year/{id}", yearRecord,
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveYear), Status::CODE_403, "Not allowed");
// endpoint for retrieving single year record by the year id in json format database::YearRepository yrRepo(m_bConf);
ENDPOINT("GET", "/api/v1/year/{id}", yearRecord, model::Year yrDb(id);
REQUEST(std::shared_ptr<IncomingRequest>, request), PATH(Int32, id)) {
auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str();
manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveYear), Status::CODE_403, "Not allowed");
database::YearRepository yrRepo(m_bConf); OATPP_ASSERT_HTTP(yrRepo.doesYearExist(yrDb,
model::Year yrDb(id); type::YearFilter::id) , Status::CODE_403, "year does not exist");
OATPP_ASSERT_HTTP(yrRepo.doesYearExist(yrDb, type::YearFilter::id) , Status::CODE_403, "year does not exist"); std::cout << "year exist\n";
yrDb = yrRepo.retrieveRecord(yrDb, type::YearFilter::id);
std::cout << "year exist" << std::endl; auto year = dto::YearDto::createShared();
yrDb = yrRepo.retrieveRecord(yrDb, type::YearFilter::id); year->id = yrDb.id;
year->year= yrDb.year;
auto year = dto::YearDto::createShared(); return createDtoResponse(Status::CODE_200, year);
year->id = yrDb.id; }
year->year= yrDb.year;
return createDtoResponse(Status::CODE_200, year); #include OATPP_CODEGEN_END(ApiController)
} private:
model::BinaryPath m_bConf;
#include OATPP_CODEGEN_END(ApiController) };
private:
std::string m_exe_path;
model::BinaryPath m_bConf;
};
} }
#endif #endif
+2 -4
View File
@@ -9,10 +9,8 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/AlbumFilter.h" #include "type/AlbumFilter.h"
namespace database namespace database {
{ class AlbumRepository : public BaseRepository {
class AlbumRepository : public BaseRepository
{
public: public:
AlbumRepository(const model::BinaryPath&); AlbumRepository(const model::BinaryPath&);
+12 -8
View File
@@ -1,6 +1,7 @@
#ifndef ARTISTREPOSITORY_H_ #ifndef ARTISTREPOSITORY_H_
#define ARTISTREPOSITORY_H_ #define ARTISTREPOSITORY_H_
#include <memory>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -8,16 +9,15 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/ArtistFilter.h" #include "type/ArtistFilter.h"
namespace database namespace database {
{ class ArtistRepository : public BaseRepository {
class ArtistRepository : public BaseRepository
{
public: public:
ArtistRepository(const model::BinaryPath&); ArtistRepository(const model::BinaryPath&);
std::vector<model::Artist> retrieveRecords(); std::vector<model::Artist> retrieveRecords();
std::pair<model::Artist, int> retrieveRecordWithSongCount(model::Artist&, type::ArtistFilter); std::pair<model::Artist, int> retrieveRecordWithSongCount(
model::Artist&, type::ArtistFilter);
model::Artist retrieveRecord(model::Artist&, type::ArtistFilter); model::Artist retrieveRecord(model::Artist&, type::ArtistFilter);
@@ -30,9 +30,13 @@ namespace database
std::pair<model::Artist, int> parseRecordWithSongCount(MYSQL_STMT*); std::pair<model::Artist, int> parseRecordWithSongCount(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented std::shared_ptr<MYSQL_BIND> valueBind(model::Artist&,
// remove parseRecord(MYSQL_RES*) std::tuple<char*>&);
model::Artist parseRecord(MYSQL_RES*); std::shared_ptr<MYSQL_BIND> valueBindWithSongCount(model::Artist&,
std::tuple<char*>&, int&);
std::tuple<char*> metadataBuffer();
model::Artist parseRecord(MYSQL_STMT*); model::Artist parseRecord(MYSQL_STMT*);
}; };
} }
+3 -5
View File
@@ -7,12 +7,10 @@
#include "model/Models.h" #include "model/Models.h"
namespace database namespace database {
{ class BaseRepository {
class BaseRepository
{
public: public:
BaseRepository(); BaseRepository() = default;
BaseRepository(const std::string&); BaseRepository(const std::string&);
BaseRepository(const model::BinaryPath&); BaseRepository(const model::BinaryPath&);
+9 -9
View File
@@ -1,6 +1,7 @@
#ifndef COVERARTREPOSITORY_H_ #ifndef COVERARTREPOSITORY_H_
#define COVERARTREPOSITORY_H_ #define COVERARTREPOSITORY_H_
#include <memory>
#include <vector> #include <vector>
#include <mysql/mysql.h> #include <mysql/mysql.h>
@@ -9,12 +10,9 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/CoverFilter.h" #include "type/CoverFilter.h"
namespace database namespace database {
{ class CoverArtRepository : public BaseRepository {
class CoverArtRepository : public BaseRepository
{
public: public:
CoverArtRepository(const std::string&);
CoverArtRepository(const model::BinaryPath&); CoverArtRepository(const model::BinaryPath&);
std::vector<model::Cover> retrieveRecords(); std::vector<model::Cover> retrieveRecords();
@@ -23,15 +21,17 @@ namespace database
bool doesCoverArtExist(const model::Cover&, type::CoverFilter); bool doesCoverArtExist(const model::Cover&, type::CoverFilter);
void deleteRecord(const model::Cover&); void deleteRecord(const model::Cover&, type::CoverFilter = type::CoverFilter::id);
void saveRecord(const model::Cover&); void saveRecord(const model::Cover&);
void updateRecord(const model::Cover&); void updateRecord(const model::Cover&);
private: private:
std::vector<model::Cover> parseRecords(MYSQL_STMT*); std::vector<model::Cover> parseRecords(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented std::shared_ptr<MYSQL_BIND> valueBind(model::Cover&,
// remove parseRecord(MYSQL_RES*) std::tuple<char*, char*>&);
model::Cover parseRecord(MYSQL_RES*);
std::tuple<char*, char*> metadataBuffer();
model::Cover parseRecord(MYSQL_STMT*); model::Cover parseRecord(MYSQL_STMT*);
}; };
} }
+10 -7
View File
@@ -1,6 +1,7 @@
#ifndef GENREREPOSITORY_H_ #ifndef GENREREPOSITORY_H_
#define GENREREPOSITORY_H_ #define GENREREPOSITORY_H_
#include <memory>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -8,10 +9,8 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/GenreFilter.h" #include "type/GenreFilter.h"
namespace database namespace database {
{ class GenreRepository : public BaseRepository {
class GenreRepository : public BaseRepository
{
public: public:
GenreRepository(const model::BinaryPath&); GenreRepository(const model::BinaryPath&);
@@ -30,9 +29,13 @@ namespace database
std::pair<model::Genre, int> parseRecordWithSongCount(MYSQL_STMT*); std::pair<model::Genre, int> parseRecordWithSongCount(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented std::shared_ptr<MYSQL_BIND> valueBind(model::Genre&,
// remove parseRecord(MYSQL_RES*) std::tuple<char*>&);
model::Genre parseRecord(MYSQL_RES*); std::shared_ptr<MYSQL_BIND> valueBindWithSongCount(model::Genre&,
std::tuple<char*>&, int&);
std::tuple<char*> metadataBuffer();
model::Genre parseRecord(MYSQL_STMT*); model::Genre parseRecord(MYSQL_STMT*);
}; };
} }
+4 -6
View File
@@ -11,18 +11,16 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/SongFilter.h" #include "type/SongFilter.h"
namespace database namespace database {
{ class SongRepository : public BaseRepository {
class SongRepository : public BaseRepository
{
public: public:
SongRepository(const model::BinaryPath&); SongRepository(const model::BinaryPath&);
std::vector<model::Song> retrieveRecords(); std::vector<model::Song> retrieveRecords();
model::Song retrieveRecord(const model::Song&, type::SongFilter); model::Song retrieveRecord(const model::Song&, type::SongFilter = type::SongFilter::id);
bool doesSongExist(const model::Song&, type::SongFilter); bool doesSongExist(const model::Song&, type::SongFilter = type::SongFilter::id);
bool deleteRecord(const model::Song&); bool deleteRecord(const model::Song&);
void saveRecord(const model::Song&); void saveRecord(const model::Song&);
+37 -37
View File
@@ -11,48 +11,48 @@
#include "type/UserFilter.h" #include "type/UserFilter.h"
namespace database { namespace database {
class UserRepository : BaseRepository { class UserRepository : BaseRepository {
public: public:
UserRepository(const model::BinaryPath&); UserRepository(const model::BinaryPath&);
model::User retrieveUserRecord(model::User&, type::UserFilter); model::User retrieveUserRecord(model::User&, type::UserFilter);
model::PassSec retrieverUserSaltRecord(model::PassSec&, type::SaltFilter); model::PassSec retrieverUserSaltRecord(model::PassSec&, type::SaltFilter);
bool doesUserRecordExist(const model::User&, type::UserFilter); bool doesUserRecordExist(const model::User&, type::UserFilter);
void saveUserRecord(const model::User&); void saveUserRecord(const model::User&);
void saveUserSalt(const model::PassSec&); void saveUserSalt(const model::PassSec&);
private: private:
struct UserLengths; struct UserLengths;
struct SaltLengths; struct SaltLengths;
struct UserLengths struct UserLengths {
{ unsigned long firstnameLength;
unsigned long firstnameLength; unsigned long lastnameLength;
unsigned long lastnameLength; unsigned long phoneLength;
unsigned long phoneLength; unsigned long emailLength;
unsigned long emailLength; unsigned long usernameLength;
unsigned long usernameLength; unsigned long passwordLength;
unsigned long passwordLength; };
struct SaltLengths {
unsigned long saltLength;
};
std::shared_ptr<MYSQL_BIND> insertUserValues(const model::User&,
std::shared_ptr<UserLengths>);
std::shared_ptr<MYSQL_BIND> insertSaltValues(const model::PassSec&,
std::shared_ptr<SaltLengths>);
std::shared_ptr<MYSQL_BIND> valueBind(model::User&,
std::tuple<char*, char*, char*, char*, char*, char*>&);
std::shared_ptr<MYSQL_BIND> saltValueBind(model::PassSec&, char*);
std::shared_ptr<UserLengths> fetchUserLengths(const model::User&);
std::shared_ptr<SaltLengths> fetchSaltLengths(const model::PassSec&);
std::tuple<char*, char*, char*, char*, char*, char*> fetchUV();
model::User parseRecord(MYSQL_STMT*);
model::PassSec parseSaltRecord(MYSQL_STMT*);
}; };
struct SaltLengths
{
unsigned long saltLength;
};
std::shared_ptr<MYSQL_BIND> insertUserValues(const model::User&, std::shared_ptr<UserLengths>);
std::shared_ptr<MYSQL_BIND> insertSaltValues(const model::PassSec&, std::shared_ptr<SaltLengths>);
std::shared_ptr<MYSQL_BIND> valueBind(model::User&, std::tuple<char*, char*, char*, char*, char*, char*>&);
std::shared_ptr<MYSQL_BIND> saltValueBind(model::PassSec&, char*);
std::shared_ptr<UserLengths> fetchUserLengths(const model::User&);
std::shared_ptr<SaltLengths> fetchSaltLengths(const model::PassSec&);
std::tuple<char*, char*, char*, char*, char*, char*> fetchUV();
model::User parseRecord(MYSQL_STMT*);
model::PassSec parseSaltRecord(MYSQL_STMT*);
};
} }
#endif #endif
+12 -11
View File
@@ -1,6 +1,7 @@
#ifndef YEARREPOSITORY_H_ #ifndef YEARREPOSITORY_H_
#define YEARREPOSITORY_H_ #define YEARREPOSITORY_H_
#include <memory>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -8,31 +9,31 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/YearFilter.h" #include "type/YearFilter.h"
namespace database namespace database {
{ class YearRepository : public BaseRepository {
class YearRepository : public BaseRepository
{
public: public:
YearRepository(const model::BinaryPath&); YearRepository(const model::BinaryPath&);
std::vector<model::Year> retrieveRecords(); std::vector<model::Year> retrieveRecords();
std::pair<model::Year, int> retrieveRecordWithSongCount(model::Year&, type::YearFilter); std::pair<model::Year, int> retrieveRecordWithSongCount(model::Year&,
type::YearFilter = type::YearFilter::id);
model::Year retrieveRecord(model::Year&, type::YearFilter); model::Year retrieveRecord(model::Year&, type::YearFilter = type::YearFilter::id);
bool doesYearExist(const model::Year&, type::YearFilter); bool doesYearExist(const model::Year&, type::YearFilter = type::YearFilter::id);
void saveRecord(const model::Year&); void saveRecord(const model::Year&);
void deleteYear(const model::Year&, type::YearFilter); void deleteYear(const model::Year&, type::YearFilter = type::YearFilter::id);
private: private:
std::vector<model::Year> parseRecords(MYSQL_STMT*); std::vector<model::Year> parseRecords(MYSQL_STMT*);
std::pair<model::Year, int> parseRecordWithSongCount(MYSQL_STMT*); std::pair<model::Year, int> parseRecordWithSongCount(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented std::shared_ptr<MYSQL_BIND> valueBind(model::Year&);
// remove parseRecord(MYSQL_RES*) std::shared_ptr<MYSQL_BIND> valueBindWithSongCount(model::Year&,
model::Year parseRecord(MYSQL_RES*); int&);
model::Year parseRecord(MYSQL_STMT*); model::Year parseRecord(MYSQL_STMT*);
}; };
} }
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp" #include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp" #include "oatpp/core/macro/codegen.hpp"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class AlbumDto : public oatpp::data::mapping::type::Object class AlbumDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(AlbumDto, Object) DTO_INIT(AlbumDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp" #include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp" #include "oatpp/core/macro/codegen.hpp"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class ArtistDto : public oatpp::data::mapping::type::Object class ArtistDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(ArtistDto, Object) DTO_INIT(ArtistDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp" #include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp" #include "oatpp/core/macro/codegen.hpp"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class CoverArtDto : public oatpp::data::mapping::type::Object class CoverArtDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(CoverArtDto, Object) DTO_INIT(CoverArtDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp" #include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp" #include "oatpp/core/macro/codegen.hpp"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class GenreDto : public oatpp::data::mapping::type::Object class GenreDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(GenreDto, Object) DTO_INIT(GenreDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
+2 -4
View File
@@ -6,12 +6,10 @@
#include "model/Models.h" #include "model/Models.h"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class SongDto : public oatpp::data::mapping::type::Object class SongDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(SongDto, Object) DTO_INIT(SongDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp" #include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp" #include "oatpp/core/macro/codegen.hpp"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class YearDto : public oatpp::data::mapping::type::Object class YearDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(YearDto, Object) DTO_INIT(YearDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h" #include "model/Models.h"
namespace manager namespace manager {
{ class AlbumManager {
class AlbumManager
{
public: public:
AlbumManager(const model::BinaryPath&); AlbumManager(const model::BinaryPath&);
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h" #include "model/Models.h"
namespace manager namespace manager {
{ class ArtistManager {
class ArtistManager
{
public: public:
ArtistManager(const model::BinaryPath&); ArtistManager(const model::BinaryPath&);
+2 -6
View File
@@ -6,12 +6,9 @@
#include "model/Models.h" #include "model/Models.h"
namespace manager namespace manager {
{ class CoverArtManager {
class CoverArtManager
{
public: public:
CoverArtManager(const std::string&);
CoverArtManager(const model::BinaryPath& bConf); CoverArtManager(const model::BinaryPath& bConf);
model::Cover saveCover(const model::Song&); model::Cover saveCover(const model::Song&);
@@ -25,7 +22,6 @@ namespace manager
std::string createImagePath(const model::Song&); std::string createImagePath(const model::Song&);
model::BinaryPath m_bConf; model::BinaryPath m_bConf;
std::string path;
}; };
} }
+4 -5
View File
@@ -9,13 +9,12 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/PathType.h" #include "type/PathType.h"
namespace manager namespace manager {
{ class DirectoryManager {
class DirectoryManager
{
public: public:
static std::string createDirectoryProcess(model::Song, const std::string&); static std::string createDirectoryProcess(model::Song, const std::string&);
static std::string createDirectoryProcess(const model::Song&, const model::BinaryPath&, type::PathType); static std::string createDirectoryProcess(const model::Song&,
const model::BinaryPath&, type::PathType);
static std::string configPath(std::string_view); static std::string configPath(std::string_view);
static std::string configPath(const model::BinaryPath&); static std::string configPath(const model::BinaryPath&);
static std::string contentOfPath(const std::string&); static std::string contentOfPath(const std::string&);
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h" #include "model/Models.h"
namespace manager namespace manager {
{ class GenreManager {
class GenreManager
{
public: public:
GenreManager(const model::BinaryPath&); GenreManager(const model::BinaryPath&);
+1 -2
View File
@@ -14,8 +14,7 @@
#include "type/SongUpload.h" #include "type/SongUpload.h"
namespace manager { namespace manager {
class SongManager class SongManager {
{
public: public:
SongManager(const model::BinaryPath&); SongManager(const model::BinaryPath&);
+14 -14
View File
@@ -14,26 +14,26 @@
#include "type/Scopes.h" #include "type/Scopes.h"
namespace manager { namespace manager {
class TokenManager { class TokenManager {
public: public:
TokenManager() = default; TokenManager() = default;
model::Token retrieveToken(const model::BinaryPath&); model::Token retrieveToken(const model::BinaryPath&);
bool isTokenValid(std::string&, type::Scope); bool isTokenValid(std::string&, type::Scope);
bool testAuth(const model::BinaryPath&); bool testAuth(const model::BinaryPath&);
private: private:
cpr::Response sendRequest(std::string_view, nlohmann::json&); cpr::Response sendRequest(std::string_view, nlohmann::json&);
nlohmann::json createTokenBody(const model::AuthCredentials&); nlohmann::json createTokenBody(const model::AuthCredentials&);
model::AuthCredentials parseAuthCredentials(const model::BinaryPath&); model::AuthCredentials parseAuthCredentials(const model::BinaryPath&);
std::vector<std::string> extractScopes(const jwt::decoded_jwt&&); std::vector<std::string> extractScopes(const jwt::decoded_jwt&&);
std::pair<bool, std::vector<std::string>> fetchAuthHeader(const std::string&); std::pair<bool, std::vector<std::string>> fetchAuthHeader(const std::string&);
bool tokenSupportsScope(const std::vector<std::string>&, const std::string&&); bool tokenSupportsScope(const std::vector<std::string>&, const std::string&&);
}; };
} }
#endif #endif
+10 -10
View File
@@ -7,19 +7,19 @@
#include "model/Models.h" #include "model/Models.h"
namespace manager { namespace manager {
class UserManager { class UserManager {
public: public:
UserManager(const model::BinaryPath&); UserManager(const model::BinaryPath&);
model::RegisterResult registerUser(model::User&); model::RegisterResult registerUser(model::User&);
bool doesUserExist(const model::User&); bool doesUserExist(const model::User&);
bool validatePassword(const model::User&); bool validatePassword(const model::User&);
void printUser(const model::User&); void printUser(const model::User&);
private: private:
model::BinaryPath m_bConf; model::BinaryPath m_bConf;
}; };
} }
#endif #endif
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h" #include "model/Models.h"
namespace manager namespace manager {
{ class YearManager {
class YearManager
{
public: public:
YearManager(const model::BinaryPath&); YearManager(const model::BinaryPath&);
+144 -144
View File
@@ -5,172 +5,172 @@
#include <vector> #include <vector>
namespace model { namespace model {
class Song { class Song {
public: public:
Song() = default; Song() = default;
Song(const int id) : id(id) { } Song(const int id) : id(id) { }
Song(const int id, const std::string& title, const std::string& artist, Song(const int id, const std::string& title, const std::string& artist,
const std::string& album, const std::string& albumArtist, const std::string& album, const std::string& albumArtist,
const std::string& genre, const int year, const int duration, const std::string& genre, const int year, const int duration,
const int track, const int disc, const std::string songPath) : const int track, const int disc, const std::string songPath) :
id(id), title(title), artist(artist), album(album), id(id), title(title), artist(artist), album(album),
albumArtist(albumArtist), genre(genre), year(year), albumArtist(albumArtist), genre(genre), year(year),
duration(duration), track(track), disc(disc), duration(duration), track(track), disc(disc),
songPath(songPath) { } songPath(songPath) { }
int id; int id;
std::string title; std::string title;
std::string artist; std::string artist;
std::string album; std::string album;
std::string albumArtist; std::string albumArtist;
std::string genre; std::string genre;
int year; int year;
int duration; int duration;
int track; int track;
int disc; int disc;
std::string songPath; std::string songPath;
std::vector<unsigned char> data; std::vector<unsigned char> data;
int coverArtId; int coverArtId;
int artistId; int artistId;
int albumId; int albumId;
int genreId; int genreId;
int yearId; int yearId;
}; };
class Artist { class Artist {
public: public:
Artist() = default; Artist() = default;
Artist(const Song& song) : id(song.artistId), artist(song.artist) { } Artist(const Song& song) : id(song.artistId), artist(song.artist) { }
Artist(const int id) : id(id) { } Artist(const int id) : id(id) { }
int id; int id;
std::string artist; std::string artist;
}; };
class Album { class Album {
public: public:
Album() = default; Album() = default;
Album(const Song& song) : Album(const Song& song) :
id(song.albumId), title(song.album),artist(song.artist), year(song.year) { } id(song.albumId), title(song.album),artist(song.artist), year(song.year) { }
Album(const int id) : id(id) { } Album(const int id) : id(id) { }
int id; int id;
std::string title; std::string title;
std::string artist; std::string artist;
int year; int year;
std::vector<Song> songs; std::vector<Song> songs;
}; };
class Genre { class Genre {
public: public:
Genre() = default; Genre() = default;
Genre(const Song& song) : Genre(const Song& song) :
id(song.genreId), category(song.genre) { } id(song.genreId), category(song.genre) { }
Genre(const int id) : id(id) { } Genre(const int id) : id(id) { }
int id; int id;
std::string category; std::string category;
}; };
class Year { class Year {
public: public:
Year() = default; Year() = default;
Year(const Song& song) : Year(const Song& song) :
id(song.yearId), year(song.year) { } id(song.yearId), year(song.year) { }
Year(const int id) : id(id) { } Year(const int id) : id(id) { }
int id; int id;
int year; int year;
}; };
class Cover { class Cover {
public: public:
Cover() = default; Cover() = default;
Cover(const Song& song) : Cover(const Song& song) :
id(song.coverArtId), songTitle(song.title) { } id(song.coverArtId), songTitle(song.title) { }
Cover(const int id) : id(id) { } Cover(const int id) : id(id) { }
int id; int id;
std::string songTitle; std::string songTitle;
std::string imagePath; std::string imagePath;
// Not being used but it should be // Not being used but it should be
std::vector<unsigned char> data; std::vector<unsigned char> data;
}; };
class Token { class Token {
public: public:
Token() = default; Token() = default;
Token(const std::string& accessToken) : Token(const std::string& accessToken) :
accessToken(accessToken) { } accessToken(accessToken) { }
Token(const std::string& accessToken, const std::string& tokenType, Token(const std::string& accessToken, const std::string& tokenType,
const int expiration) : const int expiration) :
accessToken(accessToken), tokenType(tokenType), accessToken(accessToken), tokenType(tokenType),
expiration(expiration) { } expiration(expiration) { }
std::string accessToken; std::string accessToken;
int expiration; int expiration;
std::string tokenType; std::string tokenType;
}; };
struct LoginResult { struct LoginResult {
int userId; int userId;
std::string username; std::string username;
std::string accessToken; std::string accessToken;
std::string tokenType; std::string tokenType;
std::string message; std::string message;
int expiration; int expiration;
}; };
class RegisterResult { class RegisterResult {
public: public:
std::string username; std::string username;
bool registered; bool registered;
std::string message; std::string message;
}; };
struct User { struct User {
int id; int id;
std::string firstname; std::string firstname;
std::string lastname; std::string lastname;
std::string email; std::string email;
std::string phone; std::string phone;
std::string username; std::string username;
std::string password; std::string password;
}; };
struct PassSec { struct PassSec {
int id; int id;
std::string hashPassword; std::string hashPassword;
std::string salt; std::string salt;
int userId; int userId;
}; };
struct AuthCredentials { struct AuthCredentials {
std::string domain; std::string domain;
std::string apiIdentifier; std::string apiIdentifier;
std::string clientId; std::string clientId;
std::string clientSecret; std::string clientSecret;
std::string uri; std::string uri;
std::string endpoint; std::string endpoint;
}; };
struct DatabaseConnection { struct DatabaseConnection {
std::string server; std::string server;
std::string username; std::string username;
std::string password; std::string password;
std::string database; std::string database;
}; };
class BinaryPath { class BinaryPath {
public: public:
BinaryPath() = default; BinaryPath() = default;
BinaryPath(const char *p) : path(p) { } BinaryPath(const char *p) : path(p) { }
BinaryPath(const std::string& p) : path(p) { } BinaryPath(const std::string& p) : path(p) { }
BinaryPath(const std::string&& p) : path(p) { } BinaryPath(const std::string&& p) : path(p) { }
std::string path; std::string path;
}; };
} }
#endif #endif
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef ALBUMFILTER_H_ #ifndef ALBUMFILTER_H_
#define ALBUMFILTER_H_ #define ALBUMFILTER_H_
namespace type namespace type {
{ enum class AlbumFilter {
enum class AlbumFilter
{
id = 0, id = 0,
title, title,
year year
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef ARTISTFILTER_H_ #ifndef ARTISTFILTER_H_
#define ARTISTFILTER_H_ #define ARTISTFILTER_H_
namespace type namespace type {
{ enum class ArtistFilter {
enum class ArtistFilter
{
id = 0, id = 0,
artist artist
}; };
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef COVERFILTER_H_ #ifndef COVERFILTER_H_
#define COVERFILTER_H_ #define COVERFILTER_H_
namespace type namespace type {
{ enum class CoverFilter {
enum class CoverFilter
{
id = 0, id = 0,
songTitle, songTitle,
imagePath imagePath
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef GENREFILTER_H_ #ifndef GENREFILTER_H_
#define GENREFILTER_H_ #define GENREFILTER_H_
namespace type namespace type {
{ enum class GenreFilter {
enum class GenreFilter
{
id = 0, id = 0,
category category
}; };
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef PATHTYPE_H_ #ifndef PATHTYPE_H_
#define PATHTYPE_H_ #define PATHTYPE_H_
namespace type namespace type {
{ enum PathType {
enum PathType
{
music = 0, music = 0,
archive, archive,
temp, temp,
+1 -2
View File
@@ -2,8 +2,7 @@
#define SALTFILTER_H_ #define SALTFILTER_H_
namespace type { namespace type {
enum class SaltFilter enum class SaltFilter {
{
id = 0, id = 0,
salt, salt,
userId userId
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef SCOPES_H_ #ifndef SCOPES_H_
#define SCOPES_H_ #define SCOPES_H_
namespace type namespace type {
{ enum class Scope {
enum class Scope
{
upload = 0, upload = 0,
download, download,
stream, stream,
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef SONGCHANGED_H_ #ifndef SONGCHANGED_H_
#define SONGCHANGED_H_ #define SONGCHANGED_H_
namespace type namespace type {
{ enum SongChanged {
enum SongChanged
{
title = 0, title = 0,
artist, artist,
album, album,
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef SONGFILTER_H_ #ifndef SONGFILTER_H_
#define SONGFILTER_H_ #define SONGFILTER_H_
namespace type namespace type {
{ enum class SongFilter {
enum class SongFilter
{
id = 0, id = 0,
title, title,
album, album,
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef SONGUPLOAD_H_ #ifndef SONGUPLOAD_H_
#define SONGUPLOAD_H_ #define SONGUPLOAD_H_
namespace type namespace type {
{ enum class SongUpload {
enum class SongUpload
{
Successful = 0, Successful = 0,
AlreadyExist = 1, AlreadyExist = 1,
Failed = 2 Failed = 2
+1 -2
View File
@@ -2,8 +2,7 @@
#define USERFILTER_H_ #define USERFILTER_H_
namespace type { namespace type {
enum class UserFilter enum class UserFilter {
{
id = 0, id = 0,
username username
}; };
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef YEARFILTER_H_ #ifndef YEARFILTER_H_
#define YEARFILTER_H_ #define YEARFILTER_H_
namespace type namespace type {
{ enum class YearFilter {
enum class YearFilter
{
id = 0, id = 0,
year year
}; };
+2 -4
View File
@@ -13,10 +13,8 @@
#include <tpropertymap.h> #include <tpropertymap.h>
#include <id3v2tag.h> #include <id3v2tag.h>
namespace utility namespace utility {
{ class ImageFile : public TagLib::File {
class ImageFile : public TagLib::File
{
public: public:
ImageFile(const char *file); ImageFile(const char *file);
+10 -11
View File
@@ -7,20 +7,19 @@
#include "model/Models.h" #include "model/Models.h"
namespace utility { namespace utility {
class MetadataRetriever class MetadataRetriever {
{ public:
public: model::Song retrieveMetadata(model::Song&);
model::Song retrieveMetadata(model::Song&);
model::Cover updateCoverArt(const model::Song&, model::Cover&, const std::string&); model::Cover updateCoverArt(const model::Song&, model::Cover&, const std::string&);
model::Cover applyStockCoverArt(const model::Song&, model::Cover&, const std::string&); model::Cover applyStockCoverArt(const model::Song&, model::Cover&, const std::string&);
model::Cover applyCoverArt(const model::Song&, model::Cover&); model::Cover applyCoverArt(const model::Song&, model::Cover&);
bool songContainsCoverArt(const model::Song&); bool songContainsCoverArt(const model::Song&);
void updateMetadata(model::Song&, const model::Song&); void updateMetadata(model::Song&, const model::Song&);
private: private:
}; };
} }
#endif #endif
+1 -1
View File
@@ -12,7 +12,7 @@ public:
bool isPasswordValid(const model::User&, const model::PassSec&); bool isPasswordValid(const model::User&, const model::PassSec&);
private: private:
int saltSize(); constexpr int saltSize() noexcept;
}; };
} }
+2 -4
View File
@@ -5,10 +5,8 @@
#include "model/Models.h" #include "model/Models.h"
namespace verify namespace verify {
{ class Initialization {
class Initialization
{
public: public:
static bool skipVerification(const std::string&); static bool skipVerification(const std::string&);
+3 -5
View File
@@ -23,8 +23,7 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
void run(const model::BinaryPath& bConf) void run(const model::BinaryPath& bConf) {
{
component::AppComponent component; component::AppComponent component;
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router);
@@ -58,8 +57,7 @@ void run(const model::BinaryPath& bConf)
server.run(); server.run();
} }
int main(int argc, char **argv) int main(int argc, char **argv) {
{
oatpp::base::Environment::init(); oatpp::base::Environment::init();
model::BinaryPath bConf(std::move(argv[0])); model::BinaryPath bConf(std::move(argv[0]));
@@ -68,7 +66,7 @@ int main(int argc, char **argv)
if (!verify::Initialization::skipVerification(argv[1])) { if (!verify::Initialization::skipVerification(argv[1])) {
verify::Initialization::checkIcarus(bConf); verify::Initialization::checkIcarus(bConf);
} else { } else {
std::cout << "skiping verifyication" << std::endl; std::cout << "skiping verifyication\n";
} }
} else { } else {
verify::Initialization::checkIcarus(bConf); verify::Initialization::checkIcarus(bConf);
+25 -28
View File
@@ -5,40 +5,37 @@
#include <memory> #include <memory>
namespace callback { namespace callback {
StreamCallback::StreamCallback() : StreamCallback::StreamCallback() : m_counter(0) { }
m_counter(0) { }
StreamCallback::StreamCallback(const std::string& songPath) : StreamCallback::StreamCallback(const std::string& songPath) :
m_songPath(songPath), m_songPath(songPath),
m_counter(0), m_counter(0),
m_bytesRead(0) m_bytesRead(0) {
{ // getting file size
// getting file size std::ifstream song(m_songPath.c_str(), std::ios::binary | std::ios::in | std::ios::ate);
std::ifstream song(m_songPath.c_str(), std::ios::binary | std::ios::in | std::ios::ate); m_fileSize = song.tellg();
m_fileSize = song.tellg(); std::cout << "file size is " << m_fileSize << " bytes\n";
std::cout << "file size is " << m_fileSize << " bytes" << std::endl;
}
oatpp::data::v_io_size StreamCallback::read(void *buff, oatpp::data::v_io_size count)
{
if (m_counter >= m_fileSize) {
std::cout << "done streaming song" << std::endl;
return 0;
} }
std::fstream song(m_songPath.c_str(), std::ios::binary | std::ios::in);
song.seekg(m_counter);
std::unique_ptr<char[]> data(new char[count]); oatpp::data::v_io_size StreamCallback::read(void *buff, oatpp::data::v_io_size count) {
if (m_counter >= m_fileSize) {
std::cout << "done streaming song\n";
return 0;
}
song.read(data.get(), count); std::fstream song(m_songPath.c_str(), std::ios::binary | std::ios::in);
std::memcpy(buff, data.get(), count); song.seekg(m_counter);
m_counter += count; std::unique_ptr<char[]> data(new char[count]);
song.close(); song.read(data.get(), count);
std::memcpy(buff, data.get(), count);
return count; m_counter += count;
}
song.close();
return count;
}
} }
+336 -348
View File
@@ -8,396 +8,384 @@
#include <cstring> #include <cstring>
namespace database { namespace database {
AlbumRepository::AlbumRepository(const model::BinaryPath& bConf) AlbumRepository::AlbumRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { }
: BaseRepository(bConf)
{ }
std::vector<model::Album> AlbumRepository::retrieveRecords() std::vector<model::Album> AlbumRepository::retrieveRecords() {
{ auto conn = setupMysqlConnection();
auto conn = setupMysqlConnection(); auto stmt = mysql_stmt_init(conn);
auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Album"; const std::string query = "SELECT * FROM Album";
mysql_stmt_prepare(stmt, query.c_str(), query.size()); mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt); mysql_stmt_execute(stmt);
auto albums = parseRecords(stmt); auto albums = parseRecords(stmt);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
return albums; return albums;
}
std::pair<model::Album, int> AlbumRepository::retrieveRecordWithSongCount(model::Album& album, type::AlbumFilter filter = type::AlbumFilter::id)
{
std::cout << "retrieving album with song count" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
qry << "SELECT alb.*, COUNT(*) AS SongCount FROM Album alb LEFT JOIN ";
qry << "Song sng ON alb.AlbumId=sng.AlbumId WHERE ";
switch (filter) {
case type::AlbumFilter::id:
qry << "sng.AlbumId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&album.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
qry << " GROUP BY alb.AlbumId LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
auto albWSC = parseRecordWithSongCount(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
return albWSC;
}
model::Album AlbumRepository::retrieveRecord(model::Album& album, type::AlbumFilter filter)
{
std::cout << "retrieving album record" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
qry << "SELECT alb.* FROM Album alb WHERE ";
auto titleLength = album.title.size();
switch (filter) {
case type::AlbumFilter::id:
qry << "alb.AlbumId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&album.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::AlbumFilter::title:
qry << "alb.Title = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)album.title.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
break;
default:
break;
} }
qry << " LIMIT 1";
const auto query = qry.str(); std::pair<model::Album, int> AlbumRepository::retrieveRecordWithSongCount(model::Album& album,
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); type::AlbumFilter filter = type::AlbumFilter::id) {
status = mysql_stmt_bind_param(stmt, params); std::cout << "retrieving album with song count\n";
status = mysql_stmt_execute(stmt); std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
album = parseRecord(stmt); MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
mysql_stmt_close(stmt); qry << "SELECT alb.*, COUNT(*) AS SongCount FROM Album alb LEFT JOIN ";
mysql_close(conn); qry << "Song sng ON alb.AlbumId=sng.AlbumId WHERE ";
std::cout << "done" << std::endl; switch (filter) {
case type::AlbumFilter::id:
qry << "sng.AlbumId = ?";
return album; params[0].buffer_type = MYSQL_TYPE_LONG;
} params[0].buffer = (char*)&album.id;
params[0].length = 0;
bool AlbumRepository::doesAlbumExists(const model::Album& album, type::AlbumFilter filter) params[0].is_null = 0;
{ break;
auto conn = setupMysqlConnection(); default:
auto stmt = mysql_stmt_init(conn); break;
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
std::stringstream qry;
qry << "SELECT * FROM Album WHERE ";
auto titleLength = album.title.size();
switch (filter) {
case type::AlbumFilter::id:
qry << "AlbumId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&album.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::AlbumFilter::title:
qry << "Title = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)album.title.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
break;
default:
break;
}
qry << " LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed" << std::endl;
::mysql_stmt_store_result(stmt);
auto rowCount = ::mysql_stmt_num_rows(stmt);
::mysql_stmt_close(stmt);
::mysql_close(conn);
return (rowCount > 0) ? true : false;
}
void AlbumRepository::saveAlbum(const model::Album& album)
{
std::cout << "beginning to insert album record" << std::endl;
auto conn = setupMysqlConnection();
MYSQL_STMT *stmt = mysql_stmt_init(conn);
const std::string query = "INSERT INTO Album(Title, Artist, Year) VALUES(?, ?, ?)";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
MYSQL_BIND params[3];
memset(params, 0, sizeof(params));
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)album.title.c_str();
auto titleLength = album.title.size();
params[0].length= &titleLength;
params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)album.artist.c_str();
auto artistLength = album.artist.size();
params[1].length = &artistLength;
params[1].is_null = 0;
params[2].buffer_type = MYSQL_TYPE_LONG;
params[2].buffer = (char*)&album.year;
params[2].length = 0;
params[2].is_null = 0;
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "done inserting album record" << std::endl;
}
void AlbumRepository::deleteAlbum(const model::Album& album, type::AlbumFilter filter = type::AlbumFilter::id)
{
std::cout << "deleting album record" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
qry << "DELETE FROM Album WHERE ";
switch (filter) {
case type::AlbumFilter::id:
qry << "AlbumId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&album.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
std::cout << "execute delete query" << std::endl;
}
std::vector<model::Album> AlbumRepository::parseRecords(MYSQL_STMT* stmt)
{
std::cout << "parsing album record" << std::endl;
mysql_stmt_store_result(stmt);
std::vector<model::Album> albums;
albums.reserve(mysql_stmt_num_rows(stmt));
const auto valAmt = 3;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
if (mysql_stmt_field_count(stmt) > 0) {
model::Album alb;
auto metaBuff = metadataBuffer();
auto bindedValues = valueBind(alb, metaBuff);
status = mysql_stmt_bind_result(stmt, bindedValues.get());
while (true) {
std::cout << "fetching statement result" << std::endl;
status = mysql_stmt_fetch(stmt);
if (status == 1 || status == MYSQL_NO_DATA) {
break;
}
alb.title = std::get<0>(metaBuff);
alb.artist = std::get<1>(metaBuff);
albums.push_back(std::move(alb));
}
} }
std::cout << "fetching next result" << std::endl; qry << " GROUP BY alb.AlbumId LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
auto albWSC = parseRecordWithSongCount(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
return albWSC;
} }
return albums; model::Album AlbumRepository::retrieveRecord(model::Album& album, type::AlbumFilter filter) {
} std::cout << "retrieving album record\n";
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
std::pair<model::Album, int> AlbumRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) qry << "SELECT alb.* FROM Album alb WHERE ";
{
std::cout << "parsing album record with song count" << std::endl;
mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt);
model::Album album; auto titleLength = album.title.size();
auto metaBuff = metadataBuffer(); switch (filter) {
int songCount = 0; case type::AlbumFilter::id:
auto val = valueBindWithSongCount(album, metaBuff, songCount); qry << "alb.AlbumId = ?";
if (rowCount == 0) { params[0].buffer_type = MYSQL_TYPE_LONG;
std::cout << "no results" << std::endl; params[0].buffer = (char*)&album.id;
return std::make_pair(album, songCount); params[0].length = 0;
params[0].is_null = 0;
break;
case type::AlbumFilter::title:
qry << "alb.Title = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)album.title.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
break;
default:
break;
}
qry << " LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
album = parseRecord(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "done\n";
return album;
} }
auto status = mysql_stmt_bind_result(stmt, val.get()); bool AlbumRepository::doesAlbumExists(const model::Album& album, type::AlbumFilter filter) {
status = mysql_stmt_fetch(stmt); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
album.title = std::get<0>(metaBuff); MYSQL_BIND params[1];
album.artist = std::get<1>(metaBuff); memset(params, 0, sizeof(params));
std::cout << "done parsing album record with song count" << std::endl; std::stringstream qry;
qry << "SELECT * FROM Album WHERE ";
auto albWSC = std::make_pair(album, songCount); auto titleLength = album.title.size();
switch (filter) {
case type::AlbumFilter::id:
qry << "AlbumId = ?";
return albWSC; params[0].buffer_type = MYSQL_TYPE_LONG;
} params[0].buffer = (char*)&album.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::AlbumFilter::title:
qry << "Title = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)album.title.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
break;
default:
break;
}
qry << " LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed\n";
mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
return (rowCount > 0) ? true : false;
}
void AlbumRepository::saveAlbum(const model::Album& album) {
std::cout << "beginning to insert album record\n";
auto conn = setupMysqlConnection();
MYSQL_STMT *stmt = mysql_stmt_init(conn);
const std::string query = "INSERT INTO Album(Title, Artist, Year) VALUES(?, ?, ?)";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
MYSQL_BIND params[3];
memset(params, 0, sizeof(params));
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)album.title.c_str();
auto titleLength = album.title.size();
params[0].length= &titleLength;
params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)album.artist.c_str();
auto artistLength = album.artist.size();
params[1].length = &artistLength;
params[1].is_null = 0;
params[2].buffer_type = MYSQL_TYPE_LONG;
params[2].buffer = (char*)&album.year;
params[2].length = 0;
params[2].is_null = 0;
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "done inserting album record\n";
}
void AlbumRepository::deleteAlbum(const model::Album& album,
type::AlbumFilter filter = type::AlbumFilter::id) {
std::cout << "deleting album record\n";
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
qry << "DELETE FROM Album WHERE ";
switch (filter) {
case type::AlbumFilter::id:
qry << "AlbumId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&album.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
std::cout << "execute delete query\n";
}
std::shared_ptr<MYSQL_BIND> AlbumRepository::valueBind(model::Album& album, std::vector<model::Album> AlbumRepository::parseRecords(MYSQL_STMT* stmt) {
std::tuple<char*, char*>& metadata) std::cout << "parsing album record\n";
{ mysql_stmt_store_result(stmt);
constexpr auto wordLen = 1024;
constexpr auto valueCount = 4;
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(valueCount, sizeof(MYSQL_BIND)));
values.get()[0].buffer_type = MYSQL_TYPE_LONG; std::vector<model::Album> albums;
values.get()[0].buffer = (char*)&album.id; albums.reserve(mysql_stmt_num_rows(stmt));
values.get()[1].buffer_type = MYSQL_TYPE_STRING; const auto valAmt = 3;
values.get()[1].buffer = (char*)std::get<0>(metadata); unsigned long len[valAmt];
values.get()[1].buffer_length = wordLen; my_bool nullRes[valAmt];
values.get()[2].buffer_type = MYSQL_TYPE_STRING; for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
values.get()[2].buffer = (char*)std::get<1>(metadata); if (mysql_stmt_field_count(stmt) > 0) {
values.get()[2].buffer_length = wordLen; model::Album alb;
auto metaBuff = metadataBuffer();
auto bindedValues = valueBind(alb, metaBuff);
status = mysql_stmt_bind_result(stmt, bindedValues.get());
values.get()[3].buffer_type = MYSQL_TYPE_LONG; while (true) {
values.get()[3].buffer = (char*)&album.year; std::cout << "fetching statement result\n";
status = mysql_stmt_fetch(stmt);
return values; if (status == 1 || status == MYSQL_NO_DATA) break;
}
std::shared_ptr<MYSQL_BIND> AlbumRepository::valueBindWithSongCount(model::Album& album, alb.title = std::get<0>(metaBuff);
std::tuple<char*, char*>& metadata, int& songCount) alb.artist = std::get<1>(metaBuff);
{ albums.push_back(std::move(alb));
constexpr auto wordLen = 1024; }
constexpr auto valueCount = 5; }
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(valueCount, sizeof(MYSQL_BIND))); std::cout << "fetching next result\n";
}
values.get()[0].buffer_type = MYSQL_TYPE_LONG; return albums;
values.get()[0].buffer = (char*)&album.id; }
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = (char*)std::get<0>(metadata);
values.get()[1].buffer_length = wordLen;
values.get()[2].buffer_type = MYSQL_TYPE_STRING;
values.get()[2].buffer = (char*)std::get<1>(metadata);
values.get()[2].buffer_length = wordLen;
values.get()[3].buffer_type = MYSQL_TYPE_LONG;
values.get()[3].buffer = (char*)&album.year;
values.get()[4].buffer_type = MYSQL_TYPE_LONG;
values.get()[4].buffer = (char*)&songCount;
return values;
}
std::tuple<char*, char*> AlbumRepository::metadataBuffer() std::pair<model::Album, int> AlbumRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) {
{ std::cout << "parsing album record with song count\n";
constexpr auto wordLen = 1024; mysql_stmt_store_result(stmt);
char title[wordLen]; auto rowCount = mysql_stmt_num_rows(stmt);
char artist[wordLen];
return std::make_tuple(title, artist); model::Album album;
} auto metaBuff = metadataBuffer();
int songCount = 0;
auto val = valueBindWithSongCount(album, metaBuff, songCount);
if (rowCount == 0) {
std::cout << "no results\n";
return std::make_pair(album, songCount);
}
auto status = mysql_stmt_bind_result(stmt, val.get());
status = mysql_stmt_fetch(stmt);
album.title = std::get<0>(metaBuff);
album.artist = std::get<1>(metaBuff);
std::cout << "done parsing album record with song count\n";
auto albWSC = std::make_pair(album, songCount);
return albWSC;
}
model::Album AlbumRepository::parseRecord(MYSQL_STMT *stmt) std::shared_ptr<MYSQL_BIND> AlbumRepository::valueBind(model::Album& album,
{ std::tuple<char*, char*>& metadata) {
std::cout << "parsing album record" << std::endl; constexpr auto wordLen = 1024;
mysql_stmt_store_result(stmt); constexpr auto valueCount = 4;
auto rows = mysql_stmt_num_rows(stmt); std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(valueCount, sizeof(MYSQL_BIND)));
model::Album album; values.get()[0].buffer_type = MYSQL_TYPE_LONG;
auto metaBuff = metadataBuffer(); values.get()[0].buffer = (char*)&album.id;
auto bindedValues = valueBind(album, metaBuff);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get()); values.get()[1].buffer_type = MYSQL_TYPE_STRING;
status = mysql_stmt_fetch(stmt); values.get()[1].buffer = (char*)std::get<0>(metadata);
values.get()[1].buffer_length = wordLen;
values.get()[2].buffer_type = MYSQL_TYPE_STRING;
values.get()[2].buffer = (char*)std::get<1>(metadata);
values.get()[2].buffer_length = wordLen;
values.get()[3].buffer_type = MYSQL_TYPE_LONG;
values.get()[3].buffer = (char*)&album.year;
return values;
}
std::shared_ptr<MYSQL_BIND> AlbumRepository::valueBindWithSongCount(model::Album& album,
std::tuple<char*, char*>& metadata, int& songCount) {
constexpr auto wordLen = 1024;
constexpr auto valueCount = 5;
std::shared_ptr<MYSQL_BIND> values(
(MYSQL_BIND*) std::calloc(valueCount, sizeof(MYSQL_BIND)));
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = (char*)&album.id;
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = (char*)std::get<0>(metadata);
values.get()[1].buffer_length = wordLen;
values.get()[2].buffer_type = MYSQL_TYPE_STRING;
values.get()[2].buffer = (char*)std::get<1>(metadata);
values.get()[2].buffer_length = wordLen;
values.get()[3].buffer_type = MYSQL_TYPE_LONG;
values.get()[3].buffer = (char*)&album.year;
values.get()[4].buffer_type = MYSQL_TYPE_LONG;
values.get()[4].buffer = (char*)&songCount;
return values;
}
std::tuple<char*, char*> AlbumRepository::metadataBuffer() {
constexpr auto wordLen = 1024;
char title[wordLen];
char artist[wordLen];
return std::make_tuple(title, artist);
}
model::Album AlbumRepository::parseRecord(MYSQL_STMT *stmt)
{
std::cout << "parsing album record\n";
mysql_stmt_store_result(stmt);
auto rows = mysql_stmt_num_rows(stmt);
model::Album album;
auto metaBuff = metadataBuffer();
auto bindedValues = valueBind(album, metaBuff);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt);
album.title = std::get<0>(metaBuff); album.title = std::get<0>(metaBuff);
album.artist = std::get<1>(metaBuff); album.artist = std::get<1>(metaBuff);
std::cout << "done parsing album record" << std::endl; std::cout << "done parsing album record\n";
return album; return album;
} }
} }
+314 -369
View File
@@ -7,410 +7,355 @@
#include <cstring> #include <cstring>
namespace database { namespace database {
ArtistRepository::ArtistRepository(const model::BinaryPath& binConf) ArtistRepository::ArtistRepository(const model::BinaryPath& binConf) :
: BaseRepository(binConf) BaseRepository(binConf) { }
{
}
std::vector<model::Artist> ArtistRepository::retrieveRecords() std::vector<model::Artist> ArtistRepository::retrieveRecords() {
{ auto conn = setupMysqlConnection();
auto conn = setupMysqlConnection(); auto stmt = mysql_stmt_init(conn);
auto stmt = mysql_stmt_init(conn); const std::string query = "SELECT * FROM Artist";
const std::string query = "SELECT * FROM Artist";
mysql_stmt_prepare(stmt, query.c_str(), query.size()); mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt); mysql_stmt_execute(stmt);
auto artists = parseRecords(stmt); auto artists = parseRecords(stmt);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
return artists;
}
std::pair<model::Artist, int> ArtistRepository::retrieveRecordWithSongCount(model::Artist& artist, type::ArtistFilter filter = type::ArtistFilter::id)
{
std::cout << "retrieving artist record with song count" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT art.*, COUNT(*) AS SongCount FROM Artist art LEFT JOIN ";
qry << "Song sng ON art.ArtistId=sng.ArtistId WHERE ";
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
switch (filter) {
case type::ArtistFilter::id:
qry << "sng.ArtistId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&artist.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
qry << " GROUP BY art.ArtistId LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
std::cout << "Artist record with song count query ";
std::cout << "has been performed" << std::endl;
auto artWSC = parseRecordWithSongCount(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
return artWSC;
}
model::Artist ArtistRepository::retrieveRecord(model::Artist& artist, type::ArtistFilter filter)
{
std::cout << "retrieving artist record" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT art.* FROM Artist art WHERE ";
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
auto artistLength = artist.artist.size();
switch (filter) {
case type::ArtistFilter::id:
qry << "art.ArtistId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&artist.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::ArtistFilter::artist:
qry << "art.Artist = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)artist.artist.c_str();
params[0].length = &artistLength;
params[0].is_null = 0;
break;
default:
break;
}
qry << " LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
artist = parseRecord(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "retrieved record" << std::endl;
return artist;
}
bool ArtistRepository::doesArtistExist(const model::Artist& artist, type::ArtistFilter filter)
{
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
std::stringstream qry;
qry << "SELECT * FROM Artist WHERE ";
auto artistLength = artist.artist.size();
switch (filter) {
case type::ArtistFilter::id:
qry << "ArtistId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&artist.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::ArtistFilter::artist:
qry << "Artist = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)artist.artist.c_str();
params[0].length = &artistLength;
params[0].is_null = 0;
break;
default:
break;
}
qry << " LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed" << std::endl;
mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
return (rowCount > 0) ? true : false;
}
void ArtistRepository::saveRecord(const model::Artist& artist)
{
std::cout << "inserting artist record" << std::endl;
auto conn = setupMysqlConnection();
MYSQL_STMT *stmt = mysql_stmt_init(conn);
const std::string query = "INSERT INTO Artist(Artist) VALUES(?)";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)artist.artist.c_str();
auto artistLength = artist.artist.size();
params[0].length = &artistLength;
params[0].is_null = 0;
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout<< "inserted artist record" << std::endl;
}
void ArtistRepository::deleteArtist(const model::Artist& artist, type::ArtistFilter filter = type::ArtistFilter::id) {
std::cout << "delete Artist record" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "DELETE FROM Artist WHERE ";
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
switch (filter) {
case type::ArtistFilter::id:
qry << "ArtistId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&artist.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "deleted artist record" << std::endl;
}
std::vector<model::Artist> ArtistRepository::parseRecords(MYSQL_STMT *stmt)
{
mysql_stmt_store_result(stmt);
std::vector<model::Artist> artists;
artists.reserve(mysql_stmt_num_rows(stmt));
if (mysql_stmt_field_count(stmt) == 0) {
std::cout << "field count is 0" << std::endl;
return artists; return artists;
} }
model::Artist art; std::pair<model::Artist, int> ArtistRepository::retrieveRecordWithSongCount(
const auto valAmt = 2; model::Artist& artist, type::ArtistFilter filter = type::ArtistFilter::id) {
unsigned long len[valAmt]; std::cout << "retrieving artist record with song count\n";
my_bool nullRes[valAmt]; std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
auto res = mysql_stmt_result_metadata(stmt); qry << "SELECT art.*, COUNT(*) AS SongCount FROM Artist art LEFT JOIN ";
auto fields = mysql_fetch_fields(res); qry << "Song sng ON art.ArtistId=sng.ArtistId WHERE ";
const auto strLen = 1024;
char artist[strLen]; MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
switch (filter) {
case type::ArtistFilter::id:
qry << "sng.ArtistId = ?";
MYSQL_BIND val[valAmt]; params[0].buffer_type = MYSQL_TYPE_LONG;
memset(val, 0, sizeof(val)); params[0].buffer = (char*)&artist.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
val[0].buffer_type = MYSQL_TYPE_LONG; qry << " GROUP BY art.ArtistId LIMIT 1";
val[0].buffer = (char*)&art.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_STRING; const auto query = qry.str();
val[1].buffer = (char*)artist; auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
val[1].buffer_length = strLen; status = mysql_stmt_bind_param(stmt, params);
val[1].length = &len[1]; status = mysql_stmt_execute(stmt);
val[1].is_null = &nullRes[1];
for (auto status = mysql_stmt_bind_result(stmt, val); status == 0; ) { std::cout << "Artist record with song count query ";
std::cout << "fetching statement result" << std::endl; std::cout << "has been performed\n";
auto artWSC = parseRecordWithSongCount(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
return artWSC;
}
model::Artist ArtistRepository::retrieveRecord(model::Artist& artist,
type::ArtistFilter filter) {
std::cout << "retrieving artist record\n";
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT art.* FROM Artist art WHERE ";
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
auto artistLength = artist.artist.size();
switch (filter) {
case type::ArtistFilter::id:
qry << "art.ArtistId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&artist.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::ArtistFilter::artist:
qry << "art.Artist = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)artist.artist.c_str();
params[0].length = &artistLength;
params[0].is_null = 0;
break;
default:
break;
}
qry << " LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
artist = parseRecord(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "retrieved record\n";
return artist;
}
bool ArtistRepository::doesArtistExist(const model::Artist& artist, type::ArtistFilter filter) {
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
std::stringstream qry;
qry << "SELECT * FROM Artist WHERE ";
auto artistLength = artist.artist.size();
switch (filter) {
case type::ArtistFilter::id:
qry << "ArtistId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&artist.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::ArtistFilter::artist:
qry << "Artist = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)artist.artist.c_str();
params[0].length = &artistLength;
params[0].is_null = 0;
break;
default:
break;
}
qry << " LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed\n";
mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
return (rowCount > 0) ? true : false;
}
void ArtistRepository::saveRecord(const model::Artist& artist) {
std::cout << "inserting artist record\n";
auto conn = setupMysqlConnection();
MYSQL_STMT *stmt = mysql_stmt_init(conn);
const std::string query = "INSERT INTO Artist(Artist) VALUES(?)";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)artist.artist.c_str();
auto artistLength = artist.artist.size();
params[0].length = &artistLength;
params[0].is_null = 0;
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout<< "inserted artist record\n";
}
void ArtistRepository::deleteArtist(const model::Artist& artist,
type::ArtistFilter filter = type::ArtistFilter::id) {
std::cout << "delete Artist record\n";
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "DELETE FROM Artist WHERE ";
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
switch (filter) {
case type::ArtistFilter::id:
qry << "ArtistId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&artist.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "deleted artist record\n";
}
std::vector<model::Artist> ArtistRepository::parseRecords(MYSQL_STMT *stmt) {
mysql_stmt_store_result(stmt);
std::vector<model::Artist> artists;
artists.reserve(mysql_stmt_num_rows(stmt));
constexpr auto valAmt = 2;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
if (mysql_stmt_field_count(stmt) > 0) {
model::Artist art;
auto metaBuff = metadataBuffer();
auto bindedValues = valueBind(art, metaBuff);
status = mysql_stmt_bind_result(stmt, bindedValues.get());
std::cout << "fetching statement result\n";
status = mysql_stmt_fetch(stmt);
if (status == 1 || status == MYSQL_NO_DATA) break;
art.artist = std::get<0>(metaBuff);
artists.push_back(art);
}
std::cout << "fetching next result\n";
}
return artists;
}
std::pair<model::Artist, int> ArtistRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) {
std::cout << "parsing artist record with song count\n";
mysql_stmt_store_result(stmt);
const auto rowCount = mysql_stmt_num_rows(stmt);
model::Artist artist;
auto metaBuff = metadataBuffer();
auto songCount = 0;
auto val = valueBindWithSongCount(artist, metaBuff, songCount);
if (rowCount == 0) {
std::cout << "no results\n";
return std::make_pair(artist, songCount);
}
auto status = mysql_stmt_bind_result(stmt, val.get());
status = mysql_stmt_fetch(stmt); status = mysql_stmt_fetch(stmt);
if (status == 0) { artist.artist = std::get<0>(metaBuff);
art.artist = artist;
artists.push_back(std::move(art)); std::cout << "done parsing album record with song count\n";
}
return std::make_pair(artist, songCount);
} }
return artists;
}
std::shared_ptr<MYSQL_BIND> ArtistRepository::valueBind(model::Artist& artist,
std::tuple<char*>& metadata) {
constexpr auto valueCount = 2;
constexpr auto wordLen = 1024;
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*)
std::calloc(valueCount, sizeof(MYSQL_BIND)));
model::Artist ArtistRepository::parseRecord(MYSQL_RES* results) values.get()[0].buffer_type = MYSQL_TYPE_LONG;
{ values.get()[0].buffer = (char*)&artist.id;
std::cout << "parsing artist record" << std::endl;
model::Artist artist;
auto fieldNum = mysql_num_fields(results); values.get()[1].buffer_type = MYSQL_TYPE_STRING;
auto row = mysql_fetch_row(results); values.get()[1].buffer = (char*)std::get<0>(metadata);
values.get()[1].buffer_length = wordLen;
for (auto i = 0; i != fieldNum; ++i) { return values;
const std::string field(mysql_fetch_field(results)->name);
if (field.compare("ArtistId") == 0) {
artist.id = std::stoi(row[i]);
}
if (field.compare("Artist") == 0) {
artist.artist = row[i];
}
} }
std::cout << "parsed artist record" << std::endl; std::shared_ptr<MYSQL_BIND> ArtistRepository::valueBindWithSongCount(model::Artist& artist,
std::tuple<char*>& metadata, int& songCount) {
constexpr auto valueCount = 3;
constexpr auto wordLen = 1024;
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*)
std::calloc(valueCount, sizeof(MYSQL_BIND)));
return artist; values.get()[0].buffer_type = MYSQL_TYPE_LONG;
} values.get()[0].buffer = reinterpret_cast<char*>(&artist.id);
std::pair<model::Artist, int> ArtistRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) values.get()[1].buffer_type = MYSQL_TYPE_STRING;
{ values.get()[1].buffer = reinterpret_cast<char*>(std::get<0>(metadata));
std::cout << "parsing artist record with song count" << std::endl; values.get()[1].buffer_length = wordLen;
mysql_stmt_store_result(stmt);
const auto strLen = 1024; values.get()[2].buffer_type = MYSQL_TYPE_LONG;
const auto valAmt = 3; values.get()[2].buffer = reinterpret_cast<char*>(&songCount);
unsigned long len[valAmt];
my_bool nullRes[valAmt];
model::Artist artist;
int songCount = 0;
if (mysql_stmt_num_rows(stmt) == 0) { return values;
std::cout << "no results" << std::endl;
return std::make_pair(artist, songCount);
} }
MYSQL_BIND params[valAmt];
std::memset(params, 0, sizeof(params));
char art[strLen]; std::tuple<char*> ArtistRepository::metadataBuffer() {
constexpr auto wordLen = 1024;
char artist[wordLen];
params[0].buffer_type = MYSQL_TYPE_LONG; return std::make_tuple(artist);
params[0].buffer = (char*)&artist.id;
params[0].length = &len[0];
params[0].is_null = &nullRes[0];
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)art;
params[1].buffer_length = strLen;
params[1].length = &len[1];
params[1].is_null = &nullRes[1];
params[2].buffer_type = MYSQL_TYPE_LONG;
params[2].buffer = (char*)&songCount;
params[2].length = &len[2];
params[2].is_null = &nullRes[2];
mysql_stmt_bind_result(stmt, params);
mysql_stmt_fetch(stmt);
artist.artist = std::move(art);
std::cout << "parsed artist record with song count" << std::endl;
return std::make_pair(artist, songCount);
}
model::Artist ArtistRepository::parseRecord(MYSQL_STMT *stmt)
{
std::cout << "parsing artist record" << std::endl;
mysql_stmt_store_result(stmt);
model::Artist art;
auto status = 0;
auto time = 0;
auto valAmt = 2;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
while (status == 0) {
if (mysql_stmt_field_count(stmt) > 0) {
auto res = mysql_stmt_result_metadata(stmt);
auto fields = mysql_fetch_fields(res);
auto strLen = 1024;
MYSQL_BIND val[valAmt];
memset(val, 0, sizeof(val));
char artist[strLen];
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&art.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_STRING;
val[1].buffer = (char*)&artist;
val[1].buffer_length = strLen;
val[1].length = &len[1];
val[1].is_null = &nullRes[1];
status = mysql_stmt_bind_result(stmt, val);
mysql_stmt_store_result(stmt);
status = mysql_stmt_fetch(stmt);
art.artist = artist;
}
status = mysql_stmt_next_result(stmt);
} }
std::cout << "done parsing artist record" << std::endl;
return art; model::Artist ArtistRepository::parseRecord(MYSQL_STMT *stmt) {
} std::cout << "parsing artist record\n";
mysql_stmt_store_result(stmt);
model::Artist art;
auto metaBuff = metadataBuffer();
auto bindedValues = valueBind(art, metaBuff);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt);
art.artist = std::get<0>(metaBuff);
std::cout << "done parsing artist record\n";
return art;
}
} }
+63 -73
View File
@@ -7,92 +7,82 @@
#include "manager/DirectoryManager.h" #include "manager/DirectoryManager.h"
namespace database { namespace database {
BaseRepository::BaseRepository() BaseRepository::BaseRepository(const std::string& path) : path(path) {
{ } intitalizeDetails();
BaseRepository::BaseRepository(const std::string& path) : path(path)
{
intitalizeDetails();
}
BaseRepository::BaseRepository(const model::BinaryPath& bConf)
{
initializeDetails(bConf);
}
bool BaseRepository::testConnection()
{
auto conn = mysql_init(nullptr);
if (!mysql_real_connect(conn, details.server.c_str(), details.username.c_str(),
details.password.c_str(), details.database.c_str(), 0,
nullptr, 0)) {
std::cout << "failed to connect to the database" << std::endl;
return false;
} }
mysql_close(conn); BaseRepository::BaseRepository(const model::BinaryPath& bConf) {
initializeDetails(bConf);
return true;
}
MYSQL* BaseRepository::setupMysqlConnection()
{
MYSQL *conn = mysql_init(nullptr);
if (!mysql_real_connect(conn, details.server.c_str(), details.username.c_str(),
details.password.c_str(), details.database.c_str(), 0, nullptr, 0)) {
std::cout << "connection error" << std::endl;
} }
return conn;
}
MYSQL* BaseRepository::setupMysqlConnection(model::DatabaseConnection details) bool BaseRepository::testConnection() {
{ auto conn = mysql_init(nullptr);
MYSQL *connection = mysql_init(NULL); if (!mysql_real_connect(conn, details.server.c_str(), details.username.c_str(),
details.password.c_str(), details.database.c_str(), 0, nullptr, 0)) {
std::cout << "failed to connect to the database\n";
return false;
}
// connect to the database with the details attached. mysql_close(conn);
if (!mysql_real_connect(connection,details.server.c_str(), details.username.c_str(), details.password.c_str(), details.database.c_str(), 0, NULL, 0)) {
printf("Conection error : %s\n", mysql_error(connection)); return true;
exit(1);
} }
return connection;
}
MYSQL_RES* BaseRepository::performMysqlQuery(MYSQL *conn, const std::string& query) MYSQL* BaseRepository::setupMysqlConnection() {
{ MYSQL *conn = mysql_init(nullptr);
// send the query to the database
if (mysql_query(conn, query.c_str()))
{
printf("MySQL query error : %s\n", mysql_error(conn));
exit(1);
}
return mysql_use_result(conn); if (!mysql_real_connect(conn, details.server.c_str(), details.username.c_str(),
} details.password.c_str(), details.database.c_str(), 0, nullptr, 0)) {
std::cout << "connection error\n";
}
return conn;
}
MYSQL* BaseRepository::setupMysqlConnection(model::DatabaseConnection details) {
MYSQL *connection = mysql_init(NULL);
// connect to the database with the details attached.
if (!mysql_real_connect(connection,details.server.c_str(), details.username.c_str(),
details.password.c_str(), details.database.c_str(), 0, NULL, 0)) {
std::cout << "Connection error: " << mysql_error(connection) << "\n";
std::exit(-1);
}
return connection;
}
void BaseRepository::intitalizeDetails() MYSQL_RES* BaseRepository::performMysqlQuery(MYSQL *conn, const std::string& query) {
{ // send the query to the database
auto databaseConfig = manager::DirectoryManager::databaseConfigContent(path); if (mysql_query(conn, query.c_str())) {
printf("MySQL query error : %s\n", mysql_error(conn));
std::cout << "MySQL query error : " << mysql_error(conn) << "\n";
std::exit(1);
}
return mysql_use_result(conn);
}
void BaseRepository::intitalizeDetails() {
auto databaseConfig = manager::DirectoryManager::databaseConfigContent(path);
details.database = databaseConfig["database"].get<std::string>(); details.database = databaseConfig["database"].get<std::string>();
details.password = databaseConfig["password"].get<std::string>(); details.password = databaseConfig["password"].get<std::string>();
details.server = databaseConfig["server"].get<std::string>(); details.server = databaseConfig["server"].get<std::string>();
details.username = databaseConfig["username"].get<std::string>(); details.username = databaseConfig["username"].get<std::string>();
} }
void BaseRepository::initializeDetails(const model::BinaryPath& bConf) void BaseRepository::initializeDetails(const model::BinaryPath& bConf)
{ {
auto databaseConfig = manager::DirectoryManager::databaseConfigContent(bConf); auto databaseConfig = manager::DirectoryManager::databaseConfigContent(bConf);
details.database = databaseConfig["database"].get<std::string>(); details.database = databaseConfig["database"].get<std::string>();
details.server = databaseConfig["server"].get<std::string>(); details.server = databaseConfig["server"].get<std::string>();
details.username = databaseConfig["username"].get<std::string>(); details.username = databaseConfig["username"].get<std::string>();
details.password = databaseConfig["password"].get<std::string>(); details.password = databaseConfig["password"].get<std::string>();
std::cout << "retrieved database details" << std::endl; std::cout << "retrieved database details\n";
} }
} }
+253 -303
View File
@@ -7,370 +7,320 @@
#include <cstring> #include <cstring>
namespace database { namespace database {
CoverArtRepository::CoverArtRepository(const std::string& path) : BaseRepository(path) CoverArtRepository::CoverArtRepository(const model::BinaryPath& bConf) :
{ } BaseRepository(bConf) { }
CoverArtRepository::CoverArtRepository(const model::BinaryPath& bConf) : BaseRepository(bConf)
{ }
std::vector<model::Cover> CoverArtRepository::retrieveRecords() std::vector<model::Cover> CoverArtRepository::retrieveRecords() {
{ auto conn = setupMysqlConnection();
auto conn = setupMysqlConnection(); auto stmt = mysql_stmt_init(conn);
auto stmt = mysql_stmt_init(conn); const std::string query = "SELECT * FROM CoverArt";
const std::string query = "SELECT * FROM CoverArt";
mysql_stmt_prepare(stmt, query.c_str(), query.size()); mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt); mysql_stmt_execute(stmt);
auto coverArts = parseRecords(stmt); auto coverArts = parseRecords(stmt);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
return coverArts; return coverArts;
}
model::Cover CoverArtRepository::retrieveRecord(model::Cover& cov, type::CoverFilter filter = type::CoverFilter::id)
{
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT * FROM CoverArt WHERE ";
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
auto songTitleLength = cov.songTitle.size();
switch (filter) {
case type::CoverFilter::id:
qry << "CoverArtId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&cov.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::CoverFilter::songTitle:
qry << "SongTitle = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)cov.songTitle.c_str();
params[0].length = &songTitleLength;
params[0].is_null = 0;
break;
default:
break;
} }
qry << " LIMIT 1"; model::Cover CoverArtRepository::retrieveRecord(model::Cover& cov,
type::CoverFilter filter = type::CoverFilter::id) {
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const std::string query = qry.str(); qry << "SELECT * FROM CoverArt WHERE ";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
auto covDb = parseRecord(stmt); MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
mysql_stmt_close(stmt); auto songTitleLength = cov.songTitle.size();
mysql_close(conn); switch (filter) {
std::cout << "retrieved cover art record" << std::endl; case type::CoverFilter::id:
qry << "CoverArtId = ?";
return covDb; params[0].buffer_type = MYSQL_TYPE_LONG;
} params[0].buffer = (char*)&cov.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::CoverFilter::songTitle:
qry << "SongTitle = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)cov.songTitle.c_str();
params[0].length = &songTitleLength;
params[0].is_null = 0;
break;
default:
break;
}
bool CoverArtRepository::doesCoverArtExist(const model::Cover& cover, type::CoverFilter filter) qry << " LIMIT 1";
{
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
MYSQL_BIND params[1]; const std::string query = qry.str();
memset(params, 0, sizeof(params)); auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
std::stringstream qry; auto covDb = parseRecord(stmt);
qry << "SELECT * FROM CoverArt WHERE ";
auto titleLength = cover.songTitle.size(); mysql_stmt_close(stmt);
switch (filter) { mysql_close(conn);
case type::CoverFilter::id: std::cout << "retrieved cover art record\n";
qry << "CoverArtId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG; return covDb;
params[0].buffer = (char*)&cover.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::CoverFilter::songTitle:
qry << "SongTitle = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)cover.songTitle.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
break;
default:
break;
} }
qry << " LIMIT 1";
const auto query = qry.str(); bool CoverArtRepository::doesCoverArtExist(const model::Cover& cover,
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); type::CoverFilter filter) {
status = mysql_stmt_bind_param(stmt, params); auto conn = setupMysqlConnection();
status = mysql_stmt_execute(stmt); auto stmt = mysql_stmt_init(conn);
std::cout << "the query has been performed" << std::endl; MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
mysql_stmt_store_result(stmt); std::stringstream qry;
auto rowCount = mysql_stmt_num_rows(stmt); qry << "SELECT * FROM CoverArt WHERE ";
mysql_stmt_close(stmt); auto titleLength = cover.songTitle.size();
mysql_close(conn); switch (filter) {
case type::CoverFilter::id:
qry << "CoverArtId = ?";
return (rowCount > 0) ? true : false; params[0].buffer_type = MYSQL_TYPE_LONG;
} params[0].buffer = (char*)&cover.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::CoverFilter::songTitle:
qry << "SongTitle = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)cover.songTitle.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
break;
default:
break;
}
qry << " LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed\n";
mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
return (rowCount > 0) ? true : false;
}
// TODO: change to prepared statement void CoverArtRepository::deleteRecord(const model::Cover& cov,
void CoverArtRepository::deleteRecord(const model::Cover& cov) type::CoverFilter filter) {
{ auto conn = setupMysqlConnection();
auto conn = setupMysqlConnection(); auto stmt = mysql_stmt_init(conn);
const std::string query("DELETE FROM CoverArt WHERE CoverArtId = " + std::to_string(cov.id)); std::cout << "delete CoverArt record\n";
std::stringstream qry;
qry << "DELETE FROM CoverArt WHERE ";
auto result = performMysqlQuery(conn, query); MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
mysql_close(conn); switch (filter) {
} case type::CoverFilter::id:
qry << "CoverArtId = ?";
void CoverArtRepository::saveRecord(const model::Cover& cov) params[0].buffer_type = MYSQL_TYPE_LONG;
{ params[0].buffer = (char*)&cov.id;
std::cout << "saving cover art record"; params[0].length = 0;
auto conn = setupMysqlConnection(); params[0].is_null = 0;
auto stmt = mysql_stmt_init(conn); break;
default:
break;
}
MYSQL_BIND params[2]; const auto query = qry.str();
memset(params, 0, sizeof(params));
my_bool isNull;
const std::string query = "INSERT INTO CoverArt(SongTitle, ImagePath) VALUES(?, ?)"; auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); mysql_stmt_close(stmt);
mysql_close(conn);
params[0].buffer_type = MYSQL_TYPE_STRING; std::cout << "deleted CoverArt record\n";
params[0].buffer = (char*)cov.songTitle.c_str(); }
auto songTitleLength = cov.songTitle.size();
params[0].length = &songTitleLength;
params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING; void CoverArtRepository::saveRecord(const model::Cover& cov) {
params[1].buffer = (char*)cov.imagePath.c_str(); std::cout << "saving cover art record";
auto imagePathLength = cov.imagePath.size(); auto conn = setupMysqlConnection();
params[1].length = &imagePathLength; auto stmt = mysql_stmt_init(conn);
params[1].is_null = 0;
status = mysql_stmt_bind_param(stmt, params); MYSQL_BIND params[2];
status = mysql_stmt_execute(stmt); memset(params, 0, sizeof(params));
my_bool isNull;
mysql_stmt_close(stmt); const std::string query = "INSERT INTO CoverArt(SongTitle, ImagePath) VALUES(?, ?)";
mysql_close(conn);
std::cout << "saved cover art record" << std::endl; auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
}
void CoverArtRepository::updateRecord(const model::Cover& cover) params[0].buffer_type = MYSQL_TYPE_STRING;
{ params[0].buffer = (char*)cov.songTitle.c_str();
std::stringstream qry; auto songTitleLength = cov.songTitle.size();
auto conn = setupMysqlConnection(); params[0].length = &songTitleLength;
auto stmt = mysql_stmt_init(conn); params[0].is_null = 0;
qry << "UPDATE CoverArt SET "; params[1].buffer_type = MYSQL_TYPE_STRING;
qry << "SongTitle = ?, "; params[1].buffer = (char*)cov.imagePath.c_str();
qry << "ImagePath = ? "; auto imagePathLength = cov.imagePath.size();
qry << "WHERE CoverArtId = ?"; params[1].length = &imagePathLength;
params[1].is_null = 0;
MYSQL_BIND params[3]; status = mysql_stmt_bind_param(stmt, params);
memset(params, 0, sizeof(params)); status = mysql_stmt_execute(stmt);
auto songTitleLength = cover.songTitle.size(); mysql_stmt_close(stmt);
auto imagePathLength = cover.imagePath.size(); mysql_close(conn);
params[0].buffer_type = MYSQL_TYPE_STRING; std::cout << "saved cover art record\n";
params[0].buffer = (char*)cover.songTitle.c_str(); }
params[0].length = &songTitleLength;
params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING; void CoverArtRepository::updateRecord(const model::Cover& cover) {
params[1].buffer = (char*)cover.imagePath.c_str(); std::stringstream qry;
params[1].length = &imagePathLength; auto conn = setupMysqlConnection();
params[1].is_null = 0; auto stmt = mysql_stmt_init(conn);
params[2].buffer_type = MYSQL_TYPE_LONG; qry << "UPDATE CoverArt SET ";
params[2].buffer = (char*)&cover.id; qry << "SongTitle = ?, ";
params[2].length = 0; qry << "ImagePath = ? ";
params[2].is_null = 0; qry << "WHERE CoverArtId = ?";
const std::string query = qry.str(); MYSQL_BIND params[3];
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); memset(params, 0, sizeof(params));
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt); auto songTitleLength = cover.songTitle.size();
mysql_close(conn); auto imagePathLength = cover.imagePath.size();
std::cout << "updated cover art record" << std::endl; params[0].buffer_type = MYSQL_TYPE_STRING;
} params[0].buffer = (char*)cover.songTitle.c_str();
params[0].length = &songTitleLength;
params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)cover.imagePath.c_str();
params[1].length = &imagePathLength;
params[1].is_null = 0;
params[2].buffer_type = MYSQL_TYPE_LONG;
params[2].buffer = (char*)&cover.id;
params[2].length = 0;
params[2].is_null = 0;
const std::string query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "updated cover art record\n";
}
std::vector<model::Cover> CoverArtRepository::parseRecords(MYSQL_STMT *stmt) std::vector<model::Cover> CoverArtRepository::parseRecords(MYSQL_STMT *stmt) {
{ mysql_stmt_store_result(stmt);
mysql_stmt_store_result(stmt); const auto rowCount = mysql_stmt_num_rows(stmt);
auto rowCount = mysql_stmt_num_rows(stmt); std::cout << "number of results " << rowCount << "\n";
std::cout << "number of results " << rowCount << std::endl;
std::vector<model::Cover> coverArts; std::vector<model::Cover> coverArts;
coverArts.reserve(rowCount); coverArts.reserve(rowCount);
const auto valAmt = 3; constexpr auto valAmt = 3;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) { for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
if (mysql_stmt_field_count(stmt) > 0) { if (mysql_stmt_field_count(stmt) > 0) {
model::Cover coverArt; model::Cover cover;
auto res = mysql_stmt_result_metadata(stmt); auto metaBuff = metadataBuffer();
auto fields = mysql_fetch_fields(res); auto bindedValues = valueBind(cover, metaBuff);
auto strLen = 1024; status = mysql_stmt_bind_result(stmt, bindedValues.get());
MYSQL_BIND val[valAmt]; std::cout << "fetching statement result\n";
memset(val, 0, sizeof(val));
char songTitle[strLen];
char imagePath[strLen];
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&coverArt.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_STRING;
val[1].buffer = (char*)songTitle;
val[1].buffer_length = strLen;
val[1].length = &len[1];
val[1].is_null = &nullRes[1];
val[2].buffer_type = MYSQL_TYPE_STRING;
val[2].buffer = (char*)imagePath;
val[2].buffer_length = strLen;
val[2].length = &len[2];
val[2].is_null = &nullRes[2];
status = mysql_stmt_bind_result(stmt, val);
while (true) {
std::cout << "fetching statement result" << std::endl;
status = mysql_stmt_fetch(stmt); status = mysql_stmt_fetch(stmt);
if (status == 1 || status == MYSQL_NO_DATA) { if (status == 1 || status == MYSQL_NO_DATA) break;
break;
}
coverArt.songTitle = songTitle; cover.songTitle = std::get<0>(metaBuff);
coverArt.imagePath = imagePath; cover.imagePath = std::get<1>(metaBuff);
coverArts.push_back(cover);
coverArts.push_back(std::move(coverArt));
} }
} std::cout << "fetching next result\n";
std::cout << "fetching next result" << std::endl;
}
return coverArts;
}
model::Cover CoverArtRepository::parseRecord(MYSQL_RES *results)
{
std::cout << "parsing record" << std::endl;
model::Cover cov;
auto fieldNum = mysql_num_fields(results);
MYSQL_ROW row = mysql_fetch_row(results);
for (auto i = 0; i != fieldNum; ++i) {
switch (i) {
case 0:
cov.id = std::stoi(row[i]);
break;
case 1:
cov.songTitle = row[i];
break;
case 2:
cov.imagePath = row[i];
break;
}
}
std::cout << "done parsing record" << std::endl;
return cov;
}
model::Cover CoverArtRepository::parseRecord(MYSQL_STMT *stmt)
{
std::cout << "parsing cover art record" << std::endl;
mysql_stmt_store_result(stmt);
model::Cover cover;
auto status = 0;
auto time = 0;
auto valAmt = 3;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
while (status == 0) {
if (mysql_stmt_field_count(stmt) > 0) {
auto res = mysql_stmt_result_metadata(stmt);
auto fields = mysql_fetch_fields(res);
auto strLen = 1024;
MYSQL_BIND val[valAmt];
memset(val, 0, sizeof(val));
char songTitle[strLen];
char imagePath[strLen];
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&cover.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_STRING;
val[1].buffer = (char*)&songTitle;
val[1].buffer_length = strLen;
val[1].length = &len[1];
val[1].is_null = &nullRes[1];
val[2].buffer_type = MYSQL_TYPE_STRING;
val[2].buffer = (char*)&imagePath;
val[2].buffer_length = strLen;
val[2].length = &len[2];
val[2].is_null = &nullRes[2];
status = mysql_stmt_bind_result(stmt, val);
mysql_stmt_store_result(stmt);
status = mysql_stmt_fetch(stmt);
cover.songTitle = songTitle;
cover.imagePath = imagePath;
} }
status = mysql_stmt_next_result(stmt); return coverArts;
} }
std::cout << "done parsing cover art record" << std::endl;
return cover; std::shared_ptr<MYSQL_BIND> CoverArtRepository::valueBind(model::Cover& cover,
} std::tuple<char*, char*>& metadata) {
constexpr auto valueCount = 3;
constexpr auto wordLen = 1024;
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*)
std::calloc(valueCount, sizeof(MYSQL_BIND)));
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = reinterpret_cast<char*>(&cover.id);
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = reinterpret_cast<char*>(std::get<0>(metadata));
values.get()[1].buffer_length = wordLen;
values.get()[2].buffer_type = MYSQL_TYPE_STRING;
values.get()[2].buffer = reinterpret_cast<char*>(std::get<1>(metadata));
values.get()[2].buffer_length = wordLen;
return values;
}
std::tuple<char*, char*> CoverArtRepository::metadataBuffer() {
constexpr auto wordLen = 1024;
char songTitle[wordLen];
char imagePath[wordLen];
return std::make_pair(songTitle, imagePath);
}
model::Cover CoverArtRepository::parseRecord(MYSQL_STMT *stmt) {
std::cout << "parsing cover art record\n";
mysql_stmt_store_result(stmt);
model::Cover cover;
auto metaBuff = metadataBuffer();
auto bindedValues = valueBind(cover, metaBuff);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt);
cover.songTitle = std::get<0>(metaBuff);
cover.imagePath = std::get<1>(metaBuff);
std::cout << "done parsing cover art record\n";
return cover;
}
} }
+318 -325
View File
@@ -6,357 +6,350 @@
#include <cstring> #include <cstring>
namespace database { namespace database {
GenreRepository::GenreRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { }
GenreRepository::GenreRepository(const model::BinaryPath& bConf)
: BaseRepository(bConf)
{ }
std::vector<model::Genre> GenreRepository::retrieveRecords() std::vector<model::Genre> GenreRepository::retrieveRecords() {
{ auto conn = setupMysqlConnection();
auto conn = setupMysqlConnection(); auto stmt = mysql_stmt_init(conn);
auto stmt = mysql_stmt_init(conn); const std::string query = "SELECT * FROM Genre";
const std::string query = "SELECT * FROM Genre";
mysql_stmt_prepare(stmt, query.c_str(), query.size()); mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt); mysql_stmt_execute(stmt);
auto genres = parseRecords(stmt); auto genres = parseRecords(stmt);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
return genres; return genres;
}
std::pair<model::Genre, int> GenreRepository::retrieveRecordWithSongCount(model::Genre& genre, type::GenreFilter filter = type::GenreFilter::id)
{
std::cout << "retrieving genre record with song count" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT gnr.*, COUNT(*) AS SongCount FROM Genre gnr LEFT JOIN ";
qry << "Song sng ON gnr.GenreId=sng.GenreId WHERE ";
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
switch (filter) {
case type::GenreFilter::id:
qry << "sng.GenreId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&genre.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
} }
qry << " GROUP BY gnr.GenreId LIMIT 1"; std::pair<model::Genre, int> GenreRepository::retrieveRecordWithSongCount(
model::Genre& genre, type::GenreFilter filter = type::GenreFilter::id) {
std::cout << "retrieving genre record with song count\n";
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const auto query = qry.str(); qry << "SELECT gnr.*, COUNT(*) AS SongCount FROM Genre gnr LEFT JOIN ";
qry << "Song sng ON gnr.GenreId=sng.GenreId WHERE ";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); MYSQL_BIND params[1];
status = mysql_stmt_bind_param(stmt, params); std::memset(params, 0, sizeof(params));
status = mysql_stmt_execute(stmt);
auto gnrWSC = parseRecordWithSongCount(stmt); switch (filter) {
case type::GenreFilter::id:
qry << "sng.GenreId = ?";
mysql_stmt_close(stmt); params[0].buffer_type = MYSQL_TYPE_LONG;
mysql_close(conn); params[0].buffer = (char*)&genre.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
std::cout << "retrieved genre record with song count" << std::endl; qry << " GROUP BY gnr.GenreId LIMIT 1";
return gnrWSC; const auto query = qry.str();
}
model::Genre GenreRepository::retrieveRecord(model::Genre& genre, type::GenreFilter filter) auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
{ status = mysql_stmt_bind_param(stmt, params);
// TODO: change to prepared statement status = mysql_stmt_execute(stmt);
auto gnrWSC = parseRecordWithSongCount(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "retrieved genre record with song count\n";
return gnrWSC;
}
model::Genre GenreRepository::retrieveRecord(model::Genre& genre, type::GenreFilter filter) {
std::cout << "retrieving genre record\n";
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT gnr.* FROM Genre gnr WHERE ";
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
auto categoryLength = genre.category.size();
switch (filter) {
case type::GenreFilter::id:
qry << "gnr.GenreId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = reinterpret_cast<char*>(&genre.id);
params[0].length = 0;
params[0].is_null = 0;
break;
case type::GenreFilter::category:
qry << "gnr.Category = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = const_cast<char*>(genre.category.c_str());
params[0].length = &categoryLength;
params[0].is_null = 0;
break;
default:
break;
}
qry << " ORDER BY GenreId DESC LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
genre = parseRecord(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "retrieved record\n";
return genre;
}
bool GenreRepository::doesGenreExist(const model::Genre& genre, type::GenreFilter filter) {
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
std::stringstream qry;
qry << "SELECT * FROM Genre WHERE ";
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
auto categoryLength = genre.category.size();
switch (filter) {
case type::GenreFilter::id:
qry << "GenreId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&genre.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::GenreFilter::category:
qry << "Category = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)genre.category.c_str();
params[0].length = &categoryLength;
params[0].is_null = 0;
break;
default:
break;
}
qry << " LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed\n";
mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
return (rowCount > 0) ? true : false;
}
void GenreRepository::saveRecord(const model::Genre& genre) {
std::cout << "inserting genre record\n";
auto conn = setupMysqlConnection();
MYSQL_STMT *stmt = mysql_stmt_init(conn);
const std::string query("INSERT INTO Genre(Category) VALUES(?)");
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)genre.category.c_str();
auto categoryLength = genre.category.size();
params[0].length = &categoryLength;
params[0].is_null = 0;
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "inserted record\n";
}
void GenreRepository::deleteRecord(const model::Genre& genre,
type::GenreFilter filter = type::GenreFilter::id) {
std::cout << "deleting genre record\n";
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "DELETE FROM Genre WHERE ";
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
switch (filter) {
case type::GenreFilter::id:
qry << "GenreId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&genre.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "deleted genre record\n";
}
std::vector<model::Genre> GenreRepository::parseRecords(MYSQL_STMT *stmt) {
mysql_stmt_store_result(stmt);
std::vector<model::Genre> genres;
genres.reserve(mysql_stmt_num_rows(stmt));
constexpr auto valAmt = 2;
for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
if (mysql_stmt_field_count(stmt) > 0) {
model::Genre genre;
auto metaBuff = metadataBuffer();
auto bindedValues = valueBind(genre, metaBuff);
status = mysql_stmt_bind_result(stmt, bindedValues.get());
std::cout << "fetching statement result\n";
status = mysql_stmt_fetch(stmt);
if (status == 1 || status == MYSQL_NO_DATA) break;
genre.category = std::get<0>(metaBuff);
genres.push_back(genre);
}
std::cout << "fetching statement result\n";
}
return genres;
}
std::pair<model::Genre, int> GenreRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) {
std::cout << "parsing genre record with song count\n";
mysql_stmt_store_result(stmt);
const auto rowCount = mysql_stmt_num_rows(stmt);
model::Genre genre;
int songCount = 0;
auto metaBuff = metadataBuffer();
auto val = valueBindWithSongCount(genre, metaBuff, songCount);
if (rowCount == 0) {
std::cout << "no results\n";
return std::make_pair(genre, songCount);
}
auto status = mysql_stmt_bind_result(stmt, val.get());
status = mysql_stmt_fetch(stmt);
genre.category = std::get<0>(metaBuff);
std::cout << "parsed genre record with song count\n";
return std::make_pair(genre, songCount);
}
std::shared_ptr<MYSQL_BIND> GenreRepository::valueBind(model::Genre& genre,
std::tuple<char*>& metadata) {
constexpr auto valueCount = 2;
constexpr auto wordLen = 1024;
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*)
std::calloc(valueCount, sizeof(MYSQL_BIND)));
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = reinterpret_cast<char*>(&genre.id);
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = reinterpret_cast<char*>(std::get<0>(metadata));
values.get()[1].buffer_length = wordLen;
return values;
}
std::cout << "retrieving genre record" << std::endl; std::shared_ptr<MYSQL_BIND> GenreRepository::valueBindWithSongCount(model::Genre& genre,
std::stringstream qry; std::tuple<char*>& metadata, int& songCount) {
auto conn = setupMysqlConnection(); constexpr auto valueCount = 3;
qry << "SELECT gnr.* FROM Genre gnr WHERE "; constexpr auto wordLen = 1024;
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*)
std::calloc(valueCount, sizeof(MYSQL_BIND)));
std::unique_ptr<char*> param; values.get()[0].buffer_type = MYSQL_TYPE_LONG;
switch (filter) { values.get()[0].buffer = reinterpret_cast<char*>(&genre.id);
case type::GenreFilter::id:
qry << "gnr.GenreId = " << genre.id; values.get()[1].buffer_type = MYSQL_TYPE_STRING;
break; values.get()[1].buffer = reinterpret_cast<char*>(std::get<0>(metadata));
case type::GenreFilter::category: values.get()[1].buffer_length = wordLen;
param = std::make_unique<char*>(new char[genre.category.size()]);
mysql_real_escape_string(conn, *param, genre.category.c_str(), genre.category.size()); values.get()[2].buffer_type = MYSQL_TYPE_LONG;
qry << "gnr.Category ='" << *param << "'"; values.get()[2].buffer = reinterpret_cast<char*>(&songCount);
break;
default: return values;
break;
} }
qry << " ORDER BY GenreId DESC LIMIT 1";
const auto query = qry.str(); std::tuple<char*> GenreRepository::metadataBuffer() {
auto results = performMysqlQuery(conn, query); constexpr auto wordLen = 1024;
char category[wordLen];
genre = parseRecord(results); return std::make_tuple(category);
mysql_close(conn);
std::cout << "retrieved record" << std::endl;
return genre;
}
bool GenreRepository::doesGenreExist(const model::Genre& genre, type::GenreFilter filter)
{
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
std::stringstream qry;
qry << "SELECT * FROM Genre WHERE ";
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
auto categoryLength = genre.category.size();
switch (filter) {
case type::GenreFilter::id:
qry << "GenreId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&genre.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::GenreFilter::category:
qry << "Category = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)genre.category.c_str();
params[0].length = &categoryLength;
params[0].is_null = 0;
break;
default:
break;
} }
qry << " LIMIT 1";
const auto query = qry.str(); model::Genre GenreRepository::parseRecord(MYSQL_STMT *stmt) {
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); std::cout << "parsing genre record\n";
status = mysql_stmt_bind_param(stmt, params); mysql_stmt_store_result(stmt);
status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed" << std::endl; model::Genre genre;
auto metaBuff = metadataBuffer();
mysql_stmt_store_result(stmt); auto bindedValues = valueBind(genre, metaBuff);
auto rowCount = mysql_stmt_num_rows(stmt); auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
mysql_stmt_close(stmt);
mysql_close(conn);
return (rowCount > 0) ? true : false;
}
void GenreRepository::saveRecord(const model::Genre& genre)
{
std::cout << "inserting genre record" << std::endl;
auto conn = setupMysqlConnection();
MYSQL_STMT *stmt = mysql_stmt_init(conn);
const std::string query("INSERT INTO Genre(Category) VALUES(?)");
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)genre.category.c_str();
auto categoryLength = genre.category.size();
params[0].length = &categoryLength;
params[0].is_null = 0;
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "inserted record" << std::endl;
}
void GenreRepository::deleteRecord(const model::Genre& genre, type::GenreFilter filter = type::GenreFilter::id)
{
// TODO: implement this
std::cout << "deleting genre record" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "DELETE FROM Genre WHERE ";
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
switch (filter) {
case type::GenreFilter::id:
qry << "GenreId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&genre.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "deleted genre record" << std::endl;
}
std::vector<model::Genre> GenreRepository::parseRecords(MYSQL_STMT *stmt)
{
mysql_stmt_store_result(stmt);
std::vector<model::Genre> genres;
genres.reserve(mysql_stmt_num_rows(stmt));
if (mysql_stmt_field_count(stmt) == 0) {
std::cout << "field count is 0" << std::endl;
return genres;
}
model::Genre gnr;
const auto valAmt = 2;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
auto res = mysql_stmt_result_metadata(stmt);
auto fields = mysql_fetch_fields(res);
const auto strLen = 1024;
char category[strLen];
MYSQL_BIND val[valAmt];
memset(val, 0, sizeof(val));
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&gnr.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_STRING;
val[1].buffer = (char*)category;
val[1].buffer_length = strLen;
val[1].length = &len[1];
val[1].is_null = &nullRes[1];
for (auto status = mysql_stmt_bind_result(stmt, val); status == 0;) {
std::cout << "fetching statement result" << std::endl;
status = mysql_stmt_fetch(stmt); status = mysql_stmt_fetch(stmt);
if (status == 0) { genre.category = std::get<0>(metaBuff);
gnr.category = category;
genres.push_back(std::move(gnr)); std::cout << "done parsing genre record\n";
}
return genre;
} }
return genres;
}
std::pair<model::Genre, int> GenreRepository::parseRecordWithSongCount(MYSQL_STMT *stmt)
{
std::cout << "parsing genre record with song count" << std::endl;
mysql_stmt_store_result(stmt);
const auto strLen = 1024;
const auto valAmt = 3;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
model::Genre genre;
int songCount = 0;
if (mysql_stmt_num_rows(stmt) == 0) {
std::cout << "no results" << std::endl;
return std::make_pair(genre, songCount);
}
MYSQL_BIND val[valAmt];
std::memset(val, 0, sizeof(val));
char category[strLen] ;
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&genre.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_STRING;
val[1].buffer = (char*)category;
val[1].buffer_length = strLen;
val[1].length = &len[1];
val[1].is_null = &nullRes[1];
val[2].buffer_type = MYSQL_TYPE_LONG;
val[2].buffer = (char*)&songCount;
val[2].length = &len[2];
val[2].is_null = &nullRes[2];
mysql_stmt_bind_result(stmt, val);
mysql_stmt_fetch(stmt);
genre.category = std::move(category);
std::cout << "parsed genre record with song count" << std::endl;
return std::make_pair(genre, songCount);
}
model::Genre GenreRepository::parseRecord(MYSQL_RES* results)
{
std::cout << "parsing genre record" << std::endl;
model::Genre genre;
auto fieldNum = mysql_num_fields(results);
auto row = mysql_fetch_row(results);
for (auto i =0; i != fieldNum; ++i) {
const std::string field(mysql_fetch_field(results)->name);
if (field.compare("GenreId") == 0) {
genre.id = std::stoi(row[i]);
}
if (field.compare("Category") == 0) {
genre.category = row[i];
}
}
std::cout << "parsed genre record" << std::endl;
return genre;
}
model::Genre GenreRepository::parseRecord(MYSQL_STMT *stmt)
{
// TODO: implement this
model::Genre genre;
return genre;
}
} }
File diff suppressed because it is too large Load Diff
+261 -270
View File
@@ -7,358 +7,349 @@
namespace database { namespace database {
UserRepository::UserRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { } UserRepository::UserRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { }
model::User UserRepository::retrieveUserRecord(model::User& user, model::User UserRepository::retrieveUserRecord(model::User& user,
type::UserFilter filter = type::UserFilter::username) type::UserFilter filter = type::UserFilter::username) {
{ std::stringstream qry;
std::stringstream qry; auto conn = setupMysqlConnection();
auto conn = setupMysqlConnection(); auto stmt = mysql_stmt_init(conn);
auto stmt = mysql_stmt_init(conn);
qry << "SELECT * FROM User WHERE "; qry << "SELECT * FROM User WHERE ";
MYSQL_BIND params[1]; MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params)); std::memset(params, 0, sizeof(params));
auto userLength = user.username.size(); auto userLength = user.username.size();
switch (filter) { switch (filter) {
case type::UserFilter::id: case type::UserFilter::id:
qry << "UserId = ?"; qry << "UserId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG; params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&user.id; params[0].buffer = (char*)&user.id;
params[0].length = nullptr; params[0].length = nullptr;
params[0].is_null = 0; params[0].is_null = 0;
break; break;
case type::UserFilter::username: case type::UserFilter::username:
qry << "Username = ?"; qry << "Username = ?";
params[0].buffer_type = MYSQL_TYPE_STRING; params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)user.username.c_str(); params[0].buffer = (char*)user.username.c_str();
params[0].length = &userLength; params[0].length = &userLength;
params[0].is_null = 0; params[0].is_null = 0;
break; break;
default: default:
break; break;
}
qry << " LIMIT 1";
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
user = parseRecord(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
return user;
} }
qry << " LIMIT 1"; model::PassSec UserRepository::retrieverUserSaltRecord(model::PassSec& userSec,
type::SaltFilter filter) {
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const auto query = qry.str(); qry << "SELECT * FROM Salt WHERE ";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
user = parseRecord(stmt); MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
mysql_stmt_close(stmt); switch (filter) {
mysql_close(conn); case type::SaltFilter::userId:
qry << "UserId = ?";
return user; params[0].buffer_type = MYSQL_TYPE_LONG;
} params[0].buffer = (char*)&userSec.userId;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
model::PassSec UserRepository::retrieverUserSaltRecord(model::PassSec& userSec, type::SaltFilter filter) qry << " LIMIT 1";
{
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT * FROM Salt WHERE "; const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
MYSQL_BIND params[1]; userSec = parseSaltRecord(stmt);
std::memset(params, 0, sizeof(params));
switch (filter) { mysql_stmt_close(stmt);
case type::SaltFilter::userId: mysql_close(conn);
qry << "UserId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG; return userSec;
params[0].buffer = (char*)&userSec.userId;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
} }
qry << " LIMIT 1";
const auto query = qry.str(); bool UserRepository::doesUserRecordExist(const model::User& user, type::UserFilter filter) {
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); std::stringstream qry;
status = mysql_stmt_bind_param(stmt, params); auto conn = setupMysqlConnection();
status = mysql_stmt_execute(stmt); auto stmt = mysql_stmt_init(conn);
userSec = parseSaltRecord(stmt); qry << "SELECT * FROM User WHERE ";
mysql_stmt_close(stmt); MYSQL_BIND params[1];
mysql_close(conn); std::memset(params, 0, sizeof(params));
return userSec; auto userLength = user.username.size();
} switch (filter) {
case type::UserFilter::username:
qry << "Username = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)user.username.c_str();
params[0].length = &userLength;
params[0].is_null = 0;
break;
default:
break;
}
bool UserRepository::doesUserRecordExist(const model::User& user, type::UserFilter filter) qry << " LIMIT 1";
{
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT * FROM User WHERE "; const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
MYSQL_BIND params[1]; mysql_stmt_store_result(stmt);
std::memset(params, 0, sizeof(params)); const auto rowCount = mysql_stmt_num_rows(stmt);
auto userLength = user.username.size(); mysql_stmt_close(stmt);
switch (filter) { mysql_close(conn);
case type::UserFilter::username:
qry << "Username = ?";
params[0].buffer_type = MYSQL_TYPE_STRING; return (rowCount > 0) ? true : false;
params[0].buffer = (char*)user.username.c_str();
params[0].length = &userLength;
params[0].is_null = 0;
break;
default:
break;
} }
qry << " LIMIT 1";
const auto query = qry.str(); void UserRepository::saveUserRecord(const model::User& user) {
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); std::cout << "inserting user record\n";
status = mysql_stmt_bind_param(stmt, params); auto conn = setupMysqlConnection();
status = mysql_stmt_execute(stmt); auto stmt = mysql_stmt_init(conn);
mysql_stmt_store_result(stmt); std::stringstream qry;
const auto rowCount = mysql_stmt_num_rows(stmt); qry << "INSERT INTO User(Firstname, Lastname, Phone, Email, Username, Password) ";
qry << "VALUES(?, ?, ?, ?, ?, ?)";
mysql_stmt_close(stmt); const auto query = qry.str();
mysql_close(conn); auto sizes = fetchUserLengths(user);
auto params = insertUserValues(user, sizes);
return (rowCount > 0) ? true : false; auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
} status = mysql_stmt_bind_param(stmt, params.get());
void UserRepository::saveUserRecord(const model::User& user) status = mysql_stmt_execute(stmt);
{
std::cout << "inserting user record" << std::endl;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
std::stringstream qry; mysql_stmt_close(stmt);
qry << "INSERT INTO User(Firstname, Lastname, Phone, Email, Username, Password) "; mysql_close(conn);
qry << "VALUES(?, ?, ?, ?, ?, ?)"; }
const auto query = qry.str(); void UserRepository::saveUserSalt(const model::PassSec& userSec) {
std::cout << "inserting user salt record\n";
auto sizes = fetchUserLengths(user); auto conn = setupMysqlConnection();
auto params = insertUserValues(user, sizes); auto stmt = mysql_stmt_init(conn);
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); std::stringstream qry;
status = mysql_stmt_bind_param(stmt, params.get()); qry << "INSERT INTO Salt(Salt, UserId) VALUES(?,?)";
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt); const auto query = qry.str();
mysql_close(conn);
}
void UserRepository::saveUserSalt(const model::PassSec& userSec) auto sizes = fetchSaltLengths(userSec);
{ auto values = insertSaltValues(userSec, sizes);
std::cout << "inserting user salt record" << std::endl;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
std::stringstream qry; auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
qry << "INSERT INTO Salt(Salt, UserId) VALUES(?,?)"; status = mysql_stmt_bind_param(stmt, values.get());
status = mysql_stmt_execute(stmt);
const auto query = qry.str(); mysql_stmt_close(stmt);
mysql_close(conn);
auto sizes = fetchSaltLengths(userSec); }
auto values = insertSaltValues(userSec, sizes);
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, values.get());
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
}
std::shared_ptr<MYSQL_BIND> UserRepository::insertUserValues(const model::User& user, std::shared_ptr<MYSQL_BIND> UserRepository::insertUserValues(const model::User& user,
std::shared_ptr<UserRepository::UserLengths> lengths) std::shared_ptr<UserRepository::UserLengths> lengths) {
{ std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(6, sizeof(MYSQL_BIND)));
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(6, sizeof(MYSQL_BIND)));
values.get()[0].buffer_type = MYSQL_TYPE_STRING; values.get()[0].buffer_type = MYSQL_TYPE_STRING;
values.get()[0].buffer = (char*)user.firstname.c_str(); values.get()[0].buffer = (char*)user.firstname.c_str();
values.get()[0].length = &(lengths->firstnameLength); values.get()[0].length = &(lengths->firstnameLength);
values.get()[0].is_null = 0; values.get()[0].is_null = 0;
values.get()[1].buffer_type = MYSQL_TYPE_STRING; values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = (char*)user.lastname.c_str(); values.get()[1].buffer = (char*)user.lastname.c_str();
values.get()[1].length = &(lengths->lastnameLength); values.get()[1].length = &(lengths->lastnameLength);
values.get()[1].is_null = 0; values.get()[1].is_null = 0;
values.get()[2].buffer_type = MYSQL_TYPE_STRING; values.get()[2].buffer_type = MYSQL_TYPE_STRING;
values.get()[2].buffer = (char*)user.phone.c_str(); values.get()[2].buffer = (char*)user.phone.c_str();
values.get()[2].length = &(lengths->phoneLength); values.get()[2].length = &(lengths->phoneLength);
values.get()[2].is_null = 0; values.get()[2].is_null = 0;
values.get()[3].buffer_type = MYSQL_TYPE_STRING; values.get()[3].buffer_type = MYSQL_TYPE_STRING;
values.get()[3].buffer = (char*)user.email.c_str(); values.get()[3].buffer = (char*)user.email.c_str();
values.get()[3].length = &(lengths->emailLength); values.get()[3].length = &(lengths->emailLength);
values.get()[3].is_null = 0; values.get()[3].is_null = 0;
values.get()[4].buffer_type = MYSQL_TYPE_STRING; values.get()[4].buffer_type = MYSQL_TYPE_STRING;
values.get()[4].buffer = (char*)user.username.c_str(); values.get()[4].buffer = (char*)user.username.c_str();
values.get()[4].length = &(lengths->usernameLength); values.get()[4].length = &(lengths->usernameLength);
values.get()[4].is_null = 0; values.get()[4].is_null = 0;
values.get()[5].buffer_type = MYSQL_TYPE_STRING; values.get()[5].buffer_type = MYSQL_TYPE_STRING;
values.get()[5].buffer = (char*)user.password.c_str(); values.get()[5].buffer = (char*)user.password.c_str();
values.get()[5].length = &(lengths->passwordLength); values.get()[5].length = &(lengths->passwordLength);
values.get()[5].is_null = 0; values.get()[5].is_null = 0;
return values; return values;
} }
std::shared_ptr<MYSQL_BIND> UserRepository::insertSaltValues(const model::PassSec& passSec, std::shared_ptr<MYSQL_BIND> UserRepository::insertSaltValues(const model::PassSec& passSec,
std::shared_ptr<UserRepository::SaltLengths> lengths) std::shared_ptr<UserRepository::SaltLengths> lengths) {
{ std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(6, sizeof(MYSQL_BIND)));
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(6, sizeof(MYSQL_BIND)));
values.get()[0].buffer_type = MYSQL_TYPE_STRING; values.get()[0].buffer_type = MYSQL_TYPE_STRING;
values.get()[0].buffer = (char*)passSec.hashPassword.c_str(); values.get()[0].buffer = (char*)passSec.hashPassword.c_str();
values.get()[0].length = &(lengths->saltLength); values.get()[0].length = &(lengths->saltLength);
values.get()[1].buffer_type = MYSQL_TYPE_LONG; values.get()[1].buffer_type = MYSQL_TYPE_LONG;
values.get()[1].buffer = (char*)&passSec.userId; values.get()[1].buffer = (char*)&passSec.userId;
return values;
}
return values; std::shared_ptr<MYSQL_BIND> UserRepository::valueBind(model::User& user,
} std::tuple<char*, char*, char*, char*, char*, char*>& us) {
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(7, sizeof(MYSQL_BIND)));
constexpr auto strLen = 1024;
std::shared_ptr<MYSQL_BIND> UserRepository::valueBind(model::User& user, values.get()[0].buffer_type = MYSQL_TYPE_LONG;
std::tuple<char*, char*, char*, char*, char*, char*>& us) values.get()[0].buffer = (char*)&user.id;
{
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(7, sizeof(MYSQL_BIND)));
constexpr auto strLen = 1024;
values.get()[0].buffer_type = MYSQL_TYPE_LONG; values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[0].buffer = (char*)&user.id; values.get()[1].buffer = (char*)std::get<0>(us);
values.get()[1].buffer_length = strLen;
values.get()[1].buffer_type = MYSQL_TYPE_STRING; values.get()[2].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = (char*)std::get<0>(us); values.get()[2].buffer = (char*)std::get<1>(us);
values.get()[1].buffer_length = strLen; values.get()[2].buffer_length = strLen;
values.get()[2].buffer_type = MYSQL_TYPE_STRING; values.get()[3].buffer_type = MYSQL_TYPE_STRING;
values.get()[2].buffer = (char*)std::get<1>(us); values.get()[3].buffer = (char*)std::get<2>(us);
values.get()[2].buffer_length = strLen; values.get()[3].buffer_length = strLen;
values.get()[3].buffer_type = MYSQL_TYPE_STRING;
values.get()[3].buffer = (char*)std::get<2>(us);
values.get()[3].buffer_length = strLen;
values.get()[4].buffer_type = MYSQL_TYPE_STRING; values.get()[4].buffer_type = MYSQL_TYPE_STRING;
values.get()[4].buffer = (char*)std::get<3>(us); values.get()[4].buffer = (char*)std::get<3>(us);
values.get()[4].buffer_length = strLen; values.get()[4].buffer_length = strLen;
values.get()[5].buffer_type = MYSQL_TYPE_STRING; values.get()[5].buffer_type = MYSQL_TYPE_STRING;
values.get()[5].buffer = (char*)std::get<4>(us); values.get()[5].buffer = (char*)std::get<4>(us);
values.get()[5].buffer_length = strLen; values.get()[5].buffer_length = strLen;
values.get()[6].buffer_type = MYSQL_TYPE_STRING; values.get()[6].buffer_type = MYSQL_TYPE_STRING;
values.get()[6].buffer = (char*)std::get<5>(us); values.get()[6].buffer = (char*)std::get<5>(us);
values.get()[6].buffer_length = strLen; values.get()[6].buffer_length = strLen;
return values; return values;
} }
std::shared_ptr<MYSQL_BIND> UserRepository::saltValueBind(model::PassSec& userSalt, char *salt) std::shared_ptr<MYSQL_BIND> UserRepository::saltValueBind(model::PassSec& userSalt,
{ char *salt) {
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(3, sizeof(MYSQL_BIND))); std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(3, sizeof(MYSQL_BIND)));
constexpr auto strLen = 1024; constexpr auto strLen = 1024;
values.get()[0].buffer_type = MYSQL_TYPE_LONG; values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = (char*)&userSalt.id; values.get()[0].buffer = (char*)&userSalt.id;
values.get()[1].buffer_type = MYSQL_TYPE_STRING; values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = (char*)salt; values.get()[1].buffer = (char*)salt;
values.get()[1].buffer_length = strLen; values.get()[1].buffer_length = strLen;
values.get()[2].buffer_type = MYSQL_TYPE_LONG; values.get()[2].buffer_type = MYSQL_TYPE_LONG;
values.get()[2].buffer = (char*)&userSalt.userId; values.get()[2].buffer = (char*)&userSalt.userId;
return values; return values;
} }
std::shared_ptr<UserRepository::UserLengths> UserRepository::fetchUserLengths(const model::User& user) std::shared_ptr<UserRepository::UserLengths> UserRepository::fetchUserLengths(
{ const model::User& user) {
auto userLen = std::make_shared<UserLengths>(); auto userLen = std::make_shared<UserLengths>();
userLen->firstnameLength = user.firstname.size(); userLen->firstnameLength = user.firstname.size();
userLen->lastnameLength = user.lastname.size(); userLen->lastnameLength = user.lastname.size();
userLen->phoneLength = user.phone.size(); userLen->phoneLength = user.phone.size();
userLen->emailLength = user.email.size(); userLen->emailLength = user.email.size();
userLen->usernameLength = user.username.size(); userLen->usernameLength = user.username.size();
userLen->passwordLength = user.password.size(); userLen->passwordLength = user.password.size();
return userLen; return userLen;
} }
std::shared_ptr<UserRepository::SaltLengths> UserRepository::fetchSaltLengths(const model::PassSec& passSec) std::shared_ptr<UserRepository::SaltLengths> UserRepository::fetchSaltLengths(
{ const model::PassSec& passSec) {
auto saltLen = std::make_shared<SaltLengths>(); auto saltLen = std::make_shared<SaltLengths>();
saltLen->saltLength = passSec.salt.size(); saltLen->saltLength = passSec.salt.size();
return saltLen; return saltLen;
} }
std::tuple<char*, char*, char*, char*, char*, char*> UserRepository::fetchUV() std::tuple<char*, char*, char*, char*, char*, char*> UserRepository::fetchUV() {
{ char firstname[1024];
char firstname[1024]; char lastname[1024];
char lastname[1024]; char phone[1024];
char phone[1024]; char email[1024];
char email[1024]; char username[1024];
char username[1024]; char password[1024];
char password[1024];
return std::make_tuple(firstname, lastname, phone, email, username, password); return std::make_tuple(firstname, lastname, phone, email, username, password);
} }
model::User UserRepository::parseRecord(MYSQL_STMT *stmt) model::User UserRepository::parseRecord(MYSQL_STMT *stmt) {
{ model::User user;
model::User user; auto usv = fetchUV();
auto usv = fetchUV();
auto bindedValues = valueBind(user, usv); auto bindedValues = valueBind(user, usv);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get()); auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt); status = mysql_stmt_fetch(stmt);
user.firstname = std::get<0>(usv); user.firstname = std::get<0>(usv);
user.lastname = std::get<1>(usv); user.lastname = std::get<1>(usv);
user.email = std::get<2>(usv); user.email = std::get<2>(usv);
user.phone = std::get<3>(usv); user.phone = std::get<3>(usv);
user.username = std::get<4>(usv); user.username = std::get<4>(usv);
user.password = std::get<5>(usv); user.password = std::get<5>(usv);
return user; return user;
} }
model::PassSec UserRepository::parseSaltRecord(MYSQL_STMT* stmt) model::PassSec UserRepository::parseSaltRecord(MYSQL_STMT* stmt) {
{ model::PassSec userSalt;
model::PassSec userSalt; char saltKey[1024];
char saltKey[1024];
auto bindedValues = saltValueBind(userSalt, saltKey);
auto bindedValues = saltValueBind(userSalt, saltKey); auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
auto status = mysql_stmt_bind_result(stmt, bindedValues.get()); status = mysql_stmt_fetch(stmt);
status = mysql_stmt_fetch(stmt);
userSalt.salt = saltKey;
userSalt.salt = saltKey;
return userSalt;
return userSalt; }
}
} }
+271 -270
View File
@@ -7,335 +7,336 @@
#include <cstring> #include <cstring>
namespace database { namespace database {
YearRepository::YearRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { } YearRepository::YearRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { }
std::vector<model::Year> YearRepository::retrieveRecords() std::vector<model::Year> YearRepository::retrieveRecords() {
{ auto conn = setupMysqlConnection();
auto conn = setupMysqlConnection(); auto stmt = mysql_stmt_init(conn);
auto stmt = mysql_stmt_init(conn); const std::string query = "SELECT * FROM Year";
const std::string query = "SELECT * FROM Year";
mysql_stmt_prepare(stmt, query.c_str(), query.size()); mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt); mysql_stmt_execute(stmt);
auto yearRecs = parseRecords(stmt); auto yearRecs = parseRecords(stmt);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
return yearRecs; return yearRecs;
}
std::pair<model::Year, int> YearRepository::retrieveRecordWithSongCount(model::Year& year, type::YearFilter filter = type::YearFilter::id)
{
std::cout << "retrieving year record with song count" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT yr.*, COUNT(*) AS SongCount FROM Year yr LEFT JOIN ";
qry << "Song sng ON yr.YearId=sng.YearId WHERE ";
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
switch (filter) {
case type::YearFilter::id:
qry << "sng.YearId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&year.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
} }
qry << " GROUP BY yr.YearId LIMIT 1"; std::pair<model::Year, int> YearRepository::retrieveRecordWithSongCount(model::Year& year,
type::YearFilter filter) {
std::cout << "retrieving year record with song count\n";
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const auto query = qry.str(); qry << "SELECT yr.*, COUNT(*) AS SongCount FROM Year yr LEFT JOIN ";
qry << "Song sng ON yr.YearId=sng.YearId WHERE ";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); MYSQL_BIND params[1];
status = mysql_stmt_bind_param(stmt, params); std::memset(params, 0, sizeof(params));
status = mysql_stmt_execute(stmt);
auto yearWSC = parseRecordWithSongCount(stmt); switch (filter) {
case type::YearFilter::id:
qry << "sng.YearId = ?";
mysql_stmt_close(stmt); params[0].buffer_type = MYSQL_TYPE_LONG;
mysql_close(conn); params[0].buffer = (char*)&year.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
std::cout << "retrieved year record with song count" << std::endl; qry << " GROUP BY yr.YearId LIMIT 1";
return yearWSC; const auto query = qry.str();
}
model::Year YearRepository::retrieveRecord(model::Year& year, type::YearFilter filter) auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
{ status = mysql_stmt_bind_param(stmt, params);
// TODO: switch to prepared statements status = mysql_stmt_execute(stmt);
std::cout << "retrieving year record" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
qry << "SELECT yr.* FROM Year yr WHERE ";
switch (filter) { auto yearWSC = parseRecordWithSongCount(stmt);
case type::YearFilter::id:
qry << "yr.YearId = " << year.id; mysql_stmt_close(stmt);
break; mysql_close(conn);
case type::YearFilter::year:
qry << "yr.Year = " << year.year; std::cout << "retrieved year record with song count\n";
break;
default: return yearWSC;
break;
} }
qry << " ORDER BY yr.YearId DESC LIMIT 1"; model::Year YearRepository::retrieveRecord(model::Year& year, type::YearFilter filter) {
std::cout << "retrieving year record\n";
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT yr.* FROM Year yr WHERE ";
const auto query = qry.str(); MYSQL_BIND params[1];
auto results = performMysqlQuery(conn, query); std::memset(params, 0, sizeof(0));
year = parseRecord(results); switch (filter) {
case type::YearFilter::id:
qry << "yr.YearId = ?";
mysql_close(conn); params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = reinterpret_cast<char*>(&year.id);
params[0].length = 0;
params[0].is_null = 0;
break;
case type::YearFilter::year:
qry << "yr.Year = ?";
std::cout << "retrieved record" << std::endl; params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = reinterpret_cast<char*>(&year.year);
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
return year; qry << " ORDER BY yr.YearId DESC LIMIT 1";
}
bool YearRepository::doesYearExist(const model::Year& year, type::YearFilter filter) const auto query = qry.str();
{
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
std::stringstream qry; auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
qry << "SELECT * FROM Year WHERE "; status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
MYSQL_BIND params[1]; year = parseRecord(stmt);
memset(params, 0, sizeof(params));
switch (filter) { mysql_stmt_close(stmt);
case type::YearFilter::id: mysql_close(conn);
qry << "YearId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG; std::cout << "retrieved record\n";
params[0].buffer = (char*)&year.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::YearFilter::year:
qry << "Year = ?";
params[0].buffer_type = MYSQL_TYPE_LONG; return year;
params[0].buffer = (char*)&year.year;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
} }
qry << " LIMIT 1";
const auto query = qry.str(); bool YearRepository::doesYearExist(const model::Year& year, type::YearFilter filter) {
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); auto conn = setupMysqlConnection();
status = mysql_stmt_bind_param(stmt, params); auto stmt = mysql_stmt_init(conn);
status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed" << std::endl; std::stringstream qry;
qry << "SELECT * FROM Year WHERE ";
mysql_stmt_store_result(stmt); MYSQL_BIND params[1];
auto rowCount = mysql_stmt_num_rows(stmt); memset(params, 0, sizeof(params));
mysql_stmt_close(stmt); switch (filter) {
mysql_close(conn); case type::YearFilter::id:
qry << "YearId = ?";
return (rowCount > 0) ? true : false; params[0].buffer_type = MYSQL_TYPE_LONG;
} params[0].buffer = (char*)&year.id;
params[0].length = 0;
params[0].is_null = 0;
break;
case type::YearFilter::year:
qry << "Year = ?";
void YearRepository::saveRecord(const model::Year& year) params[0].buffer_type = MYSQL_TYPE_LONG;
{ params[0].buffer = (char*)&year.year;
std::cout << "saving year record" << std::endl; params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
auto conn = setupMysqlConnection(); qry << " LIMIT 1";
MYSQL_STMT *stmt = mysql_stmt_init(conn);
const std::string query("INSERT INTO Year(Year) VALUES(?)"); const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); std::cout << "the query has been performed\n";
MYSQL_BIND params[1]; mysql_stmt_store_result(stmt);
memset(params, 0 , sizeof(params)); auto rowCount = mysql_stmt_num_rows(stmt);
params[0].buffer_type = MYSQL_TYPE_LONG; mysql_stmt_close(stmt);
params[0].buffer = (char*)&year.year; mysql_close(conn);
params[0].length = 0;
params[0].is_null = 0;
status = mysql_stmt_bind_param(stmt, params); return (rowCount > 0) ? true : false;
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "saved record" << std::endl;
}
void YearRepository::deleteYear(const model::Year& year, type::YearFilter filter = type::YearFilter::id)
{
std::cout << "deleting year record" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "DELETE FROM Year WHERE ";
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
switch (filter) {
case type::YearFilter::id:
qry << "YearId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&year.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
} }
const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); void YearRepository::saveRecord(const model::Year& year) {
status = mysql_stmt_bind_param(stmt, params); std::cout << "saving year record\n";
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt); auto conn = setupMysqlConnection();
mysql_close(conn); MYSQL_STMT *stmt = mysql_stmt_init(conn);
std::cout << "deleted year record" << std::endl; const std::string query("INSERT INTO Year(Year) VALUES(?)");
}
std::vector<model::Year> YearRepository::parseRecords(MYSQL_STMT *stmt) auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
{
mysql_stmt_store_result(stmt);
std::vector<model::Year> yearRecs; MYSQL_BIND params[1];
yearRecs.reserve(mysql_stmt_num_rows(stmt)); memset(params, 0 , sizeof(params));
if (mysql_stmt_field_count(stmt) == 0) { params[0].buffer_type = MYSQL_TYPE_LONG;
std::cout << "field count is 0" << std::endl; params[0].buffer = (char*)&year.year;
return yearRecs; params[0].length = 0;
params[0].is_null = 0;
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "saved record\n";
} }
model::Year yearRec; void YearRepository::deleteYear(const model::Year& year,
const auto valAmt = 2; type::YearFilter filter) {
unsigned long len[valAmt]; std::cout << "deleting year record\n";
my_bool nullRes[valAmt]; std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
auto res = mysql_stmt_result_metadata(stmt); qry << "DELETE FROM Year WHERE ";
MYSQL_BIND val[valAmt]; MYSQL_BIND params[1];
memset(val, 0, sizeof(val)); std::memset(params, 0, sizeof(params));
val[0].buffer_type = MYSQL_TYPE_LONG; switch (filter) {
val[0].buffer = (char*)&yearRec.id; case type::YearFilter::id:
val[0].length = &len[0]; qry << "YearId = ?";
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_LONG; params[0].buffer_type = MYSQL_TYPE_LONG;
val[1].buffer = (char*)&yearRec.year; params[0].buffer = (char*)&year.id;
val[1].length = &len[1]; params[0].length = 0;
val[1].is_null = &nullRes[1]; params[0].is_null = 0;
break;
default:
break;
}
for (auto status = mysql_stmt_bind_result(stmt, val); status == 0;) { const auto query = qry.str();
std::cout << "fetching statement result" << std::endl;
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "deleted year record\n";
}
std::vector<model::Year> YearRepository::parseRecords(MYSQL_STMT *stmt) {
mysql_stmt_store_result(stmt);
const auto rowCount = mysql_stmt_num_rows(stmt);
std::vector<model::Year> yearRecs;
yearRecs.reserve(rowCount);
if (mysql_stmt_field_count(stmt) == 0) {
std::cout << "field count is 0\n";
return yearRecs;
}
const auto valAmt = 2;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
if (mysql_stmt_field_count(stmt) > 0) {
model::Year yearRec;
std::cout << "fetching statement result\n";
auto bindedValues = valueBind(yearRec);
status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt);
if (status == 1 || status == MYSQL_NO_DATA) break;
yearRecs.push_back(yearRec);
}
std::cout << "fetching next result\n";
}
return yearRecs;
}
std::pair<model::Year, int> YearRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) {
std::cout << "parsing year record\n";
mysql_stmt_store_result(stmt);
model::Year year;
int songCount = 0;
if (mysql_stmt_num_rows(stmt) == 0) {
std::cout << "no results\n";
return std::make_pair(year, songCount);
}
auto val = valueBindWithSongCount(year, songCount);
auto status = mysql_stmt_bind_result(stmt, val.get());
status = mysql_stmt_fetch(stmt);
std::cout << "parsed year record from the database\n";
return std::make_pair(year, songCount);
}
std::shared_ptr<MYSQL_BIND> YearRepository::valueBind(model::Year& year) {
constexpr auto valueCount = 2;
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*)
std::calloc(valueCount, sizeof(MYSQL_BIND)));
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = reinterpret_cast<char*>(&year.id);
values.get()[1].buffer_type = MYSQL_TYPE_LONG;
values.get()[1].buffer = reinterpret_cast<char*>(&year.year);
return values;
}
std::shared_ptr<MYSQL_BIND> YearRepository::valueBindWithSongCount(model::Year& year,
int& songCount) {
constexpr auto valueCount = 3;
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*)
std::calloc(valueCount, sizeof(MYSQL_BIND)));
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = reinterpret_cast<char*>(&year.id);
values.get()[1].buffer_type = MYSQL_TYPE_LONG;
values.get()[1].buffer = reinterpret_cast<char*>(&year.year);
values.get()[2].buffer_type = MYSQL_TYPE_LONG;
values.get()[2].buffer = reinterpret_cast<char*>(&songCount);
return values;
}
model::Year YearRepository::parseRecord(MYSQL_STMT *stmt) {
std::cout << "parsing year record\n";
mysql_stmt_store_result(stmt);
model::Year year;
auto bindedValues = valueBind(year);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt); status = mysql_stmt_fetch(stmt);
if (status == 0) { std::cout << "done parsing year record\n";
yearRecs.push_back(std::move(yearRec));
} return year;
} }
return yearRecs;
}
std::pair<model::Year, int> YearRepository::parseRecordWithSongCount(MYSQL_STMT *stmt)
{
std::cout << "parsing year record" << std::endl;
mysql_stmt_store_result(stmt);
constexpr auto valAmt = 3;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
model::Year year;
int songCount = 0;
if (mysql_stmt_num_rows(stmt) == 0) {
std::cout << "no results" << std::endl;
return std::make_pair(year, songCount);
}
MYSQL_BIND val[valAmt];
std::memset(val, 0, sizeof(val));
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&year.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_LONG;
val[1].buffer = (char*)&year.year;
val[1].length = &len[1];
val[1].is_null = &nullRes[1];
val[2].buffer_type = MYSQL_TYPE_LONG;
val[2].buffer = (char*)&songCount;
val[2].length = &len[2];
val[2].is_null = &nullRes[2];
mysql_stmt_bind_result(stmt, val);
mysql_stmt_fetch(stmt);
std::cout << "parsed year record from the database" << std::endl;
return std::make_pair(year, songCount);
}
model::Year YearRepository::parseRecord(MYSQL_RES *results)
{
std::cout << "parsing year record" << std::endl;
model::Year year;
auto fieldNum = mysql_num_fields(results);
auto row = mysql_fetch_row(results);
for (auto i = 0; i != fieldNum; ++i) {
const std::string field(mysql_fetch_field(results)->name);
if (field.compare("YearId") == 0) {
year.id= std::stoi(row[i]);
}
if (field.compare("Year") == 0) {
year.year = std::stoi(row[i]);
}
}
std::cout << "parse year record" << std::endl;
return year;
}
model::Year YearRepository::parseRecord(MYSQL_STMT *stmt)
{
// TODO: imeplement this
// I really thought that I had already done this
model::Year year;
return year;
}
} }
+1 -1
View File
@@ -2,7 +2,7 @@
namespace dto { namespace conversion { namespace dto { namespace conversion {
LoginResultDto::ObjectWrapper DtoConversions::toLoginResultDto(const model::User& user, LoginResultDto::ObjectWrapper DtoConversions::toLoginResultDto(const model::User& user,
const model::Token& token) { const model::Token& token) {
auto logRes = dto::LoginResultDto::createShared(); auto logRes = dto::LoginResultDto::createShared();
logRes->username = user.username.c_str(); logRes->username = user.username.c_str();
logRes->token = token.accessToken.c_str(); logRes->token = token.accessToken.c_str();
+46 -52
View File
@@ -7,72 +7,66 @@
#include "type/AlbumFilter.h" #include "type/AlbumFilter.h"
namespace manager { namespace manager {
AlbumManager::AlbumManager(const model::BinaryPath& bConf) : m_bConf(bConf) { } AlbumManager::AlbumManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
model::Album AlbumManager::retrieveAlbum(model::Album& album) model::Album AlbumManager::retrieveAlbum(model::Album& album) {
{ database::AlbumRepository albRepo(m_bConf);
database::AlbumRepository albRepo(m_bConf); album = std::move(albRepo.retrieveRecord(album, type::AlbumFilter::title));
album = std::move(albRepo.retrieveRecord(album, type::AlbumFilter::title));
return album; return album;
} }
model::Album AlbumManager::saveAlbum(const model::Song& song) model::Album AlbumManager::saveAlbum(const model::Song& song) {
{ model::Album album(song);
model::Album album(song);
database::AlbumRepository albRepo(m_bConf); database::AlbumRepository albRepo(m_bConf);
// TODO: check for existence with the title and the artist // TODO: check for existence with the title and the artist
if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) { if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) {
albRepo.saveAlbum(album); albRepo.saveAlbum(album);
} else { } else {
std::cout << "album record already exists in the database" << std::endl; std::cout << "album record already exists in the database\n";
}
return album;
} }
return album; void AlbumManager::deleteAlbum(const model::Song& song) {
} model::Album album(song);
database::AlbumRepository albRepo(m_bConf);
void AlbumManager::deleteAlbum(const model::Song& song) auto albWSC = albRepo.retrieveRecordWithSongCount(album, type::AlbumFilter::id);
{
model::Album album(song);
database::AlbumRepository albRepo(m_bConf);
auto albWSC = albRepo.retrieveRecordWithSongCount(album, type::AlbumFilter::id);
if (albWSC.second > 1) { if (albWSC.second > 1) {
std::cout << "album still contain songs related to it, will not delete" << std::endl; std::cout << "album still contain songs related to it, will not delete\n";
return; return;
}
std::cout << "safe to delete the album record\n";
albRepo.deleteAlbum(album, type::AlbumFilter::id);
} }
std::cout << "safe to delete the album record" << std::endl; void AlbumManager::updateAlbum(model::Song& updatedSong,
albRepo.deleteAlbum(album, type::AlbumFilter::id); const model::Song& currSong) {
} model::Album album(updatedSong);
void AlbumManager::updateAlbum(model::Song& updatedSong, database::AlbumRepository albRepo(m_bConf);
const model::Song& currSong) if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) {
{ std::cout << "album record does not exist\n";
model::Album album(updatedSong); albRepo.saveAlbum(album);
} else {
std::cout << "album record already exists\n";
}
database::AlbumRepository albRepo(m_bConf); album = albRepo.retrieveRecord(album, type::AlbumFilter::title);
if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) { updatedSong.albumId = album.id;
std::cout << "album record does not exist" << std::endl;
albRepo.saveAlbum(album);
} else {
std::cout << "album record already exists" << std::endl;
} }
album = albRepo.retrieveRecord(album, type::AlbumFilter::title); void AlbumManager::printAlbum(const model::Album& album) {
updatedSong.albumId = album.id; std::cout << "\nalbum record\n";
} std::cout << "id: " << album.id << "\n";
std::cout << "title: " << album.title << "\n";
void AlbumManager::printAlbum(const model::Album& album) std::cout << "year: " << album.year << "\n";
{ }
std::cout << "\nalbum record" << std::endl;
std::cout << "id: " << album.id << std::endl;
std::cout << "title: " << album.title << std::endl;
std::cout << "year: " << album.year << std::endl;
}
} }
+51 -56
View File
@@ -7,75 +7,70 @@
namespace manager { namespace manager {
ArtistManager::ArtistManager(const model::BinaryPath& bConf) : m_bConf(bConf) { } ArtistManager::ArtistManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
model::Artist ArtistManager::retrieveArtist(model::Artist& artist) model::Artist ArtistManager::retrieveArtist(model::Artist& artist) {
{ std::cout << "retrieving artist record\n";
std::cout << "retrieving artist record" << std::endl; database::ArtistRepository artRepo(m_bConf);
database::ArtistRepository artRepo(m_bConf); std::cout << "initialized artist repo\n";
std::cout << "initialized artist repo" << std::endl; std::cout << artist.artist << "\n";
std::cout << artist.artist << std::endl; artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist);
artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist);
return artist; return artist;
}
model::Artist ArtistManager::saveArtist(const model::Song& song)
{
model::Artist artist;
artist.artist = song.artist;
database::ArtistRepository artRepo(m_bConf);
if (!artRepo.doesArtistExist(artist, type::ArtistFilter::artist)) {
artRepo.saveRecord(artist);
} else {
std::cout << "artist already exists" << std::endl;
} }
return artist; model::Artist ArtistManager::saveArtist(const model::Song& song) {
} model::Artist artist;
artist.artist = song.artist;
database::ArtistRepository artRepo(m_bConf);
if (!artRepo.doesArtistExist(artist, type::ArtistFilter::artist)) {
artRepo.saveRecord(artist);
} else {
std::cout << "artist already exists\n";
}
return artist;
}
void ArtistManager::deleteArtist(const model::Song& song) void ArtistManager::deleteArtist(const model::Song& song) {
{ model::Artist artist(song);
model::Artist artist(song);
database::ArtistRepository artRepo(m_bConf); database::ArtistRepository artRepo(m_bConf);
auto artWSC = artRepo.retrieveRecordWithSongCount(artist, type::ArtistFilter::id); auto artWSC = artRepo.retrieveRecordWithSongCount(artist, type::ArtistFilter::id);
if (artWSC.second > 1) { if (artWSC.second > 1) {
std::cout << "artist still contain songs related to it"; std::cout << "artist still contain songs related to it";
std::cout << ", not delete" << std::endl; std::cout << ", not delete\n";
return; return;
}
std::cout << "safe to delete the artist record\n";
artRepo.deleteArtist(artist, type::ArtistFilter::id);
} }
std::cout << "safe to delete the artist record" << std::endl; void ArtistManager::updateArtist(model::Song& updatedSong,
artRepo.deleteArtist(artist, type::ArtistFilter::id); const model::Song& currSong) {
} model::Artist artist;
artist.artist = updatedSong.artist;
void ArtistManager::updateArtist(model::Song& updatedSong, database::ArtistRepository artRepo(m_bConf);
const model::Song& currSong) if (!artRepo.doesArtistExist(artist, type::ArtistFilter::artist)) {
{ std::cout << "artist record does not exist\n";
model::Artist artist; artRepo.saveRecord(artist);
artist.artist = updatedSong.artist; } else {
std::cout << "artist record already exists\n";
}
database::ArtistRepository artRepo(m_bConf); artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist);
if (!artRepo.doesArtistExist(artist, type::ArtistFilter::artist)) { updatedSong.artistId = artist.id;
std::cout << "artist record does not exist" << std::endl;
artRepo.saveRecord(artist);
} else {
std::cout << "artist record already exists" << std::endl;
} }
artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist); void ArtistManager::printArtist(const model::Artist& artist) {
updatedSong.artistId = artist.id; std::cout << "\nartist record" << "\n";
} std::cout << "id: " << artist.id << "\n";
std::cout << "artist: " << artist.artist << "\n";
void ArtistManager::printArtist(const model::Artist& artist) }
{
std::cout << "\nartist record" << std::endl;
std::cout << "id: " << artist.id << std::endl;
std::cout << "artist: " << artist.artist << std::endl;
}
} }
+97 -102
View File
@@ -12,129 +12,124 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace manager { namespace manager {
CoverArtManager::CoverArtManager(const model::BinaryPath& bConf) : m_bConf(bConf) { } CoverArtManager::CoverArtManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
model::Cover CoverArtManager::saveCover(const model::Song& song) model::Cover CoverArtManager::saveCover(const model::Song& song) {
{ auto pathConfigContent = DirectoryManager::pathConfigContent(m_bConf);
auto pathConfigContent = DirectoryManager::pathConfigContent(m_bConf); auto stockCoverPath = DirectoryManager::configPath(m_bConf);
auto stockCoverPath = DirectoryManager::configPath(m_bConf); stockCoverPath.append("/CoverArt.png");
stockCoverPath.append("/CoverArt.png");
utility::MetadataRetriever meta; utility::MetadataRetriever meta;
model::Cover cov; model::Cover cov;
cov.songTitle = song.title; cov.songTitle = song.title;
if (meta.songContainsCoverArt(song)) { if (meta.songContainsCoverArt(song)) {
cov.imagePath = createImagePath(song); cov.imagePath = createImagePath(song);
cov = meta.applyCoverArt(song, cov); cov = meta.applyCoverArt(song, cov);
} else { } else {
cov.imagePath = pathConfigContent["cover_root_path"].get<std::string>(); cov.imagePath = pathConfigContent["cover_root_path"].get<std::string>();
cov = meta.applyStockCoverArt(song, cov, stockCoverPath); cov = meta.applyStockCoverArt(song, cov, stockCoverPath);
}
database::CoverArtRepository covRepo(m_bConf);
if (!covRepo.doesCoverArtExist(cov, type::CoverFilter::songTitle)) {
std::cout << "saving image record to the database\n";
covRepo.saveRecord(cov);
} else {
std::cout << "cover art record already exists\n";
}
std::cout << "retrieving image record from database\n";
cov = covRepo.retrieveRecord(cov, type::CoverFilter::songTitle);
return cov;
} }
database::CoverArtRepository covRepo(m_bConf);
if (!covRepo.doesCoverArtExist(cov, type::CoverFilter::songTitle)) { std::pair<bool, std::string> CoverArtManager::defaultCover(
std::cout << "saving image record to the database" << std::endl; const model::Cover& cover) {
covRepo.saveRecord(cov);
} else { auto paths = DirectoryManager::pathConfigContent(m_bConf);
std::cout << "cover art record already exists" << std::endl; const auto coverArtPath =
paths[DirectoryManager::retrievePathType(
type::PathType::coverArt)].get<std::string>();
auto stockCoverArtPath = coverArtPath;
stockCoverArtPath.append("CoverArt.png");
if (stockCoverArtPath.compare(cover.imagePath) == 0) {
return std::make_pair(true, coverArtPath);
} else {
return std::make_pair(false, coverArtPath);
}
} }
std::cout << "retrieving image record from database" << std::endl;
cov = covRepo.retrieveRecord(cov, type::CoverFilter::songTitle);
return cov; void CoverArtManager::deleteCover(const model::Song& song) {
} database::CoverArtRepository covRepo(m_bConf);
model::Cover cov(song.coverArtId);
std::pair<bool, std::string> CoverArtManager::defaultCover( cov = covRepo.retrieveRecord(cov, type::CoverFilter::id);
const model::Cover& cover) { covRepo.deleteRecord(cov);
auto paths = DirectoryManager::pathConfigContent(m_bConf); auto result = defaultCover(cov);
const auto coverArtPath = if (!result.first) {
paths[DirectoryManager::retrievePathType( fs::remove(cov.imagePath);
type::PathType::coverArt)].get<std::string>(); std::cout << "deleting cover art\n";
const auto coverArtPath = result.second;
} else {
std::cout << "song contains the stock cover art, will not delete\n";
return;
}
auto stockCoverArtPath = coverArtPath; DirectoryManager::deleteDirectories(song, result.second);
stockCoverArtPath.append("CoverArt.png");
if (stockCoverArtPath.compare(cover.imagePath) == 0) {
return std::make_pair(true, coverArtPath);
} else {
return std::make_pair(false, coverArtPath);
}
}
void CoverArtManager::deleteCover(const model::Song& song)
{
database::CoverArtRepository covRepo(m_bConf);
model::Cover cov(song.coverArtId);
cov = covRepo.retrieveRecord(cov, type::CoverFilter::id);
covRepo.deleteRecord(cov);
auto result = defaultCover(cov);
if (!result.first) {
fs::remove(cov.imagePath);
std::cout << "deleting cover art" << std::endl;
const auto coverArtPath = result.second;
} else {
std::cout << "song contains the stock cover art, will not delete" << std::endl;
return;
} }
DirectoryManager::deleteDirectories(song, result.second); void CoverArtManager::updateCover(const model::Song& updatedSong,
} const model::Song& currSong) {
database::CoverArtRepository covRepo(m_bConf);
model::Cover cover(updatedSong.coverArtId);
cover = covRepo.retrieveRecord(cover, type::CoverFilter::id);
void CoverArtManager::updateCover(const model::Song& updatedSong, auto result = defaultCover(cover);
const model::Song& currSong)
{
database::CoverArtRepository covRepo(m_bConf);
model::Cover cover(updatedSong.coverArtId);
cover = covRepo.retrieveRecord(cover, type::CoverFilter::id);
auto result = defaultCover(cover); if (result.first) {
return;
}
if (result.first) { auto imagePath = createImagePath(updatedSong);
return;
fs::copy(cover.imagePath, imagePath);
fs::remove(cover.imagePath);
DirectoryManager::deleteDirectories(currSong, result.second);
} }
auto imagePath = createImagePath(updatedSong); void CoverArtManager::updateCoverRecord(const model::Song& updatedSong) {
model::Cover updatedCover(updatedSong);
auto updatedImagePath = createImagePath(updatedSong);
fs::copy(cover.imagePath, imagePath); database::CoverArtRepository covRepo(m_bConf);
fs::remove(cover.imagePath); covRepo.updateRecord(updatedCover);
DirectoryManager::deleteDirectories(currSong, result.second);
}
void CoverArtManager::updateCoverRecord(const model::Song& updatedSong)
{
model::Cover updatedCover(updatedSong);
auto updatedImagePath = createImagePath(updatedSong);
database::CoverArtRepository covRepo(m_bConf);
covRepo.updateRecord(updatedCover);
}
std::string CoverArtManager::createImagePath(const model::Song& song)
{
auto imagePath = DirectoryManager::createDirectoryProcess(
song, m_bConf, type::PathType::coverArt);
if (song.track != 0) {
imagePath.append("track");
auto trackNum = (song.track > 9) ?
std::to_string(song.track) : "0" + std::to_string(song.track);
imagePath.append(trackNum);
} else {
imagePath.append(song.title);
} }
imagePath.append(".png");
return imagePath;
} std::string CoverArtManager::createImagePath(const model::Song& song) {
auto imagePath = DirectoryManager::createDirectoryProcess(
song, m_bConf, type::PathType::coverArt);
if (song.track != 0) {
imagePath.append("track");
auto trackNum = (song.track > 9) ?
std::to_string(song.track) : "0" + std::to_string(song.track);
imagePath.append(trackNum);
} else {
imagePath.append(song.title);
}
imagePath.append(".png");
return imagePath;
}
} }
+144 -156
View File
@@ -8,188 +8,176 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace manager { namespace manager {
std::string DirectoryManager::createDirectoryProcess(model::Song song, const std::string& rootPath) std::string DirectoryManager::createDirectoryProcess(model::Song song,
{ const std::string& rootPath) {
auto currPath = fs::path(rootPath); auto currPath = fs::path(rootPath);
if (fs::exists(currPath)) { if (fs::exists(currPath)) {
std::cout << "path exists" << std::endl; std::cout << "path exists\n";
} else { } else {
std::cout << "creating path" << std::endl; std::cout << "creating path\n";
fs::create_directory(currPath); fs::create_directory(currPath);
}
auto artPath = fs::path(currPath.string() + song.artist);
if (fs::exists(artPath)) {
std::cout << "artist path exists\n";
} else {
std::cout << "creating artist path\n";
fs::create_directory(artPath);
}
auto albPath = fs::path(artPath.string() + "/" + song.album);
if (fs::exists(albPath)) {
std::cout << "album path exists\n";
} else {
std::cout << "creating album path\n";
fs::create_directory(albPath);
}
return albPath.string() + "/";
} }
auto artPath = fs::path(currPath.string() + song.artist); std::string DirectoryManager::createDirectoryProcess(const model::Song& song,
if (fs::exists(artPath)) { const model::BinaryPath& bConf, type::PathType pType) {
std::cout << "artist path exists" << std::endl; auto path = pathConfigContent(bConf)[retrievePathType(pType)];
} else { auto rootPath = path.get<std::string>();
std::cout << "creating artist path" << std::endl; auto currPath = fs::path(rootPath);
fs::create_directory(artPath);
if (fs::exists(currPath)) {
std::cout << "path exists\n";
} else {
std::cout << "creating root music path\n";
fs::create_directory(currPath);
}
auto artPath = fs::path(currPath.string() + song.albumArtist);
if (fs::exists(artPath)) {
std::cout << "artist path exists\n";
} else {
std::cout << "creating artist path\n";
fs::create_directory(artPath);
}
auto albPath = fs::path(artPath.string() + "/" + song.album);
if (fs::exists(albPath)) {
std::cout << "album path exists\n";
} else {
std::cout << "creating album path\n";
fs::create_directory(albPath);
}
return albPath.string() + "/";
} }
auto albPath = fs::path(artPath.string() + "/" + song.album); std::string DirectoryManager::configPath(std::string_view path) {
if (fs::exists(albPath)) { return fs::canonical(path).parent_path().string();
std::cout << "album path exists" << std::endl;
} else {
std::cout << "creating album path" << std::endl;
fs::create_directory(albPath);
} }
return albPath.string() + "/"; std::string DirectoryManager::configPath(const model::BinaryPath& bConf) {
} return fs::canonical(bConf.path).parent_path().string();
std::string DirectoryManager::createDirectoryProcess(const model::Song& song,
const model::BinaryPath& bConf, type::PathType pType)
{
auto path = pathConfigContent(bConf)[retrievePathType(pType)];
auto rootPath = path.get<std::string>();
auto currPath = fs::path(rootPath);
if (fs::exists(currPath)) {
std::cout << "path exists" << std::endl;
} else {
std::cout << "creating root music path" << std::endl;
fs::create_directory(currPath);
} }
auto artPath = fs::path(currPath.string() + song.albumArtist); std::string DirectoryManager::contentOfPath(const std::string& path) {
if (fs::exists(artPath)) { std::fstream a(path, std::ios::in);
std::cout << "artist path exists" << std::endl; std::stringstream s;
} else { s << a.rdbuf();
std::cout << "creating artist path" << std::endl; a.close();
fs::create_directory(artPath);
return s.str();
} }
auto albPath = fs::path(artPath.string() + "/" + song.album); std::string DirectoryManager::retrievePathType(type::PathType pType) {
if (fs::exists(albPath)) { std::string path;
std::cout << "album path exists" << std::endl; switch (pType) {
} else { case type::PathType::music:
std::cout << "creating album path" << std::endl; path = "root_music_path";
fs::create_directory(albPath); break;
case type::PathType::archive:
path = "archive_root_path";
break;
case type::PathType::temp:
path = "temp_root_path";
break;
case type::PathType::coverArt:
path = "cover_root_path";
break;
default:
break;
}
return path;
} }
return albPath.string() + "/";
}
std::string DirectoryManager::configPath(std::string_view path) nlohmann::json DirectoryManager::credentialConfigContent(const model::BinaryPath& bConf) {
{ auto path = configPath(bConf);
return fs::canonical(path).parent_path().string(); path.append("/authcredentials.json");
}
std::string DirectoryManager::configPath(const model::BinaryPath& bConf) return nlohmann::json::parse(contentOfPath(path));
{
return fs::canonical(bConf.path).parent_path().string();
}
std::string DirectoryManager::contentOfPath(const std::string& path)
{
std::fstream a(path, std::ios::in);
std::stringstream s;
s << a.rdbuf();
a.close();
return s.str();
}
std::string DirectoryManager::retrievePathType(type::PathType pType)
{
std::string path;
switch (pType) {
case type::PathType::music:
path = "root_music_path";
break;
case type::PathType::archive:
path = "archive_root_path";
break;
case type::PathType::temp:
path = "temp_root_path";
break;
case type::PathType::coverArt:
path = "cover_root_path";
break;
default:
break;
} }
return path; nlohmann::json DirectoryManager::databaseConfigContent(const model::BinaryPath& bConf) {
} auto path = configPath(bConf);
path.append("/database.json");
return nlohmann::json::parse(contentOfPath(path));
}
nlohmann::json DirectoryManager::pathConfigContent(const model::BinaryPath& bConf) {
auto path = configPath(bConf);
path.append("/paths.json");
return nlohmann::json::parse(contentOfPath(path));
}
nlohmann::json DirectoryManager::credentialConfigContent(const model::BinaryPath& bConf) void DirectoryManager::deleteDirectories(model::Song song, const std::string& rootPath) {
{ std::cout << "checking for empty directories to delete\n";
auto path = configPath(bConf); const std::string art(rootPath + std::string("/") + song.albumArtist);
path.append("/authcredentials.json"); const std::string alb(art + "/" + song.album);
return nlohmann::json::parse(contentOfPath(path)); auto albPath = fs::path(alb);
}
nlohmann::json DirectoryManager::databaseConfigContent(const model::BinaryPath& bConf)
{
auto path = configPath(bConf);
path.append("/database.json");
return nlohmann::json::parse(contentOfPath(path));
}
nlohmann::json DirectoryManager::pathConfigContent(const model::BinaryPath& bConf)
{
auto path = configPath(bConf);
path.append("/paths.json");
return nlohmann::json::parse(contentOfPath(path));
}
void DirectoryManager::deleteDirectories(model::Song song, const std::string& rootPath)
{
std::cout << "checking for empty directories to delete" << std::endl;
const std::string art(rootPath + std::string("/") + song.albumArtist);
const std::string alb(art + "/" + song.album);
auto albPath = fs::path(alb);
if (!fs::exists(albPath)) { if (!fs::exists(albPath)) {
std::cout << "directory does not exists" << std::endl; std::cout << "directory does not exists\n";
} else if (fs::is_empty(albPath)) { } else if (fs::is_empty(albPath)) {
fs::remove(albPath); fs::remove(albPath);
} }
auto artPath = fs::path(art); auto artPath = fs::path(art);
if (!fs::exists(artPath)) { if (!fs::exists(artPath)) {
std::cout << "directory does not exists" << std::endl; std::cout << "directory does not exists\n";
return; return;
} else if (fs::is_empty(artPath)) { } else if (fs::is_empty(artPath)) {
fs::remove(artPath); fs::remove(artPath);
}
std::cout << "deleted empty directory or directories\n";
} }
std::cout << "deleted empty directory or directories" << std::endl; void DirectoryManager::deleteCoverArtFile(const std::string& covPath,
} const std::string& stockCoverPath) {
if (covPath.compare(stockCoverPath) == 0) {
void DirectoryManager::deleteCoverArtFile(const std::string& covPath, std::cout << "cover has stock cover art, will not deleted\n";
const std::string& stockCoverPath) } else {
{ std::cout << "deleting song path\n";
if (covPath.compare(stockCoverPath) == 0) { auto cov = fs::path(covPath);
std::cout << "cover has stock cover art, will not deleted" << std::endl; fs::remove(cov);
} else { }
std::cout << "deleting song path" << std::endl;
auto cov = fs::path(covPath);
fs::remove(cov);
}
}
void DirectoryManager::deleteSong(const model::Song song)
{
std::cout << "deleting song" << std::endl;
auto songPath = fs::path(song.songPath);
if (!fs::exists(songPath)) {
std::cout << "song does not exists" << std::endl;
return;
} }
fs::remove(songPath); void DirectoryManager::deleteSong(const model::Song song) {
std::cout << "deleted song" << std::endl; std::cout << "deleting song\n";
} auto songPath = fs::path(song.songPath);
if (!fs::exists(songPath)) {
std::cout << "song does not exists\n";
return;
}
fs::remove(songPath);
std::cout << "deleted song" << "\n";
}
} }
+50 -55
View File
@@ -6,72 +6,67 @@
#include "type/GenreFilter.h" #include "type/GenreFilter.h"
namespace manager { namespace manager {
GenreManager::GenreManager(const model::BinaryPath& bConf) : m_bConf(bConf) { } GenreManager::GenreManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
model::Genre GenreManager::retrieveGenre(model::Genre& genre) model::Genre GenreManager::retrieveGenre(model::Genre& genre) {
{ database::GenreRepository gnrRepo(m_bConf);
database::GenreRepository gnrRepo(m_bConf); genre = gnrRepo.retrieveRecord(genre, type::GenreFilter::category);
genre = gnrRepo.retrieveRecord(genre, type::GenreFilter::category);
return genre; return genre;
}
model::Genre GenreManager::saveGenre(const model::Song& song)
{
model::Genre genre;
genre.category = song.genre;
database::GenreRepository gnrRepo(m_bConf);
if (!gnrRepo.doesGenreExist(genre, type::GenreFilter::category)) {
gnrRepo.saveRecord(genre);
} else {
std::cout << "genre record already exists" << std::endl;
} }
return genre; model::Genre GenreManager::saveGenre(const model::Song& song) {
} model::Genre genre;
genre.category = song.genre;
database::GenreRepository gnrRepo(m_bConf);
if (!gnrRepo.doesGenreExist(genre, type::GenreFilter::category)) {
gnrRepo.saveRecord(genre);
} else {
std::cout << "genre record already exists\n";
}
return genre;
void GenreManager::deleteGenre(const model::Song& song)
{
model::Genre genre(song);
database::GenreRepository gnrRepo(m_bConf);
auto gnrWSC = gnrRepo.retrieveRecordWithSongCount(genre, type::GenreFilter::id);
if (gnrWSC.second > 1) {
std::cout << "genre still contain songs related to it";
std::cout << ", will not delete" << std::endl;
return;
} }
std::cout << "safe to delete the genre record" << std::endl;
gnrRepo.deleteRecord(genre, type::GenreFilter::id);
}
void GenreManager::updateGenre(model::Song& updatedSong, void GenreManager::deleteGenre(const model::Song& song) {
const model::Song& currSong) model::Genre genre(song);
{
model::Genre genre;
genre.category = updatedSong.genre;
database::GenreRepository gnrRepo(m_bConf); database::GenreRepository gnrRepo(m_bConf);
if (!gnrRepo.doesGenreExist(genre, type::GenreFilter::category)) { auto gnrWSC = gnrRepo.retrieveRecordWithSongCount(genre, type::GenreFilter::id);
std::cout << "genre record does not exist" << std::endl;
gnrRepo.saveRecord(genre); if (gnrWSC.second > 1) {
} else { std::cout << "genre still contain songs related to it";
std::cout << "genre record already exists" << std::endl; std::cout << ", will not delete\n";
return;
}
std::cout << "safe to delete the genre record\n";
gnrRepo.deleteRecord(genre, type::GenreFilter::id);
} }
genre = gnrRepo.retrieveRecord(genre, type::GenreFilter::category); void GenreManager::updateGenre(model::Song& updatedSong,
updatedSong.genreId = genre.id; const model::Song& currSong) {
} model::Genre genre;
genre.category = updatedSong.genre;
void GenreManager::printGenre(const model::Genre& genre) database::GenreRepository gnrRepo(m_bConf);
{ if (!gnrRepo.doesGenreExist(genre, type::GenreFilter::category)) {
std::cout << "genre record" << std::endl; std::cout << "genre record does not exist\n";
std::cout << "id: " << genre.id << std::endl; gnrRepo.saveRecord(genre);
std::cout << "category: " << genre.category << std::endl; } else {
} std::cout << "genre record already exists\n";
}
genre = gnrRepo.retrieveRecord(genre, type::GenreFilter::category);
updatedSong.genreId = genre.id;
}
void GenreManager::printGenre(const model::Genre& genre) {
std::cout << "genre record\n";
std::cout << "id: " << genre.id << "\n";
std::cout << "category: " << genre.category << "\n";
}
} }
+366 -383
View File
@@ -22,418 +22,401 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace manager { namespace manager {
SongManager::SongManager(const model::BinaryPath& bConf) SongManager::SongManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
: m_bConf(bConf) { }
std::pair<bool, type::SongUpload> SongManager::saveSong(model::Song& song) std::pair<bool, type::SongUpload> SongManager::saveSong(model::Song& song) {
{ saveSongTemp(song);
saveSongTemp(song); utility::MetadataRetriever meta;
utility::MetadataRetriever meta; auto data = std::move(song.data);
auto data = std::move(song.data); song = meta.retrieveMetadata(song);
song = meta.retrieveMetadata(song); song.data = std::move(data);
song.data = std::move(data);
database::SongRepository songRepo(m_bConf); database::SongRepository songRepo(m_bConf);
if (songRepo.doesSongExist(song, type::SongFilter::titleAndArtist)) { if (songRepo.doesSongExist(song, type::SongFilter::titleAndArtist)) {
std::cout << "\ntitle: " << song.title << "\nartist: " << song.artist << "\n"; std::cout << "\ntitle: " << song.title << "\nartist: " << song.artist << "\n";
std::cout << "does not exist\n"; std::cout << "does not exist\n";
return std::make_pair(false, type::SongUpload::AlreadyExist); return std::make_pair(false, type::SongUpload::AlreadyExist);
}
saveMisc(song);
printSong(song);
songRepo.saveRecord(song);
song = songRepo.retrieveRecord(song, type::SongFilter::titleAndArtist);
return std::make_pair(true, type::SongUpload::Successful);
} }
saveMisc(song);
printSong(song); bool SongManager::didSongChange(const model::Song& updatedSong,
const model::Song& currSong) {
if (!updatedSong.title.empty()) {
return true;
}
if (!updatedSong.artist.empty()) {
return true;
}
if (!updatedSong.album.empty()) {
return true;
}
if (updatedSong.genre.empty()) {
return true;
}
if (updatedSong.year != 0) {
return true;
}
songRepo.saveRecord(song); return false;
song = songRepo.retrieveRecord(song, type::SongFilter::titleAndArtist); }
return std::make_pair(true, type::SongUpload::Successful); bool SongManager::requiresFilesystemChange(const model::Song& updatedSong,
const model::Song& currSong) {
if (updatedSong.title.compare(currSong.title) != 0) {
return true;
}
if (updatedSong.artist.compare(currSong.album) != 0) {
return true;
}
if (updatedSong.album.compare(currSong.genre) != 0) {
return true;
}
return false;
}
bool SongManager::deleteSong(model::Song& song) {
database::SongRepository songRepo(m_bConf);
if (!songRepo.doesSongExist(song, type::SongFilter::id)) {
std::cout << "song does not exist\n";
return false;
}
song = songRepo.retrieveRecord(song, type::SongFilter::id);
auto paths = DirectoryManager::pathConfigContent(m_bConf);
auto deleted = songRepo.deleteRecord(song);
if (!deleted) {
std::cout << "song not deleted from databases\n";
return deleted;
}
deleteMisc(song);
fs::remove(song.songPath);
DirectoryManager::deleteDirectories(song, paths["root_music_path"].get<std::string>());
return deleted;
}
bool SongManager::updateSong(model::Song& updatedSong) {
database::SongRepository songRepo(m_bConf);
model::Song currSong(updatedSong.id);
currSong = songRepo.retrieveRecord(currSong, type::SongFilter::id);
if (!didSongChange(updatedSong, currSong)) {
std::cout << "no change to the song\n";
return false;
}
assignMiscId(updatedSong, currSong);
auto changes = changesInSong(updatedSong, currSong);
utility::MetadataRetriever meta;
meta.updateMetadata(updatedSong, currSong);
assignMiscFields(changes, updatedSong, currSong);
if (requiresFilesystemChange(updatedSong, currSong)) {
modifySongOnFilesystem(updatedSong, currSong);
}
printSong(updatedSong);
printSong(currSong);
updateMisc(changes, updatedSong, currSong);
return true;
}
void SongManager::printSong(const model::Song& song) {
std::cout << "\nsong" << "\n";
std::cout << "title: " << song.title << "\n";
std::cout << "artist: " << song.artist << "\n";
std::cout << "album artist: " << song.albumArtist << "\n";
std::cout << "album: " << song.album << "\n";
std::cout << "genre: " << song.genre << "\n";
std::cout << "duration: " << song.duration << "\n";
std::cout << "year: " << song.year << "\n";
std::cout << "track: " << song.track << "\n";
std::cout << "disc: " << song.disc << "\n";
std::cout << "song path: " << song.songPath << "\n";
std::cout << "cover art id: " << song.coverArtId << "\n";
std::cout << "album id: " << song.albumId << "\n";
std::cout << "artist id: " << song.artistId << "\n";
std::cout << "genre id: " << song.genreId << "\n";
std::cout << "year id: " << song.yearId << "\n";
}
std::map<type::SongChanged, bool> SongManager::changesInSong(
const model::Song& updatedSong, const model::Song& currSong) {
std::map<type::SongChanged, bool> songChanges;
std::string_view updatedTitle = updatedSong.title;
std::string_view updatedArtist = updatedSong.artist;
std::string_view updatedAlbum = updatedSong.album;
std::string_view updatedGenre = updatedSong.genre;
songChanges[type::SongChanged::title] =
(currSong.title.compare(updatedTitle) != 0 &&
updatedTitle.size() > 0) ? true : false;
songChanges[type::SongChanged::artist] =
(currSong.artist.compare(updatedArtist) != 0 &&
updatedArtist.size() > 0) ? true : false;
songChanges[type::SongChanged::album] =
(currSong.album.compare(updatedAlbum) != 0 &&
updatedAlbum.size() > 0) ? true : false;
songChanges[type::SongChanged::genre] =
(currSong.genre.compare(updatedGenre) != 0 &&
updatedGenre.size() > 0) ? true : false;
songChanges[type::SongChanged::year] =
(updatedSong.year != 0) ? true : false;
return songChanges;
} }
bool SongManager::didSongChange(const model::Song& updatedSong, std::string SongManager::createSongPath(const model::Song& song) {
const model::Song& currSong) auto songPath = DirectoryManager::createDirectoryProcess(
{ song, m_bConf, type::PathType::music);
if (!updatedSong.title.empty()) {
return true; if (song.track != 0) {
} songPath.append("track");
if (!updatedSong.artist.empty()) { auto trackNum = (song.track > 9) ?
return true; std::to_string(song.track) : "0" + std::to_string(song.track);
} songPath.append(trackNum);
if (!updatedSong.album.empty()) { } else {
return true; songPath.append(song.title);
} }
if (updatedSong.genre.empty()) { songPath.append(".mp3");
return true;
} return songPath;
if (updatedSong.year != 0) {
return true;
} }
return false;
}
bool SongManager::requiresFilesystemChange(const model::Song& updatedSong, // used to prevent empty values to appear in the updated song
const model::Song& currSong) void SongManager::assignMiscFields(
{ std::map<type::SongChanged, bool>& songChanges, model::Song& updatedSong,
if (updatedSong.title.compare(currSong.title) != 0) { const model::Song& currSong) {
return true; std::cout << "assigning miscellanes fields to updated song\n";
} updatedSong.track = currSong.track;
if (updatedSong.artist.compare(currSong.album) != 0) { for (auto scIter = songChanges.begin(); scIter != songChanges.end(); ++scIter) {
return true; type::SongChanged key = scIter->first;
} bool changed = songChanges.at(key);
if (updatedSong.album.compare(currSong.genre) != 0) {
return true;
}
return false; if (!changed) {
} switch (key) {
case type::SongChanged::title:
bool SongManager::deleteSong(model::Song& song) updatedSong.title = currSong.title;
{ std::cout << "title has not been changed\n";
database::SongRepository songRepo(m_bConf); break;
case type::SongChanged::artist:
if (!songRepo.doesSongExist(song, type::SongFilter::id)) { updatedSong.artist = currSong.artist;
std::cout << "song does not exist" << std::endl; std::cout << "artist has not been changed\n";
return false; break;
} case type::SongChanged::album:
updatedSong.album = currSong.album;
song = songRepo.retrieveRecord(song, type::SongFilter::id); std::cout << "album has not been changed\n";
break;
auto paths = DirectoryManager::pathConfigContent(m_bConf); case type::SongChanged::genre:
updatedSong.genre = currSong.genre;
auto deleted = songRepo.deleteRecord(song); std::cout << "genre has not been changed\n";
break;
if (!deleted) { case::type::SongChanged::year:
std::cout << "song not deleted from databases" << std::endl; updatedSong.year = currSong.year;
return deleted; std::cout << "year has not been changed\n";
} default:
deleteMisc(song); break;
}
fs::remove(song.songPath);
DirectoryManager::deleteDirectories(song, paths["root_music_path"].get<std::string>());
return deleted;
}
bool SongManager::updateSong(model::Song& updatedSong)
{
database::SongRepository songRepo(m_bConf);
model::Song currSong(updatedSong.id);
currSong = songRepo.retrieveRecord(currSong, type::SongFilter::id);
if (!didSongChange(updatedSong, currSong)) {
std::cout << "no change to the song" << std::endl;
return false;
}
assignMiscId(updatedSong, currSong);
auto changes = changesInSong(updatedSong, currSong);
utility::MetadataRetriever meta;
meta.updateMetadata(updatedSong, currSong);
assignMiscFields(changes, updatedSong, currSong);
if (requiresFilesystemChange(updatedSong, currSong)) {
modifySongOnFilesystem(updatedSong, currSong);
}
printSong(updatedSong);
printSong(currSong);
updateMisc(changes, updatedSong, currSong);
return true;
}
void SongManager::printSong(const model::Song& song)
{
std::cout << "\nsong" << std::endl;
std::cout << "title: " << song.title << std::endl;
std::cout << "artist: " << song.artist << std::endl;
std::cout << "album artist: " << song.albumArtist << std::endl;
std::cout << "album: " << song.album << std::endl;
std::cout << "genre: " << song.genre << std::endl;
std::cout << "duration: " << song.duration << std::endl;
std::cout << "year: " << song.year << std::endl;
std::cout << "track: " << song.track << std::endl;
std::cout << "disc: " << song.disc << std::endl;
std::cout << "song path: " << song.songPath << std::endl;
std::cout << "cover art id: " << song.coverArtId << std::endl;
std::cout << "album id: " << song.albumId << std::endl;
std::cout << "artist id: " << song.artistId << std::endl;
std::cout << "genre id: " << song.genreId << std::endl;
std::cout << "year id: " << song.yearId << std::endl;
}
std::map<type::SongChanged, bool> SongManager::changesInSong(
const model::Song& updatedSong, const model::Song& currSong)
{
std::map<type::SongChanged, bool> songChanges;
std::string_view updatedTitle = updatedSong.title;
std::string_view updatedArtist = updatedSong.artist;
std::string_view updatedAlbum = updatedSong.album;
std::string_view updatedGenre = updatedSong.genre;
songChanges[type::SongChanged::title] =
(currSong.title.compare(updatedTitle) != 0 &&
updatedTitle.size() > 0) ? true : false;
songChanges[type::SongChanged::artist] =
(currSong.artist.compare(updatedArtist) != 0 &&
updatedArtist.size() > 0) ? true : false;
songChanges[type::SongChanged::album] =
(currSong.album.compare(updatedAlbum) != 0 &&
updatedAlbum.size() > 0) ? true : false;
songChanges[type::SongChanged::genre] =
(currSong.genre.compare(updatedGenre) != 0 &&
updatedGenre.size() > 0) ? true : false;
songChanges[type::SongChanged::year] =
(updatedSong.year != 0) ? true : false;
return songChanges;
}
std::string SongManager::createSongPath(const model::Song& song)
{
auto songPath = DirectoryManager::createDirectoryProcess(
song, m_bConf, type::PathType::music);
if (song.track != 0) {
songPath.append("track");
auto trackNum = (song.track > 9) ?
std::to_string(song.track) : "0" + std::to_string(song.track);
songPath.append(trackNum);
} else {
songPath.append(song.title);
}
songPath.append(".mp3");
return songPath;
}
// used to prevent empty values to appear in the updated song
void SongManager::assignMiscFields(
std::map<type::SongChanged, bool>& songChanges, model::Song& updatedSong,
const model::Song& currSong)
{
std::cout << "assigning miscellanes fields to updated song" << std::endl;
updatedSong.track = currSong.track;
for (auto scIter = songChanges.begin(); scIter != songChanges.end(); ++scIter) {
type::SongChanged key = scIter->first;
bool changed = songChanges.at(key);
if (!changed) {
switch (key) {
case type::SongChanged::title:
updatedSong.title = currSong.title;
std::cout << "title has not been changed" << std::endl;
break;
case type::SongChanged::artist:
updatedSong.artist = currSong.artist;
std::cout << "artist has not been changed" << std::endl;
break;
case type::SongChanged::album:
updatedSong.album = currSong.album;
std::cout << "album has not been changed" << std::endl;
break;
case type::SongChanged::genre:
updatedSong.genre = currSong.genre;
std::cout << "genre has not been changed" << std::endl;
break;
case::type::SongChanged::year:
updatedSong.year = currSong.year;
std::cout << "year has not been changed" << std::endl;
default:
break;
} }
} }
} }
}
// used to dump miscellaneous id to the updated song // used to dump miscellaneous id to the updated song
void SongManager::assignMiscId(model::Song& updatedSong, void SongManager::assignMiscId(model::Song& updatedSong,
const model::Song& currSong) const model::Song& currSong) {
{ std::cout << "assigning miscellaneous Id's to updated song\n";
std::cout << "assigning miscellaneous Id's to updated song" << std::endl; updatedSong.artistId = currSong.artistId;
updatedSong.artistId = currSong.artistId; updatedSong.albumId = currSong.albumId;
updatedSong.albumId = currSong.albumId; updatedSong.genreId = currSong.genreId;
updatedSong.genreId = currSong.genreId; updatedSong.yearId = currSong.yearId;
updatedSong.yearId = currSong.yearId; updatedSong.coverArtId = currSong.coverArtId;
updatedSong.coverArtId = currSong.coverArtId;
}
// saves song to a temporary path
void SongManager::saveSongTemp(model::Song& song)
{
auto config = DirectoryManager::pathConfigContent(m_bConf);
auto tmpSongPath = config["temp_root_path"].get<std::string>();
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> dist(1,1000);
tmpSongPath.append(std::to_string(dist(rng)));
tmpSongPath.append(".mp3");
std::fstream s(tmpSongPath, std::fstream::binary | std::fstream::out);
s.write((char*)&song.data[0], song.data.size());
s.close();
song.songPath = tmpSongPath;
}
void SongManager::saveMisc(model::Song& song)
{
CoverArtManager covMgr(m_bConf);
auto pathConfigContent = DirectoryManager::pathConfigContent(m_bConf);
auto musicRootPath = pathConfigContent["root_music_path"].get<std::string>();
auto cov = covMgr.saveCover(song);
const auto songPath = createSongPath(song);
if (fs::exists(songPath)) {
std::cout << "deleting old song with the same metadata" << std::endl;
fs::remove(songPath);
}
std::cout << "copying song to the appropriate directory" << std::endl;
std::cout << song.songPath << std::endl;
std::cout << songPath << std::endl;
fs::copy(song.songPath, songPath);
fs::remove(song.songPath);
song.songPath = std::move(songPath);
std::cout << "copied song to the appropriate directory" << std::endl;
AlbumManager albMgr(m_bConf);
auto album = albMgr.saveAlbum(song);
album = albMgr.retrieveAlbum(album);
AlbumManager::printAlbum(album);
ArtistManager artMgr(m_bConf);
auto artist = artMgr.saveArtist(song);
artist = artMgr.retrieveArtist(artist);
ArtistManager::printArtist(artist);
GenreManager gnrMgr(m_bConf);
auto genre = gnrMgr.saveGenre(song);
genre = gnrMgr.retrieveGenre(genre);
GenreManager::printGenre(genre);
YearManager yrMgr(m_bConf);
auto year = yrMgr.saveYear(song);
year = yrMgr.retrieveYear(year);
YearManager::printYear(year);
song.coverArtId = cov.id;
song.albumId = album.id;
song.artistId = artist.id;
song.genreId = genre.id;
song.yearId = year.id;
std::cout << "done with miscellaneous database records" << std::endl;
}
void SongManager::deleteMisc(const model::Song& song)
{
CoverArtManager covMgr(m_bConf);
covMgr.deleteCover(song);
AlbumManager albMgr(m_bConf);
albMgr.deleteAlbum(song);
ArtistManager artMgr(m_bConf);
artMgr.deleteArtist(song);
GenreManager gnrMgr(m_bConf);
gnrMgr.deleteGenre(song);
YearManager yrMgr(m_bConf);
yrMgr.deleteYear(song);
}
// deletes miscellanes records
void SongManager::deleteMiscExceptCoverArt(const model::Song& song)
{
AlbumManager albMgr(m_bConf);
albMgr.deleteAlbum(song);
ArtistManager artMgr(m_bConf);
artMgr.deleteArtist(song);
GenreManager gnrMgr(m_bConf);
gnrMgr.deleteGenre(song);
YearManager yrMgr(m_bConf);
yrMgr.deleteYear(song);
}
void SongManager::updateMisc(
const std::map<type::SongChanged, bool>& songChanges,
model::Song& updatedSong, const model::Song& currSong)
{
auto titleChange = songChanges.at(type::SongChanged::title);
auto artistChange = songChanges.at(type::SongChanged::artist);
auto albumChange = songChanges.at(type::SongChanged::album);
auto genreChange = songChanges.at(type::SongChanged::genre);
auto yearChange = songChanges.at(type::SongChanged::year);
if (artistChange) {
ArtistManager artMgr(m_bConf);
artMgr.updateArtist(updatedSong, currSong);
}
if (albumChange) {
AlbumManager albMgr(m_bConf);
albMgr.updateAlbum(updatedSong, currSong);
}
if (genreChange) {
GenreManager gnrMgr(m_bConf);
gnrMgr.updateGenre(updatedSong, currSong);
}
if (yearChange) {
YearManager yrMgr(m_bConf);
yrMgr.updateYear(updatedSong, currSong);
} }
// determins to update the cover art record // saves song to a temporary path
if (titleChange || artistChange || albumChange) { void SongManager::saveSongTemp(model::Song& song) {
auto config = DirectoryManager::pathConfigContent(m_bConf);
auto tmpSongPath = config["temp_root_path"].get<std::string>();
std::random_device dev;
std::mt19937 rng(dev());
std::uniform_int_distribution<std::mt19937::result_type> dist(1,1000);
tmpSongPath.append(std::to_string(dist(rng)));
tmpSongPath.append(".mp3");
std::fstream s(tmpSongPath, std::fstream::binary | std::fstream::out);
s.write((char*)&song.data[0], song.data.size());
s.close();
song.songPath = tmpSongPath;
}
void SongManager::saveMisc(model::Song& song) {
CoverArtManager covMgr(m_bConf); CoverArtManager covMgr(m_bConf);
covMgr.updateCoverRecord(updatedSong); auto pathConfigContent = DirectoryManager::pathConfigContent(m_bConf);
auto musicRootPath = pathConfigContent["root_music_path"].get<std::string>();
auto cov = covMgr.saveCover(song);
const auto songPath = createSongPath(song);
if (fs::exists(songPath)) {
std::cout << "deleting old song with the same metadata\n";
fs::remove(songPath);
}
std::cout << "copying song to the appropriate directory\n";
std::cout << song.songPath << std::endl;
std::cout << songPath << std::endl;
fs::copy(song.songPath, songPath);
fs::remove(song.songPath);
song.songPath = std::move(songPath);
std::cout << "copied song to the appropriate directory\n";
AlbumManager albMgr(m_bConf);
auto album = albMgr.saveAlbum(song);
album = albMgr.retrieveAlbum(album);
AlbumManager::printAlbum(album);
ArtistManager artMgr(m_bConf);
auto artist = artMgr.saveArtist(song);
artist = artMgr.retrieveArtist(artist);
ArtistManager::printArtist(artist);
GenreManager gnrMgr(m_bConf);
auto genre = gnrMgr.saveGenre(song);
genre = gnrMgr.retrieveGenre(genre);
GenreManager::printGenre(genre);
YearManager yrMgr(m_bConf);
auto year = yrMgr.saveYear(song);
year = yrMgr.retrieveYear(year);
YearManager::printYear(year);
song.coverArtId = cov.id;
song.albumId = album.id;
song.artistId = artist.id;
song.genreId = genre.id;
song.yearId = year.id;
std::cout << "done with miscellaneous database records\n";
} }
database::SongRepository songRepo(m_bConf); void SongManager::deleteMisc(const model::Song& song) {
songRepo.updateRecord(updatedSong); CoverArtManager covMgr(m_bConf);
covMgr.deleteCover(song);
deleteMiscExceptCoverArt(currSong); AlbumManager albMgr(m_bConf);
} albMgr.deleteAlbum(song);
void SongManager::modifySongOnFilesystem(model::Song& updatedSong, ArtistManager artMgr(m_bConf);
const model::Song& currSong) artMgr.deleteArtist(song);
{
std::cout << "preparing to modify song" << std::endl;
auto songPath = createSongPath(updatedSong);
updatedSong.songPath = std::move(songPath);
std::cout << "new path " << updatedSong.songPath << std::endl; GenreManager gnrMgr(m_bConf);
gnrMgr.deleteGenre(song);
fs::copy(currSong.songPath, updatedSong.songPath); YearManager yrMgr(m_bConf);
fs::remove(currSong.songPath); yrMgr.deleteYear(song);
}
auto paths = DirectoryManager::pathConfigContent(m_bConf); // deletes miscellanes records
const auto musicRootPath = void SongManager::deleteMiscExceptCoverArt(const model::Song& song) {
paths[DirectoryManager::retrievePathType( AlbumManager albMgr(m_bConf);
albMgr.deleteAlbum(song);
ArtistManager artMgr(m_bConf);
artMgr.deleteArtist(song);
GenreManager gnrMgr(m_bConf);
gnrMgr.deleteGenre(song);
YearManager yrMgr(m_bConf);
yrMgr.deleteYear(song);
}
void SongManager::updateMisc(
const std::map<type::SongChanged, bool>& songChanges,
model::Song& updatedSong, const model::Song& currSong) {
auto titleChange = songChanges.at(type::SongChanged::title);
auto artistChange = songChanges.at(type::SongChanged::artist);
auto albumChange = songChanges.at(type::SongChanged::album);
auto genreChange = songChanges.at(type::SongChanged::genre);
auto yearChange = songChanges.at(type::SongChanged::year);
if (artistChange) {
ArtistManager artMgr(m_bConf);
artMgr.updateArtist(updatedSong, currSong);
}
if (albumChange) {
AlbumManager albMgr(m_bConf);
albMgr.updateAlbum(updatedSong, currSong);
}
if (genreChange) {
GenreManager gnrMgr(m_bConf);
gnrMgr.updateGenre(updatedSong, currSong);
}
if (yearChange) {
YearManager yrMgr(m_bConf);
yrMgr.updateYear(updatedSong, currSong);
}
// determins to update the cover art record
if (titleChange || artistChange || albumChange) {
CoverArtManager covMgr(m_bConf);
covMgr.updateCoverRecord(updatedSong);
}
database::SongRepository songRepo(m_bConf);
songRepo.updateRecord(updatedSong);
deleteMiscExceptCoverArt(currSong);
}
void SongManager::modifySongOnFilesystem(model::Song& updatedSong,
const model::Song& currSong) {
std::cout << "preparing to modify song\n";
auto songPath = createSongPath(updatedSong);
updatedSong.songPath = std::move(songPath);
std::cout << "new path " << updatedSong.songPath << "\n";
fs::copy(currSong.songPath, updatedSong.songPath);
fs::remove(currSong.songPath);
auto paths = DirectoryManager::pathConfigContent(m_bConf);
const auto musicRootPath =
paths[DirectoryManager::retrievePathType(
type::PathType::music)].get<std::string>(); type::PathType::music)].get<std::string>();
DirectoryManager::deleteDirectories(currSong, musicRootPath); DirectoryManager::deleteDirectories(currSong, musicRootPath);
CoverArtManager covMgr(m_bConf); CoverArtManager covMgr(m_bConf);
covMgr.updateCover(updatedSong, currSong); covMgr.updateCover(updatedSong, currSong);
} }
} }
+128 -138
View File
@@ -14,169 +14,159 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace manager { namespace manager {
model::Token TokenManager::retrieveToken(const model::BinaryPath& bConf) model::Token TokenManager::retrieveToken(const model::BinaryPath& bConf) {
{ auto cred = parseAuthCredentials(bConf);
auto cred = parseAuthCredentials(bConf); auto reqObj = createTokenBody(cred);
auto reqObj = createTokenBody(cred);
std::string uri{cred.uri}; std::string uri{cred.uri};
uri.append("/"); uri.append("/");
uri.append(cred.endpoint); uri.append(cred.endpoint);
auto r = sendRequest(uri, reqObj); auto r = sendRequest(uri, reqObj);
auto postRes = nlohmann::json::parse(r.text); auto postRes = nlohmann::json::parse(r.text);
model::Token lr(std::move(postRes["access_token"].get<std::string>()), model::Token lr(std::move(postRes["access_token"].get<std::string>()),
std::move(postRes["token_type"].get<std::string>()), std::move(postRes["token_type"].get<std::string>()),
postRes["expires_in"].get<int>()); postRes["expires_in"].get<int>());
return lr; return lr;
}
bool TokenManager::isTokenValid(std::string& auth, type::Scope scope)
{
auto authPair = fetchAuthHeader(auth);
if (!std::get<0>(authPair)) {
std::cout << "no Bearer found" << std::endl;
return std::get<0>(authPair);
} }
auto authHeader = std::get<1>(authPair);
auto token = authHeader.at(authHeader.size()-1); bool TokenManager::isTokenValid(std::string& auth, type::Scope scope) {
auto authPair = fetchAuthHeader(auth);
auto scopes = extractScopes(jwt::decode(token)); if (!std::get<0>(authPair)) {
std::cout << "no Bearer found\n";
switch (scope) { return std::get<0>(authPair);
case type::Scope::upload: }
return tokenSupportsScope(scopes, "upload:songs");
case type::Scope::download: auto authHeader = std::get<1>(authPair);
return tokenSupportsScope(scopes, "download:songs");
case type::Scope::stream: auto token = authHeader.at(authHeader.size()-1);
return tokenSupportsScope(scopes, "stream:songs");
case type::Scope::deleteSong: auto scopes = extractScopes(jwt::decode(token));
return tokenSupportsScope(scopes, "delete:songs");
case type::Scope::updateSong: switch (scope) {
return tokenSupportsScope(scopes, "update:songs"); case type::Scope::upload:
case type::Scope::retrieveSong: return tokenSupportsScope(scopes, "upload:songs");
return tokenSupportsScope(scopes, "read:song_details"); case type::Scope::download:
case type::Scope::retrieveAlbum: return tokenSupportsScope(scopes, "download:songs");
return tokenSupportsScope(scopes, "read:albums"); case type::Scope::stream:
case type::Scope::retrieveArtist: return tokenSupportsScope(scopes, "stream:songs");
return tokenSupportsScope(scopes, "read:artists"); case type::Scope::deleteSong:
case type::Scope::retrieveGenre: return tokenSupportsScope(scopes, "delete:songs");
return tokenSupportsScope(scopes, "read:genre"); case type::Scope::updateSong:
case type::Scope::retrieveYear: return tokenSupportsScope(scopes, "update:songs");
return tokenSupportsScope(scopes, "read:year"); case type::Scope::retrieveSong:
case type::Scope::downloadCoverArt: return tokenSupportsScope(scopes, "read:song_details");
return tokenSupportsScope(scopes, "download:cover_art"); case type::Scope::retrieveAlbum:
default: return tokenSupportsScope(scopes, "read:albums");
break; case type::Scope::retrieveArtist:
return tokenSupportsScope(scopes, "read:artists");
case type::Scope::retrieveGenre:
return tokenSupportsScope(scopes, "read:genre");
case type::Scope::retrieveYear:
return tokenSupportsScope(scopes, "read:year");
case type::Scope::downloadCoverArt:
return tokenSupportsScope(scopes, "download:cover_art");
default:
break;
}
return false;
} }
return false; bool TokenManager::testAuth(const model::BinaryPath& bConf) {
} auto cred = parseAuthCredentials(bConf);
auto reqObj = createTokenBody(cred);
bool TokenManager::testAuth(const model::BinaryPath& bConf) std::string uri(cred.uri);
{ uri.append("/");
auto cred = parseAuthCredentials(bConf); uri.append(cred.endpoint);
auto reqObj = createTokenBody(cred);
std::string uri(cred.uri); auto response = sendRequest(uri, reqObj);
uri.append("/");
uri.append(cred.endpoint);
auto response = sendRequest(uri, reqObj); return (response.status_code == 200) ? true : false;
}
return (response.status_code == 200) ? true : false;
}
cpr::Response TokenManager::sendRequest(std::string_view uri, nlohmann::json& obj) cpr::Response TokenManager::sendRequest(std::string_view uri, nlohmann::json& obj) {
{ auto resp = cpr::Post(cpr::Url{uri}, cpr::Body{obj.dump()},
auto resp = cpr::Post(cpr::Url{uri}, cpr::Body{obj.dump()},
cpr::Header{{"Content-type", "application/json"}, cpr::Header{{"Content-type", "application/json"},
{"Connection", "keep-alive"}}); {"Connection", "keep-alive"}});
return resp; return resp;
}
nlohmann::json TokenManager::createTokenBody(const model::AuthCredentials& auth)
{
nlohmann::json obj;
obj["client_id"] = auth.clientId;
obj["client_secret"] = auth.clientSecret;
obj["audience"] = auth.apiIdentifier;
obj["grant_type"] = "client_credentials";
return obj;
}
model::AuthCredentials TokenManager::parseAuthCredentials(const model::BinaryPath& bConf)
{
auto con = DirectoryManager::credentialConfigContent(bConf);
model::AuthCredentials auth;
auth.uri = "https://";
auth.uri.append(con["domain"]);
auth.apiIdentifier = con["api_identifier"];
auth.clientId = con["client_id"];
auth.clientSecret = con["client_secret"];
auth.endpoint = "oauth/token";
return auth;
}
std::vector<std::string> TokenManager::extractScopes(const jwt::decoded_jwt&& decoded)
{
std::vector<std::string> scopes;
for (auto& d : decoded.get_payload_claims()) {
if (d.first.compare("scope") == 0) {
std::cout << "found scope" << std::endl;
std::string allScopes(d.second.to_json().get<std::string>());
std::istringstream iss(allScopes);
scopes.assign(std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>());
}
} }
return scopes;
}
std::pair<bool, std::vector<std::string>> TokenManager::fetchAuthHeader(const std::string& auth) nlohmann::json TokenManager::createTokenBody(const model::AuthCredentials& auth) {
{ nlohmann::json obj;
std::istringstream iss(auth); obj["client_id"] = auth.clientId;
std::vector<std::string> authHeader{std::istream_iterator<std::string>(iss), obj["client_secret"] = auth.clientSecret;
std::istream_iterator<std::string>() obj["audience"] = auth.apiIdentifier;
}; obj["grant_type"] = "client_credentials";
bool foundBearer = false; return obj;
if (std::any_of(authHeader.begin(), authHeader.end(),
[&](std::string_view word) {
return (word.compare("Bearer") == 0);
})) {
std::cout << "Bearer found" << std::endl;
foundBearer = true;
} }
return std::make_pair(foundBearer, authHeader);
} model::AuthCredentials TokenManager::parseAuthCredentials(const model::BinaryPath& bConf) {
auto con = DirectoryManager::credentialConfigContent(bConf);
model::AuthCredentials auth;
auth.uri = "https://";
auth.uri.append(con["domain"]);
auth.apiIdentifier = con["api_identifier"];
auth.clientId = con["client_id"];
auth.clientSecret = con["client_secret"];
auth.endpoint = "oauth/token";
return auth;
}
bool TokenManager::tokenSupportsScope(const std::vector<std::string>& scopes, std::vector<std::string> TokenManager::extractScopes(const jwt::decoded_jwt&& decoded) {
const std::string&& scope) std::vector<std::string> scopes;
{
return std::any_of(scopes.begin(), scopes.end(), for (auto& d : decoded.get_payload_claims()) {
[&](std::string_view foundScope) { if (d.first.compare("scope") == 0) {
return (foundScope.compare(scope) == 0); std::cout << "found scope\n";
}); std::string allScopes(d.second.to_json().get<std::string>());
} std::istringstream iss(allScopes);
scopes.assign(std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>());
}
}
return scopes;
}
std::pair<bool, std::vector<std::string>> TokenManager::fetchAuthHeader(const std::string& auth) {
std::istringstream iss(auth);
std::vector<std::string> authHeader{std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>()
};
bool foundBearer = false;
if (std::any_of(authHeader.begin(), authHeader.end(),
[&](std::string_view word) {
return (word.compare("Bearer") == 0); })) {
std::cout << "Bearer found\n";
foundBearer = true;
}
return std::make_pair(foundBearer, authHeader);
}
bool TokenManager::tokenSupportsScope(const std::vector<std::string>& scopes,
const std::string&& scope) {
return std::any_of(scopes.begin(), scopes.end(),
[&](std::string_view foundScope) {
return (foundScope.compare(scope) == 0);
});
}
} }
+48 -48
View File
@@ -7,70 +7,70 @@
#include "utility/PasswordEncryption.h" #include "utility/PasswordEncryption.h"
namespace manager { namespace manager {
UserManager::UserManager(const model::BinaryPath& bConf) : m_bConf(bConf) { } UserManager::UserManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
model::RegisterResult UserManager::registerUser(model::User& user) { model::RegisterResult UserManager::registerUser(model::User& user) {
model::RegisterResult result; model::RegisterResult result;
result.username = user.username; result.username = user.username;
printUser(user); printUser(user);
utility::PasswordEncryption passEnc; utility::PasswordEncryption passEnc;
auto hashed = passEnc.hashPassword(user); auto hashed = passEnc.hashPassword(user);
user.password = hashed.hashPassword; user.password = hashed.hashPassword;
database::UserRepository usrRepo(m_bConf); database::UserRepository usrRepo(m_bConf);
usrRepo.saveUserRecord(user); usrRepo.saveUserRecord(user);
model::User usr; model::User usr;
usr.username = user.username; usr.username = user.username;
std::cout << usr.username << std::endl; std::cout << usr.username << "\n";
usr = usrRepo.retrieveUserRecord(usr, type::UserFilter::username); usr = usrRepo.retrieveUserRecord(usr, type::UserFilter::username);
hashed.hashPassword = usr.password; hashed.hashPassword = usr.password;
hashed.userId = usr.id; hashed.userId = usr.id;
usrRepo.saveUserSalt(hashed); usrRepo.saveUserSalt(hashed);
result.registered = true; result.registered = true;
result.message = "successfully registered"; result.message = "successfully registered";
printUser(usr); printUser(usr);
return result; return result;
} }
bool UserManager::doesUserExist(const model::User& user) { bool UserManager::doesUserExist(const model::User& user) {
database::UserRepository userRepo(m_bConf); database::UserRepository userRepo(m_bConf);
return userRepo.doesUserRecordExist(user, type::UserFilter::username); return userRepo.doesUserRecordExist(user, type::UserFilter::username);
} }
bool UserManager::validatePassword(const model::User& user) { bool UserManager::validatePassword(const model::User& user) {
database::UserRepository userRepo(m_bConf); database::UserRepository userRepo(m_bConf);
model::User usr; model::User usr;
usr.username = user.username; usr.username = user.username;
usr = userRepo.retrieveUserRecord(usr, type::UserFilter::username); usr = userRepo.retrieveUserRecord(usr, type::UserFilter::username);
model::PassSec userSec; model::PassSec userSec;
userSec.userId = usr.id; userSec.userId = usr.id;
userSec = userRepo.retrieverUserSaltRecord(userSec, type::SaltFilter::userId); userSec = userRepo.retrieverUserSaltRecord(userSec, type::SaltFilter::userId);
userSec.hashPassword = usr.password; userSec.hashPassword = usr.password;
utility::PasswordEncryption passEnc; utility::PasswordEncryption passEnc;
return passEnc.isPasswordValid(user, userSec); return passEnc.isPasswordValid(user, userSec);
} }
void UserManager::printUser(const model::User& user) { void UserManager::printUser(const model::User& user) {
std::cout << "\nuser info" << std::endl; std::cout << "\nuser info\n";
std::cout << "id: " << user.id << std::endl; std::cout << "id: " << user.id << "\n";
std::cout << "firstname: " << user.firstname << std::endl; std::cout << "firstname: " << user.firstname << "\n";
std::cout << "lastname: " << user.lastname << std::endl; std::cout << "lastname: " << user.lastname << "\n";
std::cout << "phone: " << user.phone << std::endl; std::cout << "phone: " << user.phone << "\n";
std::cout << "email: " << user.email << std::endl; std::cout << "email: " << user.email << "\n";
std::cout << "username: " << user.username << std::endl; std::cout << "username: " << user.username << "\n";
std::cout << "password: " << user.password<< std::endl; std::cout << "password: " << user.password<< "\n";
} }
} }
+48 -54
View File
@@ -6,72 +6,66 @@
#include "type/YearFilter.h" #include "type/YearFilter.h"
namespace manager { namespace manager {
YearManager::YearManager(const model::BinaryPath& bConf) YearManager::YearManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
: m_bConf(bConf) { }
model::Year YearManager::retrieveYear(model::Year& year) model::Year YearManager::retrieveYear(model::Year& year) {
{ database::YearRepository yearRepo(m_bConf);
database::YearRepository yearRepo(m_bConf); year = yearRepo.retrieveRecord(year, type::YearFilter::year);
year = yearRepo.retrieveRecord(year, type::YearFilter::year);
return year; return year;
}
model::Year YearManager::saveYear(const model::Song& song)
{
model::Year year;
year.year = song.year;
database::YearRepository yearRepo(m_bConf);
if (!yearRepo.doesYearExist(year, type::YearFilter::year)) {
yearRepo.saveRecord(year);
} else {
std::cout << "year record already exists in the database" << std::endl;
} }
return year; model::Year YearManager::saveYear(const model::Song& song) {
} model::Year year;
year.year = song.year;
void YearManager::deleteYear(const model::Song& song) database::YearRepository yearRepo(m_bConf);
{ if (!yearRepo.doesYearExist(year, type::YearFilter::year)) {
model::Year year(song); yearRepo.saveRecord(year);
} else {
std::cout << "year record already exists in the database\n";
}
database::YearRepository yrRepo(m_bConf); return year;
auto yrWSC = yrRepo.retrieveRecordWithSongCount(year, type::YearFilter::id);
if (yrWSC.second > 1) {
std::cout << "year still contain songs related to it";
std::cout << ", will not delete" << std::endl;
return;
} }
std::cout << "safe to delete the year record" << std::endl; void YearManager::deleteYear(const model::Song& song) {
yrRepo.deleteYear(year, type::YearFilter::id); model::Year year(song);
}
void YearManager::updateYear(model::Song& updatedSong, database::YearRepository yrRepo(m_bConf);
const model::Song& currSong) auto yrWSC = yrRepo.retrieveRecordWithSongCount(year, type::YearFilter::id);
{
model::Year year;
year.year = updatedSong.year;
database::YearRepository albRepo(m_bConf); if (yrWSC.second > 1) {
if (!albRepo.doesYearExist(year, type::YearFilter::year)) { std::cout << "year still contain songs related to it";
std::cout << "year record does not exist" << std::endl; std::cout << ", will not delete\n";
albRepo.saveRecord(year); return;
} else { }
std::cout << "year record already exists" << std::endl;
std::cout << "safe to delete the year record\n";
yrRepo.deleteYear(year, type::YearFilter::id);
} }
year = albRepo.retrieveRecord(year, type::YearFilter::year); void YearManager::updateYear(model::Song& updatedSong,
updatedSong.yearId = year.id; const model::Song& currSong) {
} model::Year year;
year.year = updatedSong.year;
void YearManager::printYear(const model::Year& year) database::YearRepository albRepo(m_bConf);
{ if (!albRepo.doesYearExist(year, type::YearFilter::year)) {
std::cout << "\nyear record" << std::endl; std::cout << "year record does not exist\n";
std::cout << "id: " << year.id << std::endl; albRepo.saveRecord(year);
std::cout << "year: " << year.year << std::endl; } else {
} std::cout << "year record already exists\n";
}
year = albRepo.retrieveRecord(year, type::YearFilter::year);
updatedSong.yearId = year.id;
}
void YearManager::printYear(const model::Year& year) {
std::cout << "\nyear record\n";
std::cout << "id: " << year.id << "\n";
std::cout << "year: " << year.year << "\n";
}
} }
+4 -7
View File
@@ -1,12 +1,9 @@
#include "utility/ImageFile.h" #include "utility/ImageFile.h"
namespace utility { namespace utility {
ImageFile::ImageFile(const char *file) : TagLib::File(file) ImageFile::ImageFile(const char *file) : TagLib::File(file) { }
{
}
TagLib::ByteVector ImageFile::data() TagLib::ByteVector ImageFile::data() {
{ return readBlock(length());
return readBlock(length()); }
}
} }
+164 -171
View File
@@ -19,190 +19,183 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace utility { namespace utility {
model::Song MetadataRetriever::retrieveMetadata(model::Song& song) model::Song MetadataRetriever::retrieveMetadata(model::Song& song) {
{ TagLib::MPEG::File sameFile(song.songPath.c_str());
TagLib::MPEG::File sameFile(song.songPath.c_str()); auto tag = sameFile.ID3v2Tag();
auto tag = sameFile.ID3v2Tag(); song.title = tag->title().toCString();
song.title = tag->title().toCString(); song.artist = tag->artist().toCString();
song.artist = tag->artist().toCString(); song.album = tag->album().toCString();
song.album = tag->album().toCString(); song.genre = tag->genre().toCString();
song.genre = tag->genre().toCString(); song.year = tag->year();
song.year = tag->year(); song.track = tag->track();
song.track = tag->track(); song.duration = sameFile.audioProperties()->lengthInSeconds();
song.duration = sameFile.audioProperties()->lengthInSeconds();
constexpr auto id3DiscName = "TPOS"; constexpr auto id3DiscName = "TPOS";
constexpr auto id3AlbumArtistName = "TPE2"; constexpr auto id3AlbumArtistName = "TPE2";
auto discFrame = tag->frameList(id3DiscName); auto discFrame = tag->frameList(id3DiscName);
auto albumArtistFrame = tag->frameList(id3AlbumArtistName); auto albumArtistFrame = tag->frameList(id3AlbumArtistName);
if (discFrame.isEmpty()) { if (discFrame.isEmpty()) {
constexpr auto discDefaultVal = "1"; constexpr auto discDefaultVal = "1";
TagLib::ID3v2::TextIdentificationFrame *emptyFrame = TagLib::ID3v2::TextIdentificationFrame *emptyFrame =
new TagLib::ID3v2::TextIdentificationFrame(id3DiscName); new TagLib::ID3v2::TextIdentificationFrame(id3DiscName);
tag->addFrame(emptyFrame); tag->addFrame(emptyFrame);
emptyFrame->setText(discDefaultVal); emptyFrame->setText(discDefaultVal);
song.disc = std::atoi(discDefaultVal); song.disc = std::atoi(discDefaultVal);
sameFile.save(); sameFile.save();
} else { } else {
song.disc = std::stoi(discFrame.front()->toString().toCString()); song.disc = std::stoi(discFrame.front()->toString().toCString());
}
if (albumArtistFrame.isEmpty()) {
TagLib::ID3v2::TextIdentificationFrame *emptyFrame =
new TagLib::ID3v2::TextIdentificationFrame(id3DiscName);
tag->addFrame(emptyFrame);
emptyFrame->setText(song.artist.c_str());
sameFile.save();
} else {
song.albumArtist = albumArtistFrame.front()->toString().toCString();
}
return song;
} }
if (albumArtistFrame.isEmpty()) { model::Cover MetadataRetriever::updateCoverArt(const model::Song& song, model::Cover& cov,
TagLib::ID3v2::TextIdentificationFrame *emptyFrame = const std::string& stockCoverPath) {
new TagLib::ID3v2::TextIdentificationFrame(id3DiscName); TagLib::MPEG::File sngF(song.songPath.c_str());
tag->addFrame(emptyFrame); auto tag = sngF.ID3v2Tag();
emptyFrame->setText(song.artist.c_str()); auto frameList = tag->frameListMap()["APIC"];
sameFile.save();
} else { if (frameList.isEmpty()) {
song.albumArtist = albumArtistFrame.front()->toString().toCString(); cov.imagePath.append("CoverArt.png");
if (!fs::exists(cov.imagePath)) {
std::cout << "copying stock cover path\n";
fs::copy(stockCoverPath, cov.imagePath);
}
ImageFile stockImg(cov.imagePath.c_str());
TagLib::ID3v2::AttachedPictureFrame *pic =
new TagLib::ID3v2::AttachedPictureFrame;
pic->setPicture(stockImg.data());
pic->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
tag->addFrame(pic);
sngF.save();
std::cout << "applied stock cover art" << std::endl;
} else {
auto frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(
frameList.front());
auto imgPath = manager::DirectoryManager::createDirectoryProcess(song, cov.imagePath);
imgPath.append(song.title);
imgPath.append(".png");
cov.imagePath = imgPath;
std::fstream imgSave(cov.imagePath, std::ios::out |
std::ios::binary);
imgSave.write(frame->picture().data(), frame->picture().size());
imgSave.close();
std::cout << "saved to " << cov.imagePath << "\n";
}
return cov;
}
// tags song with the stock cover art
model::Cover MetadataRetriever::applyStockCoverArt(
const model::Song& song, model::Cover& cov,
const std::string& stockCoverPath) {
TagLib::MPEG::File songFile(song.songPath.c_str());
auto tag = songFile.ID3v2Tag();
ImageFile stockImg(cov.imagePath.c_str());
TagLib::ID3v2::AttachedPictureFrame *pic =
new TagLib::ID3v2::AttachedPictureFrame;
pic->setPicture(stockImg.data());
pic->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
tag->addFrame(pic);
songFile.save();
std::cout << "applied stock cover art\n";
delete pic;
return cov;
}
// extracts cover art from the song and save it to the
// appropriate directory
model::Cover MetadataRetriever::applyCoverArt(const model::Song& song,
model::Cover& cov) {
TagLib::MPEG::File songFile(song.songPath.c_str());
auto tag = songFile.ID3v2Tag();
auto frameList = tag->frameListMap()["APIC"];
auto frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(
frameList.front());
std::fstream imgSave(cov.imagePath, std::ios::out |
std::ios::binary);
imgSave.write(frame->picture().data(), frame->picture().size());
imgSave.close();
std::cout << "saved to " << cov.imagePath << "\n";
return cov;
} }
return song; bool MetadataRetriever::songContainsCoverArt(const model::Song& song) {
} TagLib::MPEG::File songFile(song.songPath.c_str());
auto tag = songFile.ID3v2Tag();
auto frameList = tag->frameListMap()["APIC"];
model::Cover MetadataRetriever::updateCoverArt(const model::Song& song, model::Cover& cov, return !frameList.isEmpty();
const std::string& stockCoverPath)
{
TagLib::MPEG::File sngF(song.songPath.c_str());
auto tag = sngF.ID3v2Tag();
auto frameList = tag->frameListMap()["APIC"];
if (frameList.isEmpty()) {
cov.imagePath.append("CoverArt.png");
if (!fs::exists(cov.imagePath)) {
std::cout << "copying stock cover path" << std::endl;
fs::copy(stockCoverPath, cov.imagePath);
}
ImageFile stockImg(cov.imagePath.c_str());
TagLib::ID3v2::AttachedPictureFrame *pic =
new TagLib::ID3v2::AttachedPictureFrame;
pic->setPicture(stockImg.data());
pic->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
tag->addFrame(pic);
sngF.save();
std::cout << "applied stock cover art" << std::endl;
} else {
auto frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(
frameList.front());
auto imgPath = manager::DirectoryManager::createDirectoryProcess(song, cov.imagePath);
imgPath.append(song.title);
imgPath.append(".png");
cov.imagePath = imgPath;
std::fstream imgSave(cov.imagePath, std::ios::out |
std::ios::binary);
imgSave.write(frame->picture().data(), frame->picture().size());
imgSave.close();
std::cout << "saved to " << cov.imagePath << std::endl;
} }
return cov;
}
// tags song with the stock cover art void MetadataRetriever::updateMetadata(model::Song& sngUpdated, const model::Song& sngOld) {
model::Cover MetadataRetriever::applyStockCoverArt( std::cout << "updating metadata\n";
const model::Song& song, model::Cover& cov, TagLib::MPEG::File file(sngOld.songPath.c_str());
const std::string& stockCoverPath) auto tag = file.ID3v2Tag();
{
TagLib::MPEG::File songFile(song.songPath.c_str());
auto tag = songFile.ID3v2Tag();
ImageFile stockImg(cov.imagePath.c_str());
TagLib::ID3v2::AttachedPictureFrame *pic =
new TagLib::ID3v2::AttachedPictureFrame;
pic->setPicture(stockImg.data());
pic->setType(TagLib::ID3v2::AttachedPictureFrame::FrontCover);
tag->addFrame(pic);
songFile.save();
std::cout << "applied stock cover art" << std::endl;
delete pic;
return cov;
}
// extracts cover art from the song and save it to the
// appropriate directory
model::Cover MetadataRetriever::applyCoverArt(const model::Song& song,
model::Cover& cov)
{
TagLib::MPEG::File songFile(song.songPath.c_str());
auto tag = songFile.ID3v2Tag();
auto frameList = tag->frameListMap()["APIC"];
auto frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(
frameList.front());
std::fstream imgSave(cov.imagePath, std::ios::out |
std::ios::binary);
imgSave.write(frame->picture().data(), frame->picture().size());
imgSave.close();
std::cout << "saved to " << cov.imagePath << std::endl;
return cov;
}
bool MetadataRetriever::songContainsCoverArt(const model::Song& song)
{
TagLib::MPEG::File songFile(song.songPath.c_str());
auto tag = songFile.ID3v2Tag();
auto frameList = tag->frameListMap()["APIC"];
return !frameList.isEmpty();
}
void MetadataRetriever::updateMetadata(model::Song& sngUpdated, const model::Song& sngOld)
{
std::cout<<"updating metadata"<<std::endl;
TagLib::MPEG::File file(sngOld.songPath.c_str());
auto tag = file.ID3v2Tag();
if (sngUpdated.title.size() > 0) { if (sngUpdated.title.size() > 0) {
file.tag()->setTitle(sngUpdated.title); file.tag()->setTitle(sngUpdated.title);
} }
if (sngUpdated.artist.size() > 0) { if (sngUpdated.artist.size() > 0) {
file.tag()->setArtist(sngUpdated.artist); file.tag()->setArtist(sngUpdated.artist);
} }
if (sngUpdated.albumArtist.size() > 0) { if (sngUpdated.albumArtist.size() > 0) {
constexpr auto frameId = "TPE2"; constexpr auto frameId = "TPE2";
auto albumArtistFrame = tag->frameList(frameId); auto albumArtistFrame = tag->frameList(frameId);
if (albumArtistFrame.isEmpty()) { if (albumArtistFrame.isEmpty()) {
TagLib::ID3v2::TextIdentificationFrame *frame = TagLib::ID3v2::TextIdentificationFrame *frame =
new TagLib::ID3v2::TextIdentificationFrame(frameId); new TagLib::ID3v2::TextIdentificationFrame(frameId);
frame->setText(sngUpdated.albumArtist.c_str()); frame->setText(sngUpdated.albumArtist.c_str());
tag->addFrame(frame); tag->addFrame(frame);
} else { } else {
albumArtistFrame.front()->setText(sngUpdated.albumArtist.c_str()); albumArtistFrame.front()->setText(sngUpdated.albumArtist.c_str());
} }
file.save(); file.save();
} }
if (sngUpdated.album.size() > 0) { if (sngUpdated.album.size() > 0) {
file.tag()->setAlbum(sngUpdated.album); file.tag()->setAlbum(sngUpdated.album);
} }
if (sngUpdated.genre.size() > 0) { if (sngUpdated.genre.size() > 0) {
file.tag()->setGenre(sngUpdated.genre); file.tag()->setGenre(sngUpdated.genre);
} }
if (sngUpdated.year > 0) { if (sngUpdated.year > 0) {
file.tag()->setYear(sngUpdated.year); file.tag()->setYear(sngUpdated.year);
} }
// TODO: functionality to update the track number and disc number // TODO: functionality to update the track number and disc number
file.save(); file.save();
} }
} }
+27 -33
View File
@@ -7,42 +7,36 @@
namespace utility { namespace utility {
model::PassSec PasswordEncryption::hashPassword(const model::User& user) model::PassSec PasswordEncryption::hashPassword(const model::User& user) {
{ model::PassSec passSec;
model::PassSec passSec;
std::unique_ptr<char[]> salt(new char[BCRYPT_HASHSIZE]); std::unique_ptr<char[]> salt(new char[BCRYPT_HASHSIZE]);
std::unique_ptr<char[]> hash(new char[BCRYPT_HASHSIZE]); std::unique_ptr<char[]> hash(new char[BCRYPT_HASHSIZE]);
std::cout << "generating salt" << std::endl; std::cout << "generating salt" << std::endl;
bcrypt_gensalt(saltSize(), salt.get()); bcrypt_gensalt(saltSize(), salt.get());
std::cout << "hashing password" << std::endl; std::cout << "hashing password" << std::endl;
bcrypt_hashpw(user.password.c_str(), salt.get(), hash.get()); bcrypt_hashpw(user.password.c_str(), salt.get(), hash.get());
passSec.salt = salt.get(); passSec.salt = salt.get();
passSec.hashPassword = hash.get(); passSec.hashPassword = hash.get();
std::cout << "hash: " << passSec.hashPassword << std::endl; std::cout << "hash: " << passSec.hashPassword << std::endl;
std::cout << "salt: " << passSec.salt << std::endl; std::cout << "salt: " << passSec.salt << std::endl;
return passSec; return passSec;
} }
bool PasswordEncryption::isPasswordValid(const model::User& user, const model::PassSec& userSalt) bool PasswordEncryption::isPasswordValid(const model::User& user,
{ const model::PassSec& userSalt) {
std::unique_ptr<char[]> passwordHashed(new char[BCRYPT_HASHSIZE]); std::unique_ptr<char[]> passwordHashed(new char[BCRYPT_HASHSIZE]);
bcrypt_hashpw(user.password.c_str(), userSalt.salt.c_str(), passwordHashed.get()); bcrypt_hashpw(user.password.c_str(), userSalt.salt.c_str(), passwordHashed.get());
return (userSalt.hashPassword.compare(passwordHashed.get()) == 0) ? true : false; return (userSalt.hashPassword.compare(passwordHashed.get()) == 0) ? true : false;
} }
int PasswordEncryption::saltSize() constexpr int PasswordEncryption::saltSize() noexcept { return 10000; }
{
constexpr auto size = 10000;
return size;
}
} }
+66 -81
View File
@@ -11,103 +11,88 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace verify { namespace verify {
bool Initialization::skipVerification(const std::string& argument) {
bool Initialization::skipVerification(const std::string& argument) return argument.compare("--noverify") == 0;
{
return argument.compare("--noverify") == 0;
}
// verifies if the configuration settings are valid
void Initialization::checkIcarus(const model::BinaryPath& bConf)
{
auto auth = confirmConfigAuth(bConf);
auto database = confirmConfigDatabase(bConf);
auto path = confirmConfigPaths(bConf);
if ((auth && database && path) == false) {
failedConfirmation();
} }
std::cout << "icarus check passed" << std::endl;
} // verifies if the configuration settings are valid
void Initialization::checkIcarus(const model::BinaryPath& bConf) {
auto auth = confirmConfigAuth(bConf);
auto database = confirmConfigDatabase(bConf);
auto path = confirmConfigPaths(bConf);
if ((auth && database && path) == false) {
failedConfirmation();
}
std::cout << "icarus check passed\n";
}
// verifies that the authorization settings are not the default values // verifies that the authorization settings are not the default values
bool Initialization::confirmConfigAuth(const model::BinaryPath& bConf) bool Initialization::confirmConfigAuth(const model::BinaryPath& bConf) {
{ manager::TokenManager tokMgr;
manager::TokenManager tokMgr;
return tokMgr.testAuth(bConf); return tokMgr.testAuth(bConf);
} }
// verifies if database connectivity can be established // verifies if database connectivity can be established
bool Initialization::confirmConfigDatabase(const model::BinaryPath& bConf) bool Initialization::confirmConfigDatabase(const model::BinaryPath& bConf) {
{ database::BaseRepository baseRepo(bConf);
database::BaseRepository baseRepo(bConf);
return baseRepo.testConnection(); return baseRepo.testConnection();
} }
// verifies if the paths found in the config files exists // verifies if the paths found in the config files exists
bool Initialization::confirmConfigPaths(const model::BinaryPath& bConf) bool Initialization::confirmConfigPaths(const model::BinaryPath& bConf) {
{ using manager::DirectoryManager;
auto pathConfig = manager::DirectoryManager::pathConfigContent(bConf); auto pathConfig = DirectoryManager::pathConfigContent(bConf);
const auto rootMusicPath = const auto rootMusicPath =
pathConfig pathConfig
[manager:: [DirectoryManager::retrievePathType
DirectoryManager::
retrievePathType
(type::PathType::music)].get<std::string>(); (type::PathType::music)].get<std::string>();
const auto archiveRootPath = const auto archiveRootPath =
pathConfig pathConfig
[manager:: [DirectoryManager::retrievePathType
DirectoryManager::
retrievePathType
(type::PathType::archive)].get<std::string>(); (type::PathType::archive)].get<std::string>();
const auto tempRootPath = const auto tempRootPath =
pathConfig pathConfig
[manager:: [DirectoryManager::retrievePathType
DirectoryManager::
retrievePathType
(type::PathType::temp)].get<std::string>(); (type::PathType::temp)].get<std::string>();
const auto coverRootPath = const auto coverRootPath =
pathConfig pathConfig
[manager:: [DirectoryManager::retrievePathType
DirectoryManager::
retrievePathType
(type::PathType::coverArt)].get<std::string>(); (type::PathType::coverArt)].get<std::string>();
if (!fs::exists(rootMusicPath)) { if (!fs::exists(rootMusicPath)) {
std::cout << "root music path is not properly configured" << std::endl; std::cout << "root music path is not properly configured\n";
return false; return false;
}
if (!fs::exists(archiveRootPath)) {
std::cout << "archive root path is not properly configured\n";
return false;
}
if (!fs::exists(tempRootPath)) {
std::cout << "temp root path is not properly configured\n";
return false;
}
if (!fs::exists(coverRootPath)) {
std::cout << "cover art root path is not properly configured\n";
return false;
}
return true;
} }
if (!fs::exists(archiveRootPath)) {
std::cout << "archive root path is not properly configured" << std::endl;
return false;
}
if (!fs::exists(tempRootPath)) { // confirmation failed
std::cout << "temp root path is not properly configured" << std::endl; void Initialization::failedConfirmation() {
return false; std::cout << "configuration confirmation failed. check your settings\n";
std::exit(-1);
} }
if (!fs::exists(coverRootPath)) {
std::cout << "cover art root path is not properly configured" << std::endl;
return false;
}
return true;
}
// confirmation failed
void Initialization::failedConfirmation()
{
std::cout << "configuration confirmation failed. check your settings" << std::endl;
std::exit(-1);
}
} }