Code cleanup
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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&);
|
||||||
|
|
||||||
|
|||||||
@@ -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*);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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&);
|
||||||
|
|
||||||
|
|||||||
@@ -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*);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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*);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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&);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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*);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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&);
|
||||||
|
|
||||||
|
|||||||
@@ -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&);
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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&);
|
||||||
|
|||||||
@@ -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&);
|
||||||
|
|
||||||
|
|||||||
@@ -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,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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+485
-498
File diff suppressed because it is too large
Load Diff
+261
-270
@@ -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
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user