Compare commits

..

19 Commits

Author SHA1 Message Date
kdeng00 a1edbeb164 Fixed issue of the configuration verification test failing 2020-02-15 17:37:51 -05:00
kdeng00 437a6b1453 Fixed issue with special characters not being recorded properly 2020-02-15 17:32:52 -05:00
Kun Deng f2d0947b36 Merge pull request #63 from kdeng00/dist_change
API is functional again after the dependency updates
2020-02-02 20:33:48 -05:00
kdeng00 b067882c09 API is functional again after the dependency updates 2020-02-02 20:32:09 -05:00
kdeng00 57f76ee4a4 api is functional after the dependency updates 2020-02-01 20:58:48 -05:00
kdeng00 e846989a7f Not finished updating dependencies. oatpp has changed 2020-01-30 19:30:21 -05:00
kdeng00 91ae3a908e Updated json dependency 2020-01-29 19:12:23 -05:00
kdeng00 a970ba207e updating dependencies and code refactoring for the new changes 2020-01-28 21:03:56 -05:00
kdeng00 979dd66842 Made it easier to build the bcrypt library 2019-11-17 13:55:01 -05:00
kdeng00 69f5a37eb3 Code cleanup 2019-11-17 13:33:58 -05:00
kdeng00 ca1fcb801d Added functionality to check if the song already exists when uploading 2019-11-13 20:22:29 -05:00
kdeng00 3b0f199dca forgout about one file 2019-11-12 23:03:42 -05:00
kdeng00 41ae06e19a Fixed bug when song upload HTTP endpoint returns a response of the uploading song with errors 2019-11-12 22:51:07 -05:00
kdeng00 9b4a0db67a Added albumArtist field memeber to Song model. Automatically apply disc value 1 for song's metadata that have an empty disc field. Switched from TagLib::FileRef to TagLib::MPEG::File 2019-11-04 22:26:03 -05:00
kdeng00 c7bbdfe581 Code clean up 2019-11-03 13:03:32 -05:00
Kun Deng 01faa60699 Update README.md 2019-10-26 10:31:46 -04:00
amazing-username 8714d76a2a Changes to response returns when song does not exist. The cause of a segmentation fault 2019-10-26 14:23:42 +00:00
kdeng00 e764bc45de When song is uploaded the response returned is info about the song and a response 2019-10-22 20:30:43 -04:00
kdeng00 5fefc451d5 Adding coverart id field to Song dto object to return the coverart id that the song is associated with so it is easier to get the cover art 2019-10-21 21:54:50 -04:00
83 changed files with 4702 additions and 5028 deletions
+1 -1
+1 -1
+10 -7
View File
@@ -80,6 +80,7 @@ set(HEADERS
include/type/Scopes.h
include/type/SongChanged.h
include/type/SongFilter.h
include/type/SongUpload.h
include/type/UserFilter.h
include/type/YearFilter.h
include/verify/Initialization.h
@@ -122,21 +123,23 @@ set(JWT_CPP_INCLUDE
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/jwt-cpp/include
)
set (ORM_DIR
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/ormpp
)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup()
find_library(BCRYPT bcrypt ${BCRYPTLIB})
#find_library(BCRYPT bcrypt ${BCRYPTLIB})
include_directories(include ${CPR_INCLUDE_DIRS} ${TAGLIB} ${TAGLIB_HEADERS} ${BCRYPTLIB}/)
include_directories(include ${CPR_INCLUDE_DIRS} ${TAGLIB} ${TAGLIB_HEADERS} ${BCRYPTLIB})
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/cpr)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/taglib)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/oatpp)
#add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/libbcrypt)
add_library(bcrypt STATIC IMPORTED)
set_target_properties(bcrypt PROPERTIES IMPORTED_LOCATION
"${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/libbcrypt/bcrypt.a"
)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/appsettings.json ${CMAKE_BINARY_DIR}/bin/appsettings.json COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/authcredentials.json ${CMAKE_BINARY_DIR}/bin/authcredentials.json COPYONLY)
@@ -146,4 +149,4 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Images/Stock/CoverArt.png ${CMAKE_BIN
add_executable(icarus ${SOURCES} ${HEADERS})
target_include_directories(icarus PUBLIC ${JWT_CPP_INCLUDE})
target_link_libraries(icarus "-lstdc++fs" tag oatpp mysqlclient ${CONAN_LIBS} ${CPR_LIBRARIES} ${BCRYPT})
target_link_libraries(icarus "-lstdc++fs" tag oatpp mysqlclient ${CONAN_LIBS} ${CPR_LIBRARIES} bcrypt)
+3 -10
View File
@@ -53,7 +53,7 @@ Replace [domain] with the domain name of the created tenant. This can be found i
"client_secret": "Icankeepasecret"
```
For the sake of this section, I will not go over configuring the API to accept the signing algorithm since it has already been configured in the [Startip](Startup.cs).cs file. Click on permissions to create the permissions for the API.
Click on permissions to create the permissions for the API.
<h1 align "center">
<img src="Images/Configuration/configure_api.png" width=100%>
</h1>
@@ -130,6 +130,7 @@ The only requirement of the User is that the user should have full permissions t
Prior to starting the API, the database must be created. The following tables are required:
* User
* Salt
* Song
* Album
* Artist
@@ -150,13 +151,11 @@ From this point the database has been successfully created. Metadata and song fi
git clone --recursive https://github.com/kdeng00/icarus
cd 3rdparty/libbcrypt/
make
cp bcrypt.a libbcrypt.a
cp bcrypt.o libbcrypt.o
cd ../..
mkdir build
cd build
conan install ..
cmake ..
cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DUSE_SYSTEM_CURL=ON -DBUILD_CPR_TESTS=OFF -DOATPP_BUILD_TESTS=OFF
make
bin/icarus
```
@@ -166,16 +165,10 @@ Runs the server on localhost port 5002
Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the code of conduct, and the process for submitting pull requests to the project.
## Versioning
* [v0.1](https://github.com/amazing-username/Icarus/releases/tag/v0.1)
## Authors
* **Kun Deng** - [amazing-username](https://github.com/amazing-username)
See also the list of [contributors](https://github.com/amazing-username/Icarus/graphs/contributors) who participated in this project.
## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
+1
View File
@@ -13,6 +13,7 @@ CREATE TABLE CoverArt (
CREATE TABLE Album (
AlbumId INT NOT NULL AUTO_INCREMENT,
Title TEXT NOT NULL,
Artist TEXT NOT NULL,
Year INT NOT NULL,
PRIMARY KEY (AlbumId)
+1 -1
View File
@@ -1,5 +1,5 @@
[requires]
jsonformoderncpp/3.7.0@vthiery/stable
jsonformoderncpp/3.7.3@vthiery/stable
[generators]
cmake
+14 -13
View File
@@ -4,23 +4,24 @@
#include <string>
#include "oatpp/core/data/stream/FileStream.hpp"
#include "oatpp/web/protocol/http/outgoing/ChunkedBody.hpp"
#include "oatpp/core/data/stream/Stream.hpp"
#include "oatpp/core/async/Coroutine.hpp"
//#include "oatpp/web/protocol/http/outgoing/ChunkedBody.hpp"
namespace callback {
class StreamCallback : public oatpp::data::stream::ReadCallback
{
public:
StreamCallback();
StreamCallback(const std::string&);
class StreamCallback : public oatpp::data::stream::ReadCallback {
public:
StreamCallback();
StreamCallback(const std::string&);
oatpp::data::v_io_size read(void*, oatpp::data::v_io_size);
private:
std::string m_songPath;
oatpp::v_io_size read(void*, v_buff_size, oatpp::async::Action&);
private:
std::string m_songPath;
long m_bytesRead;
long m_counter;
long m_fileSize;
};
long m_bytesRead;
long m_counter;
long m_fileSize;
};
}
#endif
+22 -19
View File
@@ -9,29 +9,32 @@
#include "oatpp/web/server/HttpConnectionHandler.hpp"
namespace component {
class AppComponent {
public:
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>,
serverConnectionProvider)([&] {
return oatpp::network::server::SimpleTCPConnectionProvider::
createShared(appPort());
}());
class AppComponent
{
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)([] {
return oatpp::web::server::HttpRouter::createShared();
}());
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, httpRouter)([] {
return oatpp::web::server::HttpRouter::createShared();
}());
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::server::ConnectionHandler>,
serverConnectionHandler)([] {
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router);
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::server::ConnectionHandler>, serverConnectionHandler)([] {
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router);
return oatpp::web::server::HttpConnectionHandler::createShared(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();
}());
private:
};
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; }
};
}
#endif
+49 -57
View File
@@ -19,6 +19,7 @@
#include "database/AlbumRepository.h"
#include "dto/AlbumDto.hpp"
#include "dto/conversion/DtoConversions.h"
#include "manager/AlbumManager.h"
#include "manager/TokenManager.h"
#include "model/Models.h"
@@ -28,75 +29,66 @@
namespace fs = std::filesystem;
namespace controller {
class AlbumController : public oatpp::web::server::api::ApiController
{
public:
AlbumController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p)
{ }
class AlbumController : public oatpp::web::server::api::ApiController {
public:
AlbumController(const model::BinaryPath& bConf,
OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
AlbumController(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 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
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");
std::cout << "starting process of retrieving album\n";
database::AlbumRepository albRepo(m_bConf);
auto albsDb = albRepo.retrieveRecords();
auto albums = oatpp::data::mapping::type::
List<dto::AlbumDto::ObjectWrapper>::createShared();
std::cout << "starting process of retrieving album" << std::endl;
database::AlbumRepository albRepo(m_bConf);
auto albsDb = albRepo.retrieveRecords();
auto albums = oatpp::data::mapping::type::List<dto::AlbumDto::ObjectWrapper>::createShared();
for (auto& albDb : albsDb) {
auto alb = dto::conversion::DtoConversions::toAlbumDto(albDb);
for (auto& albDb : albsDb) {
auto alb = dto::AlbumDto::createShared();
alb->id = albDb.id;
alb->title = albDb.title.c_str();
alb->year = albDb.year;
albums->pushBack(alb);
}
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
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");
database::AlbumRepository albRepo(m_bConf);
model::Album albDb(id);
database::AlbumRepository albRepo(m_bConf);
model::Album albDb(id);
OATPP_ASSERT_HTTP(albRepo.doesAlbumExists(albDb,
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;
albDb = albRepo.retrieveRecord(albDb, type::AlbumFilter::id);
auto album = dto::conversion::DtoConversions::toAlbumDto(albDb);
auto album = dto::AlbumDto::createShared();
album->id = albDb.id;
album->title = albDb.title.c_str();
album->year = albDb.year;
return createDtoResponse(Status::CODE_200, album);
}
return createDtoResponse(Status::CODE_200, album);
}
#include OATPP_CODEGEN_END(ApiController)
private:
std::string m_exe_path;
model::BinaryPath m_bConf;
};
#include OATPP_CODEGEN_END(ApiController)
private:
model::BinaryPath m_bConf;
};
}
#endif
+52 -55
View File
@@ -28,73 +28,70 @@
namespace fs = std::filesystem;
namespace controller {
class ArtistController : public oatpp::web::server::api::ApiController
{
public:
ArtistController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p)
{ }
class ArtistController : public oatpp::web::server::api::ApiController {
public:
ArtistController(const model::BinaryPath& bConf,
OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
ArtistController(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 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
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");
std::cout << "starting process of retrieving artist\n";
database::ArtistRepository artRepo(m_bConf);
auto artsDb = artRepo.retrieveRecords();
auto artists = oatpp::data::mapping::type::
List<dto::ArtistDto::ObjectWrapper>::createShared();
std::cout << "starting process of retrieving artist" << std::endl;
database::ArtistRepository artRepo(m_bConf);
auto artsDb = artRepo.retrieveRecords();
auto artists = oatpp::data::mapping::type::List<dto::ArtistDto::ObjectWrapper>::createShared();
for (auto& artDb : artsDb) {
auto art = dto::ArtistDto::createShared();
art->id = artDb.id;
art->artist = artDb.artist.c_str();
for (auto& artDb : artsDb) {
auto art = dto::ArtistDto::createShared();
art->id = artDb.id;
art->artist = artDb.artist.c_str();
artists->pushBack(art);
}
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
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");
database::ArtistRepository artRepo(m_bConf);
model::Artist artDb(id);
database::ArtistRepository artRepo(m_bConf);
model::Artist artDb(id);
OATPP_ASSERT_HTTP(artRepo.doesArtistExist(artDb,
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;
artDb = artRepo.retrieveRecord(artDb, type::ArtistFilter::id);
auto artist = dto::ArtistDto::createShared();
artist->id = artDb.id;
artist->artist = artDb.artist.c_str();
auto artist = dto::ArtistDto::createShared();
artist->id = artDb.id;
artist->artist = artDb.artist.c_str();
return createDtoResponse(Status::CODE_200, artist);
}
return createDtoResponse(Status::CODE_200, artist);
}
#include OATPP_CODEGEN_END(ApiController)
private:
std::string m_exe_path;
model::BinaryPath m_bConf;
};
#include OATPP_CODEGEN_END(ApiController)
private:
model::BinaryPath m_bConf;
};
}
#endif
+71 -73
View File
@@ -27,95 +27,93 @@
namespace fs = std::filesystem;
namespace controller {
class CoverArtController : public oatpp::web::server::api::ApiController
{
public:
CoverArtController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p)
{ }
class CoverArtController : public oatpp::web::server::api::ApiController {
public:
CoverArtController(const model::BinaryPath& bConf,
OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
CoverArtController(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 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
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");
std::cout << "starting process of retrieving cover art\n";
database::CoverArtRepository covRepo(m_bConf);
auto covsDb = covRepo.retrieveRecords();
auto coverArts = oatpp::data::mapping::type::
List<dto::CoverArtDto::ObjectWrapper>::createShared();
std::cout << "starting process of retrieving cover art" << std::endl;
database::CoverArtRepository covRepo(m_bConf);
auto covsDb = covRepo.retrieveRecords();
auto coverArts = oatpp::data::mapping::type::List<dto::CoverArtDto::ObjectWrapper>::createShared();
for (auto& covDb : covsDb) {
auto cov = dto::CoverArtDto::createShared();
cov->id = covDb.id;
cov->songTitle = covDb.songTitle.c_str();
for (auto& covDb : covsDb) {
auto cov = dto::CoverArtDto::createShared();
cov->id = covDb.id;
cov->songTitle = covDb.songTitle.c_str();
coverArts->pushBack(cov);
}
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
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");
database::CoverArtRepository covRepo(m_bConf);
model::Cover covDb;
covDb.id = id;
database::CoverArtRepository covRepo(m_bConf);
model::Cover covDb;
covDb.id = id;
OATPP_ASSERT_HTTP(covRepo.doesCoverArtExist(covDb,
type::CoverFilter::id) , Status::CODE_403, "song does not exist");
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;
covDb = covRepo.retrieveRecord(covDb, type::CoverFilter::id);
auto coverArt = dto::CoverArtDto::createShared();
coverArt->id = covDb.id;
coverArt->songTitle = covDb.songTitle.c_str();
auto coverArt = dto::CoverArtDto::createShared();
coverArt->id = covDb.id;
coverArt->songTitle = covDb.songTitle.c_str();
return createDtoResponse(Status::CODE_200, coverArt);
}
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,
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");
database::CoverArtRepository covRepo(m_bConf);
model::Cover covDb;
covDb.id = id;
covDb = covRepo.retrieveRecord(covDb, type::CoverFilter::id);
database::CoverArtRepository covRepo(m_bConf);
model::Cover covDb;
covDb.id = id;
covDb = covRepo.retrieveRecord(covDb, type::CoverFilter::id);
auto rawCover = oatpp::base::StrBuffer::loadFromFile(covDb.imagePath.c_str());
auto response = createResponse(Status::CODE_200, rawCover);
response->putHeader(Header::CONTENT_TYPE, "image/*");
auto rawCover = oatpp::base::StrBuffer::loadFromFile(covDb.imagePath.c_str());
auto response = createResponse(Status::CODE_200, rawCover);
response->putHeader(Header::CONTENT_TYPE, "image/*");
return response;
}
return response;
}
#include OATPP_CODEGEN_END(ApiController)
private:
std::string m_exe_path;
model::BinaryPath m_bConf;
};
#include OATPP_CODEGEN_END(ApiController)
private:
model::BinaryPath m_bConf;
};
}
#endif
+52 -55
View File
@@ -28,73 +28,70 @@
namespace fs = std::filesystem;
namespace controller {
class GenreController : public oatpp::web::server::api::ApiController
{
public:
GenreController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p)
{ }
class GenreController : public oatpp::web::server::api::ApiController {
public:
GenreController(const model::BinaryPath& bConf,
OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
GenreController(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 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
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");
std::cout << "starting process of retrieving genre\n";
database::GenreRepository gnrRepo(m_bConf);
auto gnrsDb = gnrRepo.retrieveRecords();
auto genres = oatpp::data::mapping::type::
List<dto::GenreDto::ObjectWrapper>::createShared();
std::cout << "starting process of retrieving genre" << std::endl;
database::GenreRepository gnrRepo(m_bConf);
auto gnrsDb = gnrRepo.retrieveRecords();
auto genres = oatpp::data::mapping::type::List<dto::GenreDto::ObjectWrapper>::createShared();
for (auto& gnrDb : gnrsDb) {
auto gnr = dto::GenreDto::createShared();
gnr->id = gnrDb.id;
gnr->category = gnrDb.category.c_str();
for (auto& gnrDb : gnrsDb) {
auto gnr = dto::GenreDto::createShared();
gnr->id = gnrDb.id;
gnr->category = gnrDb.category.c_str();
genres->pushBack(gnr);
}
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
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");
database::GenreRepository gnrRepo(m_bConf);
model::Genre gnrDb(id);
database::GenreRepository gnrRepo(m_bConf);
model::Genre gnrDb(id);
OATPP_ASSERT_HTTP(gnrRepo.doesGenreExist(gnrDb,
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;
gnrDb = gnrRepo.retrieveRecord(gnrDb, type::GenreFilter::id);
auto genre = dto::GenreDto::createShared();
genre->id = gnrDb.id;
genre->category= gnrDb.category.c_str();
auto genre = dto::GenreDto::createShared();
genre->id = gnrDb.id;
genre->category= gnrDb.category.c_str();
return createDtoResponse(Status::CODE_200, genre);
}
return createDtoResponse(Status::CODE_200, genre);
}
#include OATPP_CODEGEN_END(ApiController)
private:
std::string m_exe_path;
model::BinaryPath m_bConf;
};
#include OATPP_CODEGEN_END(ApiController)
private:
model::BinaryPath m_bConf;
};
}
#endif
+27 -31
View File
@@ -16,46 +16,42 @@
#include "model/Models.h"
namespace controller {
class LoginController : public oatpp::web::server::api::ApiController {
public:
LoginController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), exe_path(p)
{ }
LoginController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
:oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf)
{ }
class LoginController : public oatpp::web::server::api::ApiController {
public:
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)) {
OATPP_LOGI("icarus", "logging in");
ENDPOINT("POST", "/api/v1/login", data, BODY_DTO(dto::UserDto::ObjectWrapper, usr)) {
OATPP_LOGI("icarus", "logging in");
manager::UserManager usrMgr(m_bConf);
auto user = dto::conversion::DtoConversions::toUser(usr);
manager::UserManager usrMgr(m_bConf);
auto user = dto::conversion::DtoConversions::toUser(usr);
if (!usrMgr.doesUserExist(user) || !usrMgr.validatePassword(user)) {
auto logRes = dto::LoginResultDto::createShared();
logRes->message = "invalid credentials";
std::cout << "user does not exist" << std::endl;
return createDtoResponse(Status::CODE_401, logRes);
}
if (!usrMgr.doesUserExist(user) || !usrMgr.validatePassword(user)) {
auto logRes = dto::LoginResultDto::createShared();
logRes->message = "invalid credentials";
std::cout << "user does not exist\n";
return createDtoResponse(Status::CODE_401, logRes);
}
std::cout << "user exists" << std::endl;
std::cout << "user exists\n";
manager::TokenManager tok;
auto token = tok.retrieveToken(m_bConf);
manager::TokenManager tok;
auto token = tok.retrieveToken(m_bConf);
auto logRes = dto::conversion::DtoConversions::toLoginResultDto(user, token);
logRes->message = "Successful";
auto logRes = dto::conversion::DtoConversions::toLoginResultDto(user, token);
logRes->message = "Successful";
return createDtoResponse(Status::CODE_200, logRes);
}
return createDtoResponse(Status::CODE_200, logRes);
}
#include OATPP_CODEGEN_END(ApiController)
private:
std::string exe_path;
model::BinaryPath m_bConf;
};
#include OATPP_CODEGEN_END(ApiController)
private:
model::BinaryPath m_bConf;
};
}
#endif
+5 -2
View File
@@ -17,8 +17,8 @@ namespace controller {
class RegisterController : public oatpp::web::server::api::ApiController {
public:
RegisterController(const model::BinaryPath& bConf,
OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) :
oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) :
oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
#include OATPP_CODEGEN_BEGIN(ApiController)
@@ -26,6 +26,9 @@ namespace controller {
BODY_DTO(dto::UserDto::ObjectWrapper, usr)) {
manager::UserManager usrMgr(m_bConf);
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 registerResult = dto::conversion::DtoConversions::toRegisterResultDto(res);
+177 -157
View File
@@ -9,227 +9,247 @@
#include <memory>
#include <vector>
#include <oatpp/core/async/Coroutine.hpp>
#include "oatpp/core/data/stream/ChunkedBuffer.hpp"
#include "oatpp/core/data/stream/FileStream.hpp"
#include "oatpp/core/base/StrBuffer.hpp"
#include "oatpp/core/macro/codegen.hpp"
#include "oatpp/core/macro/component.hpp"
#include "oatpp/web/mime/multipart/InMemoryPartReader.hpp"
#include "oatpp/web/mime/multipart/Reader.hpp"
#include "oatpp/web/protocol/http/outgoing/ChunkedBody.hpp"
#include "oatpp/web/protocol/http/outgoing/StreamingBody.hpp"
#include "oatpp/web/server/api/ApiController.hpp"
#include "callback/StreamCallback.h"
#include "database/SongRepository.h"
#include "dto/SongDto.hpp"
#include "dto/conversion/DtoConversions.h"
#include "manager/SongManager.h"
#include "manager/TokenManager.h"
#include "model/Models.h"
#include "type/Scopes.h"
#include "type/SongFilter.h"
#include "type/SongUpload.h"
namespace fs = std::filesystem;
namespace controller {
class SongController : public oatpp::web::server::api::ApiController {
public:
SongController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p)
{ }
class SongController : public oatpp::web::server::api::ApiController {
public:
SongController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
SongController(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 for uploading a song
ENDPOINT("POST", "/api/v1/song/data", songUpload,
//AUTHORIZATION(std::shared_ptr<oatpp::web::server::handler::DefaultBearerAuthorizationObject>, authObject),
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
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");
auto mp =
std::make_shared<oatpp::web::mime::multipart::Multipart>
(request->getHeaders());
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::make_unique<const char*>(file->getInMemoryData()->c_str());
auto buffSize = file->getKnownSize();
auto buff = std::unique_ptr<char>(new char[file->getKnownSize()]);
auto buffSize = file->getInputStream()->read(buff.get(), file->getKnownSize());
std::vector<unsigned char> data(*buff, *buff + buffSize);
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;
sng.data = std::move(data);
manager::SongManager songMgr(m_bConf);
songMgr.saveSong(sng);
auto songDto = dto::conversion::DtoConversions::toSongDto(sng);
return createResponse(Status::CODE_200, "OK");
}
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
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");
std::cout << "starting process of retrieving songs" << std::endl;
database::SongRepository songRepo(m_bConf);
auto songsDb = songRepo.retrieveRecords();
auto songs = oatpp::data::mapping::type::List<dto::SongDto::ObjectWrapper>::createShared();
std::cout << "starting process of retrieving songs\n";
database::SongRepository songRepo(m_bConf);
auto songsDb = songRepo.retrieveRecords();
auto songs = oatpp::data::mapping::type::List<dto::SongDto::ObjectWrapper>::createShared();
std::cout << "creating object to send" << std::endl;
for (auto& songDb : songsDb) {
auto song = dto::SongDto::createShared();
song->id = songDb.id;
song->title = songDb.title.c_str();
song->artist = songDb.artist.c_str();
song->album = songDb.album.c_str();
song->genre = songDb.genre.c_str();
song->year = songDb.year;
song->duration = songDb.duration;
song->track = songDb.track;
song->disc = songDb.disc;
std::cout << "creating object to send\n";
for (auto& songDb : songsDb) {
auto song = dto::conversion::DtoConversions::toSongDto(songDb);
songs->pushBack(song);
}
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("GET", "/api/v1/song/{id}", songRecord,
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::retrieveSong), Status::CODE_403, "Not allowed");
ENDPOINT("GET", "/api/v1/song/{id}", songRecord,
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::retrieveSong), Status::CODE_403, "Not allowed");
database::SongRepository songRepo(m_bConf);
model::Song songDb(id);
database::SongRepository songRepo(m_bConf);
model::Song songDb(id);
OATPP_ASSERT_HTTP(songRepo.doesSongExist(songDb, type::SongFilter::id) , Status::CODE_403,
"song does not exist");
if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) {
return songDoesNotExist();
}
std::cout << "song exists" << std::endl;
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
std::cout << "song exists\n";
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
auto song = dto::SongDto::createShared();
song->id = songDb.id;
song->title = songDb.title.c_str();
song->artist = songDb.artist.c_str();
song->album = songDb.album.c_str();
song->genre = songDb.genre.c_str();
song->year = songDb.year;
song->duration = songDb.duration;
song->track = songDb.track;
song->disc = songDb.disc;
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,
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::download), Status::CODE_403, "Not allowed");
ENDPOINT("GET", "/api/v1/song/data/{id}", downloadSong,
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::download), Status::CODE_403, "Not allowed");
database::SongRepository songRepo(m_bConf);
model::Song songDb(id);
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
database::SongRepository songRepo(m_bConf);
model::Song songDb(id);
if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) {
return songDoesNotExist();
}
auto rawSong = oatpp::base::StrBuffer::loadFromFile(songDb.songPath.c_str());
auto response = createResponse(Status::CODE_200, rawSong);
response->putHeader(Header::CONTENT_TYPE, "audio/mpeg");
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
return response;
}
auto rawSong = oatpp::base::StrBuffer::loadFromFile(songDb.songPath.c_str());
auto response = createResponse(Status::CODE_200, rawSong);
response->putHeader(Header::CONTENT_TYPE, "audio/mpeg");
ENDPOINT("UPDATE", "/api/v1/song/{id}", songUpdate,
REQUEST(std::shared_ptr<IncomingRequest>, request),
BODY_DTO(dto::SongDto::ObjectWrapper, songDto), PATH(Int32, id)) {
songDto->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::updateSong), Status::CODE_403, "Not allowed");
return response;
}
ENDPOINT("UPDATE", "/api/v1/song/{id}", songUpdate,
REQUEST(std::shared_ptr<IncomingRequest>, request),
BODY_DTO(dto::SongDto::ObjectWrapper, songDto), PATH(Int32, id)) {
songDto->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::updateSong), Status::CODE_403, "Not allowed");
auto updatedSong = manager::SongManager::songDtoConv(songDto);
manager::SongManager songMgr(m_bConf);
songMgr.updateSong(updatedSong);
auto updatedSong = dto::conversion::DtoConversions::toSong(songDto);
manager::SongManager songMgr(m_bConf);
auto result = songMgr.updateSong(updatedSong);
if (!result) {
return songDoesNotExist();
}
return createResponse(Status::CODE_200, "OK");
}
return createResponse(Status::CODE_200, "OK");
}
// endpoint to delete a song
ENDPOINT("DELETE", "api/v1/song/data/{id}", songDelete,
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::deleteSong), Status::CODE_403, "Not allowed");
// endpoint to delete a song
ENDPOINT("DELETE", "api/v1/song/data/{id}", songDelete,
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::deleteSong), Status::CODE_403, "Not allowed");
model::Song song(id);
model::Song song(id);
manager::SongManager sngMgr(m_bConf);
sngMgr.deleteSong(song);
manager::SongManager sngMgr(m_bConf);
auto result = sngMgr.deleteSong(song);
if (!result) {
return songDoesNotExist();
}
return createResponse(Status::CODE_200, "OK");
}
return createResponse(Status::CODE_200, "OK");
}
// endpoint for streaming a song
ENDPOINT("GET", "/api/v1/song/stream/{id}", streamSong,
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::stream), Status::CODE_403, "Not allowed");
// endpoint for streaming a song
ENDPOINT("GET", "/api/v1/song/stream/{id}", streamSong,
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::stream), Status::CODE_403, "Not allowed");
database::SongRepository songRepo(m_bConf);
model::Song songDb(id);
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
database::SongRepository songRepo(m_bConf);
model::Song songDb(id);
if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) {
return songDoesNotExist();
}
oatpp::data::v_io_size dSize = 1024;
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
auto db = std::make_shared<oatpp::web::protocol::http::outgoing::ChunkedBody>(
std::make_shared<callback::StreamCallback>(songDb.songPath), nullptr, dSize);
auto dSize = 1024;
auto response = OutgoingResponse::createShared(Status::CODE_200, db);
response->putHeader(Header::CONNECTION, Header::Value::CONNECTION_KEEP_ALIVE);
response->putHeader(Header::CONTENT_TYPE, "audio/mpeg");
auto callback = std::make_shared<callback::StreamCallback>(songDb.songPath);
auto db = std::make_shared<oatpp::web::protocol::http::outgoing::StreamingBody>(
callback
);
return response;
}
auto response = OutgoingResponse::createShared(Status::CODE_200, db);
response->putHeader(Header::CONNECTION, Header::Value::CONNECTION_KEEP_ALIVE);
response->putHeader(Header::CONTENT_TYPE, "audio/mpeg");
#include OATPP_CODEGEN_END(ApiController)
private:
std::string m_exe_path;
return response;
}
model::BinaryPath m_bConf;
#include OATPP_CODEGEN_END(ApiController)
private:
std::shared_ptr<oatpp::web::protocol::http::outgoing::Response>
songDoesNotExist() {
const long m_dataSize = std::numeric_limits<long long int>::max();
};
return createResponse(Status::CODE_404, "Song not found");
}
model::BinaryPath m_bConf;
const long m_dataSize = std::numeric_limits<long long int>::max();
};
}
#endif
+53 -55
View File
@@ -27,73 +27,71 @@
namespace fs = std::filesystem;
namespace controller {
class YearController : public oatpp::web::server::api::ApiController
{
public:
YearController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p)
{ }
class YearController : public oatpp::web::server::api::ApiController {
public:
YearController(const model::BinaryPath& bConf,
OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
YearController(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 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
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");
std::cout << "starting process of retrieving year\n";
database::YearRepository yrRepo(m_bConf);
auto yrsDb = yrRepo.retrieveRecords();
auto yearRecs = oatpp::data::mapping::type::
List<dto::YearDto::ObjectWrapper>::createShared();
std::cout << "starting process of retrieving year" << std::endl;
database::YearRepository yrRepo(m_bConf);
auto yrsDb = yrRepo.retrieveRecords();
auto yearRecs = oatpp::data::mapping::type::List<dto::YearDto::ObjectWrapper>::createShared();
for (auto& yrDb : yrsDb) {
auto yr = dto::YearDto::createShared();
yr->id = yrDb.id;
yr->year = yrDb.year;
for (auto& yrDb : yrsDb) {
auto yr = dto::YearDto::createShared();
yr->id = yrDb.id;
yr->year = yrDb.year;
yearRecs->pushBack(yr);
}
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
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");
database::YearRepository yrRepo(m_bConf);
model::Year yrDb(id);
database::YearRepository yrRepo(m_bConf);
model::Year yrDb(id);
OATPP_ASSERT_HTTP(yrRepo.doesYearExist(yrDb,
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;
yrDb = yrRepo.retrieveRecord(yrDb, type::YearFilter::id);
auto year = dto::YearDto::createShared();
year->id = yrDb.id;
year->year= yrDb.year;
auto year = dto::YearDto::createShared();
year->id = yrDb.id;
year->year= yrDb.year;
return createDtoResponse(Status::CODE_200, year);
}
return createDtoResponse(Status::CODE_200, year);
}
#include OATPP_CODEGEN_END(ApiController)
private:
std::string m_exe_path;
model::BinaryPath m_bConf;
};
#include OATPP_CODEGEN_END(ApiController)
private:
model::BinaryPath m_bConf;
};
}
#endif
+10 -7
View File
@@ -1,6 +1,7 @@
#ifndef ALBUMREPOSITORY_H_
#define ALBUMREPOSITORY_H_
#include <memory>
#include <utility>
#include <vector>
@@ -8,10 +9,8 @@
#include "model/Models.h"
#include "type/AlbumFilter.h"
namespace database
{
class AlbumRepository : public BaseRepository
{
namespace database {
class AlbumRepository : public BaseRepository {
public:
AlbumRepository(const model::BinaryPath&);
@@ -30,9 +29,13 @@ namespace database
std::pair<model::Album, int> parseRecordWithSongCount(MYSQL_STMT*);
// TODO: after parseRecord(MYSQL_STMT*) is implemented remove
// parseRecord(MYSQL_RES*)
model::Album parseRecord(MYSQL_RES*);
std::shared_ptr<MYSQL_BIND> valueBind(model::Album&,
std::tuple<char*, char*>&);
std::shared_ptr<MYSQL_BIND> valueBindWithSongCount(model::Album&,
std::tuple<char*, char*>&, int&);
std::tuple<char*, char*> metadataBuffer();
model::Album parseRecord(MYSQL_STMT*);
};
}
+12 -8
View File
@@ -1,6 +1,7 @@
#ifndef ARTISTREPOSITORY_H_
#define ARTISTREPOSITORY_H_
#include <memory>
#include <utility>
#include <vector>
@@ -8,16 +9,15 @@
#include "model/Models.h"
#include "type/ArtistFilter.h"
namespace database
{
class ArtistRepository : public BaseRepository
{
namespace database {
class ArtistRepository : public BaseRepository {
public:
ArtistRepository(const model::BinaryPath&);
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);
@@ -30,9 +30,13 @@ namespace database
std::pair<model::Artist, int> parseRecordWithSongCount(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented
// remove parseRecord(MYSQL_RES*)
model::Artist parseRecord(MYSQL_RES*);
std::shared_ptr<MYSQL_BIND> valueBind(model::Artist&,
std::tuple<char*>&);
std::shared_ptr<MYSQL_BIND> valueBindWithSongCount(model::Artist&,
std::tuple<char*>&, int&);
std::tuple<char*> metadataBuffer();
model::Artist parseRecord(MYSQL_STMT*);
};
}
+3 -5
View File
@@ -7,12 +7,10 @@
#include "model/Models.h"
namespace database
{
class BaseRepository
{
namespace database {
class BaseRepository {
public:
BaseRepository();
BaseRepository() = default;
BaseRepository(const std::string&);
BaseRepository(const model::BinaryPath&);
+9 -9
View File
@@ -1,6 +1,7 @@
#ifndef COVERARTREPOSITORY_H_
#define COVERARTREPOSITORY_H_
#include <memory>
#include <vector>
#include <mysql/mysql.h>
@@ -9,12 +10,9 @@
#include "model/Models.h"
#include "type/CoverFilter.h"
namespace database
{
class CoverArtRepository : public BaseRepository
{
namespace database {
class CoverArtRepository : public BaseRepository {
public:
CoverArtRepository(const std::string&);
CoverArtRepository(const model::BinaryPath&);
std::vector<model::Cover> retrieveRecords();
@@ -23,15 +21,17 @@ namespace database
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 updateRecord(const model::Cover&);
private:
std::vector<model::Cover> parseRecords(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented
// remove parseRecord(MYSQL_RES*)
model::Cover parseRecord(MYSQL_RES*);
std::shared_ptr<MYSQL_BIND> valueBind(model::Cover&,
std::tuple<char*, char*>&);
std::tuple<char*, char*> metadataBuffer();
model::Cover parseRecord(MYSQL_STMT*);
};
}
+10 -7
View File
@@ -1,6 +1,7 @@
#ifndef GENREREPOSITORY_H_
#define GENREREPOSITORY_H_
#include <memory>
#include <utility>
#include <vector>
@@ -8,10 +9,8 @@
#include "model/Models.h"
#include "type/GenreFilter.h"
namespace database
{
class GenreRepository : public BaseRepository
{
namespace database {
class GenreRepository : public BaseRepository {
public:
GenreRepository(const model::BinaryPath&);
@@ -30,9 +29,13 @@ namespace database
std::pair<model::Genre, int> parseRecordWithSongCount(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented
// remove parseRecord(MYSQL_RES*)
model::Genre parseRecord(MYSQL_RES*);
std::shared_ptr<MYSQL_BIND> valueBind(model::Genre&,
std::tuple<char*>&);
std::shared_ptr<MYSQL_BIND> valueBindWithSongCount(model::Genre&,
std::tuple<char*>&, int&);
std::tuple<char*> metadataBuffer();
model::Genre parseRecord(MYSQL_STMT*);
};
}
+10 -9
View File
@@ -2,6 +2,7 @@
#define SONGREPOSITORY_H_
#include <memory>
#include <utility>
#include <vector>
#include <mysql/mysql.h>
@@ -10,28 +11,28 @@
#include "model/Models.h"
#include "type/SongFilter.h"
namespace database
{
class SongRepository : public BaseRepository
{
namespace database {
class SongRepository : public BaseRepository {
public:
SongRepository(const std::string&);
SongRepository(const model::BinaryPath&);
std::vector<model::Song> retrieveRecords();
model::Song retrieveRecord(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&);
void saveRecord(const model::Song&);
void updateRecord(const model::Song&);
private:
std::vector<model::Song> parseRecords(MYSQL_RES*); // TODO: to be removed
std::shared_ptr<MYSQL_BIND> valueBind(model::Song&,
std::tuple<char*, char*, char*, char*, char*, char*>&);
std::tuple<char*, char*, char*, char*, char*, char*> metadataBuffer();
std::vector<model::Song> parseRecords(MYSQL_STMT*);
model::Song parseRecord(MYSQL_RES*); // TODO: to be removed
model::Song parseRecord(MYSQL_STMT*);
};
}
+37 -37
View File
@@ -11,48 +11,48 @@
#include "type/UserFilter.h"
namespace database {
class UserRepository : BaseRepository {
public:
UserRepository(const model::BinaryPath&);
class UserRepository : BaseRepository {
public:
UserRepository(const model::BinaryPath&);
model::User retrieveUserRecord(model::User&, type::UserFilter);
model::PassSec retrieverUserSaltRecord(model::PassSec&, type::SaltFilter);
model::User retrieveUserRecord(model::User&, type::UserFilter);
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 saveUserSalt(const model::PassSec&);
private:
struct UserLengths;
struct SaltLengths;
void saveUserRecord(const model::User&);
void saveUserSalt(const model::PassSec&);
private:
struct UserLengths;
struct SaltLengths;
struct UserLengths
{
unsigned long firstnameLength;
unsigned long lastnameLength;
unsigned long phoneLength;
unsigned long emailLength;
unsigned long usernameLength;
unsigned long passwordLength;
struct UserLengths {
unsigned long firstnameLength;
unsigned long lastnameLength;
unsigned long phoneLength;
unsigned long emailLength;
unsigned long usernameLength;
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
+12 -11
View File
@@ -1,6 +1,7 @@
#ifndef YEARREPOSITORY_H_
#define YEARREPOSITORY_H_
#include <memory>
#include <utility>
#include <vector>
@@ -8,31 +9,31 @@
#include "model/Models.h"
#include "type/YearFilter.h"
namespace database
{
class YearRepository : public BaseRepository
{
namespace database {
class YearRepository : public BaseRepository {
public:
YearRepository(const model::BinaryPath&);
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 deleteYear(const model::Year&, type::YearFilter);
void deleteYear(const model::Year&, type::YearFilter = type::YearFilter::id);
private:
std::vector<model::Year> parseRecords(MYSQL_STMT*);
std::pair<model::Year, int> parseRecordWithSongCount(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented
// remove parseRecord(MYSQL_RES*)
model::Year parseRecord(MYSQL_RES*);
std::shared_ptr<MYSQL_BIND> valueBind(model::Year&);
std::shared_ptr<MYSQL_BIND> valueBindWithSongCount(model::Year&,
int&);
model::Year parseRecord(MYSQL_STMT*);
};
}
+3 -4
View File
@@ -4,16 +4,15 @@
#include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp"
namespace dto
{
namespace 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_FIELD(Int32, id);
DTO_FIELD(String, title);
DTO_FIELD(String, artist);
DTO_FIELD(Int32, year);
};
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp"
namespace dto
{
namespace 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_FIELD(Int32, id);
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp"
namespace dto
{
namespace 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_FIELD(Int32, id);
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp"
namespace dto
{
namespace 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_FIELD(Int32, id);
+4 -4
View File
@@ -6,23 +6,23 @@
#include "model/Models.h"
namespace dto
{
namespace 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_FIELD(Int32, id);
DTO_FIELD(String, title);
DTO_FIELD(String, artist);
DTO_FIELD(String, album_artist);
DTO_FIELD(String, album);
DTO_FIELD(String, genre);
DTO_FIELD(Int32, track);
DTO_FIELD(Int32, disc);
DTO_FIELD(Int32, year);
DTO_FIELD(Int32, duration);
DTO_FIELD(Int32, coverart_id);
};
#include OATPP_CODEGEN_END(DTO)
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp"
namespace dto
{
namespace 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_FIELD(Int32, id);
+5
View File
@@ -1,6 +1,7 @@
#ifndef DTOCONVERSIONS_H_
#define DTOCONVERSIONS_H_
#include "dto/AlbumDto.hpp"
#include "dto/LoginResultDto.hpp"
#include "dto/SongDto.hpp"
#include "model/Models.h"
@@ -13,6 +14,10 @@ namespace dto { namespace conversion {
static dto::RegisterResultDto::ObjectWrapper toRegisterResultDto(
const model::RegisterResult&);
static dto::AlbumDto::ObjectWrapper toAlbumDto(const model::Album&);
static dto::SongDto::ObjectWrapper toSongDto(const model::Song&);
static model::Song toSong(dto::SongDto::ObjectWrapper&);
static model::User toUser(dto::UserDto::ObjectWrapper&);
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h"
namespace manager
{
class AlbumManager
{
namespace manager {
class AlbumManager {
public:
AlbumManager(const model::BinaryPath&);
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h"
namespace manager
{
class ArtistManager
{
namespace manager {
class ArtistManager {
public:
ArtistManager(const model::BinaryPath&);
+2 -6
View File
@@ -6,12 +6,9 @@
#include "model/Models.h"
namespace manager
{
class CoverArtManager
{
namespace manager {
class CoverArtManager {
public:
CoverArtManager(const std::string&);
CoverArtManager(const model::BinaryPath& bConf);
model::Cover saveCover(const model::Song&);
@@ -25,7 +22,6 @@ namespace manager
std::string createImagePath(const model::Song&);
model::BinaryPath m_bConf;
std::string path;
};
}
+12 -6
View File
@@ -3,19 +3,21 @@
#include <string>
#include <string_view>
#include <filesystem>
#include <nlohmann/json.hpp>
#include "model/Models.h"
#include "type/PathType.h"
namespace manager
{
class DirectoryManager
{
namespace manager {
class DirectoryManager {
public:
static std::string createDirectoryProcess(model::Song, const std::string&);
static std::string createDirectoryProcess(const model::Song&, const model::BinaryPath&, type::PathType);
DirectoryManager() = default;
static std::string createDirectoryProcess(const model::Song&, const std::string&);
static std::string createDirectoryProcess(const model::Song&,
const model::BinaryPath&, type::PathType);
static std::string configPath(std::string_view);
static std::string configPath(const model::BinaryPath&);
static std::string contentOfPath(const std::string&);
@@ -30,6 +32,10 @@ namespace manager
void deleteCoverArtFile(const std::string&, const std::string&);
private:
std::filesystem::path relativeDiscSongPathFilesystem(const std::filesystem::path&,
const model::Song&);
std::string relativeDiscSongPath(const std::filesystem::path&, const model::Song&);
void deleteSong(const model::Song);
};
}
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h"
namespace manager
{
class GenreManager
{
namespace manager {
class GenreManager {
public:
GenreManager(const model::BinaryPath&);
+7 -12
View File
@@ -4,30 +4,26 @@
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <nlohmann/json.hpp>
#include "dto/SongDto.hpp"
#include "model/Models.h"
#include "type/SongChanged.h"
#include "type/SongUpload.h"
namespace manager
{
class SongManager
{
namespace manager {
class SongManager {
public:
SongManager(std::string&);
SongManager(const model::BinaryPath&);
std::pair<bool, type::SongUpload> saveSong(model::Song&);
bool didSongChange(const model::Song&, const model::Song&);
bool requiresFilesystemChange(const model::Song&, const model::Song&);
void saveSong(model::Song&);
void deleteSong(model::Song&);
void updateSong(model::Song&);
static model::Song songDtoConv(dto::SongDto::ObjectWrapper&);
bool deleteSong(model::Song&);
bool updateSong(model::Song&);
static void printSong(const model::Song&);
private:
@@ -47,7 +43,6 @@ namespace manager
void modifySongOnFilesystem(model::Song&, const model::Song&);
model::BinaryPath m_bConf;
std::string exe_path;
};
}
+14 -15
View File
@@ -14,27 +14,26 @@
#include "type/Scopes.h"
namespace manager {
class TokenManager {
public:
TokenManager();
class TokenManager {
public:
TokenManager() = default;
model::Token retrieveToken(const model::BinaryPath&);
model::Token retrieveToken(const model::BinaryPath&);
bool isTokenValid(std::string&, type::Scope);
bool testAuth(const model::BinaryPath&);
private:
cpr::Response sendRequest(std::string_view, nlohmann::json&);
bool isTokenValid(std::string&, type::Scope);
bool testAuth(const model::BinaryPath&);
private:
cpr::Response sendRequest(std::string_view, nlohmann::json&);
nlohmann::json createTokenBody(const model::AuthCredentials&);
nlohmann::json createTokenBody(const model::AuthCredentials&);
model::AuthCredentials parseAuthCredentials(std::string_view);
model::AuthCredentials parseAuthCredentials(const model::BinaryPath&);
model::AuthCredentials parseAuthCredentials(const model::BinaryPath&);
std::vector<std::string> extractScopes(const jwt::decoded_jwt&&);
std::pair<bool, std::vector<std::string>> fetchAuthHeader(const std::string&);
std::vector<std::string> extractScopes(const jwt::decoded_jwt&&);
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
+10 -10
View File
@@ -7,19 +7,19 @@
#include "model/Models.h"
namespace manager {
class UserManager {
public:
UserManager(const model::BinaryPath&);
class UserManager {
public:
UserManager(const model::BinaryPath&);
model::RegisterResult registerUser(model::User&);
model::RegisterResult registerUser(model::User&);
bool doesUserExist(const model::User&);
bool validatePassword(const model::User&);
bool doesUserExist(const model::User&);
bool validatePassword(const model::User&);
void printUser(const model::User&);
private:
model::BinaryPath m_bConf;
};
void printUser(const model::User&);
private:
model::BinaryPath m_bConf;
};
}
#endif
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h"
namespace manager
{
class YearManager
{
namespace manager {
class YearManager {
public:
YearManager(const model::BinaryPath&);
+144 -144
View File
@@ -5,172 +5,172 @@
#include <vector>
namespace model {
struct Song {
Song() = default;
Song(const int id) : id(id) { }
class Song {
public:
Song() = default;
Song(const int id) : id(id) { }
Song(const int id, const std::string& title, const std::string& artist,
const std::string& album, const std::string& albumArtist,
const std::string& genre, const int year, const int duration,
const int track, const int disc, const std::string songPath) :
id(id), title(title), artist(artist), album(album),
albumArtist(albumArtist), genre(genre), year(year),
duration(duration), track(track), disc(disc),
songPath(songPath) { }
int id;
std::string title;
std::string artist;
std::string album;
std::string genre;
int year;
int duration;
int track;
int disc;
std::string songPath;
std::vector<unsigned char> data;
int coverArtId;
int artistId;
int albumId;
int genreId;
int yearId;
};
int id;
std::string title;
std::string artist;
std::string album;
std::string albumArtist;
std::string genre;
int year;
int duration;
int track;
int disc;
std::string songPath;
std::vector<unsigned char> data;
int coverArtId;
int artistId;
int albumId;
int genreId;
int yearId;
};
struct Artist {
Artist() = default;
Artist(const Song& song)
{
id = song.artistId;
artist = song.artist;
}
Artist(const int id) : id(id) { }
class Artist {
public:
Artist() = default;
Artist(const Song& song) : id(song.artistId), artist(song.artist) { }
Artist(const int id) : id(id) { }
int id;
std::string artist;
};
int id;
std::string artist;
};
struct Album {
Album() = default;
Album(const Song& song)
{
id = song.albumId;
title = song.album;
year = song.year;
}
Album(const int id) : id(id) { }
class Album {
public:
Album() = default;
Album(const Song& song) :
id(song.albumId), title(song.album),artist(song.artist), year(song.year) { }
Album(const int id) : id(id) { }
int id;
std::string title;
int year;
std::vector<Song> songs;
};
int id;
std::string title;
std::string artist;
int year;
std::vector<Song> songs;
};
struct Genre {
Genre() = default;
Genre(const Song& song)
{
id = song.genreId;
category = song.genre;
}
Genre(const int id) : id(id) { }
class Genre {
public:
Genre() = default;
Genre(const Song& song) :
id(song.genreId), category(song.genre) { }
Genre(const int id) : id(id) { }
int id;
std::string category;
int id;
std::string category;
};
};
struct Year {
Year() = default;
Year(const Song& song)
{
id = song.yearId;
year = song.year;
}
Year(const int id) : id(id) { }
class Year {
public:
Year() = default;
Year(const Song& song) :
id(song.yearId), year(song.year) { }
Year(const int id) : id(id) { }
int id;
int year;
};
int id;
int year;
};
struct Cover {
Cover() = default;
Cover(const Song& song)
{
id = song.coverArtId;
songTitle = song.title;
}
Cover(const int id) : id(id) { }
class Cover {
public:
Cover() = default;
Cover(const Song& song) :
id(song.coverArtId), songTitle(song.title) { }
Cover(const int id) : id(id) { }
int id;
std::string songTitle;
std::string imagePath;
// Not being used but it should be
std::vector<unsigned char> data;
};
int id;
std::string songTitle;
std::string imagePath;
// Not being used but it should be
std::vector<unsigned char> data;
};
class Token {
public:
Token() = default;
Token(const std::string& accessToken) :
accessToken(accessToken) { }
Token(const std::string& accessToken, const std::string& tokenType,
const int expiration) :
accessToken(accessToken), tokenType(tokenType),
expiration(expiration) { }
class Token {
public:
Token() = default;
Token(const std::string& accessToken) :
accessToken(accessToken) { }
Token(const std::string& accessToken, const std::string& tokenType,
const int expiration) :
accessToken(accessToken), tokenType(tokenType),
expiration(expiration) { }
std::string accessToken;
int expiration;
std::string tokenType;
};
std::string accessToken;
int expiration;
std::string tokenType;
};
struct LoginResult {
int userId;
std::string username;
std::string accessToken;
std::string tokenType;
std::string message;
int expiration;
};
struct LoginResult {
int userId;
std::string username;
std::string accessToken;
std::string tokenType;
std::string message;
int expiration;
};
class RegisterResult {
public:
std::string username;
bool registered;
std::string message;
};
class RegisterResult {
public:
std::string username;
bool registered;
std::string message;
};
struct User {
int id;
std::string firstname;
std::string lastname;
std::string email;
std::string phone;
std::string username;
std::string password;
};
struct User {
int id;
std::string firstname;
std::string lastname;
std::string email;
std::string phone;
std::string username;
std::string password;
};
struct PassSec {
int id;
std::string hashPassword;
std::string salt;
int userId;
};
struct PassSec {
int id;
std::string hashPassword;
std::string salt;
int userId;
};
struct AuthCredentials {
std::string domain;
std::string apiIdentifier;
std::string clientId;
std::string clientSecret;
std::string uri;
std::string endpoint;
};
struct AuthCredentials {
std::string domain;
std::string apiIdentifier;
std::string clientId;
std::string clientSecret;
std::string uri;
std::string endpoint;
};
struct DatabaseConnection {
std::string server;
std::string username;
std::string password;
std::string database;
};
struct DatabaseConnection {
std::string server;
std::string username;
std::string password;
std::string database;
};
struct BinaryPath {
BinaryPath() = default;
BinaryPath(const char *p) : path(std::move(p)) { }
BinaryPath(std::string& p) : path(p) { }
BinaryPath(const std::string& p) : path(p) { }
class BinaryPath {
public:
BinaryPath() = default;
BinaryPath(const char *p) : path(p) { }
BinaryPath(const std::string& p) : path(p) { }
BinaryPath(const std::string&& p) : path(p) { }
std::string path;
};
std::string path;
};
}
#endif
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef ALBUMFILTER_H_
#define ALBUMFILTER_H_
namespace type
{
enum class AlbumFilter
{
namespace type {
enum class AlbumFilter {
id = 0,
title,
year
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef ARTISTFILTER_H_
#define ARTISTFILTER_H_
namespace type
{
enum class ArtistFilter
{
namespace type {
enum class ArtistFilter {
id = 0,
artist
};
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef COVERFILTER_H_
#define COVERFILTER_H_
namespace type
{
enum class CoverFilter
{
namespace type {
enum class CoverFilter {
id = 0,
songTitle,
imagePath
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef GENREFILTER_H_
#define GENREFILTER_H_
namespace type
{
enum class GenreFilter
{
namespace type {
enum class GenreFilter {
id = 0,
category
};
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef PATHTYPE_H_
#define PATHTYPE_H_
namespace type
{
enum PathType
{
namespace type {
enum PathType {
music = 0,
archive,
temp,
+1 -2
View File
@@ -2,8 +2,7 @@
#define SALTFILTER_H_
namespace type {
enum class SaltFilter
{
enum class SaltFilter {
id = 0,
salt,
userId
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef SCOPES_H_
#define SCOPES_H_
namespace type
{
enum class Scope
{
namespace type {
enum class Scope {
upload = 0,
download,
stream,
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef SONGCHANGED_H_
#define SONGCHANGED_H_
namespace type
{
enum SongChanged
{
namespace type {
enum SongChanged {
title = 0,
artist,
album,
+7 -5
View File
@@ -1,16 +1,18 @@
#ifndef SONGFILTER_H_
#define SONGFILTER_H_
namespace type
{
enum class SongFilter
{
namespace type {
enum class SongFilter {
id = 0,
title,
album,
artist,
albumArtist,
genre,
year
year,
titleAndArtist,
titleAlbArtistAlbum,
titleAlbArtistAlbumTrack
};
}
+12
View File
@@ -0,0 +1,12 @@
#ifndef SONGUPLOAD_H_
#define SONGUPLOAD_H_
namespace type {
enum class SongUpload {
Successful = 0,
AlreadyExist = 1,
Failed = 2
};
}
#endif
+1 -2
View File
@@ -2,8 +2,7 @@
#define USERFILTER_H_
namespace type {
enum class UserFilter
{
enum class UserFilter {
id = 0,
username
};
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef YEARFILTER_H_
#define YEARFILTER_H_
namespace type
{
enum class YearFilter
{
namespace type {
enum class YearFilter {
id = 0,
year
};
+2 -4
View File
@@ -13,10 +13,8 @@
#include <tpropertymap.h>
#include <id3v2tag.h>
namespace utility
{
class ImageFile : public TagLib::File
{
namespace utility {
class ImageFile : public TagLib::File {
public:
ImageFile(const char *file);
+17 -12
View File
@@ -4,23 +4,28 @@
#include <iostream>
#include <string>
#include <attachedpictureframe.h>
#include <textidentificationframe.h>
#include <fileref.h>
#include <mpegfile.h>
#include <tag.h>
#include "model/Models.h"
namespace utility {
class MetadataRetriever
{
public:
model::Song retrieveMetadata(std::string&);
class MetadataRetriever {
public:
model::Song retrieveMetadata(model::Song&);
model::Cover updateCoverArt(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 updateCoverArt(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&);
bool songContainsCoverArt(const model::Song&);
bool songContainsCoverArt(const model::Song&);
void updateMetadata(model::Song&, const model::Song&);
private:
};
void updateMetadata(model::Song&, const model::Song&);
private:
};
}
#endif
+1 -1
View File
@@ -12,7 +12,7 @@ public:
bool isPasswordValid(const model::User&, const model::PassSec&);
private:
int saltSize();
constexpr int saltSize() noexcept;
};
}
+2 -4
View File
@@ -5,10 +5,8 @@
#include "model/Models.h"
namespace verify
{
class Initialization
{
namespace verify {
class Initialization {
public:
static bool skipVerification(const std::string&);
+3 -5
View File
@@ -23,8 +23,7 @@
namespace fs = std::filesystem;
void run(const model::BinaryPath& bConf)
{
void run(const model::BinaryPath& bConf) {
component::AppComponent component;
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router);
@@ -58,8 +57,7 @@ void run(const model::BinaryPath& bConf)
server.run();
}
int main(int argc, char **argv)
{
int main(int argc, char **argv) {
oatpp::base::Environment::init();
model::BinaryPath bConf(std::move(argv[0]));
@@ -68,7 +66,7 @@ int main(int argc, char **argv)
if (!verify::Initialization::skipVerification(argv[1])) {
verify::Initialization::checkIcarus(bConf);
} else {
std::cout << "skiping verifyication" << std::endl;
std::cout << "skiping verifyication\n";
}
} else {
verify::Initialization::checkIcarus(bConf);
+27 -28
View File
@@ -5,40 +5,39 @@
#include <memory>
namespace callback {
StreamCallback::StreamCallback() :
m_counter(0) { }
StreamCallback::StreamCallback() : m_counter(0) { }
StreamCallback::StreamCallback(const std::string& songPath) :
m_songPath(songPath),
m_counter(0),
m_bytesRead(0)
{
// getting file size
std::ifstream song(m_songPath.c_str(), std::ios::binary | std::ios::in | std::ios::ate);
m_fileSize = song.tellg();
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;
StreamCallback::StreamCallback(const std::string& songPath) :
m_songPath(songPath),
m_counter(0),
m_bytesRead(0) {
// getting file size
std::ifstream song(m_songPath.c_str(), std::ios::binary | std::ios::in | std::ios::ate);
m_fileSize = song.tellg();
std::cout << "file size is " << m_fileSize << " bytes\n";
}
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]);
song.read(data.get(), count);
std::memcpy(buff, data.get(), count);
oatpp::v_io_size StreamCallback::read(void *buff, v_buff_size count,
oatpp::async::Action& action) {
if (m_counter >= m_fileSize) {
std::cout << "done streaming song\n";
return 0;
}
m_counter += count;
std::fstream song(m_songPath.c_str(), std::ios::binary | std::ios::in);
song.seekg(m_counter);
song.close();
std::unique_ptr<char[]> data(new char[count]);
return count;
}
song.read(data.get(), count);
std::memcpy(buff, data.get(), count);
m_counter += count;
song.close();
return count;
}
}
+355 -413
View File
@@ -7,443 +7,385 @@
#include <string>
#include <cstring>
database::AlbumRepository::AlbumRepository(const model::BinaryPath& bConf)
: BaseRepository(bConf)
{ }
namespace database {
AlbumRepository::AlbumRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { }
std::vector<model::Album> database::AlbumRepository::retrieveRecords()
{
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
std::vector<model::Album> AlbumRepository::retrieveRecords() {
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Album";
mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt);
const std::string query = "SELECT * FROM Album";
mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt);
auto albums = parseRecords(stmt);
auto albums = parseRecords(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
mysql_stmt_close(stmt);
mysql_close(conn);
return albums;
}
std::pair<model::Album, int> database::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[4];
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 database::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;
return albums;
}
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::pair<model::Album, int> AlbumRepository::retrieveRecordWithSongCount(model::Album& album,
type::AlbumFilter filter = type::AlbumFilter::id) {
std::cout << "retrieving album with song count\n";
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);
mysql_close(conn);
qry << "SELECT alb.*, COUNT(*) AS SongCount FROM Album alb LEFT JOIN ";
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;
}
bool database::AlbumRepository::doesAlbumExists(const model::Album& album, type::AlbumFilter 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 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 database::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, Year) VALUES(?, ?)";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
MYSQL_BIND params[2];
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_LONG;
params[1].buffer = (char*)&album.year;
params[1].length = 0;
params[1].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 database::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> database::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 res = mysql_stmt_result_metadata(stmt);
auto fields = mysql_fetch_fields(res);
const auto strLen = 1024;
MYSQL_BIND val[valAmt];
memset(val, 0, sizeof(val));
char title[strLen];
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&alb.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_STRING;
val[1].buffer = (char*)title;
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*)&alb.year;
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);
if (status == 1 || status == MYSQL_NO_DATA) {
break;
}
alb.title = title;
albums.push_back(std::move(alb));
}
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;
}
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);
// TODO: check to see if this is not used, if not then remove it
model::Album database::AlbumRepository::parseRecord(MYSQL_RES* results)
{
std::cout << "parsing album record" << std::endl;
model::Album album;
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
auto fieldNum = mysql_num_fields(results);
auto row = mysql_fetch_row(results);
qry << "SELECT alb.* FROM Album alb WHERE ";
for (auto i = 0; i != fieldNum; ++i) {
const std::string field(mysql_fetch_field(results)->name);
auto titleLength = album.title.size();
switch (filter) {
case type::AlbumFilter::id:
qry << "alb.AlbumId = ?";
if (field.compare("AlbumId") == 0) {
album.id = std::stoi(row[i]);
}
if (field.compare("Title") == 0) {
album.title = row[i];
}
if (field.compare("Year") == 0) {
album.year = std::stoi(row[i]);
}
}
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 = ?";
return album;
}
std::pair<model::Album, int> database::AlbumRepository::parseRecordWithSongCount(MYSQL_STMT *stmt)
{
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;
int songCount = 0;
if (rowCount == 0) {
std::cout << "no results" << std::endl;
return std::make_pair(album, songCount);
}
if (mysql_stmt_field_count(stmt) == 0) {
std::cout << "field count is 0, must be an incorrect query" << std::endl;
return std::make_pair(model::Album(), 0);
}
auto res = mysql_stmt_result_metadata(stmt);
constexpr auto valAmt = 4;
constexpr auto strLen = 1024;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
MYSQL_BIND val[valAmt];
std::memset(val, 0, sizeof(val));
char title[strLen];
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&album.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_STRING;
val[1].buffer = (char*)title;
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*)&album.year;
val[2].length = &len[2];
val[2].is_null = &nullRes[2];
val[3].buffer_type = MYSQL_TYPE_LONG;
val[3].buffer = (char*)&songCount;
val[3].length = &len[3];
val[3].is_null = &nullRes[3];
auto status = mysql_stmt_bind_result(stmt, val);
status = mysql_stmt_fetch(stmt);
album.title = std::move(title);
std::cout << "done parsing album record with song count" << std::endl;
auto albWSC = std::make_pair(album, songCount);
return albWSC;
}
model::Album database::AlbumRepository::parseRecord(MYSQL_STMT *stmt)
{
std::cout << "parsing album record" << std::endl;
mysql_stmt_store_result(stmt);
auto rows = mysql_stmt_num_rows(stmt);
model::Album album;
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 title[strLen];
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&album.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_STRING;
val[1].buffer = (char*)title;
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*)&album.year;
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);
album.title = 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;
}
status = mysql_stmt_next_result(stmt);
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;
}
std::cout << "done parsing album record" << std::endl;
bool AlbumRepository::doesAlbumExists(const model::Album& album, type::AlbumFilter filter) {
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
return album;
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\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::vector<model::Album> AlbumRepository::parseRecords(MYSQL_STMT* stmt) {
std::cout << "parsing album record\n";
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\n";
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\n";
}
return albums;
}
std::pair<model::Album, int> AlbumRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) {
std::cout << "parsing album record with song count\n";
mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt);
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;
}
std::shared_ptr<MYSQL_BIND> AlbumRepository::valueBind(model::Album& album,
std::tuple<char*, char*>& metadata) {
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;
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;
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.artist = std::get<1>(metaBuff);
std::cout << "done parsing album record\n";
return album;
}
}
+315 -369
View File
@@ -6,410 +6,356 @@
#include <string>
#include <cstring>
database::ArtistRepository::ArtistRepository(const model::BinaryPath& binConf)
: BaseRepository(binConf)
{
}
namespace database {
ArtistRepository::ArtistRepository(const model::BinaryPath& binConf) :
BaseRepository(binConf) { }
std::vector<model::Artist> database::ArtistRepository::retrieveRecords()
{
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Artist";
std::vector<model::Artist> ArtistRepository::retrieveRecords() {
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Artist";
mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt);
mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt);
auto artists = parseRecords(stmt);
auto artists = parseRecords(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
mysql_stmt_close(stmt);
mysql_close(conn);
return artists;
}
std::pair<model::Artist, int> database::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 database::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 database::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 database::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 database::ArtistRepository::deleteArtist(const model::Artist& artist, type::ArtistFilter filter = type::ArtistFilter::id) {
// TODO: implement this
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> database::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;
}
model::Artist art;
const auto valAmt = 2;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
std::pair<model::Artist, int> ArtistRepository::retrieveRecordWithSongCount(
model::Artist& artist, type::ArtistFilter filter = type::ArtistFilter::id) {
std::cout << "retrieving artist record with song count\n";
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
auto res = mysql_stmt_result_metadata(stmt);
auto fields = mysql_fetch_fields(res);
const auto strLen = 1024;
qry << "SELECT art.*, COUNT(*) AS SongCount FROM Artist art LEFT JOIN ";
qry << "Song sng ON art.ArtistId=sng.ArtistId WHERE ";
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];
memset(val, 0, sizeof(val));
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;
}
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&art.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
qry << " GROUP BY art.ArtistId LIMIT 1";
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];
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);
for (auto status = mysql_stmt_bind_result(stmt, val); status == 0; ) {
std::cout << "fetching statement result" << std::endl;
std::cout << "Artist record with song count query ";
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);
if (status == 0) {
art.artist = artist;
artists.push_back(std::move(art));
}
artist.artist = std::get<0>(metaBuff);
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 database::ArtistRepository::parseRecord(MYSQL_RES* results)
{
std::cout << "parsing artist record" << std::endl;
model::Artist artist;
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = (char*)&artist.id;
auto fieldNum = mysql_num_fields(results);
auto row = mysql_fetch_row(results);
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = (char*)std::get<0>(metadata);
values.get()[1].buffer_length = wordLen;
for (auto i = 0; i != fieldNum; ++i) {
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];
}
return values;
}
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> database::ArtistRepository::parseRecordWithSongCount(MYSQL_STMT *stmt)
{
std::cout << "parsing artist record with song count" << std::endl;
mysql_stmt_store_result(stmt);
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;
const auto strLen = 1024;
const auto valAmt = 3;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
values.get()[2].buffer_type = MYSQL_TYPE_LONG;
values.get()[2].buffer = reinterpret_cast<char*>(&songCount);
model::Artist artist;
int songCount = 0;
if (mysql_stmt_num_rows(stmt) == 0) {
std::cout << "no results" << std::endl;
return std::make_pair(artist, songCount);
return values;
}
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;
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 database::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);
return std::make_tuple(artist);
}
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;
}
}
+64 -72
View File
@@ -6,91 +6,83 @@
#include "manager/DirectoryManager.h"
database::BaseRepository::BaseRepository()
{ }
database::BaseRepository::BaseRepository(const std::string& path) : path(path)
{
intitalizeDetails();
}
database::BaseRepository::BaseRepository(const model::BinaryPath& bConf)
{
initializeDetails(bConf);
}
bool database::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;
namespace database {
BaseRepository::BaseRepository(const std::string& path) : path(path) {
intitalizeDetails();
}
mysql_close(conn);
return true;
}
MYSQL* database::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;
BaseRepository::BaseRepository(const model::BinaryPath& bConf) {
initializeDetails(bConf);
}
return conn;
}
MYSQL* database::BaseRepository::setupMysqlConnection(model::DatabaseConnection details)
{
MYSQL *connection = mysql_init(NULL);
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\n";
return false;
}
// 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)) {
printf("Conection error : %s\n", mysql_error(connection));
exit(1);
mysql_close(conn);
return true;
}
return connection;
}
MYSQL_RES* database::BaseRepository::performMysqlQuery(MYSQL *conn, const std::string& query)
{
// send the query to the database
if (mysql_query(conn, query.c_str()))
{
printf("MySQL query error : %s\n", mysql_error(conn));
exit(1);
}
MYSQL* BaseRepository::setupMysqlConnection() {
MYSQL *conn = mysql_init(nullptr);
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 database::BaseRepository::intitalizeDetails()
{
auto databaseConfig = manager::DirectoryManager::databaseConfigContent(path);
MYSQL_RES* BaseRepository::performMysqlQuery(MYSQL *conn, const std::string& query) {
// send the query to the database
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.password = databaseConfig["password"].get<std::string>();
details.server = databaseConfig["server"].get<std::string>();
details.username = databaseConfig["username"].get<std::string>();
}
void database::BaseRepository::initializeDetails(const model::BinaryPath& bConf)
{
auto databaseConfig = manager::DirectoryManager::databaseConfigContent(bConf);
details.database = databaseConfig["database"].get<std::string>();
details.password = databaseConfig["password"].get<std::string>();
details.server = databaseConfig["server"].get<std::string>();
details.username = databaseConfig["username"].get<std::string>();
}
void BaseRepository::initializeDetails(const model::BinaryPath& bConf)
{
auto databaseConfig = manager::DirectoryManager::databaseConfigContent(bConf);
details.database = databaseConfig["database"].get<std::string>();
details.server = databaseConfig["server"].get<std::string>();
details.username = databaseConfig["username"].get<std::string>();
details.password = databaseConfig["password"].get<std::string>();
details.database = databaseConfig["database"].get<std::string>();
details.server = databaseConfig["server"].get<std::string>();
details.username = databaseConfig["username"].get<std::string>();
details.password = databaseConfig["password"].get<std::string>();
std::cout << "retrieved database details" << std::endl;
std::cout << "retrieved database details\n";
}
}
+254 -302
View File
@@ -6,369 +6,321 @@
#include <string>
#include <cstring>
database::CoverArtRepository::CoverArtRepository(const std::string& path) : BaseRepository(path)
{ }
database::CoverArtRepository::CoverArtRepository(const model::BinaryPath& bConf) : BaseRepository(bConf)
{ }
namespace database {
CoverArtRepository::CoverArtRepository(const model::BinaryPath& bConf) :
BaseRepository(bConf) { }
std::vector<model::Cover> database::CoverArtRepository::retrieveRecords()
{
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM CoverArt";
std::vector<model::Cover> CoverArtRepository::retrieveRecords() {
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM CoverArt";
mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt);
mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt);
auto coverArts = parseRecords(stmt);
auto coverArts = parseRecords(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
mysql_stmt_close(stmt);
mysql_close(conn);
return coverArts;
}
model::Cover database::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;
return coverArts;
}
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();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
qry << "SELECT * FROM CoverArt WHERE ";
auto covDb = parseRecord(stmt);
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "retrieved cover art record" << std::endl;
auto songTitleLength = cov.songTitle.size();
switch (filter) {
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 database::CoverArtRepository::doesCoverArtExist(const model::Cover& cover, type::CoverFilter filter)
{
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << " LIMIT 1";
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
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);
std::stringstream qry;
qry << "SELECT * FROM CoverArt WHERE ";
auto covDb = parseRecord(stmt);
auto titleLength = cover.songTitle.size();
switch (filter) {
case type::CoverFilter::id:
qry << "CoverArtId = ?";
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "retrieved cover art record\n";
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;
return covDb;
}
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);
bool CoverArtRepository::doesCoverArtExist(const model::Cover& cover,
type::CoverFilter filter) {
auto conn = setupMysqlConnection();
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);
auto rowCount = mysql_stmt_num_rows(stmt);
std::stringstream qry;
qry << "SELECT * FROM CoverArt WHERE ";
mysql_stmt_close(stmt);
mysql_close(conn);
auto titleLength = cover.songTitle.size();
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 database::CoverArtRepository::deleteRecord(const model::Cover& cov)
{
auto conn = setupMysqlConnection();
const std::string query("DELETE FROM CoverArt WHERE CoverArtId = " + std::to_string(cov.id));
void CoverArtRepository::deleteRecord(const model::Cover& cov,
type::CoverFilter filter) {
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
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 database::CoverArtRepository::saveRecord(const model::Cover& cov)
{
std::cout << "saving cover art record";
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&cov.id;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
MYSQL_BIND params[2];
memset(params, 0, sizeof(params));
my_bool isNull;
const auto query = qry.str();
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;
params[0].buffer = (char*)cov.songTitle.c_str();
auto songTitleLength = cov.songTitle.size();
params[0].length = &songTitleLength;
params[0].is_null = 0;
std::cout << "deleted CoverArt record\n";
}
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)cov.imagePath.c_str();
auto imagePathLength = cov.imagePath.size();
params[1].length = &imagePathLength;
params[1].is_null = 0;
void CoverArtRepository::saveRecord(const model::Cover& cov) {
std::cout << "saving cover art record";
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
MYSQL_BIND params[2];
memset(params, 0, sizeof(params));
my_bool isNull;
mysql_stmt_close(stmt);
mysql_close(conn);
const std::string query = "INSERT INTO CoverArt(SongTitle, ImagePath) VALUES(?, ?)";
std::cout << "saved cover art record" << std::endl;
}
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
void database::CoverArtRepository::updateRecord(const model::Cover& cover)
{
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)cov.songTitle.c_str();
auto songTitleLength = cov.songTitle.size();
params[0].length = &songTitleLength;
params[0].is_null = 0;
qry << "UPDATE CoverArt SET ";
qry << "SongTitle = ?, ";
qry << "ImagePath = ? ";
qry << "WHERE CoverArtId = ?";
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)cov.imagePath.c_str();
auto imagePathLength = cov.imagePath.size();
params[1].length = &imagePathLength;
params[1].is_null = 0;
MYSQL_BIND params[3];
memset(params, 0, sizeof(params));
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
auto songTitleLength = cover.songTitle.size();
auto imagePathLength = cover.imagePath.size();
mysql_stmt_close(stmt);
mysql_close(conn);
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)cover.songTitle.c_str();
params[0].length = &songTitleLength;
params[0].is_null = 0;
std::cout << "saved cover art record\n";
}
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)cover.imagePath.c_str();
params[1].length = &imagePathLength;
params[1].is_null = 0;
void CoverArtRepository::updateRecord(const model::Cover& cover) {
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
params[2].buffer_type = MYSQL_TYPE_LONG;
params[2].buffer = (char*)&cover.id;
params[2].length = 0;
params[2].is_null = 0;
qry << "UPDATE CoverArt SET ";
qry << "SongTitle = ?, ";
qry << "ImagePath = ? ";
qry << "WHERE CoverArtId = ?";
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_BIND params[3];
memset(params, 0, sizeof(params));
mysql_stmt_close(stmt);
mysql_close(conn);
auto songTitleLength = cover.songTitle.size();
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> database::CoverArtRepository::parseRecords(MYSQL_STMT *stmt)
{
mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt);
std::cout << "number of results " << rowCount << std::endl;
std::vector<model::Cover> CoverArtRepository::parseRecords(MYSQL_STMT *stmt) {
mysql_stmt_store_result(stmt);
const auto rowCount = mysql_stmt_num_rows(stmt);
std::cout << "number of results " << rowCount << "\n";
std::vector<model::Cover> coverArts;
coverArts.reserve(rowCount);
std::vector<model::Cover> coverArts;
coverArts.reserve(rowCount);
const auto valAmt = 3;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
constexpr auto valAmt = 3;
for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
if (mysql_stmt_field_count(stmt) > 0) {
model::Cover coverArt;
auto res = mysql_stmt_result_metadata(stmt);
auto fields = mysql_fetch_fields(res);
auto strLen = 1024;
for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
if (mysql_stmt_field_count(stmt) > 0) {
model::Cover cover;
auto metaBuff = metadataBuffer();
auto bindedValues = valueBind(cover, metaBuff);
status = mysql_stmt_bind_result(stmt, bindedValues.get());
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*)&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;
std::cout << "fetching statement result\n";
status = mysql_stmt_fetch(stmt);
if (status == 1 || status == MYSQL_NO_DATA) {
break;
}
if (status == 1 || status == MYSQL_NO_DATA) break;
coverArt.songTitle = songTitle;
coverArt.imagePath = imagePath;
coverArts.push_back(std::move(coverArt));
cover.songTitle = std::get<0>(metaBuff);
cover.imagePath = std::get<1>(metaBuff);
coverArts.push_back(cover);
}
}
std::cout << "fetching next result" << std::endl;
}
return coverArts;
}
model::Cover database::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 database::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;
std::cout << "fetching next result\n";
}
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;
}
}
+319 -323
View File
@@ -5,355 +5,351 @@
#include <sstream>
#include <cstring>
database::GenreRepository::GenreRepository(const model::BinaryPath& bConf)
: BaseRepository(bConf)
{ }
namespace database {
GenreRepository::GenreRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { }
std::vector<model::Genre> database::GenreRepository::retrieveRecords()
{
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Genre";
std::vector<model::Genre> GenreRepository::retrieveRecords() {
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Genre";
mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt);
mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt);
auto genres = parseRecords(stmt);
auto genres = parseRecords(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
mysql_stmt_close(stmt);
mysql_close(conn);
return genres;
}
std::pair<model::Genre, int> database::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;
return genres;
}
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());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
auto gnrWSC = parseRecordWithSongCount(stmt);
switch (filter) {
case type::GenreFilter::id:
qry << "sng.GenreId = ?";
mysql_stmt_close(stmt);
mysql_close(conn);
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;
}
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 database::GenreRepository::retrieveRecord(model::Genre& genre, type::GenreFilter filter)
{
// TODO: change to prepared statement
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
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::stringstream qry;
auto conn = setupMysqlConnection();
qry << "SELECT gnr.* FROM Genre gnr WHERE ";
std::shared_ptr<MYSQL_BIND> GenreRepository::valueBindWithSongCount(model::Genre& genre,
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)));
std::unique_ptr<char*> param;
switch (filter) {
case type::GenreFilter::id:
qry << "gnr.GenreId = " << genre.id;
break;
case type::GenreFilter::category:
param = std::make_unique<char*>(new char[genre.category.size()]);
mysql_real_escape_string(conn, *param, genre.category.c_str(), genre.category.size());
qry << "gnr.Category ='" << *param << "'";
break;
default:
break;
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;
values.get()[2].buffer_type = MYSQL_TYPE_LONG;
values.get()[2].buffer = reinterpret_cast<char*>(&songCount);
return values;
}
qry << " ORDER BY GenreId DESC LIMIT 1";
const auto query = qry.str();
auto results = performMysqlQuery(conn, query);
std::tuple<char*> GenreRepository::metadataBuffer() {
constexpr auto wordLen = 1024;
char category[wordLen];
genre = parseRecord(results);
mysql_close(conn);
std::cout << "retrieved record" << std::endl;
return genre;
}
bool database::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;
return std::make_tuple(category);
}
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);
model::Genre GenreRepository::parseRecord(MYSQL_STMT *stmt) {
std::cout << "parsing genre record\n";
mysql_stmt_store_result(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 database::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 database::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> database::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;
model::Genre genre;
auto metaBuff = metadataBuffer();
auto bindedValues = valueBind(genre, metaBuff);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt);
if (status == 0) {
gnr.category = category;
genres.push_back(std::move(gnr));
}
genre.category = std::get<0>(metaBuff);
std::cout << "done parsing genre record\n";
return genre;
}
return genres;
}
std::pair<model::Genre, int> database::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 database::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 database::GenreRepository::parseRecord(MYSQL_STMT *stmt)
{
// TODO: implement this
model::Genre genre;
return genre;
}
File diff suppressed because it is too large Load Diff
+263 -265
View File
@@ -7,351 +7,349 @@
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,
type::UserFilter filter = type::UserFilter::username)
{
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
model::User UserRepository::retrieveUserRecord(model::User& user,
type::UserFilter filter = type::UserFilter::username) {
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT * FROM User WHERE ";
qry << "SELECT * FROM User WHERE ";
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
auto userLength = user.username.size();
switch (filter) {
case type::UserFilter::id:
break;
case type::UserFilter::username:
qry << "Username = ?";
auto userLength = user.username.size();
switch (filter) {
case type::UserFilter::id:
qry << "UserId = ?";
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;
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&user.id;
params[0].length = nullptr;
params[0].is_null = 0;
break;
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;
}
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();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
qry << "SELECT * FROM Salt WHERE ";
user = parseRecord(stmt);
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
mysql_stmt_close(stmt);
mysql_close(conn);
switch (filter) {
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)
{
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << " LIMIT 1";
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];
std::memset(params, 0, sizeof(params));
userSec = parseSaltRecord(stmt);
switch (filter) {
case type::SaltFilter::userId:
qry << "UserId = ?";
mysql_stmt_close(stmt);
mysql_close(conn);
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;
return userSec;
}
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);
bool UserRepository::doesUserRecordExist(const model::User& user, type::UserFilter filter) {
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
userSec = parseSaltRecord(stmt);
qry << "SELECT * FROM User WHERE ";
mysql_stmt_close(stmt);
mysql_close(conn);
MYSQL_BIND params[1];
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)
{
std::stringstream qry;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << " LIMIT 1";
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];
std::memset(params, 0, sizeof(params));
mysql_stmt_store_result(stmt);
const auto rowCount = mysql_stmt_num_rows(stmt);
auto userLength = user.username.size();
switch (filter) {
case type::UserFilter::username:
qry << "Username = ?";
mysql_stmt_close(stmt);
mysql_close(conn);
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;
return (rowCount > 0) ? true : false;
}
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);
void UserRepository::saveUserRecord(const model::User& user) {
std::cout << "inserting user record\n";
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
mysql_stmt_store_result(stmt);
const auto rowCount = mysql_stmt_num_rows(stmt);
std::stringstream qry;
qry << "INSERT INTO User(Firstname, Lastname, Phone, Email, Username, Password) ";
qry << "VALUES(?, ?, ?, ?, ?, ?)";
mysql_stmt_close(stmt);
mysql_close(conn);
const auto query = qry.str();
auto sizes = fetchUserLengths(user);
auto params = insertUserValues(user, sizes);
return (rowCount > 0) ? true : false;
}
void UserRepository::saveUserRecord(const model::User& user)
{
std::cout << "inserting user record" << std::endl;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params.get());
status = mysql_stmt_execute(stmt);
std::stringstream qry;
qry << "INSERT INTO User(Firstname, Lastname, Phone, Email, Username, Password) ";
qry << "VALUES(?, ?, ?, ?, ?, ?)";
mysql_stmt_close(stmt);
mysql_close(conn);
}
const auto query = qry.str();
void UserRepository::saveUserSalt(const model::PassSec& userSec) {
std::cout << "inserting user salt record\n";
auto sizes = fetchUserLengths(user);
auto params = insertUserValues(user, sizes);
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params.get());
status = mysql_stmt_execute(stmt);
std::stringstream qry;
qry << "INSERT INTO Salt(Salt, UserId) VALUES(?,?)";
mysql_stmt_close(stmt);
mysql_close(conn);
}
const auto query = qry.str();
void UserRepository::saveUserSalt(const model::PassSec& userSec)
{
std::cout << "inserting user salt record" << std::endl;
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
auto sizes = fetchSaltLengths(userSec);
auto values = insertSaltValues(userSec, sizes);
std::stringstream qry;
qry << "INSERT INTO Salt(Salt, UserId) VALUES(?,?)";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, values.get());
status = mysql_stmt_execute(stmt);
const auto query = qry.str();
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);
}
mysql_stmt_close(stmt);
mysql_close(conn);
}
std::shared_ptr<MYSQL_BIND> UserRepository::insertUserValues(const model::User& user,
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> UserRepository::insertUserValues(const model::User& user,
std::shared_ptr<UserRepository::UserLengths> lengths) {
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 = (char*)user.firstname.c_str();
values.get()[0].length = &(lengths->firstnameLength);
values.get()[0].is_null = 0;
values.get()[0].buffer_type = MYSQL_TYPE_STRING;
values.get()[0].buffer = (char*)user.firstname.c_str();
values.get()[0].length = &(lengths->firstnameLength);
values.get()[0].is_null = 0;
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = (char*)user.lastname.c_str();
values.get()[1].length = &(lengths->lastnameLength);
values.get()[1].is_null = 0;
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = (char*)user.lastname.c_str();
values.get()[1].length = &(lengths->lastnameLength);
values.get()[1].is_null = 0;
values.get()[2].buffer_type = MYSQL_TYPE_STRING;
values.get()[2].buffer = (char*)user.phone.c_str();
values.get()[2].length = &(lengths->phoneLength);
values.get()[2].is_null = 0;
values.get()[2].buffer_type = MYSQL_TYPE_STRING;
values.get()[2].buffer = (char*)user.phone.c_str();
values.get()[2].length = &(lengths->phoneLength);
values.get()[2].is_null = 0;
values.get()[3].buffer_type = MYSQL_TYPE_STRING;
values.get()[3].buffer = (char*)user.email.c_str();
values.get()[3].length = &(lengths->emailLength);
values.get()[3].is_null = 0;
values.get()[3].buffer_type = MYSQL_TYPE_STRING;
values.get()[3].buffer = (char*)user.email.c_str();
values.get()[3].length = &(lengths->emailLength);
values.get()[3].is_null = 0;
values.get()[4].buffer_type = MYSQL_TYPE_STRING;
values.get()[4].buffer = (char*)user.username.c_str();
values.get()[4].length = &(lengths->usernameLength);
values.get()[4].is_null = 0;
values.get()[4].buffer_type = MYSQL_TYPE_STRING;
values.get()[4].buffer = (char*)user.username.c_str();
values.get()[4].length = &(lengths->usernameLength);
values.get()[4].is_null = 0;
values.get()[5].buffer_type = MYSQL_TYPE_STRING;
values.get()[5].buffer = (char*)user.password.c_str();
values.get()[5].length = &(lengths->passwordLength);
values.get()[5].is_null = 0;
values.get()[5].buffer_type = MYSQL_TYPE_STRING;
values.get()[5].buffer = (char*)user.password.c_str();
values.get()[5].length = &(lengths->passwordLength);
values.get()[5].is_null = 0;
return values;
}
return values;
}
std::shared_ptr<MYSQL_BIND> UserRepository::insertSaltValues(const model::PassSec& passSec,
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> UserRepository::insertSaltValues(const model::PassSec& passSec,
std::shared_ptr<UserRepository::SaltLengths> lengths) {
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 = (char*)passSec.hashPassword.c_str();
values.get()[0].length = &(lengths->saltLength);
values.get()[0].buffer_type = MYSQL_TYPE_STRING;
values.get()[0].buffer = (char*)passSec.hashPassword.c_str();
values.get()[0].length = &(lengths->saltLength);
values.get()[1].buffer_type = MYSQL_TYPE_LONG;
values.get()[1].buffer = (char*)&passSec.userId;
values.get()[1].buffer_type = MYSQL_TYPE_LONG;
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,
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;
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = (char*)&user.id;
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = (char*)&user.id;
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
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()[1].buffer = (char*)std::get<0>(us);
values.get()[1].buffer_length = strLen;
values.get()[2].buffer_type = MYSQL_TYPE_STRING;
values.get()[2].buffer = (char*)std::get<1>(us);
values.get()[2].buffer_length = strLen;
values.get()[2].buffer_type = MYSQL_TYPE_STRING;
values.get()[2].buffer = (char*)std::get<1>(us);
values.get()[2].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()[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 = (char*)std::get<3>(us);
values.get()[4].buffer_length = strLen;
values.get()[4].buffer_type = MYSQL_TYPE_STRING;
values.get()[4].buffer = (char*)std::get<3>(us);
values.get()[4].buffer_length = strLen;
values.get()[5].buffer_type = MYSQL_TYPE_STRING;
values.get()[5].buffer = (char*)std::get<4>(us);
values.get()[5].buffer_length = strLen;
values.get()[5].buffer_type = MYSQL_TYPE_STRING;
values.get()[5].buffer = (char*)std::get<4>(us);
values.get()[5].buffer_length = strLen;
values.get()[6].buffer_type = MYSQL_TYPE_STRING;
values.get()[6].buffer = (char*)std::get<5>(us);
values.get()[6].buffer_length = strLen;
values.get()[6].buffer_type = MYSQL_TYPE_STRING;
values.get()[6].buffer = (char*)std::get<5>(us);
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> values((MYSQL_BIND*) std::calloc(3, sizeof(MYSQL_BIND)));
constexpr auto strLen = 1024;
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)));
constexpr auto strLen = 1024;
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = (char*)&userSalt.id;
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = (char*)&userSalt.id;
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = (char*)salt;
values.get()[1].buffer_length = strLen;
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = (char*)salt;
values.get()[1].buffer_length = strLen;
values.get()[2].buffer_type = MYSQL_TYPE_LONG;
values.get()[2].buffer = (char*)&userSalt.userId;
values.get()[2].buffer_type = MYSQL_TYPE_LONG;
values.get()[2].buffer = (char*)&userSalt.userId;
return values;
}
return values;
}
std::shared_ptr<UserRepository::UserLengths> UserRepository::fetchUserLengths(const model::User& user)
{
auto userLen = std::make_shared<UserLengths>();
userLen->firstnameLength = user.firstname.size();
userLen->lastnameLength = user.lastname.size();
userLen->phoneLength = user.phone.size();
userLen->emailLength = user.email.size();
userLen->usernameLength = user.username.size();
userLen->passwordLength = user.password.size();
std::shared_ptr<UserRepository::UserLengths> UserRepository::fetchUserLengths(
const model::User& user) {
auto userLen = std::make_shared<UserLengths>();
userLen->firstnameLength = user.firstname.size();
userLen->lastnameLength = user.lastname.size();
userLen->phoneLength = user.phone.size();
userLen->emailLength = user.email.size();
userLen->usernameLength = user.username.size();
userLen->passwordLength = user.password.size();
return userLen;
}
return userLen;
}
std::shared_ptr<UserRepository::SaltLengths> UserRepository::fetchSaltLengths(const model::PassSec& passSec)
{
auto saltLen = std::make_shared<SaltLengths>();
saltLen->saltLength = passSec.salt.size();
std::shared_ptr<UserRepository::SaltLengths> UserRepository::fetchSaltLengths(
const model::PassSec& passSec) {
auto saltLen = std::make_shared<SaltLengths>();
saltLen->saltLength = passSec.salt.size();
return saltLen;
}
return saltLen;
}
std::tuple<char*, char*, char*, char*, char*, char*> UserRepository::fetchUV()
{
char firstname[1024];
char lastname[1024];
char phone[1024];
char email[1024];
char username[1024];
char password[1024];
std::tuple<char*, char*, char*, char*, char*, char*> UserRepository::fetchUV() {
char firstname[1024];
char lastname[1024];
char phone[1024];
char email[1024];
char username[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 user;
auto usv = fetchUV();
model::User UserRepository::parseRecord(MYSQL_STMT *stmt) {
model::User user;
auto usv = fetchUV();
auto bindedValues = valueBind(user, usv);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt);
auto bindedValues = valueBind(user, usv);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt);
user.firstname = std::get<0>(usv);
user.lastname = std::get<1>(usv);
user.email = std::get<2>(usv);
user.phone = std::get<3>(usv);
user.username = std::get<4>(usv);
user.password = std::get<5>(usv);
user.firstname = std::get<0>(usv);
user.lastname = std::get<1>(usv);
user.email = std::get<2>(usv);
user.phone = std::get<3>(usv);
user.username = std::get<4>(usv);
user.password = std::get<5>(usv);
return user;
}
model::PassSec UserRepository::parseSaltRecord(MYSQL_STMT* stmt)
{
model::PassSec userSalt;
char saltKey[1024];
auto bindedValues = saltValueBind(userSalt, saltKey);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt);
userSalt.salt = saltKey;
return userSalt;
}
return user;
}
model::PassSec UserRepository::parseSaltRecord(MYSQL_STMT* stmt) {
model::PassSec userSalt;
char saltKey[1024];
auto bindedValues = saltValueBind(userSalt, saltKey);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt);
userSalt.salt = saltKey;
return userSalt;
}
}
+272 -272
View File
@@ -6,337 +6,337 @@
#include <string>
#include <cstring>
database::YearRepository::YearRepository(const model::BinaryPath& bConf)
: BaseRepository(bConf)
{ }
namespace database {
YearRepository::YearRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { }
std::vector<model::Year> database::YearRepository::retrieveRecords()
{
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Year";
std::vector<model::Year> YearRepository::retrieveRecords() {
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Year";
mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt);
mysql_stmt_prepare(stmt, query.c_str(), query.size());
mysql_stmt_execute(stmt);
auto yearRecs = parseRecords(stmt);
auto yearRecs = parseRecords(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
mysql_stmt_close(stmt);
mysql_close(conn);
return yearRecs;
}
std::pair<model::Year, int> database::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;
return yearRecs;
}
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());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
auto yearWSC = parseRecordWithSongCount(stmt);
switch (filter) {
case type::YearFilter::id:
qry << "sng.YearId = ?";
mysql_stmt_close(stmt);
mysql_close(conn);
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;
}
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 database::YearRepository::retrieveRecord(model::Year& year, type::YearFilter filter)
{
// TODO: switch to prepared statements
std::cout << "retrieving year record" << std::endl;
std::stringstream qry;
auto conn = setupMysqlConnection();
qry << "SELECT yr.* FROM Year yr WHERE ";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
switch (filter) {
case type::YearFilter::id:
qry << "yr.YearId = " << year.id;
break;
case type::YearFilter::year:
qry << "yr.Year = " << year.year;
break;
default:
break;
auto yearWSC = parseRecordWithSongCount(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "retrieved year record with song count\n";
return yearWSC;
}
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();
auto results = performMysqlQuery(conn, query);
MYSQL_BIND params[1];
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 database::YearRepository::doesYearExist(const model::Year& year, type::YearFilter filter)
{
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
const auto query = qry.str();
std::stringstream qry;
qry << "SELECT * FROM Year WHERE ";
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];
memset(params, 0, sizeof(params));
year = parseRecord(stmt);
switch (filter) {
case type::YearFilter::id:
qry << "YearId = ?";
mysql_stmt_close(stmt);
mysql_close(conn);
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 = ?";
std::cout << "retrieved record\n";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&year.year;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
return year;
}
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);
bool YearRepository::doesYearExist(const model::Year& year, type::YearFilter filter) {
auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
std::cout << "the query has been performed" << std::endl;
std::stringstream qry;
qry << "SELECT * FROM Year WHERE ";
mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt);
MYSQL_BIND params[1];
memset(params, 0, sizeof(params));
mysql_stmt_close(stmt);
mysql_close(conn);
switch (filter) {
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 database::YearRepository::saveRecord(const model::Year& year)
{
std::cout << "saving year record" << std::endl;
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&year.year;
params[0].length = 0;
params[0].is_null = 0;
break;
default:
break;
}
auto conn = setupMysqlConnection();
MYSQL_STMT *stmt = mysql_stmt_init(conn);
qry << " LIMIT 1";
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];
memset(params, 0 , sizeof(params));
mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt);
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&year.year;
params[0].length = 0;
params[0].is_null = 0;
mysql_stmt_close(stmt);
mysql_close(conn);
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt);
mysql_close(conn);
std::cout << "saved record" << std::endl;
}
void database::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;
return (rowCount > 0) ? true : false;
}
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);
void YearRepository::saveRecord(const model::Year& year) {
std::cout << "saving year record\n";
mysql_stmt_close(stmt);
mysql_close(conn);
auto conn = setupMysqlConnection();
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> database::YearRepository::parseRecords(MYSQL_STMT *stmt)
{
mysql_stmt_store_result(stmt);
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
std::vector<model::Year> yearRecs;
yearRecs.reserve(mysql_stmt_num_rows(stmt));
MYSQL_BIND params[1];
memset(params, 0 , sizeof(params));
if (mysql_stmt_field_count(stmt) == 0) {
std::cout << "field count is 0" << std::endl;
return yearRecs;
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&year.year;
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;
const auto valAmt = 2;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
void YearRepository::deleteYear(const model::Year& year,
type::YearFilter filter) {
std::cout << "deleting year record\n";
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];
memset(val, 0, sizeof(val));
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&yearRec.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
switch (filter) {
case type::YearFilter::id:
qry << "YearId = ?";
val[1].buffer_type = MYSQL_TYPE_LONG;
val[1].buffer = (char*)&yearRec.year;
val[1].length = &len[1];
val[1].is_null = &nullRes[1];
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;
}
for (auto status = mysql_stmt_bind_result(stmt, val); status == 0;) {
std::cout << "fetching statement result" << std::endl;
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 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);
if (status == 0) {
yearRecs.push_back(std::move(yearRec));
}
std::cout << "done parsing year record\n";
return year;
}
return yearRecs;
}
std::pair<model::Year, int> database::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 database::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 database::YearRepository::parseRecord(MYSQL_STMT *stmt)
{
// TODO: imeplement this
// I really thought that I had already done this
model::Year year;
return year;
}
+35 -2
View File
@@ -1,8 +1,8 @@
#include "dto/conversion/DtoConversions.h"
namespace dto { namespace conversion {
dto::LoginResultDto::ObjectWrapper DtoConversions::toLoginResultDto(const model::User& user,
const model::Token& token) {
LoginResultDto::ObjectWrapper DtoConversions::toLoginResultDto(const model::User& user,
const model::Token& token) {
auto logRes = dto::LoginResultDto::createShared();
logRes->username = user.username.c_str();
logRes->token = token.accessToken.c_str();
@@ -24,16 +24,49 @@ namespace dto { namespace conversion {
}
dto::AlbumDto::ObjectWrapper DtoConversions::toAlbumDto(const model::Album& album) {
auto result = dto::AlbumDto::createShared();
result->id = (album.id != 0) ? album.id : 0;
result->title = (!album.title.empty()) ? album.title.c_str() : "";
result->artist = (!album.artist.empty()) ? album.artist.c_str() : "";
result->year = (album.year != 0) ? album.year : 0;
return result;
}
dto::SongDto::ObjectWrapper DtoConversions::toSongDto(const model::Song& song) {
auto result = dto::SongDto::createShared();
result->id = (song.id != 0) ? song.id : 0;
result->title = (!song.title.empty()) ? song.title.c_str() : "";
result->album = (!song.album.empty()) ? song.album.c_str() : "";
result->artist = (!song.artist.empty()) ? song.artist.c_str() : "";
result->album_artist = (!song.albumArtist.empty()) ? song.albumArtist.c_str() : "";
result->genre = (!song.genre.empty()) ? song.genre.c_str() : "";
result->duration = (song.duration != 0) ? song.duration : 0;
result->year = (song.year != 0) ? song.year : 0;
result->track = (song.track != 0) ? song.track : 0;
result->disc = (song.disc != 0) ? song.disc : 0;
result->coverart_id = (song.coverArtId != 0) ? song.coverArtId : 0;
return result;
}
model::Song DtoConversions::toSong(dto::SongDto::ObjectWrapper& songDto) {
model::Song song;
song.id = (songDto->id.getPtr() == nullptr) ? 0 : songDto->id->getValue();
song.title = (songDto->title == nullptr) ? "" : songDto->title->c_str();
song.album = (songDto->album == nullptr) ? "" : songDto->album->c_str();
song.artist = (songDto->artist == nullptr) ? "" : songDto->artist->c_str();
song.albumArtist = (songDto->album_artist == nullptr) ?
"" : songDto->album_artist->c_str();
song.genre = (songDto->genre == nullptr) ? "" : songDto->genre->c_str();
song.year = (songDto->year.getPtr() == nullptr) ? 0 : songDto->year->getValue();
song.track = (songDto->track.getPtr() == nullptr) ? 0 : songDto->track->getValue();
song.disc = (songDto->disc.getPtr() == nullptr) ? 0 : songDto->disc->getValue();
song.coverArtId = (songDto->coverart_id.getPtr() == nullptr) ?
0 : songDto->coverart_id->getValue();
return song;
}
+47 -56
View File
@@ -6,76 +6,67 @@
#include "model/Models.h"
#include "type/AlbumFilter.h"
manager::AlbumManager::AlbumManager(const model::BinaryPath& bConf)
: m_bConf(bConf)
{ }
namespace manager {
AlbumManager::AlbumManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
model::Album manager::AlbumManager::retrieveAlbum(model::Album& album)
{
database::AlbumRepository albRepo(m_bConf);
album = std::move(albRepo.retrieveRecord(album, type::AlbumFilter::title));
model::Album AlbumManager::retrieveAlbum(model::Album& album) {
database::AlbumRepository albRepo(m_bConf);
album = std::move(albRepo.retrieveRecord(album, type::AlbumFilter::title));
return album;
}
return album;
}
model::Album manager::AlbumManager::saveAlbum(const model::Song& song)
{
model::Album album;
album.title = song.album;
album.year = song.year;
model::Album AlbumManager::saveAlbum(const model::Song& song) {
model::Album album(song);
database::AlbumRepository albRepo(m_bConf);
if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) {
albRepo.saveAlbum(album);
} else {
std::cout << "album record already exists in the database" << std::endl;
database::AlbumRepository albRepo(m_bConf);
// TODO: check for existence with the title and the artist
if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) {
albRepo.saveAlbum(album);
} else {
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);
void manager::AlbumManager::deleteAlbum(const model::Song& song)
{
model::Album album(song);
database::AlbumRepository albRepo(m_bConf);
auto albWSC = albRepo.retrieveRecordWithSongCount(album, type::AlbumFilter::id);
database::AlbumRepository albRepo(m_bConf);
auto albWSC = albRepo.retrieveRecordWithSongCount(album, type::AlbumFilter::id);
if (albWSC.second > 1) {
std::cout << "album still contain songs related to it, will not delete" << std::endl;
return;
if (albWSC.second > 1) {
std::cout << "album still contain songs related to it, will not delete\n";
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;
albRepo.deleteAlbum(album, type::AlbumFilter::id);
}
void AlbumManager::updateAlbum(model::Song& updatedSong,
const model::Song& currSong) {
model::Album album(updatedSong);
void manager::AlbumManager::updateAlbum(model::Song& updatedSong,
const model::Song& currSong)
{
model::Album album;
album.title = updatedSong.album;
album.year = updatedSong.year;
database::AlbumRepository albRepo(m_bConf);
if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) {
std::cout << "album record does not exist\n";
albRepo.saveAlbum(album);
} else {
std::cout << "album record already exists\n";
}
database::AlbumRepository albRepo(m_bConf);
if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) {
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);
updatedSong.albumId = album.id;
}
album = albRepo.retrieveRecord(album, type::AlbumFilter::title);
updatedSong.albumId = album.id;
}
void manager::AlbumManager::printAlbum(const model::Album& album)
{
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;
void AlbumManager::printAlbum(const model::Album& album) {
std::cout << "\nalbum record\n";
std::cout << "id: " << album.id << "\n";
std::cout << "title: " << album.title << "\n";
std::cout << "year: " << album.year << "\n";
}
}
+53 -57
View File
@@ -5,76 +5,72 @@
#include "database/ArtistRepository.h"
#include "type/ArtistFilter.h"
manager::ArtistManager::ArtistManager(const model::BinaryPath& bConf)
: m_bConf(bConf)
{ }
namespace manager {
ArtistManager::ArtistManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
model::Artist manager::ArtistManager::retrieveArtist(model::Artist& artist)
{
std::cout << "retrieving artist record" << std::endl;
database::ArtistRepository artRepo(m_bConf);
std::cout << "initialized artist repo" << std::endl;
std::cout << artist.artist << std::endl;
artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist);
model::Artist ArtistManager::retrieveArtist(model::Artist& artist) {
std::cout << "retrieving artist record\n";
database::ArtistRepository artRepo(m_bConf);
std::cout << "initialized artist repo\n";
std::cout << artist.artist << "\n";
artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist);
return artist;
}
model::Artist manager::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;
}
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 manager::ArtistManager::deleteArtist(const model::Song& song)
{
model::Artist artist(song);
void ArtistManager::deleteArtist(const model::Song& song) {
model::Artist artist(song);
database::ArtistRepository artRepo(m_bConf);
auto artWSC = artRepo.retrieveRecordWithSongCount(artist, type::ArtistFilter::id);
database::ArtistRepository artRepo(m_bConf);
auto artWSC = artRepo.retrieveRecordWithSongCount(artist, type::ArtistFilter::id);
if (artWSC.second > 1) {
std::cout << "artist still contain songs related to it";
std::cout << ", not delete" << std::endl;
return;
if (artWSC.second > 1) {
std::cout << "artist still contain songs related to it";
std::cout << ", not delete\n";
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;
artRepo.deleteArtist(artist, type::ArtistFilter::id);
}
void ArtistManager::updateArtist(model::Song& updatedSong,
const model::Song& currSong) {
model::Artist artist;
artist.artist = updatedSong.artist;
void manager::ArtistManager::updateArtist(model::Song& updatedSong,
const model::Song& currSong)
{
model::Artist artist;
artist.artist = updatedSong.artist;
database::ArtistRepository artRepo(m_bConf);
if (!artRepo.doesArtistExist(artist, type::ArtistFilter::artist)) {
std::cout << "artist record does not exist\n";
artRepo.saveRecord(artist);
} else {
std::cout << "artist record already exists\n";
}
database::ArtistRepository artRepo(m_bConf);
if (!artRepo.doesArtistExist(artist, type::ArtistFilter::artist)) {
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);
updatedSong.artistId = artist.id;
}
artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist);
updatedSong.artistId = artist.id;
}
void manager::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;
void ArtistManager::printArtist(const model::Artist& artist) {
std::cout << "\nartist record" << "\n";
std::cout << "id: " << artist.id << "\n";
std::cout << "artist: " << artist.artist << "\n";
}
}
+98 -105
View File
@@ -11,132 +11,125 @@
namespace fs = std::filesystem;
manager::CoverArtManager::CoverArtManager(const std::string& configPath) : path(configPath)
{ }
manager::CoverArtManager::CoverArtManager(const model::BinaryPath& bConf) : m_bConf(bConf)
{ }
namespace manager {
CoverArtManager::CoverArtManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
model::Cover manager::CoverArtManager::saveCover(const model::Song& song)
{
auto pathConfigContent = manager::DirectoryManager::pathConfigContent(m_bConf);
auto stockCoverPath = manager::DirectoryManager::configPath(m_bConf);
stockCoverPath.append("/CoverArt.png");
model::Cover CoverArtManager::saveCover(const model::Song& song) {
auto pathConfigContent = DirectoryManager::pathConfigContent(m_bConf);
auto stockCoverPath = DirectoryManager::configPath(m_bConf);
stockCoverPath.append("/CoverArt.png");
utility::MetadataRetriever meta;
model::Cover cov;
cov.songTitle = song.title;
utility::MetadataRetriever meta;
model::Cover cov;
cov.songTitle = song.title;
if (meta.songContainsCoverArt(song)) {
cov.imagePath = createImagePath(song);
cov = meta.applyCoverArt(song, cov);
} else {
cov.imagePath = pathConfigContent["cover_root_path"].get<std::string>();
cov = meta.applyStockCoverArt(song, cov, stockCoverPath);
if (meta.songContainsCoverArt(song)) {
cov.imagePath = createImagePath(song);
cov = meta.applyCoverArt(song, cov);
} else {
cov.imagePath = pathConfigContent["cover_root_path"].get<std::string>();
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::cout << "saving image record to the database" << std::endl;
covRepo.saveRecord(cov);
} else {
std::cout << "cover art record already exists" << std::endl;
std::pair<bool, std::string> CoverArtManager::defaultCover(
const model::Cover& cover) {
auto paths = DirectoryManager::pathConfigContent(m_bConf);
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> manager::CoverArtManager::defaultCover(
const model::Cover& cover) {
cov = covRepo.retrieveRecord(cov, type::CoverFilter::id);
covRepo.deleteRecord(cov);
auto paths = manager::DirectoryManager::pathConfigContent(m_bConf);
const auto coverArtPath =
paths[manager::DirectoryManager::retrievePathType(
type::PathType::coverArt)].get<std::string>();
auto result = defaultCover(cov);
if (!result.first) {
fs::remove(cov.imagePath);
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;
stockCoverArtPath.append("CoverArt.png");
if (stockCoverArtPath.compare(cover.imagePath) == 0) {
return std::make_pair(true, coverArtPath);
} else {
return std::make_pair(false, coverArtPath);
}
}
void manager::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);
}
manager::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 manager::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);
auto result = defaultCover(cover);
auto result = defaultCover(cover);
if (result.first) {
return;
}
if (result.first) {
return;
auto imagePath = createImagePath(updatedSong);
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);
fs::remove(cover.imagePath);
manager::DirectoryManager::deleteDirectories(currSong, result.second);
}
void manager::CoverArtManager::updateCoverRecord(const model::Song& updatedSong)
{
model::Cover updatedCover(updatedSong);
auto updatedImagePath = createImagePath(updatedSong);
database::CoverArtRepository covRepo(m_bConf);
covRepo.updateRecord(updatedCover);
}
std::string manager::CoverArtManager::createImagePath(const model::Song& song)
{
auto imagePath = manager::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);
database::CoverArtRepository covRepo(m_bConf);
covRepo.updateRecord(updatedCover);
}
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;
}
}
+202 -152
View File
@@ -7,186 +7,236 @@
namespace fs = std::filesystem;
namespace manager {
std::string DirectoryManager::createDirectoryProcess(const model::Song& song,
const std::string& rootPath) {
auto currPath = fs::path(rootPath);
std::string manager::DirectoryManager::createDirectoryProcess(model::Song song, const std::string& rootPath)
{
auto currPath = fs::path(rootPath);
if (fs::exists(currPath)) {
std::cout << "path exists\n";
} else {
std::cout << "creating path\n";
fs::create_directory(currPath);
}
if (fs::exists(currPath)) {
std::cout << "path exists" << std::endl;
} else {
std::cout << "creating path" << std::endl;
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.albumArtist);
if (fs::exists(albPath)) {
std::cout << "album path exists\n";
} else {
std::cout << "creating album path\n";
fs::create_directory(albPath);
}
auto discPath = DirectoryManager().relativeDiscSongPathFilesystem(albPath, song);
if (fs::exists(discPath)) {
std::cout << "disc path exists\n";
} else {
std::cout << "creating disc path\n";
fs::create_directory(discPath);
}
return discPath.string() + "/";
}
auto artPath = fs::path(currPath.string() + song.artist);
if (fs::exists(artPath)) {
std::cout << "artist path exists" << std::endl;
} else {
std::cout << "creating artist path" << std::endl;
fs::create_directory(artPath);
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\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);
}
auto discPath = DirectoryManager().relativeDiscSongPathFilesystem(albPath, song);
if (fs::exists(discPath)) {
std::cout << "disc path exists\n";
} else {
std::cout << "creating disc path\n";
fs::create_directory(discPath);
}
return discPath.string() + "/";
}
auto albPath = fs::path(artPath.string() + "/" + song.album);
if (fs::exists(albPath)) {
std::cout << "album path exists" << std::endl;
} else {
std::cout << "creating album path" << std::endl;
fs::create_directory(albPath);
std::string DirectoryManager::configPath(std::string_view path) {
return fs::canonical(path).parent_path().string();
}
return albPath.string() + "/";
}
std::string manager::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);
std::string DirectoryManager::configPath(const model::BinaryPath& bConf) {
return fs::canonical(bConf.path).parent_path().string();
}
auto artPath = fs::path(currPath.string() + song.artist);
if (fs::exists(artPath)) {
std::cout << "artist path exists" << std::endl;
} else {
std::cout << "creating artist path" << std::endl;
fs::create_directory(artPath);
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();
}
auto albPath = fs::path(artPath.string() + "/" + song.album);
if (fs::exists(albPath)) {
std::cout << "album path exists" << std::endl;
} else {
std::cout << "creating album path" << std::endl;
fs::create_directory(albPath);
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;
}
return albPath.string() + "/";
}
std::string manager::DirectoryManager::configPath(std::string_view path)
{
return fs::canonical(path).parent_path().string();
}
nlohmann::json DirectoryManager::credentialConfigContent(const model::BinaryPath& bConf) {
auto path = configPath(bConf);
path.append("/authcredentials.json");
std::string manager::DirectoryManager::configPath(const model::BinaryPath& bConf)
{
return fs::canonical(bConf.path).parent_path().string();
}
std::string manager::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 manager::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 nlohmann::json::parse(contentOfPath(path));
}
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 manager::DirectoryManager::credentialConfigContent(const model::BinaryPath& bConf)
{
auto path = configPath(bConf);
path.append("/authcredentials.json");
void DirectoryManager::deleteDirectories(model::Song song, const std::string& rootPath) {
std::cout << "checking for empty directories to delete\n";
const std::string art(rootPath + std::string("/") + song.albumArtist);
const std::string alb(art + "/" + song.album);
const std::string disc(alb + "/" + std::to_string(song.disc) + "/");
return nlohmann::json::parse(contentOfPath(path));
}
auto discPath = fs::path(disc);
nlohmann::json manager::DirectoryManager::databaseConfigContent(const model::BinaryPath& bConf)
{
auto path = configPath(bConf);
path.append("/database.json");
if (fs::exists(discPath)) {
std::cout << "disc directory does not exist\n";
} else if (fs::is_empty(discPath)) {
fs::remove(discPath);
}
return nlohmann::json::parse(contentOfPath(path));
}
nlohmann::json manager::DirectoryManager::pathConfigContent(const model::BinaryPath& bConf)
{
auto path = configPath(bConf);
path.append("/paths.json");
return nlohmann::json::parse(contentOfPath(path));
}
void manager::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.artist);
const std::string alb(art + "/" + song.album);
auto albPath = fs::path(alb);
auto albPath = fs::path(alb);
if (!fs::exists(albPath)) {
std::cout << "directory does not exists" << std::endl;
} else if (fs::is_empty(albPath)) {
fs::remove(albPath);
}
if (!fs::exists(albPath)) {
std::cout << "directory does not exists\n";
} else if (fs::is_empty(albPath)) {
fs::remove(albPath);
}
auto artPath = fs::path(art);
auto artPath = fs::path(art);
if (!fs::exists(artPath)) {
std::cout << "directory does not exists" << std::endl;
return;
} else if (fs::is_empty(artPath)) {
fs::remove(artPath);
if (!fs::exists(artPath)) {
std::cout << "directory does not exists\n";
return;
} else if (fs::is_empty(artPath)) {
fs::remove(artPath);
}
std::cout << "deleted empty directory or directories\n";
}
std::cout << "deleted empty directory or directories" << std::endl;
}
void manager::DirectoryManager::deleteCoverArtFile(const std::string& covPath, const std::string& stockCoverPath)
{
if (covPath.compare(stockCoverPath) == 0) {
std::cout << "cover has stock cover art, will not deleted" << std::endl;
} else {
std::cout << "deleting song path" << std::endl;
auto cov = fs::path(covPath);
fs::remove(cov);
}
}
void manager::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;
void DirectoryManager::deleteCoverArtFile(const std::string& covPath,
const std::string& stockCoverPath) {
if (covPath.compare(stockCoverPath) == 0) {
std::cout << "cover has stock cover art, will not deleted\n";
} else {
std::cout << "deleting song path\n";
auto cov = fs::path(covPath);
fs::remove(cov);
}
}
fs::remove(songPath);
std::cout << "deleted song" << std::endl;
}
fs::path DirectoryManager::relativeDiscSongPathFilesystem(const fs::path& albPath,
const model::Song& song) {
std::string albPathStr(albPath.string() + "/disc");
if (song.disc >= 10) {
albPathStr.append(std::to_string(song.disc));
} else {
albPathStr.append("0");
albPathStr.append(std::to_string(song.disc));
}
albPathStr.append("/");
auto relPath = fs::path(albPathStr.c_str());
return relPath;
}
std::string DirectoryManager::relativeDiscSongPath(const fs::path& albPath,
const model::Song& song) {
std::string albPathStr(albPath.string() + "/disc");
if (song.disc >= 10) {
albPathStr.append(std::to_string(song.disc));
} else {
albPathStr.append("0");
albPathStr.append(std::to_string(song.disc));
}
albPathStr.append("/");
return albPathStr;
}
void DirectoryManager::deleteSong(const model::Song song) {
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";
}
}
+51 -56
View File
@@ -5,73 +5,68 @@
#include "database/GenreRepository.h"
#include "type/GenreFilter.h"
manager::GenreManager::GenreManager(const model::BinaryPath& bConf)
: m_bConf(bConf)
{ }
namespace manager {
GenreManager::GenreManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
model::Genre manager::GenreManager::retrieveGenre(model::Genre& genre)
{
database::GenreRepository gnrRepo(m_bConf);
genre = gnrRepo.retrieveRecord(genre, type::GenreFilter::category);
model::Genre GenreManager::retrieveGenre(model::Genre& genre) {
database::GenreRepository gnrRepo(m_bConf);
genre = gnrRepo.retrieveRecord(genre, type::GenreFilter::category);
return genre;
}
model::Genre manager::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;
}
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";
}
void manager::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;
return genre;
}
std::cout << "safe to delete the genre record" << std::endl;
gnrRepo.deleteRecord(genre, type::GenreFilter::id);
}
void manager::GenreManager::updateGenre(model::Song& updatedSong,
const model::Song& currSong)
{
model::Genre genre;
genre.category = updatedSong.genre;
void GenreManager::deleteGenre(const model::Song& song) {
model::Genre genre(song);
database::GenreRepository gnrRepo(m_bConf);
if (!gnrRepo.doesGenreExist(genre, type::GenreFilter::category)) {
std::cout << "genre record does not exist" << std::endl;
gnrRepo.saveRecord(genre);
} else {
std::cout << "genre record already exists" << std::endl;
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\n";
return;
}
std::cout << "safe to delete the genre record\n";
gnrRepo.deleteRecord(genre, type::GenreFilter::id);
}
genre = gnrRepo.retrieveRecord(genre, type::GenreFilter::category);
updatedSong.genreId = genre.id;
}
void GenreManager::updateGenre(model::Song& updatedSong,
const model::Song& currSong) {
model::Genre genre;
genre.category = updatedSong.genre;
void manager::GenreManager::printGenre(const model::Genre& genre)
{
std::cout << "genre record" << std::endl;
std::cout << "id: " << genre.id << std::endl;
std::cout << "category: " << genre.category << std::endl;
database::GenreRepository gnrRepo(m_bConf);
if (!gnrRepo.doesGenreExist(genre, type::GenreFilter::category)) {
std::cout << "genre record does not exist\n";
gnrRepo.saveRecord(genre);
} 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";
}
}
+368 -393
View File
@@ -5,7 +5,7 @@
#include <random>
#include <nlohmann/json.hpp>
#include "oatpp/web/protocol/http/outgoing/ChunkedBody.hpp"
//#include "oatpp/web/protocol/http/outgoing/ChunkedBody.hpp"
#include "oatpp/web/server/api/ApiController.hpp"
#include "database/CoverArtRepository.h"
@@ -21,427 +21,402 @@
namespace fs = std::filesystem;
manager::SongManager::SongManager(std::string& x_path)
: exe_path(x_path)
{ }
manager::SongManager::SongManager(const model::BinaryPath& bConf)
: m_bConf(bConf)
{ }
namespace manager {
SongManager::SongManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
bool manager::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;
std::pair<bool, type::SongUpload> SongManager::saveSong(model::Song& song) {
saveSongTemp(song);
utility::MetadataRetriever meta;
auto data = std::move(song.data);
song = meta.retrieveMetadata(song);
song.data = std::move(data);
database::SongRepository songRepo(m_bConf);
if (songRepo.doesSongExist(song, type::SongFilter::titleAlbArtistAlbum)) {
std::cout << "\ntitle: " << song.title << "\nartist: " << song.artist << "\n";
std::cout << "does not exist\n";
return std::make_pair(false, type::SongUpload::AlreadyExist);
}
saveMisc(song);
printSong(song);
songRepo.saveRecord(song);
song = songRepo.retrieveRecord(song, type::SongFilter::titleAlbArtistAlbum);
return std::make_pair(true, type::SongUpload::Successful);
}
return false;
}
bool manager::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;
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;
}
return false;
}
return false;
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;
}
void manager::SongManager::saveSong(model::Song& song)
{
saveSongTemp(song);
utility::MetadataRetriever meta;
auto data = std::move(song.data);
song = meta.retrieveMetadata(song.songPath);
song.data = std::move(data);
std::string SongManager::createSongPath(const model::Song& song) {
auto songPath = DirectoryManager::createDirectoryProcess(
song, m_bConf, type::PathType::music);
saveMisc(song);
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");
printSong(song);
database::SongRepository songRepo(m_bConf);
songRepo.saveRecord(song);
}
void manager::SongManager::deleteSong(model::Song& song)
{
database::SongRepository songRepo(m_bConf);
if (!songRepo.doesSongExist(song, type::SongFilter::id)) {
std::cout << "song does not exist" << std::endl;
return;
return songPath;
}
song = songRepo.retrieveRecord(song, type::SongFilter::id);
auto paths = manager::DirectoryManager::pathConfigContent(m_bConf);
// 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\n";
updatedSong.track = currSong.track;
for (auto scIter = songChanges.begin(); scIter != songChanges.end(); ++scIter) {
type::SongChanged key = scIter->first;
bool changed = songChanges.at(key);
auto deleted = songRepo.deleteRecord(song);
if (!deleted) {
std::cout << "song not deleted from databases" << std::endl;
return;
}
deleteMisc(song);
fs::remove(song.songPath);
manager::DirectoryManager::deleteDirectories(song, paths["root_music_path"].get<std::string>());
}
void manager::SongManager::updateSong(model::Song& updatedSong)
{
database::SongRepository songRepo(m_bConf);
model::Song currSong(updatedSong.id);
OATPP_ASSERT_HTTP(songRepo.doesSongExist(currSong, type::SongFilter::id) , oatpp::web::protocol::http::Status::CODE_404, "song does not exist");
currSong = songRepo.retrieveRecord(currSong, type::SongFilter::id);
if (!didSongChange(updatedSong, currSong)) {
std::cout << "no change to the song" << std::endl;
return;
}
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);
}
model::Song manager::SongManager::songDtoConv(dto::SongDto::ObjectWrapper& songDto)
{
std::cout << "coverting dto::SongDto to model::Song" << std::endl;
model::Song song;
song.id = songDto->id;
song.title = (songDto->title == nullptr) ? "" : songDto->title->c_str();
song.album = (songDto->album == nullptr) ? "" : songDto->album->c_str();
song.artist = (songDto->artist == nullptr) ? "" : songDto->artist->c_str();
song.genre = (songDto->genre == nullptr) ? "" : songDto->genre->c_str();
song.year = (songDto->year.getPtr() == nullptr) ? 0 : songDto->year->getValue();
song.track = (songDto->track.getPtr() == nullptr) ? 0 : songDto->track->getValue();
song.disc = (songDto->disc.getPtr() == nullptr) ? 0 : songDto->disc->getValue();
return song;
}
void manager::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: " << 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> manager::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 manager::SongManager::createSongPath(const model::Song& song)
{
auto songPath = manager::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 manager::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;
if (!changed) {
switch (key) {
case type::SongChanged::title:
updatedSong.title = currSong.title;
std::cout << "title has not been changed\n";
break;
case type::SongChanged::artist:
updatedSong.artist = currSong.artist;
std::cout << "artist has not been changed\n";
break;
case type::SongChanged::album:
updatedSong.album = currSong.album;
std::cout << "album has not been changed\n";
break;
case type::SongChanged::genre:
updatedSong.genre = currSong.genre;
std::cout << "genre has not been changed\n";
break;
case::type::SongChanged::year:
updatedSong.year = currSong.year;
std::cout << "year has not been changed\n";
default:
break;
}
}
}
}
}
// used to dump miscellaneous id to the updated song
void manager::SongManager::assignMiscId(model::Song& updatedSong,
const model::Song& currSong)
{
std::cout << "assigning miscellaneous Id's to updated song" << std::endl;
updatedSong.artistId = currSong.artistId;
updatedSong.albumId = currSong.albumId;
updatedSong.genreId = currSong.genreId;
updatedSong.yearId = currSong.yearId;
updatedSong.coverArtId = currSong.coverArtId;
}
// saves song to a temporary path
void manager::SongManager::saveSongTemp(model::Song& song)
{
auto config = manager::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 manager::SongManager::saveMisc(model::Song& song)
{
CoverArtManager covMgr(m_bConf);
auto pathConfigContent = manager::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);
manager::AlbumManager::printAlbum(album);
ArtistManager artMgr(m_bConf);
auto artist = artMgr.saveArtist(song);
artist = artMgr.retrieveArtist(artist);
manager::ArtistManager::printArtist(artist);
GenreManager gnrMgr(m_bConf);
auto genre = gnrMgr.saveGenre(song);
genre = gnrMgr.retrieveGenre(genre);
manager::GenreManager::printGenre(genre);
YearManager yrMgr(m_bConf);
auto year = yrMgr.saveYear(song);
year = yrMgr.retrieveYear(year);
manager::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 manager::SongManager::deleteMisc(const model::Song& song)
{
manager::CoverArtManager covMgr(m_bConf);
covMgr.deleteCover(song);
manager::AlbumManager albMgr(m_bConf);
albMgr.deleteAlbum(song);
manager::ArtistManager artMgr(m_bConf);
artMgr.deleteArtist(song);
manager::GenreManager gnrMgr(m_bConf);
gnrMgr.deleteGenre(song);
manager::YearManager yrMgr(m_bConf);
yrMgr.deleteYear(song);
}
// deletes miscellanes records
void manager::SongManager::deleteMiscExceptCoverArt(const model::Song& song)
{
manager::AlbumManager albMgr(m_bConf);
albMgr.deleteAlbum(song);
manager::ArtistManager artMgr(m_bConf);
artMgr.deleteArtist(song);
manager::GenreManager gnrMgr(m_bConf);
gnrMgr.deleteGenre(song);
manager::YearManager yrMgr(m_bConf);
yrMgr.deleteYear(song);
}
void manager::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) {
manager::ArtistManager artMgr(m_bConf);
artMgr.updateArtist(updatedSong, currSong);
}
if (albumChange) {
manager::AlbumManager albMgr(m_bConf);
albMgr.updateAlbum(updatedSong, currSong);
}
if (genreChange) {
manager::GenreManager gnrMgr(m_bConf);
gnrMgr.updateGenre(updatedSong, currSong);
}
if (yearChange) {
manager::YearManager yrMgr(m_bConf);
yrMgr.updateYear(updatedSong, currSong);
// used to dump miscellaneous id to the updated song
void SongManager::assignMiscId(model::Song& updatedSong,
const model::Song& currSong) {
std::cout << "assigning miscellaneous Id's to updated song\n";
updatedSong.artistId = currSong.artistId;
updatedSong.albumId = currSong.albumId;
updatedSong.genreId = currSong.genreId;
updatedSong.yearId = currSong.yearId;
updatedSong.coverArtId = currSong.coverArtId;
}
// determins to update the cover art record
if (titleChange || artistChange || albumChange) {
manager::CoverArtManager covMgr(m_bConf);
covMgr.updateCoverRecord(updatedSong);
// 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;
}
database::SongRepository songRepo(m_bConf);
songRepo.updateRecord(updatedSong);
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>();
deleteMiscExceptCoverArt(currSong);
}
auto cov = covMgr.saveCover(song);
const auto songPath = createSongPath(song);
void manager::SongManager::modifySongOnFilesystem(model::Song& updatedSong,
const model::Song& currSong)
{
std::cout << "preparing to modify song" << std::endl;
auto songPath = createSongPath(updatedSong);
updatedSong.songPath = std::move(songPath);
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 << "\n";
std::cout << songPath << "\n";
fs::copy(song.songPath, songPath);
fs::remove(song.songPath);
song.songPath = std::move(songPath);
std::cout << "copied song to the appropriate directory\n";
std::cout << "new path " << updatedSong.songPath << std::endl;
AlbumManager albMgr(m_bConf);
auto album = albMgr.saveAlbum(song);
album = albMgr.retrieveAlbum(album);
AlbumManager::printAlbum(album);
fs::copy(currSong.songPath, updatedSong.songPath);
fs::remove(currSong.songPath);
ArtistManager artMgr(m_bConf);
auto artist = artMgr.saveArtist(song);
artist = artMgr.retrieveArtist(artist);
ArtistManager::printArtist(artist);
auto paths = manager::DirectoryManager::pathConfigContent(m_bConf);
const auto musicRootPath =
paths[manager::DirectoryManager::retrievePathType(
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";
}
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
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>();
manager::DirectoryManager::deleteDirectories(currSong, musicRootPath);
DirectoryManager::deleteDirectories(currSong, musicRootPath);
manager::CoverArtManager covMgr(m_bConf);
covMgr.updateCover(updatedSong, currSong);
CoverArtManager covMgr(m_bConf);
covMgr.updateCover(updatedSong, currSong);
}
}
+128 -160
View File
@@ -14,191 +14,159 @@
namespace fs = std::filesystem;
namespace manager {
TokenManager::TokenManager()
{
}
model::Token TokenManager::retrieveToken(const model::BinaryPath& bConf) {
auto cred = parseAuthCredentials(bConf);
auto reqObj = createTokenBody(cred);
std::string uri{cred.uri};
uri.append("/");
uri.append(cred.endpoint);
model::Token TokenManager::retrieveToken(const model::BinaryPath& bConf)
{
auto cred = parseAuthCredentials(bConf);
auto reqObj = createTokenBody(cred);
auto r = sendRequest(uri, reqObj);
auto postRes = nlohmann::json::parse(r.text);
std::string uri{cred.uri};
uri.append("/");
uri.append(cred.endpoint);
model::Token lr(std::move(postRes["access_token"].get<std::string>()),
std::move(postRes["token_type"].get<std::string>()),
postRes["expires_in"].get<int>());
auto r = sendRequest(uri, reqObj);
auto postRes = nlohmann::json::parse(r.text);
model::Token lr(std::move(postRes["access_token"].get<std::string>()),
std::move(postRes["token_type"].get<std::string>()),
postRes["expires_in"].get<int>());
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);
return lr;
}
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) {
case type::Scope::upload:
return tokenSupportsScope(scopes, "upload:songs");
case type::Scope::download:
return tokenSupportsScope(scopes, "download:songs");
case type::Scope::stream:
return tokenSupportsScope(scopes, "stream:songs");
case type::Scope::deleteSong:
return tokenSupportsScope(scopes, "delete:songs");
case type::Scope::updateSong:
return tokenSupportsScope(scopes, "update:songs");
case type::Scope::retrieveSong:
return tokenSupportsScope(scopes, "read:song_details");
case type::Scope::retrieveAlbum:
return tokenSupportsScope(scopes, "read:albums");
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 std::get<0>(authPair);
}
auto authHeader = std::get<1>(authPair);
auto token = authHeader.at(authHeader.size()-1);
auto scopes = extractScopes(jwt::decode(token));
switch (scope) {
case type::Scope::upload:
return tokenSupportsScope(scopes, "upload:songs");
case type::Scope::download:
return tokenSupportsScope(scopes, "download:songs");
case type::Scope::stream:
return tokenSupportsScope(scopes, "stream:songs");
case type::Scope::deleteSong:
return tokenSupportsScope(scopes, "delete:songs");
case type::Scope::updateSong:
return tokenSupportsScope(scopes, "update:songs");
case type::Scope::retrieveSong:
return tokenSupportsScope(scopes, "read:song_details");
case type::Scope::retrieveAlbum:
return tokenSupportsScope(scopes, "read:albums");
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)
{
auto cred = parseAuthCredentials(bConf);
auto reqObj = createTokenBody(cred);
std::string uri(cred.uri);
uri.append("/");
uri.append(cred.endpoint);
std::string uri(cred.uri);
uri.append("/");
uri.append(cred.endpoint);
auto response = sendRequest(uri, reqObj);
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)
{
auto resp = cpr::Post(cpr::Url{uri}, cpr::Body{obj.dump()},
cpr::Response TokenManager::sendRequest(std::string_view uri, nlohmann::json& obj) {
auto resp = cpr::Post(cpr::Url{uri}, cpr::Body{obj.dump()},
cpr::Header{{"Content-type", "application/json"},
{"Connection", "keep-alive"}});
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;
}
[[depreacted("use the other function with the same name")]]
model::AuthCredentials TokenManager::parseAuthCredentials(std::string_view path)
{
auto exe_path = DirectoryManager::configPath(path);
exe_path.append("/authcredentials.json");
auto con = DirectoryManager::credentialConfigContent(exe_path);
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;
}
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 resp;
}
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>()
};
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";
bool foundBearer = false;
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 obj;
}
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,
const std::string&& scope)
{
return std::any_of(scopes.begin(), scopes.end(),
[&](std::string_view foundScope) {
return (foundScope.compare(scope) == 0);
});
}
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\n";
std::string allScopes(d.second.to_json().get<std::string>());
std::istringstream iss(allScopes);
scopes.assign(std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>());
}
}
return scopes;
}
std::pair<bool, std::vector<std::string>> TokenManager::fetchAuthHeader(const std::string& auth) {
std::istringstream iss(auth);
std::vector<std::string> authHeader{std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>()
};
bool foundBearer = false;
if (std::any_of(authHeader.begin(), authHeader.end(),
[&](std::string_view word) {
return (word.compare("Bearer") == 0); })) {
std::cout << "Bearer found\n";
foundBearer = true;
}
return std::make_pair(foundBearer, authHeader);
}
bool TokenManager::tokenSupportsScope(const std::vector<std::string>& scopes,
const std::string&& scope) {
return std::any_of(scopes.begin(), scopes.end(),
[&](std::string_view foundScope) {
return (foundScope.compare(scope) == 0);
});
}
}
+48 -48
View File
@@ -7,70 +7,70 @@
#include "utility/PasswordEncryption.h"
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 result;
result.username = user.username;
printUser(user);
model::RegisterResult UserManager::registerUser(model::User& user) {
model::RegisterResult result;
result.username = user.username;
printUser(user);
utility::PasswordEncryption passEnc;
auto hashed = passEnc.hashPassword(user);
user.password = hashed.hashPassword;
utility::PasswordEncryption passEnc;
auto hashed = passEnc.hashPassword(user);
user.password = hashed.hashPassword;
database::UserRepository usrRepo(m_bConf);
usrRepo.saveUserRecord(user);
database::UserRepository usrRepo(m_bConf);
usrRepo.saveUserRecord(user);
model::User usr;
usr.username = user.username;
model::User usr;
usr.username = user.username;
std::cout << usr.username << std::endl;
usr = usrRepo.retrieveUserRecord(usr, type::UserFilter::username);
hashed.hashPassword = usr.password;
hashed.userId = usr.id;
std::cout << usr.username << "\n";
usr = usrRepo.retrieveUserRecord(usr, type::UserFilter::username);
hashed.hashPassword = usr.password;
hashed.userId = usr.id;
usrRepo.saveUserSalt(hashed);
result.registered = true;
result.message = "successfully registered";
printUser(usr);
usrRepo.saveUserSalt(hashed);
result.registered = true;
result.message = "successfully registered";
printUser(usr);
return result;
}
return result;
}
bool UserManager::doesUserExist(const model::User& user) {
database::UserRepository userRepo(m_bConf);
bool UserManager::doesUserExist(const model::User& user) {
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) {
database::UserRepository userRepo(m_bConf);
model::User usr;
usr.username = user.username;
usr = userRepo.retrieveUserRecord(usr, type::UserFilter::username);
bool UserManager::validatePassword(const model::User& user) {
database::UserRepository userRepo(m_bConf);
model::User usr;
usr.username = user.username;
usr = userRepo.retrieveUserRecord(usr, type::UserFilter::username);
model::PassSec userSec;
userSec.userId = usr.id;
userSec = userRepo.retrieverUserSaltRecord(userSec, type::SaltFilter::userId);
userSec.hashPassword = usr.password;
model::PassSec userSec;
userSec.userId = usr.id;
userSec = userRepo.retrieverUserSaltRecord(userSec, type::SaltFilter::userId);
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) {
std::cout << "\nuser info" << std::endl;
std::cout << "id: " << user.id << std::endl;
std::cout << "firstname: " << user.firstname << std::endl;
std::cout << "lastname: " << user.lastname << std::endl;
std::cout << "phone: " << user.phone << std::endl;
std::cout << "email: " << user.email << std::endl;
std::cout << "username: " << user.username << std::endl;
std::cout << "password: " << user.password<< std::endl;
}
void UserManager::printUser(const model::User& user) {
std::cout << "\nuser info\n";
std::cout << "id: " << user.id << "\n";
std::cout << "firstname: " << user.firstname << "\n";
std::cout << "lastname: " << user.lastname << "\n";
std::cout << "phone: " << user.phone << "\n";
std::cout << "email: " << user.email << "\n";
std::cout << "username: " << user.username << "\n";
std::cout << "password: " << user.password<< "\n";
}
}
+49 -54
View File
@@ -5,72 +5,67 @@
#include "database/YearRepository.h"
#include "type/YearFilter.h"
manager::YearManager::YearManager(const model::BinaryPath& bConf)
: m_bConf(bConf)
{ }
namespace manager {
YearManager::YearManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
model::Year manager::YearManager::retrieveYear(model::Year& year)
{
database::YearRepository yearRepo(m_bConf);
year = yearRepo.retrieveRecord(year, type::YearFilter::year);
model::Year YearManager::retrieveYear(model::Year& year) {
database::YearRepository yearRepo(m_bConf);
year = yearRepo.retrieveRecord(year, type::YearFilter::year);
return year;
}
model::Year manager::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;
}
return year;
}
model::Year YearManager::saveYear(const model::Song& song) {
model::Year year;
year.year = song.year;
void manager::YearManager::deleteYear(const model::Song& song)
{
model::Year year(song);
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\n";
}
database::YearRepository yrRepo(m_bConf);
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;
return year;
}
std::cout << "safe to delete the year record" << std::endl;
yrRepo.deleteYear(year, type::YearFilter::id);
}
void YearManager::deleteYear(const model::Song& song) {
model::Year year(song);
void manager::YearManager::updateYear(model::Song& updatedSong,
const model::Song& currSong)
{
model::Year year;
year.year = updatedSong.year;
database::YearRepository yrRepo(m_bConf);
auto yrWSC = yrRepo.retrieveRecordWithSongCount(year, type::YearFilter::id);
database::YearRepository albRepo(m_bConf);
if (!albRepo.doesYearExist(year, type::YearFilter::year)) {
std::cout << "year record does not exist" << std::endl;
albRepo.saveRecord(year);
} else {
std::cout << "year record already exists" << std::endl;
if (yrWSC.second > 1) {
std::cout << "year still contain songs related to it";
std::cout << ", will not delete\n";
return;
}
std::cout << "safe to delete the year record\n";
yrRepo.deleteYear(year, type::YearFilter::id);
}
year = albRepo.retrieveRecord(year, type::YearFilter::year);
updatedSong.yearId = year.id;
}
void YearManager::updateYear(model::Song& updatedSong,
const model::Song& currSong) {
model::Year year;
year.year = updatedSong.year;
void manager::YearManager::printYear(const model::Year& year)
{
std::cout << "\nyear record" << std::endl;
std::cout << "id: " << year.id << std::endl;
std::cout << "year: " << year.year << std::endl;
database::YearRepository albRepo(m_bConf);
if (!albRepo.doesYearExist(year, type::YearFilter::year)) {
std::cout << "year record does not exist\n";
albRepo.saveRecord(year);
} 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";
}
}
+5 -6
View File
@@ -1,10 +1,9 @@
#include "utility/ImageFile.h"
utility::ImageFile::ImageFile(const char *file) : TagLib::File(file)
{
}
namespace utility {
ImageFile::ImageFile(const char *file) : TagLib::File(file) { }
TagLib::ByteVector utility::ImageFile::data()
{
return readBlock(length());
TagLib::ByteVector ImageFile::data() {
return readBlock(length());
}
}
+169 -149
View File
@@ -6,10 +6,6 @@
#include <sstream>
#include <string.h>
#include <attachedpictureframe.h>
#include <fileref.h>
#include <mpegfile.h>
#include <tag.h>
#include "manager/DirectoryManager.h"
#include "utility/ImageFile.h"
@@ -17,161 +13,185 @@
namespace fs = std::filesystem;
model::Song utility::MetadataRetriever::retrieveMetadata(std::string& songPath)
{
TagLib::FileRef file(songPath.c_str());
model::Song song;
song.title = file.tag()->title().toCString();
song.artist = file.tag()->artist().toCString();
song.album = file.tag()->album().toCString();
song.genre = file.tag()->genre().toCString();
song.year = file.tag()->year();
song.track = file.tag()->track();
song.duration = file.audioProperties()->lengthInSeconds();
song.songPath = songPath;
namespace utility {
model::Song MetadataRetriever::retrieveMetadata(model::Song& song) {
TagLib::MPEG::File sameFile(song.songPath.c_str());
auto tag = sameFile.ID3v2Tag();
song.title = tag->title().toCString(true);
song.artist = tag->artist().toCString(true);
song.album = tag->album().toCString(true);
song.genre = tag->genre().toCString(true);
song.year = tag->year();
song.track = tag->track();
// TODO: Move over to this eventually since at the moment
// I am only targetting mp3 files
// Used to retrieve disc
TagLib::MPEG::File sameFile(songPath.c_str());
auto tag = sameFile.ID3v2Tag();
song.duration = sameFile.audioProperties()->lengthInSeconds();
auto frame = tag->frameList("TPOS");
if (frame.isEmpty()) {
song.disc = 1;
// TODO: set default disc to 1 if none found
} else {
song.disc = std::stoi(frame.front()->toString().toCString());
constexpr auto id3DiscName = "TPOS";
constexpr auto id3AlbumArtistName = "TPE2";
auto discFrame = tag->frameList(id3DiscName);
auto albumArtistFrame = tag->frameList(id3AlbumArtistName);
if (discFrame.isEmpty()) {
constexpr auto discDefaultVal = "1";
TagLib::ID3v2::TextIdentificationFrame *emptyFrame =
new TagLib::ID3v2::TextIdentificationFrame(id3DiscName);
tag->addFrame(emptyFrame);
emptyFrame->setText(discDefaultVal);
song.disc = std::atoi(discDefaultVal);
sameFile.save();
} else {
song.disc = std::stoi(discFrame.front()->toString().toCString());
}
if (albumArtistFrame.isEmpty()) {
TagLib::ID3v2::TextIdentificationFrame *emptyFrame =
new TagLib::ID3v2::TextIdentificationFrame(id3AlbumArtistName);
tag->addFrame(emptyFrame);
emptyFrame->setText(song.artist.c_str());
sameFile.save();
} else {
song.albumArtist = albumArtistFrame.front()->toString().toCString(true);
}
return song;
}
model::Cover MetadataRetriever::updateCoverArt(const model::Song& song, model::Cover& cov,
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\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\n";
} 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 utility::MetadataRetriever::updateCoverArt(const model::Song& song, model::Cover& cov, 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 !frameList.isEmpty();
}
return cov;
}
// tags song with the stock cover art
model::Cover utility::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();
utility::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 utility::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 utility::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 utility::MetadataRetriever::updateMetadata(model::Song& sngUpdated, const model::Song& sngOld)
{
std::cout<<"updating metadata"<<std::endl;
TagLib::FileRef file(sngOld.songPath.c_str());
void MetadataRetriever::updateMetadata(model::Song& sngUpdated, const model::Song& sngOld) {
std::cout << "updating metadata\n";
TagLib::MPEG::File file(sngOld.songPath.c_str());
auto tag = file.ID3v2Tag();
if (sngUpdated.title.size() > 0) {
file.tag()->setTitle(sngUpdated.title);
}
if (sngUpdated.artist.size() > 0) {
file.tag()->setArtist(sngUpdated.artist);
}
if (sngUpdated.album.size() > 0) {
file.tag()->setAlbum(sngUpdated.album);
}
if (sngUpdated.genre.size() > 0) {
file.tag()->setGenre(sngUpdated.genre);
}
if (sngUpdated.year > 0) {
file.tag()->setYear(sngUpdated.year);
}
if (sngUpdated.title.size() > 0) {
file.tag()->setTitle(sngUpdated.title);
}
if (sngUpdated.artist.size() > 0) {
file.tag()->setArtist(sngUpdated.artist);
}
if (sngUpdated.albumArtist.size() > 0) {
constexpr auto frameId = "TPE2";
auto albumArtistFrame = tag->frameList(frameId);
if (albumArtistFrame.isEmpty()) {
TagLib::ID3v2::TextIdentificationFrame *frame =
new TagLib::ID3v2::TextIdentificationFrame(frameId);
frame->setText(sngUpdated.albumArtist.c_str());
tag->addFrame(frame);
} else {
albumArtistFrame.front()->setText(sngUpdated.albumArtist.c_str());
}
// TODO: functionality to update the track number and disc number
file.save();
}
if (sngUpdated.album.size() > 0) {
file.tag()->setAlbum(sngUpdated.album);
}
if (sngUpdated.genre.size() > 0) {
file.tag()->setGenre(sngUpdated.genre);
}
if (sngUpdated.year > 0) {
file.tag()->setYear(sngUpdated.year);
}
file.save();
// TODO: functionality to update the track number and disc number
file.save();
}
}
+27 -33
View File
@@ -7,42 +7,36 @@
namespace utility {
model::PassSec PasswordEncryption::hashPassword(const model::User& user)
{
model::PassSec passSec;
model::PassSec PasswordEncryption::hashPassword(const model::User& user) {
model::PassSec passSec;
std::unique_ptr<char[]> salt(new char[BCRYPT_HASHSIZE]);
std::unique_ptr<char[]> hash(new char[BCRYPT_HASHSIZE]);
std::unique_ptr<char[]> salt(new char[BCRYPT_HASHSIZE]);
std::unique_ptr<char[]> hash(new char[BCRYPT_HASHSIZE]);
std::cout << "generating salt" << std::endl;
bcrypt_gensalt(saltSize(), salt.get());
std::cout << "hashing password" << std::endl;
bcrypt_hashpw(user.password.c_str(), salt.get(), hash.get());
std::cout << "generating salt\n";
bcrypt_gensalt(saltSize(), salt.get());
std::cout << "hashing password\n";
bcrypt_hashpw(user.password.c_str(), salt.get(), hash.get());
passSec.salt = salt.get();
passSec.hashPassword = hash.get();
passSec.salt = salt.get();
passSec.hashPassword = hash.get();
std::cout << "hash: " << passSec.hashPassword << std::endl;
std::cout << "salt: " << passSec.salt << std::endl;
std::cout << "hash: " << passSec.hashPassword << "\n";
std::cout << "salt: " << passSec.salt << "\n";
return passSec;
}
bool PasswordEncryption::isPasswordValid(const model::User& user, const model::PassSec& userSalt)
{
std::unique_ptr<char[]> passwordHashed(new char[BCRYPT_HASHSIZE]);
bcrypt_hashpw(user.password.c_str(), userSalt.salt.c_str(), passwordHashed.get());
return (userSalt.hashPassword.compare(passwordHashed.get()) == 0) ? true : false;
}
int PasswordEncryption::saltSize()
{
constexpr auto size = 10000;
return size;
}
return passSec;
}
bool PasswordEncryption::isPasswordValid(const model::User& user,
const model::PassSec& userSalt) {
std::unique_ptr<char[]> passwordHashed(new char[BCRYPT_HASHSIZE]);
bcrypt_hashpw(user.password.c_str(), userSalt.salt.c_str(), passwordHashed.get());
return (userSalt.hashPassword.compare(passwordHashed.get()) == 0) ? true : false;
}
constexpr int PasswordEncryption::saltSize() noexcept { return 10000; }
}
+66 -81
View File
@@ -11,103 +11,88 @@
namespace fs = std::filesystem;
namespace verify {
bool Initialization::skipVerification(const std::string& argument)
{
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();
bool Initialization::skipVerification(const std::string& argument) {
return argument.compare("--noverify") == 0;
}
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)) {
failedConfirmation();
}
std::cout << "icarus check passed\n";
}
// verifies that the authorization settings are not the default values
bool Initialization::confirmConfigAuth(const model::BinaryPath& bConf)
{
manager::TokenManager tokMgr;
// verifies that the authorization settings are not the default values
bool Initialization::confirmConfigAuth(const model::BinaryPath& bConf) {
manager::TokenManager tokMgr;
return tokMgr.testAuth(bConf);
}
return tokMgr.testAuth(bConf);
}
// verifies if database connectivity can be established
bool Initialization::confirmConfigDatabase(const model::BinaryPath& bConf)
{
database::BaseRepository baseRepo(bConf);
// verifies if database connectivity can be established
bool Initialization::confirmConfigDatabase(const model::BinaryPath& bConf) {
database::BaseRepository baseRepo(bConf);
return baseRepo.testConnection();
}
return baseRepo.testConnection();
}
// verifies if the paths found in the config files exists
bool Initialization::confirmConfigPaths(const model::BinaryPath& bConf)
{
auto pathConfig = manager::DirectoryManager::pathConfigContent(bConf);
// verifies if the paths found in the config files exists
bool Initialization::confirmConfigPaths(const model::BinaryPath& bConf) {
using manager::DirectoryManager;
auto pathConfig = DirectoryManager::pathConfigContent(bConf);
const auto rootMusicPath =
pathConfig
[manager::
DirectoryManager::
retrievePathType
const auto rootMusicPath =
pathConfig
[DirectoryManager::retrievePathType
(type::PathType::music)].get<std::string>();
const auto archiveRootPath =
pathConfig
[manager::
DirectoryManager::
retrievePathType
const auto archiveRootPath =
pathConfig
[DirectoryManager::retrievePathType
(type::PathType::archive)].get<std::string>();
const auto tempRootPath =
pathConfig
[manager::
DirectoryManager::
retrievePathType
const auto tempRootPath =
pathConfig
[DirectoryManager::retrievePathType
(type::PathType::temp)].get<std::string>();
const auto coverRootPath =
pathConfig
[manager::
DirectoryManager::
retrievePathType
const auto coverRootPath =
pathConfig
[DirectoryManager::retrievePathType
(type::PathType::coverArt)].get<std::string>();
if (!fs::exists(rootMusicPath)) {
std::cout << "root music path is not properly configured" << std::endl;
return false;
if (!fs::exists(rootMusicPath)) {
std::cout << "root music path is not properly configured\n";
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)) {
std::cout << "temp root path is not properly configured" << std::endl;
return false;
// confirmation failed
void Initialization::failedConfirmation() {
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);
}
}