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/Scopes.h
include/type/SongChanged.h include/type/SongChanged.h
include/type/SongFilter.h include/type/SongFilter.h
include/type/SongUpload.h
include/type/UserFilter.h include/type/UserFilter.h
include/type/YearFilter.h include/type/YearFilter.h
include/verify/Initialization.h include/verify/Initialization.h
@@ -122,21 +123,23 @@ set(JWT_CPP_INCLUDE
${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/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) include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup() 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/cpr)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/taglib) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/taglib)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/3rdparty/oatpp) 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}/appsettings.json ${CMAKE_BINARY_DIR}/bin/appsettings.json COPYONLY)
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/authcredentials.json ${CMAKE_BINARY_DIR}/bin/authcredentials.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}) add_executable(icarus ${SOURCES} ${HEADERS})
target_include_directories(icarus PUBLIC ${JWT_CPP_INCLUDE}) 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" "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"> <h1 align "center">
<img src="Images/Configuration/configure_api.png" width=100%> <img src="Images/Configuration/configure_api.png" width=100%>
</h1> </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: Prior to starting the API, the database must be created. The following tables are required:
* User * User
* Salt
* Song * Song
* Album * Album
* Artist * 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 git clone --recursive https://github.com/kdeng00/icarus
cd 3rdparty/libbcrypt/ cd 3rdparty/libbcrypt/
make make
cp bcrypt.a libbcrypt.a
cp bcrypt.o libbcrypt.o
cd ../.. cd ../..
mkdir build mkdir build
cd build cd build
conan install .. conan install ..
cmake .. cmake .. -DCMAKE_BUILD_TYPE=RELEASE -DUSE_SYSTEM_CURL=ON -DBUILD_CPR_TESTS=OFF -DOATPP_BUILD_TESTS=OFF
make make
bin/icarus 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. 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 ## Authors
* **Kun Deng** - [amazing-username](https://github.com/amazing-username) * **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 ## License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details 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 ( CREATE TABLE Album (
AlbumId INT NOT NULL AUTO_INCREMENT, AlbumId INT NOT NULL AUTO_INCREMENT,
Title TEXT NOT NULL, Title TEXT NOT NULL,
Artist TEXT NOT NULL,
Year INT NOT NULL, Year INT NOT NULL,
PRIMARY KEY (AlbumId) PRIMARY KEY (AlbumId)
+1 -1
View File
@@ -1,5 +1,5 @@
[requires] [requires]
jsonformoderncpp/3.7.0@vthiery/stable jsonformoderncpp/3.7.3@vthiery/stable
[generators] [generators]
cmake cmake
+5 -4
View File
@@ -4,16 +4,17 @@
#include <string> #include <string>
#include "oatpp/core/data/stream/FileStream.hpp" #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 { namespace callback {
class StreamCallback : public oatpp::data::stream::ReadCallback class StreamCallback : public oatpp::data::stream::ReadCallback {
{
public: public:
StreamCallback(); StreamCallback();
StreamCallback(const std::string&); StreamCallback(const std::string&);
oatpp::data::v_io_size read(void*, oatpp::data::v_io_size); oatpp::v_io_size read(void*, v_buff_size, oatpp::async::Action&);
private: private:
std::string m_songPath; std::string m_songPath;
+10 -7
View File
@@ -9,28 +9,31 @@
#include "oatpp/web/server/HttpConnectionHandler.hpp" #include "oatpp/web/server/HttpConnectionHandler.hpp"
namespace component { namespace component {
class AppComponent {
class AppComponent
{
public: public:
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>, serverConnectionProvider)([] { OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::ServerConnectionProvider>,
return oatpp::network::server::SimpleTCPConnectionProvider::createShared(5002); serverConnectionProvider)([&] {
return oatpp::network::server::SimpleTCPConnectionProvider::
createShared(appPort());
}()); }());
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, httpRouter)([] { OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, httpRouter)([] {
return oatpp::web::server::HttpRouter::createShared(); return oatpp::web::server::HttpRouter::createShared();
}()); }());
OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::server::ConnectionHandler>, serverConnectionHandler)([] { OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::network::server::ConnectionHandler>,
serverConnectionHandler)([] {
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); 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)([] { OATPP_CREATE_COMPONENT(std::shared_ptr<oatpp::data::mapping::ObjectMapper>,
apiObjectMapper)([] {
return oatpp::parser::json::mapping::ObjectMapper::createShared(); return oatpp::parser::json::mapping::ObjectMapper::createShared();
}()); }());
private: private:
constexpr int appPort() noexcept { return 5002; }
}; };
} }
+18 -26
View File
@@ -19,6 +19,7 @@
#include "database/AlbumRepository.h" #include "database/AlbumRepository.h"
#include "dto/AlbumDto.hpp" #include "dto/AlbumDto.hpp"
#include "dto/conversion/DtoConversions.h"
#include "manager/AlbumManager.h" #include "manager/AlbumManager.h"
#include "manager/TokenManager.h" #include "manager/TokenManager.h"
#include "model/Models.h" #include "model/Models.h"
@@ -28,39 +29,32 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class AlbumController : public oatpp::web::server::api::ApiController class AlbumController : public oatpp::web::server::api::ApiController {
{
public: public:
AlbumController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) AlbumController(const model::BinaryPath& bConf,
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) 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 for retrieving all album records in json format
ENDPOINT("GET", "/api/v1/album", albumRecords, ENDPOINT("GET", "/api/v1/album", albumRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) REQUEST(std::shared_ptr<IncomingRequest>, request)) {
{
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveAlbum), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveAlbum), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving album" << std::endl; std::cout << "starting process of retrieving album\n";
database::AlbumRepository albRepo(m_bConf); database::AlbumRepository albRepo(m_bConf);
auto albsDb = albRepo.retrieveRecords(); auto albsDb = albRepo.retrieveRecords();
auto albums = oatpp::data::mapping::type::List<dto::AlbumDto::ObjectWrapper>::createShared(); auto albums = oatpp::data::mapping::type::
List<dto::AlbumDto::ObjectWrapper>::createShared();
for (auto& albDb : albsDb) { for (auto& albDb : albsDb) {
auto alb = dto::AlbumDto::createShared(); auto alb = dto::conversion::DtoConversions::toAlbumDto(albDb);
alb->id = albDb.id;
alb->title = albDb.title.c_str();
alb->year = albDb.year;
albums->pushBack(alb); albums->pushBack(alb);
} }
@@ -75,27 +69,25 @@ public:
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveAlbum), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveAlbum), Status::CODE_403, "Not allowed");
database::AlbumRepository albRepo(m_bConf); database::AlbumRepository albRepo(m_bConf);
model::Album albDb(id); 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" << std::endl; std::cout << "album exists\n";
albDb = albRepo.retrieveRecord(albDb, type::AlbumFilter::id); albDb = albRepo.retrieveRecord(albDb, type::AlbumFilter::id);
auto album = dto::AlbumDto::createShared(); auto album = dto::conversion::DtoConversions::toAlbumDto(albDb);
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) #include OATPP_CODEGEN_END(ApiController)
private: private:
std::string m_exe_path;
model::BinaryPath m_bConf; model::BinaryPath m_bConf;
}; };
} }
+15 -18
View File
@@ -28,33 +28,29 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class ArtistController : public oatpp::web::server::api::ApiController class ArtistController : public oatpp::web::server::api::ApiController {
{
public: public:
ArtistController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) ArtistController(const model::BinaryPath& bConf,
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) 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 for retrieving all artist records in json format
ENDPOINT("GET", "/api/v1/artist", artistRecords, ENDPOINT("GET", "/api/v1/artist", artistRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) REQUEST(std::shared_ptr<IncomingRequest>, request)) {
{
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveArtist), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveArtist), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving artist" << std::endl; std::cout << "starting process of retrieving artist\n";
database::ArtistRepository artRepo(m_bConf); database::ArtistRepository artRepo(m_bConf);
auto artsDb = artRepo.retrieveRecords(); auto artsDb = artRepo.retrieveRecords();
auto artists = oatpp::data::mapping::type::List<dto::ArtistDto::ObjectWrapper>::createShared(); auto artists = oatpp::data::mapping::type::
List<dto::ArtistDto::ObjectWrapper>::createShared();
for (auto& artDb : artsDb) { for (auto& artDb : artsDb) {
auto art = dto::ArtistDto::createShared(); auto art = dto::ArtistDto::createShared();
@@ -74,14 +70,16 @@ public:
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveArtist), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveArtist), Status::CODE_403, "Not allowed");
database::ArtistRepository artRepo(m_bConf); database::ArtistRepository artRepo(m_bConf);
model::Artist artDb(id); 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" << std::endl; std::cout << "artist exist\n";
artDb = artRepo.retrieveRecord(artDb, type::ArtistFilter::id); artDb = artRepo.retrieveRecord(artDb, type::ArtistFilter::id);
auto artist = dto::ArtistDto::createShared(); auto artist = dto::ArtistDto::createShared();
@@ -93,7 +91,6 @@ public:
#include OATPP_CODEGEN_END(ApiController) #include OATPP_CODEGEN_END(ApiController)
private: private:
std::string m_exe_path;
model::BinaryPath m_bConf; model::BinaryPath m_bConf;
}; };
} }
+17 -19
View File
@@ -27,33 +27,29 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class CoverArtController : public oatpp::web::server::api::ApiController class CoverArtController : public oatpp::web::server::api::ApiController {
{
public: public:
CoverArtController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) CoverArtController(const model::BinaryPath& bConf,
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) 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 for retrieving all cover art records in json format
ENDPOINT("GET", "/api/v1/coverart", coverArtRecords, ENDPOINT("GET", "/api/v1/coverart", coverArtRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) REQUEST(std::shared_ptr<IncomingRequest>, request)) {
{
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving cover art" << std::endl; std::cout << "starting process of retrieving cover art\n";
database::CoverArtRepository covRepo(m_bConf); database::CoverArtRepository covRepo(m_bConf);
auto covsDb = covRepo.retrieveRecords(); auto covsDb = covRepo.retrieveRecords();
auto coverArts = oatpp::data::mapping::type::List<dto::CoverArtDto::ObjectWrapper>::createShared(); auto coverArts = oatpp::data::mapping::type::
List<dto::CoverArtDto::ObjectWrapper>::createShared();
for (auto& covDb : covsDb) { for (auto& covDb : covsDb) {
auto cov = dto::CoverArtDto::createShared(); auto cov = dto::CoverArtDto::createShared();
@@ -73,15 +69,17 @@ public:
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed");
database::CoverArtRepository covRepo(m_bConf); database::CoverArtRepository covRepo(m_bConf);
model::Cover covDb; model::Cover covDb;
covDb.id = id; 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" << std::endl; std::cout << "cover art exists\n";
covDb = covRepo.retrieveRecord(covDb, type::CoverFilter::id); covDb = covRepo.retrieveRecord(covDb, type::CoverFilter::id);
auto coverArt = dto::CoverArtDto::createShared(); auto coverArt = dto::CoverArtDto::createShared();
@@ -97,7 +95,8 @@ public:
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::downloadCoverArt), Status::CODE_403, "Not allowed");
database::CoverArtRepository covRepo(m_bConf); database::CoverArtRepository covRepo(m_bConf);
model::Cover covDb; model::Cover covDb;
@@ -114,7 +113,6 @@ public:
#include OATPP_CODEGEN_END(ApiController) #include OATPP_CODEGEN_END(ApiController)
private: private:
std::string m_exe_path;
model::BinaryPath m_bConf; model::BinaryPath m_bConf;
}; };
} }
+15 -18
View File
@@ -28,33 +28,29 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class GenreController : public oatpp::web::server::api::ApiController class GenreController : public oatpp::web::server::api::ApiController {
{
public: public:
GenreController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) GenreController(const model::BinaryPath& bConf,
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) 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 for retrieving all genre records in json format
ENDPOINT("GET", "/api/v1/genre", genreRecords, ENDPOINT("GET", "/api/v1/genre", genreRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) REQUEST(std::shared_ptr<IncomingRequest>, request)) {
{
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveGenre), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveGenre), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving genre" << std::endl; std::cout << "starting process of retrieving genre\n";
database::GenreRepository gnrRepo(m_bConf); database::GenreRepository gnrRepo(m_bConf);
auto gnrsDb = gnrRepo.retrieveRecords(); auto gnrsDb = gnrRepo.retrieveRecords();
auto genres = oatpp::data::mapping::type::List<dto::GenreDto::ObjectWrapper>::createShared(); auto genres = oatpp::data::mapping::type::
List<dto::GenreDto::ObjectWrapper>::createShared();
for (auto& gnrDb : gnrsDb) { for (auto& gnrDb : gnrsDb) {
auto gnr = dto::GenreDto::createShared(); auto gnr = dto::GenreDto::createShared();
@@ -74,14 +70,16 @@ public:
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveGenre), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveGenre), Status::CODE_403, "Not allowed");
database::GenreRepository gnrRepo(m_bConf); database::GenreRepository gnrRepo(m_bConf);
model::Genre gnrDb(id); 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" << std::endl; std::cout << "genre exist\n";
gnrDb = gnrRepo.retrieveRecord(gnrDb, type::GenreFilter::id); gnrDb = gnrRepo.retrieveRecord(gnrDb, type::GenreFilter::id);
auto genre = dto::GenreDto::createShared(); auto genre = dto::GenreDto::createShared();
@@ -93,7 +91,6 @@ public:
#include OATPP_CODEGEN_END(ApiController) #include OATPP_CODEGEN_END(ApiController)
private: private:
std::string m_exe_path;
model::BinaryPath m_bConf; model::BinaryPath m_bConf;
}; };
} }
+5 -9
View File
@@ -18,12 +18,9 @@
namespace controller { namespace controller {
class LoginController : public oatpp::web::server::api::ApiController { class LoginController : public oatpp::web::server::api::ApiController {
public: public:
LoginController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) LoginController(const model::BinaryPath& bConf,
: oatpp::web::server::api::ApiController(objectMapper), exe_path(p) OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
{ } :oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) { }
LoginController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
:oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf)
{ }
#include OATPP_CODEGEN_BEGIN(ApiController) #include OATPP_CODEGEN_BEGIN(ApiController)
@@ -37,11 +34,11 @@ public:
if (!usrMgr.doesUserExist(user) || !usrMgr.validatePassword(user)) { if (!usrMgr.doesUserExist(user) || !usrMgr.validatePassword(user)) {
auto logRes = dto::LoginResultDto::createShared(); auto logRes = dto::LoginResultDto::createShared();
logRes->message = "invalid credentials"; logRes->message = "invalid credentials";
std::cout << "user does not exist" << std::endl; std::cout << "user does not exist\n";
return createDtoResponse(Status::CODE_401, logRes); return createDtoResponse(Status::CODE_401, logRes);
} }
std::cout << "user exists" << std::endl; std::cout << "user exists\n";
manager::TokenManager tok; manager::TokenManager tok;
auto token = tok.retrieveToken(m_bConf); auto token = tok.retrieveToken(m_bConf);
@@ -54,7 +51,6 @@ public:
#include OATPP_CODEGEN_END(ApiController) #include OATPP_CODEGEN_END(ApiController)
private: private:
std::string exe_path;
model::BinaryPath m_bConf; model::BinaryPath m_bConf;
}; };
} }
@@ -26,6 +26,9 @@ namespace controller {
BODY_DTO(dto::UserDto::ObjectWrapper, usr)) { BODY_DTO(dto::UserDto::ObjectWrapper, usr)) {
manager::UserManager usrMgr(m_bConf); manager::UserManager usrMgr(m_bConf);
auto user = dto::conversion::DtoConversions::toUser(usr); auto user = dto::conversion::DtoConversions::toUser(usr);
if (usrMgr.doesUserExist(user)) {
return createResponse(Status::CODE_401, "user already exists");
}
auto res = usrMgr.registerUser(user); auto res = usrMgr.registerUser(user);
auto registerResult = dto::conversion::DtoConversions::toRegisterResultDto(res); auto registerResult = dto::conversion::DtoConversions::toRegisterResultDto(res);
+76 -56
View File
@@ -9,54 +9,58 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include <oatpp/core/async/Coroutine.hpp>
#include "oatpp/core/data/stream/ChunkedBuffer.hpp" #include "oatpp/core/data/stream/ChunkedBuffer.hpp"
#include "oatpp/core/data/stream/FileStream.hpp" #include "oatpp/core/data/stream/FileStream.hpp"
#include "oatpp/core/base/StrBuffer.hpp"
#include "oatpp/core/macro/codegen.hpp" #include "oatpp/core/macro/codegen.hpp"
#include "oatpp/core/macro/component.hpp" #include "oatpp/core/macro/component.hpp"
#include "oatpp/web/mime/multipart/InMemoryPartReader.hpp" #include "oatpp/web/mime/multipart/InMemoryPartReader.hpp"
#include "oatpp/web/mime/multipart/Reader.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 "oatpp/web/server/api/ApiController.hpp"
#include "callback/StreamCallback.h" #include "callback/StreamCallback.h"
#include "database/SongRepository.h" #include "database/SongRepository.h"
#include "dto/SongDto.hpp" #include "dto/SongDto.hpp"
#include "dto/conversion/DtoConversions.h"
#include "manager/SongManager.h" #include "manager/SongManager.h"
#include "manager/TokenManager.h" #include "manager/TokenManager.h"
#include "model/Models.h" #include "model/Models.h"
#include "type/Scopes.h" #include "type/Scopes.h"
#include "type/SongFilter.h" #include "type/SongFilter.h"
#include "type/SongUpload.h"
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class SongController : public oatpp::web::server::api::ApiController { class SongController : public oatpp::web::server::api::ApiController {
public: public:
SongController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p)
{ }
SongController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) SongController(const model::BinaryPath& bConf, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper))
: oatpp::web::server::api::ApiController(objectMapper), m_bConf(bConf) : 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 for uploading a song
ENDPOINT("POST", "/api/v1/song/data", songUpload, ENDPOINT("POST", "/api/v1/song/data", songUpload,
REQUEST(std::shared_ptr<IncomingRequest>, request)) //AUTHORIZATION(std::shared_ptr<oatpp::web::server::handler::DefaultBearerAuthorizationObject>, authObject),
{ REQUEST(std::shared_ptr<IncomingRequest>, request)) {
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok;
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()); manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::upload), Status::CODE_403, "Not allowed");
auto mp =
std::make_shared<oatpp::web::mime::multipart::Multipart>
(request->getHeaders());
oatpp::web::mime::multipart::Reader mp_reader(mp.get()); oatpp::web::mime::multipart::Reader mp_reader(mp.get());
mp_reader.setPartReader("file", oatpp::web::mime::multipart::createInMemoryPartReader(m_dataSize)); mp_reader.setPartReader("file",
oatpp::web::mime::multipart::createInMemoryPartReader(m_dataSize));
request->transferBody(&mp_reader); request->transferBody(&mp_reader);
@@ -64,47 +68,47 @@ public:
OATPP_ASSERT_HTTP(file, Status::CODE_400, "file is null"); OATPP_ASSERT_HTTP(file, Status::CODE_400, "file is null");
auto buff = std::unique_ptr<char>(new char[file->getKnownSize()]); auto buff = std::make_unique<const char*>(file->getInMemoryData()->c_str());
auto buffSize = file->getInputStream()->read(buff.get(), file->getKnownSize()); auto buffSize = file->getKnownSize();
std::vector<unsigned char> data(buff.get(), buff.get() + buffSize); std::vector<unsigned char> data(*buff, *buff + buffSize);
model::Song sng; model::Song sng;
sng.data = std::move(data); sng.data = std::move(data);
manager::SongManager songMgr(m_bConf); manager::SongManager songMgr(m_bConf);
songMgr.saveSong(sng); 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;
}
}
return createResponse(Status::CODE_200, "OK"); auto songDto = dto::conversion::DtoConversions::toSongDto(sng);
return createDtoResponse(Status::CODE_200, songDto);
} }
// endpoint for retrieving all song records in json format // endpoint for retrieving all song records in json format
ENDPOINT("GET", "/api/v1/song", songRecords, ENDPOINT("GET", "/api/v1/song", songRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) REQUEST(std::shared_ptr<IncomingRequest>, request)) {
{
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveSong), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveSong), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving songs" << std::endl; std::cout << "starting process of retrieving songs\n";
database::SongRepository songRepo(m_bConf); database::SongRepository songRepo(m_bConf);
auto songsDb = songRepo.retrieveRecords(); auto songsDb = songRepo.retrieveRecords();
auto songs = oatpp::data::mapping::type::List<dto::SongDto::ObjectWrapper>::createShared(); auto songs = oatpp::data::mapping::type::List<dto::SongDto::ObjectWrapper>::createShared();
std::cout << "creating object to send" << std::endl; std::cout << "creating object to send\n";
for (auto& songDb : songsDb) { for (auto& songDb : songsDb) {
auto song = dto::SongDto::createShared(); auto song = dto::conversion::DtoConversions::toSongDto(songDb);
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;
songs->pushBack(song); songs->pushBack(song);
} }
@@ -124,22 +128,14 @@ public:
database::SongRepository songRepo(m_bConf); database::SongRepository songRepo(m_bConf);
model::Song songDb(id); model::Song songDb(id);
OATPP_ASSERT_HTTP(songRepo.doesSongExist(songDb, type::SongFilter::id) , Status::CODE_403, if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) {
"song does not exist"); return songDoesNotExist();
}
std::cout << "song exists" << std::endl; std::cout << "song exists\n";
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id); songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
auto song = dto::SongDto::createShared(); auto song = dto::conversion::DtoConversions::toSongDto(songDb);
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;
return createDtoResponse(Status::CODE_200, song); return createDtoResponse(Status::CODE_200, song);
} }
@@ -150,10 +146,15 @@ public:
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::download), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::download), Status::CODE_403, "Not allowed");
database::SongRepository songRepo(m_bConf); database::SongRepository songRepo(m_bConf);
model::Song songDb(id); model::Song songDb(id);
if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) {
return songDoesNotExist();
}
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id); songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
auto rawSong = oatpp::base::StrBuffer::loadFromFile(songDb.songPath.c_str()); auto rawSong = oatpp::base::StrBuffer::loadFromFile(songDb.songPath.c_str());
@@ -172,11 +173,15 @@ public:
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::updateSong), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::updateSong), Status::CODE_403, "Not allowed");
auto updatedSong = manager::SongManager::songDtoConv(songDto); auto updatedSong = dto::conversion::DtoConversions::toSong(songDto);
manager::SongManager songMgr(m_bConf); manager::SongManager songMgr(m_bConf);
songMgr.updateSong(updatedSong); auto result = songMgr.updateSong(updatedSong);
if (!result) {
return songDoesNotExist();
}
return createResponse(Status::CODE_200, "OK"); return createResponse(Status::CODE_200, "OK");
} }
@@ -188,12 +193,16 @@ public:
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::deleteSong), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::deleteSong), Status::CODE_403, "Not allowed");
model::Song song(id); model::Song song(id);
manager::SongManager sngMgr(m_bConf); manager::SongManager sngMgr(m_bConf);
sngMgr.deleteSong(song); auto result = sngMgr.deleteSong(song);
if (!result) {
return songDoesNotExist();
}
return createResponse(Status::CODE_200, "OK"); return createResponse(Status::CODE_200, "OK");
} }
@@ -205,16 +214,23 @@ public:
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::stream), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::stream), Status::CODE_403, "Not allowed");
database::SongRepository songRepo(m_bConf); database::SongRepository songRepo(m_bConf);
model::Song songDb(id); model::Song songDb(id);
if (!songRepo.doesSongExist(songDb, type::SongFilter::id)) {
return songDoesNotExist();
}
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id); songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
oatpp::data::v_io_size dSize = 1024; auto dSize = 1024;
auto db = std::make_shared<oatpp::web::protocol::http::outgoing::ChunkedBody>( auto callback = std::make_shared<callback::StreamCallback>(songDb.songPath);
std::make_shared<callback::StreamCallback>(songDb.songPath), nullptr, dSize); auto db = std::make_shared<oatpp::web::protocol::http::outgoing::StreamingBody>(
callback
);
auto response = OutgoingResponse::createShared(Status::CODE_200, db); auto response = OutgoingResponse::createShared(Status::CODE_200, db);
response->putHeader(Header::CONNECTION, Header::Value::CONNECTION_KEEP_ALIVE); response->putHeader(Header::CONNECTION, Header::Value::CONNECTION_KEEP_ALIVE);
@@ -225,7 +241,11 @@ public:
#include OATPP_CODEGEN_END(ApiController) #include OATPP_CODEGEN_END(ApiController)
private: private:
std::string m_exe_path; std::shared_ptr<oatpp::web::protocol::http::outgoing::Response>
songDoesNotExist() {
return createResponse(Status::CODE_404, "Song not found");
}
model::BinaryPath m_bConf; model::BinaryPath m_bConf;
+16 -18
View File
@@ -27,33 +27,29 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace controller { namespace controller {
class YearController : public oatpp::web::server::api::ApiController class YearController : public oatpp::web::server::api::ApiController {
{
public: public:
YearController(std::string p, OATPP_COMPONENT(std::shared_ptr<ObjectMapper>, objectMapper)) YearController(const model::BinaryPath& bConf,
: oatpp::web::server::api::ApiController(objectMapper), m_exe_path(p) 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 for retrieving all year records in json format
ENDPOINT("GET", "/api/v1/year", yearRecords, ENDPOINT("GET", "/api/v1/year", yearRecords,
REQUEST(std::shared_ptr<IncomingRequest>, request)) REQUEST(std::shared_ptr<IncomingRequest>, request)) {
{
auto authHeader = request->getHeader("Authorization"); auto authHeader = request->getHeader("Authorization");
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveYear), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveYear), Status::CODE_403, "Not allowed");
std::cout << "starting process of retrieving year" << std::endl; std::cout << "starting process of retrieving year\n";
database::YearRepository yrRepo(m_bConf); database::YearRepository yrRepo(m_bConf);
auto yrsDb = yrRepo.retrieveRecords(); auto yrsDb = yrRepo.retrieveRecords();
auto yearRecs = oatpp::data::mapping::type::List<dto::YearDto::ObjectWrapper>::createShared(); auto yearRecs = oatpp::data::mapping::type::
List<dto::YearDto::ObjectWrapper>::createShared();
for (auto& yrDb : yrsDb) { for (auto& yrDb : yrsDb) {
auto yr = dto::YearDto::createShared(); auto yr = dto::YearDto::createShared();
@@ -73,14 +69,16 @@ public:
OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope"); OATPP_ASSERT_HTTP(authHeader, Status::CODE_403, "Nope");
auto auth = authHeader->std_str(); auto auth = authHeader->std_str();
manager::TokenManager tok; manager::TokenManager tok;
OATPP_ASSERT_HTTP(tok.isTokenValid(auth, type::Scope::retrieveYear), Status::CODE_403, "Not allowed"); OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::retrieveYear), Status::CODE_403, "Not allowed");
database::YearRepository yrRepo(m_bConf); database::YearRepository yrRepo(m_bConf);
model::Year yrDb(id); 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" << std::endl; std::cout << "year exist\n";
yrDb = yrRepo.retrieveRecord(yrDb, type::YearFilter::id); yrDb = yrRepo.retrieveRecord(yrDb, type::YearFilter::id);
auto year = dto::YearDto::createShared(); auto year = dto::YearDto::createShared();
@@ -92,8 +90,8 @@ public:
#include OATPP_CODEGEN_END(ApiController) #include OATPP_CODEGEN_END(ApiController)
private: private:
std::string m_exe_path;
model::BinaryPath m_bConf; model::BinaryPath m_bConf;
}; };
} }
#endif #endif
+10 -7
View File
@@ -1,6 +1,7 @@
#ifndef ALBUMREPOSITORY_H_ #ifndef ALBUMREPOSITORY_H_
#define ALBUMREPOSITORY_H_ #define ALBUMREPOSITORY_H_
#include <memory>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -8,10 +9,8 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/AlbumFilter.h" #include "type/AlbumFilter.h"
namespace database namespace database {
{ class AlbumRepository : public BaseRepository {
class AlbumRepository : public BaseRepository
{
public: public:
AlbumRepository(const model::BinaryPath&); AlbumRepository(const model::BinaryPath&);
@@ -30,9 +29,13 @@ namespace database
std::pair<model::Album, int> parseRecordWithSongCount(MYSQL_STMT*); std::pair<model::Album, int> parseRecordWithSongCount(MYSQL_STMT*);
// TODO: after parseRecord(MYSQL_STMT*) is implemented remove std::shared_ptr<MYSQL_BIND> valueBind(model::Album&,
// parseRecord(MYSQL_RES*) std::tuple<char*, char*>&);
model::Album parseRecord(MYSQL_RES*); std::shared_ptr<MYSQL_BIND> valueBindWithSongCount(model::Album&,
std::tuple<char*, char*>&, int&);
std::tuple<char*, char*> metadataBuffer();
model::Album parseRecord(MYSQL_STMT*); model::Album parseRecord(MYSQL_STMT*);
}; };
} }
+12 -8
View File
@@ -1,6 +1,7 @@
#ifndef ARTISTREPOSITORY_H_ #ifndef ARTISTREPOSITORY_H_
#define ARTISTREPOSITORY_H_ #define ARTISTREPOSITORY_H_
#include <memory>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -8,16 +9,15 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/ArtistFilter.h" #include "type/ArtistFilter.h"
namespace database namespace database {
{ class ArtistRepository : public BaseRepository {
class ArtistRepository : public BaseRepository
{
public: public:
ArtistRepository(const model::BinaryPath&); ArtistRepository(const model::BinaryPath&);
std::vector<model::Artist> retrieveRecords(); std::vector<model::Artist> retrieveRecords();
std::pair<model::Artist, int> retrieveRecordWithSongCount(model::Artist&, type::ArtistFilter); std::pair<model::Artist, int> retrieveRecordWithSongCount(
model::Artist&, type::ArtistFilter);
model::Artist retrieveRecord(model::Artist&, type::ArtistFilter); model::Artist retrieveRecord(model::Artist&, type::ArtistFilter);
@@ -30,9 +30,13 @@ namespace database
std::pair<model::Artist, int> parseRecordWithSongCount(MYSQL_STMT*); std::pair<model::Artist, int> parseRecordWithSongCount(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented std::shared_ptr<MYSQL_BIND> valueBind(model::Artist&,
// remove parseRecord(MYSQL_RES*) std::tuple<char*>&);
model::Artist parseRecord(MYSQL_RES*); std::shared_ptr<MYSQL_BIND> valueBindWithSongCount(model::Artist&,
std::tuple<char*>&, int&);
std::tuple<char*> metadataBuffer();
model::Artist parseRecord(MYSQL_STMT*); model::Artist parseRecord(MYSQL_STMT*);
}; };
} }
+3 -5
View File
@@ -7,12 +7,10 @@
#include "model/Models.h" #include "model/Models.h"
namespace database namespace database {
{ class BaseRepository {
class BaseRepository
{
public: public:
BaseRepository(); BaseRepository() = default;
BaseRepository(const std::string&); BaseRepository(const std::string&);
BaseRepository(const model::BinaryPath&); BaseRepository(const model::BinaryPath&);
+9 -9
View File
@@ -1,6 +1,7 @@
#ifndef COVERARTREPOSITORY_H_ #ifndef COVERARTREPOSITORY_H_
#define COVERARTREPOSITORY_H_ #define COVERARTREPOSITORY_H_
#include <memory>
#include <vector> #include <vector>
#include <mysql/mysql.h> #include <mysql/mysql.h>
@@ -9,12 +10,9 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/CoverFilter.h" #include "type/CoverFilter.h"
namespace database namespace database {
{ class CoverArtRepository : public BaseRepository {
class CoverArtRepository : public BaseRepository
{
public: public:
CoverArtRepository(const std::string&);
CoverArtRepository(const model::BinaryPath&); CoverArtRepository(const model::BinaryPath&);
std::vector<model::Cover> retrieveRecords(); std::vector<model::Cover> retrieveRecords();
@@ -23,15 +21,17 @@ namespace database
bool doesCoverArtExist(const model::Cover&, type::CoverFilter); bool doesCoverArtExist(const model::Cover&, type::CoverFilter);
void deleteRecord(const model::Cover&); void deleteRecord(const model::Cover&, type::CoverFilter = type::CoverFilter::id);
void saveRecord(const model::Cover&); void saveRecord(const model::Cover&);
void updateRecord(const model::Cover&); void updateRecord(const model::Cover&);
private: private:
std::vector<model::Cover> parseRecords(MYSQL_STMT*); std::vector<model::Cover> parseRecords(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented std::shared_ptr<MYSQL_BIND> valueBind(model::Cover&,
// remove parseRecord(MYSQL_RES*) std::tuple<char*, char*>&);
model::Cover parseRecord(MYSQL_RES*);
std::tuple<char*, char*> metadataBuffer();
model::Cover parseRecord(MYSQL_STMT*); model::Cover parseRecord(MYSQL_STMT*);
}; };
} }
+10 -7
View File
@@ -1,6 +1,7 @@
#ifndef GENREREPOSITORY_H_ #ifndef GENREREPOSITORY_H_
#define GENREREPOSITORY_H_ #define GENREREPOSITORY_H_
#include <memory>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -8,10 +9,8 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/GenreFilter.h" #include "type/GenreFilter.h"
namespace database namespace database {
{ class GenreRepository : public BaseRepository {
class GenreRepository : public BaseRepository
{
public: public:
GenreRepository(const model::BinaryPath&); GenreRepository(const model::BinaryPath&);
@@ -30,9 +29,13 @@ namespace database
std::pair<model::Genre, int> parseRecordWithSongCount(MYSQL_STMT*); std::pair<model::Genre, int> parseRecordWithSongCount(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented std::shared_ptr<MYSQL_BIND> valueBind(model::Genre&,
// remove parseRecord(MYSQL_RES*) std::tuple<char*>&);
model::Genre parseRecord(MYSQL_RES*); std::shared_ptr<MYSQL_BIND> valueBindWithSongCount(model::Genre&,
std::tuple<char*>&, int&);
std::tuple<char*> metadataBuffer();
model::Genre parseRecord(MYSQL_STMT*); model::Genre parseRecord(MYSQL_STMT*);
}; };
} }
+10 -9
View File
@@ -2,6 +2,7 @@
#define SONGREPOSITORY_H_ #define SONGREPOSITORY_H_
#include <memory> #include <memory>
#include <utility>
#include <vector> #include <vector>
#include <mysql/mysql.h> #include <mysql/mysql.h>
@@ -10,28 +11,28 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/SongFilter.h" #include "type/SongFilter.h"
namespace database namespace database {
{ class SongRepository : public BaseRepository {
class SongRepository : public BaseRepository
{
public: public:
SongRepository(const std::string&);
SongRepository(const model::BinaryPath&); SongRepository(const model::BinaryPath&);
std::vector<model::Song> retrieveRecords(); 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&); bool deleteRecord(const model::Song&);
void saveRecord(const model::Song&); void saveRecord(const model::Song&);
void updateRecord(const model::Song&); void updateRecord(const model::Song&);
private: 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*); std::vector<model::Song> parseRecords(MYSQL_STMT*);
model::Song parseRecord(MYSQL_RES*); // TODO: to be removed
model::Song parseRecord(MYSQL_STMT*); model::Song parseRecord(MYSQL_STMT*);
}; };
} }
+8 -8
View File
@@ -26,8 +26,7 @@ private:
struct UserLengths; struct UserLengths;
struct SaltLengths; struct SaltLengths;
struct UserLengths struct UserLengths {
{
unsigned long firstnameLength; unsigned long firstnameLength;
unsigned long lastnameLength; unsigned long lastnameLength;
unsigned long phoneLength; unsigned long phoneLength;
@@ -35,14 +34,16 @@ private:
unsigned long usernameLength; unsigned long usernameLength;
unsigned long passwordLength; unsigned long passwordLength;
}; };
struct SaltLengths struct SaltLengths {
{
unsigned long saltLength; unsigned long saltLength;
}; };
std::shared_ptr<MYSQL_BIND> insertUserValues(const model::User&, std::shared_ptr<UserLengths>); std::shared_ptr<MYSQL_BIND> insertUserValues(const model::User&,
std::shared_ptr<MYSQL_BIND> insertSaltValues(const model::PassSec&, std::shared_ptr<SaltLengths>); std::shared_ptr<UserLengths>);
std::shared_ptr<MYSQL_BIND> valueBind(model::User&, std::tuple<char*, char*, char*, char*, char*, char*>&); 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<MYSQL_BIND> saltValueBind(model::PassSec&, char*);
std::shared_ptr<UserLengths> fetchUserLengths(const model::User&); std::shared_ptr<UserLengths> fetchUserLengths(const model::User&);
std::shared_ptr<SaltLengths> fetchSaltLengths(const model::PassSec&); std::shared_ptr<SaltLengths> fetchSaltLengths(const model::PassSec&);
@@ -54,5 +55,4 @@ private:
}; };
} }
#endif #endif
+12 -11
View File
@@ -1,6 +1,7 @@
#ifndef YEARREPOSITORY_H_ #ifndef YEARREPOSITORY_H_
#define YEARREPOSITORY_H_ #define YEARREPOSITORY_H_
#include <memory>
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -8,31 +9,31 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/YearFilter.h" #include "type/YearFilter.h"
namespace database namespace database {
{ class YearRepository : public BaseRepository {
class YearRepository : public BaseRepository
{
public: public:
YearRepository(const model::BinaryPath&); YearRepository(const model::BinaryPath&);
std::vector<model::Year> retrieveRecords(); std::vector<model::Year> retrieveRecords();
std::pair<model::Year, int> retrieveRecordWithSongCount(model::Year&, type::YearFilter); std::pair<model::Year, int> retrieveRecordWithSongCount(model::Year&,
type::YearFilter = type::YearFilter::id);
model::Year retrieveRecord(model::Year&, type::YearFilter); model::Year retrieveRecord(model::Year&, type::YearFilter = type::YearFilter::id);
bool doesYearExist(const model::Year&, type::YearFilter); bool doesYearExist(const model::Year&, type::YearFilter = type::YearFilter::id);
void saveRecord(const model::Year&); void saveRecord(const model::Year&);
void deleteYear(const model::Year&, type::YearFilter); void deleteYear(const model::Year&, type::YearFilter = type::YearFilter::id);
private: private:
std::vector<model::Year> parseRecords(MYSQL_STMT*); std::vector<model::Year> parseRecords(MYSQL_STMT*);
std::pair<model::Year, int> parseRecordWithSongCount(MYSQL_STMT*); std::pair<model::Year, int> parseRecordWithSongCount(MYSQL_STMT*);
// TODO: After parseRecord(MYSQL_STMT*) is implemented std::shared_ptr<MYSQL_BIND> valueBind(model::Year&);
// remove parseRecord(MYSQL_RES*) std::shared_ptr<MYSQL_BIND> valueBindWithSongCount(model::Year&,
model::Year parseRecord(MYSQL_RES*); int&);
model::Year parseRecord(MYSQL_STMT*); model::Year parseRecord(MYSQL_STMT*);
}; };
} }
+3 -4
View File
@@ -4,16 +4,15 @@
#include "oatpp/core/data/mapping/type/Object.hpp" #include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp" #include "oatpp/core/macro/codegen.hpp"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class AlbumDto : public oatpp::data::mapping::type::Object class AlbumDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(AlbumDto, Object) DTO_INIT(AlbumDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
DTO_FIELD(String, title); DTO_FIELD(String, title);
DTO_FIELD(String, artist);
DTO_FIELD(Int32, year); DTO_FIELD(Int32, year);
}; };
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp" #include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp" #include "oatpp/core/macro/codegen.hpp"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class ArtistDto : public oatpp::data::mapping::type::Object class ArtistDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(ArtistDto, Object) DTO_INIT(ArtistDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp" #include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp" #include "oatpp/core/macro/codegen.hpp"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class CoverArtDto : public oatpp::data::mapping::type::Object class CoverArtDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(CoverArtDto, Object) DTO_INIT(CoverArtDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp" #include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp" #include "oatpp/core/macro/codegen.hpp"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class GenreDto : public oatpp::data::mapping::type::Object class GenreDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(GenreDto, Object) DTO_INIT(GenreDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
+4 -4
View File
@@ -6,23 +6,23 @@
#include "model/Models.h" #include "model/Models.h"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class SongDto : public oatpp::data::mapping::type::Object class SongDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(SongDto, Object) DTO_INIT(SongDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
DTO_FIELD(String, title); DTO_FIELD(String, title);
DTO_FIELD(String, artist); DTO_FIELD(String, artist);
DTO_FIELD(String, album_artist);
DTO_FIELD(String, album); DTO_FIELD(String, album);
DTO_FIELD(String, genre); DTO_FIELD(String, genre);
DTO_FIELD(Int32, track); DTO_FIELD(Int32, track);
DTO_FIELD(Int32, disc); DTO_FIELD(Int32, disc);
DTO_FIELD(Int32, year); DTO_FIELD(Int32, year);
DTO_FIELD(Int32, duration); DTO_FIELD(Int32, duration);
DTO_FIELD(Int32, coverart_id);
}; };
#include OATPP_CODEGEN_END(DTO) #include OATPP_CODEGEN_END(DTO)
+2 -4
View File
@@ -4,12 +4,10 @@
#include "oatpp/core/data/mapping/type/Object.hpp" #include "oatpp/core/data/mapping/type/Object.hpp"
#include "oatpp/core/macro/codegen.hpp" #include "oatpp/core/macro/codegen.hpp"
namespace dto namespace dto {
{
#include OATPP_CODEGEN_BEGIN(DTO) #include OATPP_CODEGEN_BEGIN(DTO)
class YearDto : public oatpp::data::mapping::type::Object class YearDto : public oatpp::data::mapping::type::Object {
{
DTO_INIT(YearDto, Object) DTO_INIT(YearDto, Object)
DTO_FIELD(Int32, id); DTO_FIELD(Int32, id);
+5
View File
@@ -1,6 +1,7 @@
#ifndef DTOCONVERSIONS_H_ #ifndef DTOCONVERSIONS_H_
#define DTOCONVERSIONS_H_ #define DTOCONVERSIONS_H_
#include "dto/AlbumDto.hpp"
#include "dto/LoginResultDto.hpp" #include "dto/LoginResultDto.hpp"
#include "dto/SongDto.hpp" #include "dto/SongDto.hpp"
#include "model/Models.h" #include "model/Models.h"
@@ -13,6 +14,10 @@ namespace dto { namespace conversion {
static dto::RegisterResultDto::ObjectWrapper toRegisterResultDto( static dto::RegisterResultDto::ObjectWrapper toRegisterResultDto(
const model::RegisterResult&); 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::Song toSong(dto::SongDto::ObjectWrapper&);
static model::User toUser(dto::UserDto::ObjectWrapper&); static model::User toUser(dto::UserDto::ObjectWrapper&);
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h" #include "model/Models.h"
namespace manager namespace manager {
{ class AlbumManager {
class AlbumManager
{
public: public:
AlbumManager(const model::BinaryPath&); AlbumManager(const model::BinaryPath&);
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h" #include "model/Models.h"
namespace manager namespace manager {
{ class ArtistManager {
class ArtistManager
{
public: public:
ArtistManager(const model::BinaryPath&); ArtistManager(const model::BinaryPath&);
+2 -6
View File
@@ -6,12 +6,9 @@
#include "model/Models.h" #include "model/Models.h"
namespace manager namespace manager {
{ class CoverArtManager {
class CoverArtManager
{
public: public:
CoverArtManager(const std::string&);
CoverArtManager(const model::BinaryPath& bConf); CoverArtManager(const model::BinaryPath& bConf);
model::Cover saveCover(const model::Song&); model::Cover saveCover(const model::Song&);
@@ -25,7 +22,6 @@ namespace manager
std::string createImagePath(const model::Song&); std::string createImagePath(const model::Song&);
model::BinaryPath m_bConf; model::BinaryPath m_bConf;
std::string path;
}; };
} }
+12 -6
View File
@@ -3,19 +3,21 @@
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <filesystem>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "model/Models.h" #include "model/Models.h"
#include "type/PathType.h" #include "type/PathType.h"
namespace manager namespace manager {
{ class DirectoryManager {
class DirectoryManager
{
public: public:
static std::string createDirectoryProcess(model::Song, const std::string&); DirectoryManager() = default;
static std::string createDirectoryProcess(const model::Song&, const model::BinaryPath&, type::PathType);
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(std::string_view);
static std::string configPath(const model::BinaryPath&); static std::string configPath(const model::BinaryPath&);
static std::string contentOfPath(const std::string&); static std::string contentOfPath(const std::string&);
@@ -30,6 +32,10 @@ namespace manager
void deleteCoverArtFile(const std::string&, const std::string&); void deleteCoverArtFile(const std::string&, const std::string&);
private: 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); void deleteSong(const model::Song);
}; };
} }
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h" #include "model/Models.h"
namespace manager namespace manager {
{ class GenreManager {
class GenreManager
{
public: public:
GenreManager(const model::BinaryPath&); GenreManager(const model::BinaryPath&);
+7 -12
View File
@@ -4,30 +4,26 @@
#include <iostream> #include <iostream>
#include <map> #include <map>
#include <string> #include <string>
#include <utility>
#include <nlohmann/json.hpp> #include <nlohmann/json.hpp>
#include "dto/SongDto.hpp" #include "dto/SongDto.hpp"
#include "model/Models.h" #include "model/Models.h"
#include "type/SongChanged.h" #include "type/SongChanged.h"
#include "type/SongUpload.h"
namespace manager namespace manager {
{ class SongManager {
class SongManager
{
public: public:
SongManager(std::string&);
SongManager(const model::BinaryPath&); SongManager(const model::BinaryPath&);
std::pair<bool, type::SongUpload> saveSong(model::Song&);
bool didSongChange(const model::Song&, const model::Song&); bool didSongChange(const model::Song&, const model::Song&);
bool requiresFilesystemChange(const model::Song&, const model::Song&); bool requiresFilesystemChange(const model::Song&, const model::Song&);
bool deleteSong(model::Song&);
void saveSong(model::Song&); bool updateSong(model::Song&);
void deleteSong(model::Song&);
void updateSong(model::Song&);
static model::Song songDtoConv(dto::SongDto::ObjectWrapper&);
static void printSong(const model::Song&); static void printSong(const model::Song&);
private: private:
@@ -47,7 +43,6 @@ namespace manager
void modifySongOnFilesystem(model::Song&, const model::Song&); void modifySongOnFilesystem(model::Song&, const model::Song&);
model::BinaryPath m_bConf; model::BinaryPath m_bConf;
std::string exe_path;
}; };
} }
+1 -2
View File
@@ -16,7 +16,7 @@
namespace manager { namespace manager {
class TokenManager { class TokenManager {
public: public:
TokenManager(); TokenManager() = default;
model::Token retrieveToken(const model::BinaryPath&); model::Token retrieveToken(const model::BinaryPath&);
@@ -27,7 +27,6 @@ private:
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::vector<std::string> extractScopes(const jwt::decoded_jwt&&);
+2 -4
View File
@@ -3,10 +3,8 @@
#include "model/Models.h" #include "model/Models.h"
namespace manager namespace manager {
{ class YearManager {
class YearManager
{
public: public:
YearManager(const model::BinaryPath&); YearManager(const model::BinaryPath&);
+35 -35
View File
@@ -5,14 +5,24 @@
#include <vector> #include <vector>
namespace model { namespace model {
struct Song { class Song {
public:
Song() = default; Song() = default;
Song(const int id) : id(id) { } Song(const int id) : id(id) { }
Song(const int id, const std::string& title, const std::string& artist,
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; int id;
std::string title; std::string title;
std::string artist; std::string artist;
std::string album; std::string album;
std::string albumArtist;
std::string genre; std::string genre;
int year; int year;
int duration; int duration;
@@ -27,42 +37,35 @@ struct Song {
int yearId; int yearId;
}; };
struct Artist { class Artist {
public:
Artist() = default; Artist() = default;
Artist(const Song& song) Artist(const Song& song) : id(song.artistId), artist(song.artist) { }
{
id = song.artistId;
artist = song.artist;
}
Artist(const int id) : id(id) { } Artist(const int id) : id(id) { }
int id; int id;
std::string artist; std::string artist;
}; };
struct Album { class Album {
public:
Album() = default; Album() = default;
Album(const Song& song) Album(const Song& song) :
{ id(song.albumId), title(song.album),artist(song.artist), year(song.year) { }
id = song.albumId;
title = song.album;
year = song.year;
}
Album(const int id) : id(id) { } Album(const int id) : id(id) { }
int id; int id;
std::string title; std::string title;
std::string artist;
int year; int year;
std::vector<Song> songs; std::vector<Song> songs;
}; };
struct Genre { class Genre {
public:
Genre() = default; Genre() = default;
Genre(const Song& song) Genre(const Song& song) :
{ id(song.genreId), category(song.genre) { }
id = song.genreId;
category = song.genre;
}
Genre(const int id) : id(id) { } Genre(const int id) : id(id) { }
int id; int id;
@@ -70,26 +73,22 @@ struct Genre {
}; };
struct Year { class Year {
public:
Year() = default; Year() = default;
Year(const Song& song) Year(const Song& song) :
{ id(song.yearId), year(song.year) { }
id = song.yearId;
year = song.year;
}
Year(const int id) : id(id) { } Year(const int id) : id(id) { }
int id; int id;
int year; int year;
}; };
struct Cover { class Cover {
public:
Cover() = default; Cover() = default;
Cover(const Song& song) Cover(const Song& song) :
{ id(song.coverArtId), songTitle(song.title) { }
id = song.coverArtId;
songTitle = song.title;
}
Cover(const int id) : id(id) { } Cover(const int id) : id(id) { }
int id; int id;
@@ -163,11 +162,12 @@ struct DatabaseConnection {
std::string database; std::string database;
}; };
struct BinaryPath { class BinaryPath {
public:
BinaryPath() = default; BinaryPath() = default;
BinaryPath(const char *p) : path(std::move(p)) { } BinaryPath(const char *p) : path(p) { }
BinaryPath(std::string& p) : path(p) { }
BinaryPath(const std::string& p) : path(p) { } BinaryPath(const std::string& p) : path(p) { }
BinaryPath(const std::string&& p) : path(p) { }
std::string path; std::string path;
}; };
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef ALBUMFILTER_H_ #ifndef ALBUMFILTER_H_
#define ALBUMFILTER_H_ #define ALBUMFILTER_H_
namespace type namespace type {
{ enum class AlbumFilter {
enum class AlbumFilter
{
id = 0, id = 0,
title, title,
year year
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef ARTISTFILTER_H_ #ifndef ARTISTFILTER_H_
#define ARTISTFILTER_H_ #define ARTISTFILTER_H_
namespace type namespace type {
{ enum class ArtistFilter {
enum class ArtistFilter
{
id = 0, id = 0,
artist artist
}; };
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef COVERFILTER_H_ #ifndef COVERFILTER_H_
#define COVERFILTER_H_ #define COVERFILTER_H_
namespace type namespace type {
{ enum class CoverFilter {
enum class CoverFilter
{
id = 0, id = 0,
songTitle, songTitle,
imagePath imagePath
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef GENREFILTER_H_ #ifndef GENREFILTER_H_
#define GENREFILTER_H_ #define GENREFILTER_H_
namespace type namespace type {
{ enum class GenreFilter {
enum class GenreFilter
{
id = 0, id = 0,
category category
}; };
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef PATHTYPE_H_ #ifndef PATHTYPE_H_
#define PATHTYPE_H_ #define PATHTYPE_H_
namespace type namespace type {
{ enum PathType {
enum PathType
{
music = 0, music = 0,
archive, archive,
temp, temp,
+1 -2
View File
@@ -2,8 +2,7 @@
#define SALTFILTER_H_ #define SALTFILTER_H_
namespace type { namespace type {
enum class SaltFilter enum class SaltFilter {
{
id = 0, id = 0,
salt, salt,
userId userId
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef SCOPES_H_ #ifndef SCOPES_H_
#define SCOPES_H_ #define SCOPES_H_
namespace type namespace type {
{ enum class Scope {
enum class Scope
{
upload = 0, upload = 0,
download, download,
stream, stream,
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef SONGCHANGED_H_ #ifndef SONGCHANGED_H_
#define SONGCHANGED_H_ #define SONGCHANGED_H_
namespace type namespace type {
{ enum SongChanged {
enum SongChanged
{
title = 0, title = 0,
artist, artist,
album, album,
+7 -5
View File
@@ -1,16 +1,18 @@
#ifndef SONGFILTER_H_ #ifndef SONGFILTER_H_
#define SONGFILTER_H_ #define SONGFILTER_H_
namespace type namespace type {
{ enum class SongFilter {
enum class SongFilter
{
id = 0, id = 0,
title, title,
album, album,
artist, artist,
albumArtist,
genre, 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_ #define USERFILTER_H_
namespace type { namespace type {
enum class UserFilter enum class UserFilter {
{
id = 0, id = 0,
username username
}; };
+2 -4
View File
@@ -1,10 +1,8 @@
#ifndef YEARFILTER_H_ #ifndef YEARFILTER_H_
#define YEARFILTER_H_ #define YEARFILTER_H_
namespace type namespace type {
{ enum class YearFilter {
enum class YearFilter
{
id = 0, id = 0,
year year
}; };
+2 -4
View File
@@ -13,10 +13,8 @@
#include <tpropertymap.h> #include <tpropertymap.h>
#include <id3v2tag.h> #include <id3v2tag.h>
namespace utility namespace utility {
{ class ImageFile : public TagLib::File {
class ImageFile : public TagLib::File
{
public: public:
ImageFile(const char *file); ImageFile(const char *file);
+8 -3
View File
@@ -4,13 +4,18 @@
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <attachedpictureframe.h>
#include <textidentificationframe.h>
#include <fileref.h>
#include <mpegfile.h>
#include <tag.h>
#include "model/Models.h" #include "model/Models.h"
namespace utility { namespace utility {
class MetadataRetriever class MetadataRetriever {
{
public: public:
model::Song retrieveMetadata(std::string&); model::Song retrieveMetadata(model::Song&);
model::Cover updateCoverArt(const model::Song&, model::Cover&, const std::string&); model::Cover updateCoverArt(const model::Song&, model::Cover&, const std::string&);
model::Cover applyStockCoverArt(const model::Song&, model::Cover&, const std::string&); model::Cover applyStockCoverArt(const model::Song&, model::Cover&, const std::string&);
+1 -1
View File
@@ -12,7 +12,7 @@ public:
bool isPasswordValid(const model::User&, const model::PassSec&); bool isPasswordValid(const model::User&, const model::PassSec&);
private: private:
int saltSize(); constexpr int saltSize() noexcept;
}; };
} }
+2 -4
View File
@@ -5,10 +5,8 @@
#include "model/Models.h" #include "model/Models.h"
namespace verify namespace verify {
{ class Initialization {
class Initialization
{
public: public:
static bool skipVerification(const std::string&); static bool skipVerification(const std::string&);
+3 -5
View File
@@ -23,8 +23,7 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
void run(const model::BinaryPath& bConf) void run(const model::BinaryPath& bConf) {
{
component::AppComponent component; component::AppComponent component;
OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router); OATPP_COMPONENT(std::shared_ptr<oatpp::web::server::HttpRouter>, router);
@@ -58,8 +57,7 @@ void run(const model::BinaryPath& bConf)
server.run(); server.run();
} }
int main(int argc, char **argv) int main(int argc, char **argv) {
{
oatpp::base::Environment::init(); oatpp::base::Environment::init();
model::BinaryPath bConf(std::move(argv[0])); model::BinaryPath bConf(std::move(argv[0]));
@@ -68,7 +66,7 @@ int main(int argc, char **argv)
if (!verify::Initialization::skipVerification(argv[1])) { if (!verify::Initialization::skipVerification(argv[1])) {
verify::Initialization::checkIcarus(bConf); verify::Initialization::checkIcarus(bConf);
} else { } else {
std::cout << "skiping verifyication" << std::endl; std::cout << "skiping verifyication\n";
} }
} else { } else {
verify::Initialization::checkIcarus(bConf); verify::Initialization::checkIcarus(bConf);
+7 -8
View File
@@ -5,25 +5,24 @@
#include <memory> #include <memory>
namespace callback { namespace callback {
StreamCallback::StreamCallback() : StreamCallback::StreamCallback() : m_counter(0) { }
m_counter(0) { }
StreamCallback::StreamCallback(const std::string& songPath) : StreamCallback::StreamCallback(const std::string& songPath) :
m_songPath(songPath), m_songPath(songPath),
m_counter(0), m_counter(0),
m_bytesRead(0) m_bytesRead(0) {
{
// getting file size // getting file size
std::ifstream song(m_songPath.c_str(), std::ios::binary | std::ios::in | std::ios::ate); std::ifstream song(m_songPath.c_str(), std::ios::binary | std::ios::in | std::ios::ate);
m_fileSize = song.tellg(); m_fileSize = song.tellg();
std::cout << "file size is " << m_fileSize << " bytes" << std::endl; std::cout << "file size is " << m_fileSize << " bytes\n";
} }
oatpp::data::v_io_size StreamCallback::read(void *buff, oatpp::data::v_io_size count)
{ oatpp::v_io_size StreamCallback::read(void *buff, v_buff_size count,
oatpp::async::Action& action) {
if (m_counter >= m_fileSize) { if (m_counter >= m_fileSize) {
std::cout << "done streaming song" << std::endl; std::cout << "done streaming song\n";
return 0; return 0;
} }
+123 -181
View File
@@ -7,13 +7,11 @@
#include <string> #include <string>
#include <cstring> #include <cstring>
database::AlbumRepository::AlbumRepository(const model::BinaryPath& bConf) namespace database {
: BaseRepository(bConf) AlbumRepository::AlbumRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { }
{ }
std::vector<model::Album> database::AlbumRepository::retrieveRecords() std::vector<model::Album> AlbumRepository::retrieveRecords() {
{
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -30,14 +28,14 @@ std::vector<model::Album> database::AlbumRepository::retrieveRecords()
} }
std::pair<model::Album, int> database::AlbumRepository::retrieveRecordWithSongCount(model::Album& album, type::AlbumFilter filter = type::AlbumFilter::id) std::pair<model::Album, int> AlbumRepository::retrieveRecordWithSongCount(model::Album& album,
{ type::AlbumFilter filter = type::AlbumFilter::id) {
std::cout << "retrieving album with song count" << std::endl; std::cout << "retrieving album with song count\n";
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
MYSQL_BIND params[4]; MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params)); std::memset(params, 0, sizeof(params));
qry << "SELECT alb.*, COUNT(*) AS SongCount FROM Album alb LEFT JOIN "; qry << "SELECT alb.*, COUNT(*) AS SongCount FROM Album alb LEFT JOIN ";
@@ -71,9 +69,8 @@ std::pair<model::Album, int> database::AlbumRepository::retrieveRecordWithSongCo
return albWSC; return albWSC;
} }
model::Album database::AlbumRepository::retrieveRecord(model::Album& album, type::AlbumFilter filter) model::Album AlbumRepository::retrieveRecord(model::Album& album, type::AlbumFilter filter) {
{ std::cout << "retrieving album record\n";
std::cout << "retrieving album record" << std::endl;
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -117,13 +114,12 @@ model::Album database::AlbumRepository::retrieveRecord(model::Album& album, type
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "done" << std::endl; std::cout << "done\n";
return album; return album;
} }
bool database::AlbumRepository::doesAlbumExists(const model::Album& album, type::AlbumFilter filter) bool AlbumRepository::doesAlbumExists(const model::Album& album, type::AlbumFilter filter) {
{
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -162,29 +158,28 @@ bool database::AlbumRepository::doesAlbumExists(const model::Album& album, type:
status = mysql_stmt_bind_param(stmt, params); status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt); status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed" << std::endl; std::cout << "the query has been performed\n";
::mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
auto rowCount = ::mysql_stmt_num_rows(stmt); auto rowCount = mysql_stmt_num_rows(stmt);
::mysql_stmt_close(stmt); mysql_stmt_close(stmt);
::mysql_close(conn); mysql_close(conn);
return (rowCount > 0) ? true : false; return (rowCount > 0) ? true : false;
} }
void database::AlbumRepository::saveAlbum(const model::Album& album) void AlbumRepository::saveAlbum(const model::Album& album) {
{ std::cout << "beginning to insert album record\n";
std::cout << "beginning to insert album record" << std::endl;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
MYSQL_STMT *stmt = mysql_stmt_init(conn); MYSQL_STMT *stmt = mysql_stmt_init(conn);
const std::string query = "INSERT INTO Album(Title, Year) VALUES(?, ?)"; const std::string query = "INSERT INTO Album(Title, Artist, Year) VALUES(?, ?, ?)";
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
MYSQL_BIND params[2]; MYSQL_BIND params[3];
memset(params, 0, sizeof(params)); memset(params, 0, sizeof(params));
params[0].buffer_type = MYSQL_TYPE_STRING; params[0].buffer_type = MYSQL_TYPE_STRING;
@@ -193,23 +188,29 @@ void database::AlbumRepository::saveAlbum(const model::Album& album)
params[0].length= &titleLength; params[0].length= &titleLength;
params[0].is_null = 0; params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_LONG; params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)&album.year; params[1].buffer = (char*)album.artist.c_str();
params[1].length = 0; auto artistLength = album.artist.size();
params[1].length = &artistLength;
params[1].is_null = 0; 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_bind_param(stmt, params);
status = mysql_stmt_execute(stmt); status = mysql_stmt_execute(stmt);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "done inserting album record" << std::endl; std::cout << "done inserting album record\n";
} }
void database::AlbumRepository::deleteAlbum(const model::Album& album, type::AlbumFilter filter = type::AlbumFilter::id) void AlbumRepository::deleteAlbum(const model::Album& album,
{ type::AlbumFilter filter = type::AlbumFilter::id) {
std::cout << "deleting album record" << std::endl; std::cout << "deleting album record\n";
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
@@ -239,13 +240,12 @@ void database::AlbumRepository::deleteAlbum(const model::Album& album, type::Alb
status = mysql_stmt_bind_param(stmt, params); status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt); status = mysql_stmt_execute(stmt);
std::cout << "execute delete query" << std::endl; std::cout << "execute delete query\n";
} }
std::vector<model::Album> database::AlbumRepository::parseRecords(MYSQL_STMT* stmt) std::vector<model::Album> AlbumRepository::parseRecords(MYSQL_STMT* stmt) {
{ std::cout << "parsing album record\n";
std::cout << "parsing album record" << std::endl;
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
std::vector<model::Album> albums; std::vector<model::Album> albums;
@@ -258,192 +258,134 @@ std::vector<model::Album> database::AlbumRepository::parseRecords(MYSQL_STMT* st
for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) { for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
if (mysql_stmt_field_count(stmt) > 0) { if (mysql_stmt_field_count(stmt) > 0) {
model::Album alb; model::Album alb;
auto res = mysql_stmt_result_metadata(stmt); auto metaBuff = metadataBuffer();
auto fields = mysql_fetch_fields(res); auto bindedValues = valueBind(alb, metaBuff);
const auto strLen = 1024; status = mysql_stmt_bind_result(stmt, bindedValues.get());
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) { while (true) {
std::cout << "fetching statement result" << std::endl; std::cout << "fetching statement result\n";
status = mysql_stmt_fetch(stmt); status = mysql_stmt_fetch(stmt);
if (status == 1 || status == MYSQL_NO_DATA) { if (status == 1 || status == MYSQL_NO_DATA) break;
break;
}
alb.title = title; alb.title = std::get<0>(metaBuff);
alb.artist = std::get<1>(metaBuff);
albums.push_back(std::move(alb)); albums.push_back(std::move(alb));
} }
} }
std::cout << "fetching next result" << std::endl; std::cout << "fetching next result\n";
} }
return albums; return albums;
} }
// 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;
auto fieldNum = mysql_num_fields(results); std::pair<model::Album, int> AlbumRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) {
auto row = mysql_fetch_row(results); std::cout << "parsing album record with song count\n";
for (auto i = 0; i != fieldNum; ++i) {
const std::string field(mysql_fetch_field(results)->name);
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]);
}
}
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); mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt); auto rowCount = mysql_stmt_num_rows(stmt);
model::Album album; model::Album album;
auto metaBuff = metadataBuffer();
int songCount = 0; int songCount = 0;
auto val = valueBindWithSongCount(album, metaBuff, songCount);
if (rowCount == 0) { if (rowCount == 0) {
std::cout << "no results" << std::endl; std::cout << "no results\n";
return std::make_pair(album, songCount); return std::make_pair(album, songCount);
} }
if (mysql_stmt_field_count(stmt) == 0) { auto status = mysql_stmt_bind_result(stmt, val.get());
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); status = mysql_stmt_fetch(stmt);
album.title = std::move(title); album.title = std::get<0>(metaBuff);
album.artist = std::get<1>(metaBuff);
std::cout << "done parsing album record with song count" << std::endl; std::cout << "done parsing album record with song count\n";
auto albWSC = std::make_pair(album, songCount); auto albWSC = std::make_pair(album, songCount);
return albWSC; return albWSC;
} }
model::Album database::AlbumRepository::parseRecord(MYSQL_STMT *stmt)
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" << std::endl; std::cout << "parsing album record\n";
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
auto rows = mysql_stmt_num_rows(stmt); auto rows = mysql_stmt_num_rows(stmt);
model::Album album; model::Album album;
auto status = 0; auto metaBuff = metadataBuffer();
auto time = 0; auto bindedValues = valueBind(album, metaBuff);
auto valAmt = 3; auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
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); status = mysql_stmt_fetch(stmt);
album.title = title; album.title = std::get<0>(metaBuff);
} album.artist = std::get<1>(metaBuff);
status = mysql_stmt_next_result(stmt); std::cout << "done parsing album record\n";
}
std::cout << "done parsing album record" << std::endl;
return album; return album;
} }
}
+125 -179
View File
@@ -6,14 +6,12 @@
#include <string> #include <string>
#include <cstring> #include <cstring>
database::ArtistRepository::ArtistRepository(const model::BinaryPath& binConf) namespace database {
: BaseRepository(binConf) ArtistRepository::ArtistRepository(const model::BinaryPath& binConf) :
{ BaseRepository(binConf) { }
}
std::vector<model::Artist> database::ArtistRepository::retrieveRecords() std::vector<model::Artist> ArtistRepository::retrieveRecords() {
{
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Artist"; const std::string query = "SELECT * FROM Artist";
@@ -29,9 +27,9 @@ std::vector<model::Artist> database::ArtistRepository::retrieveRecords()
return artists; return artists;
} }
std::pair<model::Artist, int> database::ArtistRepository::retrieveRecordWithSongCount(model::Artist& artist, type::ArtistFilter filter = type::ArtistFilter::id) std::pair<model::Artist, int> ArtistRepository::retrieveRecordWithSongCount(
{ model::Artist& artist, type::ArtistFilter filter = type::ArtistFilter::id) {
std::cout << "retrieving artist record with song count" << std::endl; std::cout << "retrieving artist record with song count\n";
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -63,7 +61,7 @@ std::pair<model::Artist, int> database::ArtistRepository::retrieveRecordWithSong
status = mysql_stmt_execute(stmt); status = mysql_stmt_execute(stmt);
std::cout << "Artist record with song count query "; std::cout << "Artist record with song count query ";
std::cout << "has been performed" << std::endl; std::cout << "has been performed\n";
auto artWSC = parseRecordWithSongCount(stmt); auto artWSC = parseRecordWithSongCount(stmt);
@@ -73,9 +71,9 @@ std::pair<model::Artist, int> database::ArtistRepository::retrieveRecordWithSong
return artWSC; return artWSC;
} }
model::Artist database::ArtistRepository::retrieveRecord(model::Artist& artist, type::ArtistFilter filter) model::Artist ArtistRepository::retrieveRecord(model::Artist& artist,
{ type::ArtistFilter filter) {
std::cout << "retrieving artist record" << std::endl; std::cout << "retrieving artist record\n";
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -118,13 +116,12 @@ model::Artist database::ArtistRepository::retrieveRecord(model::Artist& artist,
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "retrieved record" << std::endl; std::cout << "retrieved record\n";
return artist; return artist;
} }
bool database::ArtistRepository::doesArtistExist(const model::Artist& artist, type::ArtistFilter filter) bool ArtistRepository::doesArtistExist(const model::Artist& artist, type::ArtistFilter filter) {
{
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -163,7 +160,7 @@ bool database::ArtistRepository::doesArtistExist(const model::Artist& artist, ty
status = mysql_stmt_bind_param(stmt, params); status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt); status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed" << std::endl; std::cout << "the query has been performed\n";
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt); auto rowCount = mysql_stmt_num_rows(stmt);
@@ -174,9 +171,8 @@ bool database::ArtistRepository::doesArtistExist(const model::Artist& artist, ty
return (rowCount > 0) ? true : false; return (rowCount > 0) ? true : false;
} }
void database::ArtistRepository::saveRecord(const model::Artist& artist) void ArtistRepository::saveRecord(const model::Artist& artist) {
{ std::cout << "inserting artist record\n";
std::cout << "inserting artist record" << std::endl;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
MYSQL_STMT *stmt = mysql_stmt_init(conn); MYSQL_STMT *stmt = mysql_stmt_init(conn);
@@ -200,12 +196,12 @@ void database::ArtistRepository::saveRecord(const model::Artist& artist)
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout<< "inserted artist record" << std::endl; std::cout<< "inserted artist record\n";
} }
void database::ArtistRepository::deleteArtist(const model::Artist& artist, type::ArtistFilter filter = type::ArtistFilter::id) { void ArtistRepository::deleteArtist(const model::Artist& artist,
// TODO: implement this type::ArtistFilter filter = type::ArtistFilter::id) {
std::cout << "delete Artist record" << std::endl; std::cout << "delete Artist record\n";
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -237,179 +233,129 @@ void database::ArtistRepository::deleteArtist(const model::Artist& artist, type:
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "deleted artist record" << std::endl; std::cout << "deleted artist record\n";
} }
std::vector<model::Artist> database::ArtistRepository::parseRecords(MYSQL_STMT *stmt) std::vector<model::Artist> ArtistRepository::parseRecords(MYSQL_STMT *stmt) {
{
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
std::vector<model::Artist> artists; std::vector<model::Artist> artists;
artists.reserve(mysql_stmt_num_rows(stmt)); artists.reserve(mysql_stmt_num_rows(stmt));
if (mysql_stmt_field_count(stmt) == 0) { constexpr auto valAmt = 2;
std::cout << "field count is 0" << std::endl;
return artists;
}
model::Artist art;
const auto valAmt = 2;
unsigned long len[valAmt]; unsigned long len[valAmt];
my_bool nullRes[valAmt]; my_bool nullRes[valAmt];
auto res = mysql_stmt_result_metadata(stmt); for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
auto fields = mysql_fetch_fields(res);
const auto strLen = 1024;
char artist[strLen];
MYSQL_BIND val[valAmt];
memset(val, 0, sizeof(val));
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];
for (auto status = mysql_stmt_bind_result(stmt, val); status == 0; ) {
std::cout << "fetching statement result" << std::endl;
status = mysql_stmt_fetch(stmt);
if (status == 0) {
art.artist = artist;
artists.push_back(std::move(art));
}
}
return artists;
}
model::Artist database::ArtistRepository::parseRecord(MYSQL_RES* results)
{
std::cout << "parsing artist record" << std::endl;
model::Artist artist;
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("ArtistId") == 0) {
artist.id = std::stoi(row[i]);
}
if (field.compare("Artist") == 0) {
artist.artist = row[i];
}
}
std::cout << "parsed artist record" << std::endl;
return artist;
}
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);
const auto strLen = 1024;
const auto valAmt = 3;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
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);
}
MYSQL_BIND params[valAmt];
std::memset(params, 0, sizeof(params));
char art[strLen];
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) { if (mysql_stmt_field_count(stmt) > 0) {
auto res = mysql_stmt_result_metadata(stmt); model::Artist art;
auto fields = mysql_fetch_fields(res); auto metaBuff = metadataBuffer();
auto strLen = 1024; auto bindedValues = valueBind(art, metaBuff);
status = mysql_stmt_bind_result(stmt, bindedValues.get());
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);
std::cout << "fetching statement result\n";
status = mysql_stmt_fetch(stmt); status = mysql_stmt_fetch(stmt);
art.artist = artist; if (status == 1 || status == MYSQL_NO_DATA) break;
art.artist = std::get<0>(metaBuff);
artists.push_back(art);
}
std::cout << "fetching next result\n";
} }
status = mysql_stmt_next_result(stmt); return artists;
} }
std::cout << "done parsing artist record" << std::endl;
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);
artist.artist = std::get<0>(metaBuff);
std::cout << "done parsing album record with song count\n";
return std::make_pair(artist, songCount);
}
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)));
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = (char*)&artist.id;
values.get()[1].buffer_type = MYSQL_TYPE_STRING;
values.get()[1].buffer = (char*)std::get<0>(metadata);
values.get()[1].buffer_length = wordLen;
return values;
}
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)));
values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = reinterpret_cast<char*>(&artist.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;
}
std::tuple<char*> ArtistRepository::metadataBuffer() {
constexpr auto wordLen = 1024;
char artist[wordLen];
return std::make_tuple(artist);
}
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; return art;
} }
}
+21 -29
View File
@@ -6,27 +6,21 @@
#include "manager/DirectoryManager.h" #include "manager/DirectoryManager.h"
database::BaseRepository::BaseRepository() namespace database {
{ } BaseRepository::BaseRepository(const std::string& path) : path(path) {
database::BaseRepository::BaseRepository(const std::string& path) : path(path)
{
intitalizeDetails(); intitalizeDetails();
} }
database::BaseRepository::BaseRepository(const model::BinaryPath& bConf) BaseRepository::BaseRepository(const model::BinaryPath& bConf) {
{
initializeDetails(bConf); initializeDetails(bConf);
} }
bool database::BaseRepository::testConnection() bool BaseRepository::testConnection() {
{
auto conn = mysql_init(nullptr); auto conn = mysql_init(nullptr);
if (!mysql_real_connect(conn, details.server.c_str(), details.username.c_str(), if (!mysql_real_connect(conn, details.server.c_str(), details.username.c_str(),
details.password.c_str(), details.database.c_str(), 0, details.password.c_str(), details.database.c_str(), 0, nullptr, 0)) {
nullptr, 0)) { std::cout << "failed to connect to the database\n";
std::cout << "failed to connect to the database" << std::endl;
return false; return false;
} }
@@ -36,46 +30,43 @@ bool database::BaseRepository::testConnection()
} }
MYSQL* database::BaseRepository::setupMysqlConnection() MYSQL* BaseRepository::setupMysqlConnection() {
{
MYSQL *conn = mysql_init(nullptr); MYSQL *conn = mysql_init(nullptr);
if (!mysql_real_connect(conn, details.server.c_str(), details.username.c_str(), if (!mysql_real_connect(conn, details.server.c_str(), details.username.c_str(),
details.password.c_str(), details.database.c_str(), 0, nullptr, 0)) { details.password.c_str(), details.database.c_str(), 0, nullptr, 0)) {
std::cout << "connection error" << std::endl; std::cout << "connection error\n";
} }
return conn; return conn;
} }
MYSQL* database::BaseRepository::setupMysqlConnection(model::DatabaseConnection details) MYSQL* BaseRepository::setupMysqlConnection(model::DatabaseConnection details) {
{
MYSQL *connection = mysql_init(NULL); MYSQL *connection = mysql_init(NULL);
// connect to the database with the details attached. // 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)) { if (!mysql_real_connect(connection,details.server.c_str(), details.username.c_str(),
printf("Conection error : %s\n", mysql_error(connection)); details.password.c_str(), details.database.c_str(), 0, NULL, 0)) {
exit(1); std::cout << "Connection error: " << mysql_error(connection) << "\n";
std::exit(-1);
} }
return connection; return connection;
} }
MYSQL_RES* database::BaseRepository::performMysqlQuery(MYSQL *conn, const std::string& query) MYSQL_RES* BaseRepository::performMysqlQuery(MYSQL *conn, const std::string& query) {
{
// send the query to the database // send the query to the database
if (mysql_query(conn, query.c_str())) if (mysql_query(conn, query.c_str())) {
{
printf("MySQL query error : %s\n", mysql_error(conn)); printf("MySQL query error : %s\n", mysql_error(conn));
exit(1); std::cout << "MySQL query error : " << mysql_error(conn) << "\n";
std::exit(1);
} }
return mysql_use_result(conn); return mysql_use_result(conn);
} }
void database::BaseRepository::intitalizeDetails() void BaseRepository::intitalizeDetails() {
{
auto databaseConfig = manager::DirectoryManager::databaseConfigContent(path); auto databaseConfig = manager::DirectoryManager::databaseConfigContent(path);
details.database = databaseConfig["database"].get<std::string>(); details.database = databaseConfig["database"].get<std::string>();
@@ -83,7 +74,7 @@ void database::BaseRepository::intitalizeDetails()
details.server = databaseConfig["server"].get<std::string>(); details.server = databaseConfig["server"].get<std::string>();
details.username = databaseConfig["username"].get<std::string>(); details.username = databaseConfig["username"].get<std::string>();
} }
void database::BaseRepository::initializeDetails(const model::BinaryPath& bConf) void BaseRepository::initializeDetails(const model::BinaryPath& bConf)
{ {
auto databaseConfig = manager::DirectoryManager::databaseConfigContent(bConf); auto databaseConfig = manager::DirectoryManager::databaseConfigContent(bConf);
@@ -92,5 +83,6 @@ void database::BaseRepository::initializeDetails(const model::BinaryPath& bConf)
details.username = databaseConfig["username"].get<std::string>(); details.username = databaseConfig["username"].get<std::string>();
details.password = databaseConfig["password"].get<std::string>(); details.password = databaseConfig["password"].get<std::string>();
std::cout << "retrieved database details" << std::endl; std::cout << "retrieved database details\n";
}
} }
+93 -141
View File
@@ -6,15 +6,12 @@
#include <string> #include <string>
#include <cstring> #include <cstring>
database::CoverArtRepository::CoverArtRepository(const std::string& path) : BaseRepository(path) namespace database {
{ } CoverArtRepository::CoverArtRepository(const model::BinaryPath& bConf) :
BaseRepository(bConf) { }
database::CoverArtRepository::CoverArtRepository(const model::BinaryPath& bConf) : BaseRepository(bConf)
{ }
std::vector<model::Cover> database::CoverArtRepository::retrieveRecords() std::vector<model::Cover> CoverArtRepository::retrieveRecords() {
{
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM CoverArt"; const std::string query = "SELECT * FROM CoverArt";
@@ -30,8 +27,8 @@ std::vector<model::Cover> database::CoverArtRepository::retrieveRecords()
return coverArts; return coverArts;
} }
model::Cover database::CoverArtRepository::retrieveRecord(model::Cover& cov, type::CoverFilter filter = type::CoverFilter::id) model::Cover CoverArtRepository::retrieveRecord(model::Cover& cov,
{ type::CoverFilter filter = type::CoverFilter::id) {
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -74,14 +71,14 @@ model::Cover database::CoverArtRepository::retrieveRecord(model::Cover& cov, typ
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "retrieved cover art record" << std::endl; std::cout << "retrieved cover art record\n";
return covDb; return covDb;
} }
bool database::CoverArtRepository::doesCoverArtExist(const model::Cover& cover, type::CoverFilter filter) bool CoverArtRepository::doesCoverArtExist(const model::Cover& cover,
{ type::CoverFilter filter) {
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -120,7 +117,7 @@ bool database::CoverArtRepository::doesCoverArtExist(const model::Cover& cover,
status = mysql_stmt_bind_param(stmt, params); status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt); status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed" << std::endl; std::cout << "the query has been performed\n";
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt); auto rowCount = mysql_stmt_num_rows(stmt);
@@ -132,19 +129,43 @@ bool database::CoverArtRepository::doesCoverArtExist(const model::Cover& cover,
} }
// TODO: change to prepared statement void CoverArtRepository::deleteRecord(const model::Cover& cov,
void database::CoverArtRepository::deleteRecord(const model::Cover& cov) type::CoverFilter filter) {
{
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
const std::string query("DELETE FROM CoverArt WHERE CoverArtId = " + std::to_string(cov.id)); 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 = ?";
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;
} }
void database::CoverArtRepository::saveRecord(const model::Cover& cov) 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 CoverArt record\n";
}
void CoverArtRepository::saveRecord(const model::Cover& cov) {
std::cout << "saving cover art record"; std::cout << "saving cover art record";
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -175,11 +196,10 @@ void database::CoverArtRepository::saveRecord(const model::Cover& cov)
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "saved cover art record" << std::endl; std::cout << "saved cover art record\n";
} }
void database::CoverArtRepository::updateRecord(const model::Cover& cover) void CoverArtRepository::updateRecord(const model::Cover& cover) {
{
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -218,157 +238,89 @@ void database::CoverArtRepository::updateRecord(const model::Cover& cover)
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "updated cover art record" << std::endl; std::cout << "updated cover art record\n";
} }
std::vector<model::Cover> database::CoverArtRepository::parseRecords(MYSQL_STMT *stmt) std::vector<model::Cover> CoverArtRepository::parseRecords(MYSQL_STMT *stmt) {
{
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt); const auto rowCount = mysql_stmt_num_rows(stmt);
std::cout << "number of results " << rowCount << std::endl; std::cout << "number of results " << rowCount << "\n";
std::vector<model::Cover> coverArts; std::vector<model::Cover> coverArts;
coverArts.reserve(rowCount); coverArts.reserve(rowCount);
const auto valAmt = 3; constexpr auto valAmt = 3;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) { for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
if (mysql_stmt_field_count(stmt) > 0) { if (mysql_stmt_field_count(stmt) > 0) {
model::Cover coverArt; model::Cover cover;
auto res = mysql_stmt_result_metadata(stmt); auto metaBuff = metadataBuffer();
auto fields = mysql_fetch_fields(res); auto bindedValues = valueBind(cover, metaBuff);
auto strLen = 1024; status = mysql_stmt_bind_result(stmt, bindedValues.get());
MYSQL_BIND val[valAmt]; std::cout << "fetching statement result\n";
memset(val, 0, sizeof(val));
char songTitle[strLen];
char imagePath[strLen];
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&coverArt.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_STRING;
val[1].buffer = (char*)songTitle;
val[1].buffer_length = strLen;
val[1].length = &len[1];
val[1].is_null = &nullRes[1];
val[2].buffer_type = MYSQL_TYPE_STRING;
val[2].buffer = (char*)imagePath;
val[2].buffer_length = strLen;
val[2].length = &len[2];
val[2].is_null = &nullRes[2];
status = mysql_stmt_bind_result(stmt, val);
while (true) {
std::cout << "fetching statement result" << std::endl;
status = mysql_stmt_fetch(stmt); status = mysql_stmt_fetch(stmt);
if (status == 1 || status == MYSQL_NO_DATA) { if (status == 1 || status == MYSQL_NO_DATA) break;
break;
}
coverArt.songTitle = songTitle; cover.songTitle = std::get<0>(metaBuff);
coverArt.imagePath = imagePath; cover.imagePath = std::get<1>(metaBuff);
coverArts.push_back(cover);
coverArts.push_back(std::move(coverArt));
} }
} std::cout << "fetching next result\n";
std::cout << "fetching next result" << std::endl;
} }
return coverArts; return coverArts;
} }
model::Cover database::CoverArtRepository::parseRecord(MYSQL_RES *results) std::shared_ptr<MYSQL_BIND> CoverArtRepository::valueBind(model::Cover& cover,
{ std::tuple<char*, char*>& metadata) {
std::cout << "parsing record" << std::endl; constexpr auto valueCount = 3;
model::Cover cov; constexpr auto wordLen = 1024;
auto fieldNum = mysql_num_fields(results); std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*)
std::calloc(valueCount, sizeof(MYSQL_BIND)));
MYSQL_ROW row = mysql_fetch_row(results); values.get()[0].buffer_type = MYSQL_TYPE_LONG;
values.get()[0].buffer = reinterpret_cast<char*>(&cover.id);
for (auto i = 0; i != fieldNum; ++i) { values.get()[1].buffer_type = MYSQL_TYPE_STRING;
switch (i) { values.get()[1].buffer = reinterpret_cast<char*>(std::get<0>(metadata));
case 0: values.get()[1].buffer_length = wordLen;
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; 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;
} }
model::Cover database::CoverArtRepository::parseRecord(MYSQL_STMT *stmt)
{
std::cout << "parsing cover art record" << std::endl;
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); mysql_stmt_store_result(stmt);
model::Cover cover; model::Cover cover;
auto status = 0; auto metaBuff = metadataBuffer();
auto time = 0; auto bindedValues = valueBind(cover, metaBuff);
auto valAmt = 3; auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
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); status = mysql_stmt_fetch(stmt);
cover.songTitle = songTitle; cover.songTitle = std::get<0>(metaBuff);
cover.imagePath = imagePath; cover.imagePath = std::get<1>(metaBuff);
}
status = mysql_stmt_next_result(stmt); std::cout << "done parsing cover art record\n";
}
std::cout << "done parsing cover art record" << std::endl;
return cover; return cover;
} }
}
+124 -128
View File
@@ -5,13 +5,11 @@
#include <sstream> #include <sstream>
#include <cstring> #include <cstring>
database::GenreRepository::GenreRepository(const model::BinaryPath& bConf) namespace database {
: BaseRepository(bConf) GenreRepository::GenreRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { }
{ }
std::vector<model::Genre> database::GenreRepository::retrieveRecords() std::vector<model::Genre> GenreRepository::retrieveRecords() {
{
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Genre"; const std::string query = "SELECT * FROM Genre";
@@ -27,9 +25,9 @@ std::vector<model::Genre> database::GenreRepository::retrieveRecords()
return genres; return genres;
} }
std::pair<model::Genre, int> database::GenreRepository::retrieveRecordWithSongCount(model::Genre& genre, type::GenreFilter filter = type::GenreFilter::id) std::pair<model::Genre, int> GenreRepository::retrieveRecordWithSongCount(
{ model::Genre& genre, type::GenreFilter filter = type::GenreFilter::id) {
std::cout << "retrieving genre record with song count" << std::endl; std::cout << "retrieving genre record with song count\n";
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -66,29 +64,38 @@ std::pair<model::Genre, int> database::GenreRepository::retrieveRecordWithSongCo
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "retrieved genre record with song count" << std::endl; std::cout << "retrieved genre record with song count\n";
return gnrWSC; return gnrWSC;
} }
model::Genre database::GenreRepository::retrieveRecord(model::Genre& genre, type::GenreFilter filter) model::Genre GenreRepository::retrieveRecord(model::Genre& genre, type::GenreFilter filter) {
{ std::cout << "retrieving genre record\n";
// TODO: change to prepared statement
std::cout << "retrieving genre record" << std::endl;
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT gnr.* FROM Genre gnr WHERE "; qry << "SELECT gnr.* FROM Genre gnr WHERE ";
std::unique_ptr<char*> param; MYSQL_BIND params[1];
std::memset(params, 0, sizeof(params));
auto categoryLength = genre.category.size();
switch (filter) { switch (filter) {
case type::GenreFilter::id: case type::GenreFilter::id:
qry << "gnr.GenreId = " << genre.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; break;
case type::GenreFilter::category: case type::GenreFilter::category:
param = std::make_unique<char*>(new char[genre.category.size()]); qry << "gnr.Category = ?";
mysql_real_escape_string(conn, *param, genre.category.c_str(), genre.category.size());
qry << "gnr.Category ='" << *param << "'"; 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; break;
default: default:
break; break;
@@ -97,19 +104,21 @@ model::Genre database::GenreRepository::retrieveRecord(model::Genre& genre, type
qry << " ORDER BY GenreId DESC LIMIT 1"; qry << " ORDER BY GenreId DESC LIMIT 1";
const auto query = qry.str(); const auto query = qry.str();
auto results = performMysqlQuery(conn, query); 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(results); genre = parseRecord(stmt);
mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "retrieved record" << std::endl; std::cout << "retrieved record\n";
return genre; return genre;
} }
bool database::GenreRepository::doesGenreExist(const model::Genre& genre, type::GenreFilter filter) bool GenreRepository::doesGenreExist(const model::Genre& genre, type::GenreFilter filter) {
{
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -148,7 +157,7 @@ bool database::GenreRepository::doesGenreExist(const model::Genre& genre, type::
status = mysql_stmt_bind_param(stmt, params); status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt); status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed" << std::endl; std::cout << "the query has been performed\n";
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt); auto rowCount = mysql_stmt_num_rows(stmt);
@@ -159,9 +168,8 @@ bool database::GenreRepository::doesGenreExist(const model::Genre& genre, type::
return (rowCount > 0) ? true : false; return (rowCount > 0) ? true : false;
} }
void database::GenreRepository::saveRecord(const model::Genre& genre) void GenreRepository::saveRecord(const model::Genre& genre) {
{ std::cout << "inserting genre record\n";
std::cout << "inserting genre record" << std::endl;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
MYSQL_STMT *stmt = mysql_stmt_init(conn); MYSQL_STMT *stmt = mysql_stmt_init(conn);
@@ -185,13 +193,12 @@ void database::GenreRepository::saveRecord(const model::Genre& genre)
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "inserted record" << std::endl; std::cout << "inserted record\n";
} }
void database::GenreRepository::deleteRecord(const model::Genre& genre, type::GenreFilter filter = type::GenreFilter::id) void GenreRepository::deleteRecord(const model::Genre& genre,
{ type::GenreFilter filter = type::GenreFilter::id) {
// TODO: implement this std::cout << "deleting genre record\n";
std::cout << "deleting genre record" << std::endl;
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -223,137 +230,126 @@ void database::GenreRepository::deleteRecord(const model::Genre& genre, type::Ge
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "deleted genre record" << std::endl; std::cout << "deleted genre record\n";
} }
std::vector<model::Genre> database::GenreRepository::parseRecords(MYSQL_STMT *stmt) std::vector<model::Genre> GenreRepository::parseRecords(MYSQL_STMT *stmt) {
{
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
std::vector<model::Genre> genres; std::vector<model::Genre> genres;
genres.reserve(mysql_stmt_num_rows(stmt)); genres.reserve(mysql_stmt_num_rows(stmt));
if (mysql_stmt_field_count(stmt) == 0) { constexpr auto valAmt = 2;
std::cout << "field count is 0" << std::endl;
return genres;
}
model::Genre gnr; for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
const auto valAmt = 2; if (mysql_stmt_field_count(stmt) > 0) {
unsigned long len[valAmt]; model::Genre genre;
my_bool nullRes[valAmt]; auto metaBuff = metadataBuffer();
auto bindedValues = valueBind(genre, metaBuff);
status = mysql_stmt_bind_result(stmt, bindedValues.get());
auto res = mysql_stmt_result_metadata(stmt); std::cout << "fetching statement result\n";
auto fields = mysql_fetch_fields(res);
const auto strLen = 1024;
char category[strLen];
MYSQL_BIND val[valAmt];
memset(val, 0, sizeof(val));
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&gnr.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_STRING;
val[1].buffer = (char*)category;
val[1].buffer_length = strLen;
val[1].length = &len[1];
val[1].is_null = &nullRes[1];
for (auto status = mysql_stmt_bind_result(stmt, val); status == 0;) {
std::cout << "fetching statement result" << std::endl;
status = mysql_stmt_fetch(stmt); status = mysql_stmt_fetch(stmt);
if (status == 0) { if (status == 1 || status == MYSQL_NO_DATA) break;
gnr.category = category;
genres.push_back(std::move(gnr)); genre.category = std::get<0>(metaBuff);
genres.push_back(genre);
} }
std::cout << "fetching statement result\n";
} }
return genres; return genres;
} }
std::pair<model::Genre, int> database::GenreRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) std::pair<model::Genre, int> GenreRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) {
{ std::cout << "parsing genre record with song count\n";
std::cout << "parsing genre record with song count" << std::endl;
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
const auto rowCount = mysql_stmt_num_rows(stmt);
const auto strLen = 1024;
const auto valAmt = 3;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
model::Genre genre; model::Genre genre;
int songCount = 0; int songCount = 0;
if (mysql_stmt_num_rows(stmt) == 0) { auto metaBuff = metadataBuffer();
std::cout << "no results" << std::endl; auto val = valueBindWithSongCount(genre, metaBuff, songCount);
if (rowCount == 0) {
std::cout << "no results\n";
return std::make_pair(genre, songCount); return std::make_pair(genre, songCount);
} }
MYSQL_BIND val[valAmt]; auto status = mysql_stmt_bind_result(stmt, val.get());
std::memset(val, 0, sizeof(val)); status = mysql_stmt_fetch(stmt);
char category[strLen] ; genre.category = std::get<0>(metaBuff);
val[0].buffer_type = MYSQL_TYPE_LONG; std::cout << "parsed genre record with song count\n";
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); return std::make_pair(genre, songCount);
} }
model::Genre database::GenreRepository::parseRecord(MYSQL_RES* results)
{ std::shared_ptr<MYSQL_BIND> GenreRepository::valueBind(model::Genre& genre,
std::cout << "parsing genre record" << std::endl; 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::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)));
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;
}
std::tuple<char*> GenreRepository::metadataBuffer() {
constexpr auto wordLen = 1024;
char category[wordLen];
return std::make_tuple(category);
}
model::Genre GenreRepository::parseRecord(MYSQL_STMT *stmt) {
std::cout << "parsing genre record\n";
mysql_stmt_store_result(stmt);
model::Genre genre; 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);
auto fieldNum = mysql_num_fields(results); genre.category = std::get<0>(metaBuff);
auto row = mysql_fetch_row(results);
for (auto i =0; i != fieldNum; ++i) { std::cout << "done parsing genre record\n";
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; return genre;
} }
model::Genre database::GenreRepository::parseRecord(MYSQL_STMT *stmt)
{
// TODO: implement this
model::Genre genre;
return genre;
} }
+278 -414
View File
@@ -7,18 +7,17 @@
#include "type/SongFilter.h" #include "type/SongFilter.h"
database::SongRepository::SongRepository(const std::string& path) : BaseRepository(path) namespace database {
{ } SongRepository::SongRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { }
database::SongRepository::SongRepository(const model::BinaryPath& bConf) : BaseRepository(bConf)
{ }
std::vector<model::Song> database::SongRepository::retrieveRecords() std::vector<model::Song> SongRepository::retrieveRecords() {
{
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Song"; std::stringstream qry;
qry << "SELECT sng.*, alb.Artist AS AlbumArtist FROM Song sng ";
qry << "LEFT JOIN Album alb ON sng.AlbumId=alb.AlbumId";
const auto query = qry.str();
::mysql_stmt_prepare(stmt, query.c_str(), query.size()); ::mysql_stmt_prepare(stmt, query.c_str(), query.size());
::mysql_stmt_execute(stmt); ::mysql_stmt_execute(stmt);
@@ -32,21 +31,39 @@ std::vector<model::Song> database::SongRepository::retrieveRecords()
} }
model::Song database::SongRepository::retrieveRecord(model::Song& song, type::SongFilter filter) model::Song SongRepository::retrieveRecord(const model::Song& song, type::SongFilter filter) {
{
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
MYSQL_BIND params[1]; auto valueFilterCount = 1;
switch (filter) {
case type::SongFilter::titleAndArtist:
valueFilterCount = 2;
break;
case type::SongFilter::titleAlbArtistAlbum:
valueFilterCount = 3;
break;
case type::SongFilter::titleAlbArtistAlbumTrack:
valueFilterCount = 4;
break;
default:
break;
}
MYSQL_BIND params[valueFilterCount];
memset(params, 0, sizeof(params)); memset(params, 0, sizeof(params));
qry << "SELECT * FROM Song WHERE "; qry << "SELECT sng.*, alb.Artist AS AlbumArtist FROM Song sng ";
qry << "LEFT JOIN Album alb ON sng.AlbumId=alb.AlbumId WHERE ";
auto titleLength = song.title.size(); auto titleLength = song.title.size();
auto artistLength = song.artist.size();
auto albumArtistLength = song.albumArtist.size();
auto albumLength = song.album.size();
switch (filter) { switch (filter) {
case type::SongFilter::id: case type::SongFilter::id:
qry << "SongId = ?"; qry << "sng.SongId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG; params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&song.id; params[0].buffer = (char*)&song.id;
@@ -54,52 +71,126 @@ model::Song database::SongRepository::retrieveRecord(model::Song& song, type::So
params[0].is_null = 0;; params[0].is_null = 0;;
break; break;
case type::SongFilter::title: case type::SongFilter::title:
qry << "Title = ?"; qry << "sng.Title = ?";
params[0].buffer_type = MYSQL_TYPE_STRING; params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)song.title.c_str(); params[0].buffer = (char*)song.title.c_str();
params[0].length = &titleLength; params[0].length = &titleLength;
params[0].is_null = 0; params[0].is_null = 0;
break; break;
case type::SongFilter::titleAndArtist:
qry << "sng.Title = ? AND sng.Artist = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)song.title.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)song.artist.c_str();
params[1].length = &artistLength;
params[1].is_null = 0;
std::cout << "title: " << song.title.c_str() << " artist: " <<
song.artist.c_str() << "\n";
break;
case type::SongFilter::titleAlbArtistAlbum:
qry << "sng.Title = ? AND sng.Album = ? AND alb.Artist = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)song.title.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)song.album.c_str();
params[1].length = &albumLength;
params[1].is_null = 0;
params[2].buffer_type = MYSQL_TYPE_STRING;
params[2].buffer = (char*)song.albumArtist.c_str();
params[2].length = &albumArtistLength;
params[2].is_null = 0;
break;
case type::SongFilter::titleAlbArtistAlbumTrack:
qry << "sng.Title = ? AND sng.Album = ? AND alb.Artist = ? AND sng.Track = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)song.title.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)song.album.c_str();
params[1].length = &titleLength;
params[1].is_null = 0;
params[2].buffer_type = MYSQL_TYPE_STRING;
params[2].buffer = (char*)song.albumArtist.c_str();
params[2].length = &titleLength;
params[2].is_null = 0;
params[3].buffer_type = MYSQL_TYPE_LONG;
params[3].buffer = (char*)&song.track;
params[3].length = 0;
params[3].is_null = 0;;
break;
default: default:
break; break;
} }
qry << " LIMIT 1"; qry << " LIMIT 1";
const std::string query = qry.str(); const auto query = qry.str();
auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size()); auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params); status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt); status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed" << std::endl; std::cout << "the query has been performed\n";
song = parseRecord(stmt); auto retrievedSong = parseRecord(stmt);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "done" << std::endl;
return song; return retrievedSong;
} }
bool database::SongRepository::doesSongExist(const model::Song& song, type::SongFilter filter) bool SongRepository::doesSongExist(const model::Song& song, type::SongFilter filter) {
{ std::cout << "checking to see if song exists\n";
std::cout << "checking to see if song exists" << std::endl;
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
auto valueFilterCount = 1;
switch (filter) {
case type::SongFilter::titleAndArtist:
valueFilterCount = 2;
break;
case type::SongFilter::titleAlbArtistAlbum:
valueFilterCount = 3;
break;
case type::SongFilter::titleAlbArtistAlbumTrack:
valueFilterCount = 4;
break;
default:
break;
}
MYSQL_BIND params[1];
MYSQL_BIND params[valueFilterCount];
memset(params, 0, sizeof(params)); memset(params, 0, sizeof(params));
qry << "SELECT * FROM Song WHERE "; qry << "SELECT sng.* FROM Song sng ";
qry << "LEFT JOIN Album alb ON sng.AlbumId = alb.AlbumId WHERE ";
auto titleLength = song.title.size(); auto titleLength = song.title.size();
auto artistLength = song.artist.size();
auto albumArtistLength = song.albumArtist.size();
auto albumLength = song.album.size();
switch (filter) { switch (filter) {
case type::SongFilter::id: case type::SongFilter::id:
qry << "SongId = ?"; qry << "sng.SongId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG; params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&song.id; params[0].buffer = (char*)&song.id;
@@ -107,13 +198,67 @@ bool database::SongRepository::doesSongExist(const model::Song& song, type::Song
params[0].is_null = 0; params[0].is_null = 0;
break; break;
case type::SongFilter::title: case type::SongFilter::title:
qry << "Title = ?"; qry << "sng.Title = ?";
params[0].buffer_type = MYSQL_TYPE_STRING; params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)song.title.c_str(); params[0].buffer = (char*)song.title.c_str();
params[0].length = &titleLength; params[0].length = &titleLength;
params[0].is_null = 0; params[0].is_null = 0;
break; break;
case type::SongFilter::titleAndArtist:
qry << "sng.Title = ? AND sng.Artist = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)song.title.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)song.artist.c_str();
params[1].length = &artistLength;
params[1].is_null = 0;
break;
case type::SongFilter::titleAlbArtistAlbum:
qry << "sng.Title = ? AND sng.Album = ? AND alb.Artist = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)song.title.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)song.album.c_str();
params[1].length = &albumLength;
params[1].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)song.albumArtist.c_str();
params[1].length = &albumArtistLength;
params[1].is_null = 0;
break;
case type::SongFilter::titleAlbArtistAlbumTrack:
qry << "sng.Title = ? AND sng.Album = ? AND alb.Artist = ? AND sng.Track = ?";
params[0].buffer_type = MYSQL_TYPE_STRING;
params[0].buffer = (char*)song.title.c_str();
params[0].length = &titleLength;
params[0].is_null = 0;
params[1].buffer_type = MYSQL_TYPE_STRING;
params[1].buffer = (char*)song.album.c_str();
params[1].length = &titleLength;
params[1].is_null = 0;
params[2].buffer_type = MYSQL_TYPE_STRING;
params[2].buffer = (char*)song.albumArtist.c_str();
params[2].length = &titleLength;
params[2].is_null = 0;
params[3].buffer_type = MYSQL_TYPE_LONG;
params[3].buffer = (char*)&song.track;
params[3].length = 0;
params[3].is_null = 0;;
break;
default: default:
break; break;
} }
@@ -125,20 +270,18 @@ bool database::SongRepository::doesSongExist(const model::Song& song, type::Song
status = mysql_stmt_bind_param(stmt, params); status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt); status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed" << std::endl; std::cout << "the query has been performed\n";
::mysql_stmt_store_result(stmt); ::mysql_stmt_store_result(stmt);
auto rowCount = ::mysql_stmt_num_rows(stmt); auto rowCount = ::mysql_stmt_num_rows(stmt);
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "done" << std::endl;
return (rowCount > 0) ? true : false; return (rowCount > 0) ? true : false;
} }
bool database::SongRepository::deleteRecord(const model::Song& song) bool SongRepository::deleteRecord(const model::Song& song) {
{
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto status = 0; auto status = 0;
@@ -151,9 +294,8 @@ bool database::SongRepository::deleteRecord(const model::Song& song)
return (result == 0) ? true : false; return (result == 0) ? true : false;
} }
void database::SongRepository::saveRecord(const model::Song& song) void SongRepository::saveRecord(const model::Song& song) {
{ std::cout << "beginning to insert song record\n";
std::cout << "beginning to insert song record" << std::endl;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto status = 0; auto status = 0;
@@ -249,12 +391,11 @@ void database::SongRepository::saveRecord(const model::Song& song)
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "done inserting song record" << std::endl; std::cout << "done inserting song record\n";
} }
void database::SongRepository::updateRecord(const model::Song& song) void SongRepository::updateRecord(const model::Song& song) {
{ std::cout << "executing query to update record\n";
std::cout << "executing query to update record" << std::endl;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -340,251 +481,127 @@ void database::SongRepository::updateRecord(const model::Song& song)
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "updated song record" << std::endl; std::cout << "updated song record\n";
} }
// TODO: delete this, not being used std::shared_ptr<MYSQL_BIND> SongRepository::valueBind(model::Song& song,
std::vector<model::Song> database::SongRepository::parseRecords(MYSQL_RES* results) std::tuple<char*, char*, char*, char*, char*, char*>& metadata) {
{ constexpr auto strLen = 1024;
auto fieldNum = mysql_num_fields(results); constexpr auto valueCount = 16;
auto numRows = mysql_num_rows(results); std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(valueCount, sizeof(MYSQL_BIND)));
unsigned long len[valueCount];
my_bool nullRes[valueCount];
std::vector<model::Song> songs;
songs.reserve(numRows);
for (MYSQL_ROW row = nullptr; (row = mysql_fetch_row(results)) != nullptr; ) { values.get()[0].buffer_type = MYSQL_TYPE_LONG;
model::Song song; values.get()[0].buffer = (char*)&song.id;
for (auto i = 0; i != fieldNum; ++i) { values.get()[1].buffer_type = MYSQL_TYPE_STRING;
/** values.get()[1].buffer = (char*)std::get<0>(metadata);
auto field = mysql_fetch_field(results); values.get()[1].buffer_length = strLen;
if (field->name == NULL) {
std::cout << "null field" << std::endl;
break;
}
*/
/**
std::string field;
if ((i + 0) == fieldNum) {
std::cout << "goodbye" << std::endl;
break;
} else {
std::cout << "still good" << std::endl;
field.assign(mysql_fetch_field(results)->name);
}
//const std::string field(row[i].field);
std::cout << field << std::endl;
if (field.compare("SongId") == 0) { values.get()[2].buffer_type = MYSQL_TYPE_STRING;
song.id = std::stoi(row[i]); values.get()[2].buffer = (char*)std::get<1>(metadata);
} values.get()[2].buffer_length = strLen;
if (field.compare("Title") == 0) {
song.title = row[i]; values.get()[3].buffer_type = MYSQL_TYPE_STRING;
} values.get()[3].buffer = (char*)std::get<2>(metadata);
if (field.compare("Artist") == 0) { values.get()[3].buffer_length = strLen;
song.artist = row[i];
} values.get()[4].buffer_type = MYSQL_TYPE_STRING;
if (field.compare("Album") == 0) { values.get()[4].buffer = (char*)std::get<3>(metadata);
song.album = row[i]; values.get()[4].buffer_length = strLen;
}
if (field.compare("Genre") == 0) { values.get()[5].buffer_type = MYSQL_TYPE_LONG;
song.genre = row[i]; values.get()[5].buffer = (char*)&song.year;
}
if (field.compare("Year") == 0) { values.get()[6].buffer_type = MYSQL_TYPE_LONG;
song.year = std::stoi(row[i]); values.get()[6].buffer = (char*)&song.duration;
}
if (field.compare("Duration") == 0) { values.get()[7].buffer_type = MYSQL_TYPE_LONG;
song.duration = std::stoi(row[i]); values.get()[7].buffer = (char*)&song.track;
}
if (field.compare("Track") == 0) { values.get()[8].buffer_type = MYSQL_TYPE_LONG;
song.track = std::stoi(row[i]); values.get()[8].buffer = (char*)&song.disc;
}
if (field.compare("Disc") == 0) { values.get()[9].buffer_type = MYSQL_TYPE_STRING;
song.disc = std::stoi(row[i]); values.get()[9].buffer = (char*)std::get<4>(metadata);
} values.get()[9].buffer_length = strLen;
if (field.compare("SongPath") == 0) {
song.songPath = row[i]; values.get()[10].buffer_type = MYSQL_TYPE_LONG;
} values.get()[10].buffer = (char*)&song.coverArtId;
if (field.compare("CoverArtId") == 0) {
song.coverArtId = std::stoi(row[i]); values.get()[11].buffer_type = MYSQL_TYPE_LONG;
} values.get()[11].buffer = (char*)&song.artistId;
*/
switch (i) { values.get()[12].buffer_type = MYSQL_TYPE_LONG;
case 0: values.get()[12].buffer = (char*)&song.albumId;;
song.id = std::stoi(row[i]);
break; values.get()[13].buffer_type = MYSQL_TYPE_LONG;
case 1: values.get()[13].buffer = (char*)&song.genreId;
song.title = row[i];
break; values.get()[14].buffer_type = MYSQL_TYPE_LONG;
case 2: values.get()[14].buffer = (char*)&song.yearId;
song.artist= row[i];
break; values.get()[15].buffer_type = MYSQL_TYPE_STRING;
case 3: values.get()[15].buffer = (char*)std::get<5>(metadata);
song.album = row[i]; values.get()[15].buffer_length = strLen;
break;
case 4: return values;
song.genre = row[i];
break;
case 5:
song.year = std::stoi(row[i]);
break;
case 6:
song.duration = std::stoi(row[i]);
break;
case 7:
song.track = std::stoi(row[i]);
break;
case 8:
song.disc = std::stoi(row[i]);
break;
case 9:
song.songPath = row[i];
break;
case 10:
song.coverArtId = std::stoi(row[i]);
break;
}
} }
songs.push_back(song);
std::tuple<char*, char*, char*, char*, char*, char*> SongRepository::metadataBuffer() {
constexpr auto length = 1024;
char title[length];
char artist[length];
char album[length];
char genre[length];
char path[length];
char albumArtist[length];
return std::make_tuple(title, artist, album, genre, path, albumArtist);
} }
return songs;
}
std::vector<model::Song> database::SongRepository::parseRecords(MYSQL_STMT *stmt) std::vector<model::Song> SongRepository::parseRecords(MYSQL_STMT *stmt) {
{
::mysql_stmt_store_result(stmt); ::mysql_stmt_store_result(stmt);
auto c = ::mysql_stmt_num_rows(stmt); auto c = ::mysql_stmt_num_rows(stmt);
std::cout << "number of results " << c << std::endl; std::cout << "number of results " << c << "\n";
std::vector<model::Song> songs; std::vector<model::Song> songs;
songs.reserve(c); songs.reserve(c);
auto status = 0; auto status = 0;
auto time = 0; auto time = 0;
auto valAmt = 15;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
while (status == 0) { while (status == 0) {
std::cout << time++ << " time" << std::endl;
std::cout << "field count " << ::mysql_stmt_field_count(stmt) << std::endl;
if (::mysql_stmt_field_count(stmt) > 0) { if (::mysql_stmt_field_count(stmt) > 0) {
model::Song song; model::Song song;
auto res = ::mysql_stmt_result_metadata(stmt); auto metaBuff = metadataBuffer();
auto fields = ::mysql_fetch_fields(res); auto val = valueBind(song, metaBuff);
auto strLen = 1024;
MYSQL_BIND val[valAmt];
memset(val, 0, sizeof(val));
char title[strLen]; status = ::mysql_stmt_bind_result(stmt, val.get());
char album[strLen];
char artist[strLen];
char genre[strLen];
char path[strLen];
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&song.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_STRING;
val[2].buffer = (char*)artist;
val[2].buffer_length = strLen;
val[2].length = &len[2];
val[2].is_null = &nullRes[2];
val[3].buffer_type = MYSQL_TYPE_STRING;
val[3].buffer = (char*)album;
val[3].buffer_length = strLen;
val[3].length = &len[3];
val[3].is_null = &nullRes[3];
val[4].buffer_type = MYSQL_TYPE_STRING;
val[4].buffer = (char*)genre;
val[4].buffer_length = strLen;
val[4].length = &len[4];
val[4].is_null = &nullRes[4];
val[5].buffer_type = MYSQL_TYPE_LONG;
val[5].buffer = (char*)&song.year;
val[5].length = &len[5];
val[5].is_null = &nullRes[5];
val[6].buffer_type = MYSQL_TYPE_LONG;
val[6].buffer = (char*)&song.duration;
val[6].length = &len[6];
val[6].is_null = &nullRes[6];
val[7].buffer_type = MYSQL_TYPE_LONG;
val[7].buffer = (char*)&song.track;
val[7].length = &len[7];
val[7].is_null = &nullRes[7];
val[8].buffer_type = MYSQL_TYPE_LONG;
val[8].buffer = (char*)&song.disc;
val[8].length = &len[8];
val[8].is_null = &nullRes[8];
val[9].buffer_type = MYSQL_TYPE_STRING;
val[9].buffer = (char*)path;
val[9].buffer_length = strLen;
val[9].length = &len[9];
val[9].is_null = &nullRes[9];
val[10].buffer_type = MYSQL_TYPE_LONG;
val[10].buffer = (char*)&song.coverArtId;
val[10].length = &len[10];
val[10].is_null = &nullRes[10];
val[11].buffer_type = MYSQL_TYPE_LONG;
val[11].buffer = (char*)&song.artistId;
val[11].length = &len[11];
val[11].is_null = &nullRes[11];
val[12].buffer_type = MYSQL_TYPE_LONG;
val[12].buffer = (char*)&song.albumId;;
val[12].length = &len[12];
val[12].is_null = &nullRes[12];
val[13].buffer_type = MYSQL_TYPE_LONG;
val[13].buffer = (char*)&song.genreId;
val[13].length = &len[13];
val[13].is_null = &nullRes[13];
val[14].buffer_type = MYSQL_TYPE_LONG;
val[14].buffer = (char*)&song.yearId;
val[14].length = &len[14];
val[14].is_null = &nullRes[14];
status = ::mysql_stmt_bind_result(stmt, val);
while (1) { while (1) {
std::cout << "fetching statement result" << std::endl; std::cout << "fetching statement result\n";
status = ::mysql_stmt_fetch(stmt); status = ::mysql_stmt_fetch(stmt);
if (status == 1 || status == MYSQL_NO_DATA) { if (status == 1 || status == MYSQL_NO_DATA) {
break; break;
} }
song.title = title;
song.album = album; song.title = std::get<0>(metaBuff);
song.artist = artist; song.artist = std::get<1>(metaBuff);
song.genre = genre; song.album = std::get<2>(metaBuff);
song.songPath = path; song.genre = std::get<3>(metaBuff);
song.songPath = std::get<4>(metaBuff);
song.albumArtist = std::get<5>(metaBuff);
songs.push_back(song); songs.push_back(song);
} }
} }
std::cout << "fetching next result" << std::endl; std::cout << "fetching next result\n";
status = ::mysql_stmt_next_result(stmt); status = ::mysql_stmt_next_result(stmt);
} }
@@ -592,177 +609,24 @@ std::vector<model::Song> database::SongRepository::parseRecords(MYSQL_STMT *stmt
} }
// TODO: delete this, not being used anymore model::Song SongRepository::parseRecord(MYSQL_STMT *stmt) {
model::Song database::SongRepository::parseRecord(MYSQL_RES* results) mysql_stmt_store_result(stmt);
{ std::cout << "amount of rows: " << mysql_stmt_num_rows(stmt) << "\n";
model::Song song; model::Song song;
auto metaBuff = metadataBuffer();
auto bindedValues = valueBind(song, metaBuff);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt);
auto fieldNum = mysql_num_fields(results); song.title = std::get<0>(metaBuff);
auto row = mysql_fetch_row(results); song.artist = std::get<1>(metaBuff);
song.album = std::get<2>(metaBuff);
song.genre = std::get<3>(metaBuff);
song.songPath = std::get<4>(metaBuff);
song.albumArtist = std::get<5>(metaBuff);
for (auto i = 0; i != fieldNum; ++i) { std::cout << "done parsing record\n";
const std::string field(mysql_fetch_field(results)->name);
switch (i) {
case 0:
song.id = std::stoi(row[i]);
break;
case 1:
song.title = row[i];
break;
case 2:
song.artist= row[i];
break;
case 3:
song.album = row[i];
break;
case 4:
song.genre = row[i];
break;
case 5:
song.year = std::stoi(row[i]);
break;
case 6:
song.duration = std::stoi(row[i]);
break;
case 7:
song.track = std::stoi(row[i]);
break;
case 8:
song.disc = std::stoi(row[i]);
break;
case 9:
song.songPath = row[i];
break;
case 10:
song.coverArtId = std::stoi(row[i]);
break;
}
}
std::cout << "done parsing record" << std::endl;
return song; return song;
} }
model::Song database::SongRepository::parseRecord(MYSQL_STMT *stmt)
{
model::Song song;
auto status = 0;
auto time = 0;
auto valAmt = 15;
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];
char album[strLen];
char artist[strLen];
char genre[strLen];
char path[strLen];
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&song.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_STRING;
val[2].buffer = (char*)artist;
val[2].buffer_length = strLen;
val[2].length = &len[2];
val[2].is_null = &nullRes[2];
val[3].buffer_type = MYSQL_TYPE_STRING;
val[3].buffer = (char*)album;
val[3].buffer_length = strLen;
val[3].length = &len[3];
val[3].is_null = &nullRes[3];
val[4].buffer_type = MYSQL_TYPE_STRING;
val[4].buffer = (char*)genre;
val[4].buffer_length = strLen;
val[4].length = &len[4];
val[4].is_null = &nullRes[4];
val[5].buffer_type = MYSQL_TYPE_LONG;
val[5].buffer = (char*)&song.year;
val[5].length = &len[5];
val[5].is_null = &nullRes[5];
val[6].buffer_type = MYSQL_TYPE_LONG;
val[6].buffer = (char*)&song.duration;
val[6].length = &len[6];
val[6].is_null = &nullRes[6];
val[7].buffer_type = MYSQL_TYPE_LONG;
val[7].buffer = (char*)&song.track;
val[7].length = &len[7];
val[7].is_null = &nullRes[7];
val[8].buffer_type = MYSQL_TYPE_LONG;
val[8].buffer = (char*)&song.disc;
val[8].length = &len[8];
val[8].is_null = &nullRes[8];
val[9].buffer_type = MYSQL_TYPE_STRING;
val[9].buffer = (char*)path;
val[9].buffer_length = strLen;
val[9].length = &len[9];
val[9].is_null = &nullRes[9];
val[10].buffer_type = MYSQL_TYPE_LONG;
val[10].buffer = (char*)&song.coverArtId;
val[10].length = &len[10];
val[10].is_null = &nullRes[10];
val[11].buffer_type = MYSQL_TYPE_LONG;
val[11].buffer = (char*)&song.artistId;
val[11].length = &len[11];
val[11].is_null = &nullRes[11];
val[12].buffer_type = MYSQL_TYPE_LONG;
val[12].buffer = (char*)&song.albumId;;
val[12].length = &len[12];
val[12].is_null = &nullRes[12];
val[13].buffer_type = MYSQL_TYPE_LONG;
val[13].buffer = (char*)&song.genreId;
val[13].length = &len[13];
val[13].is_null = &nullRes[13];
val[14].buffer_type = MYSQL_TYPE_LONG;
val[14].buffer = (char*)&song.yearId;
val[14].length = &len[14];
val[14].is_null = &nullRes[14];
status = ::mysql_stmt_bind_result(stmt, val);
::mysql_stmt_store_result(stmt);
status = ::mysql_stmt_fetch(stmt);
song.title = title;
song.album = album;
song.artist = artist;
song.genre = genre;
song.songPath = path;
}
status = ::mysql_stmt_next_result(stmt);
}
std::cout << "done parsing record" << std::endl;
return song;
} }
+30 -32
View File
@@ -11,8 +11,7 @@ UserRepository::UserRepository(const model::BinaryPath& bConf) : BaseRepository(
model::User UserRepository::retrieveUserRecord(model::User& user, model::User UserRepository::retrieveUserRecord(model::User& user,
type::UserFilter filter = type::UserFilter::username) type::UserFilter filter = type::UserFilter::username) {
{
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -25,6 +24,13 @@ model::User UserRepository::retrieveUserRecord(model::User& user,
auto userLength = user.username.size(); auto userLength = user.username.size();
switch (filter) { switch (filter) {
case type::UserFilter::id: case type::UserFilter::id:
qry << "UserId = ?";
params[0].buffer_type = MYSQL_TYPE_LONG;
params[0].buffer = (char*)&user.id;
params[0].length = nullptr;
params[0].is_null = 0;
break; break;
case type::UserFilter::username: case type::UserFilter::username:
qry << "Username = ?"; qry << "Username = ?";
@@ -53,8 +59,8 @@ model::User UserRepository::retrieveUserRecord(model::User& user,
return user; return user;
} }
model::PassSec UserRepository::retrieverUserSaltRecord(model::PassSec& userSec, type::SaltFilter filter) model::PassSec UserRepository::retrieverUserSaltRecord(model::PassSec& userSec,
{ type::SaltFilter filter) {
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -93,8 +99,7 @@ model::PassSec UserRepository::retrieverUserSaltRecord(model::PassSec& userSec,
} }
bool UserRepository::doesUserRecordExist(const model::User& user, type::UserFilter filter) bool UserRepository::doesUserRecordExist(const model::User& user, type::UserFilter filter) {
{
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -133,9 +138,10 @@ bool UserRepository::doesUserRecordExist(const model::User& user, type::UserFilt
return (rowCount > 0) ? true : false; return (rowCount > 0) ? true : false;
} }
void UserRepository::saveUserRecord(const model::User& user)
{
std::cout << "inserting user record" << std::endl; void UserRepository::saveUserRecord(const model::User& user) {
std::cout << "inserting user record\n";
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -144,7 +150,6 @@ void UserRepository::saveUserRecord(const model::User& user)
qry << "VALUES(?, ?, ?, ?, ?, ?)"; qry << "VALUES(?, ?, ?, ?, ?, ?)";
const auto query = qry.str(); const auto query = qry.str();
auto sizes = fetchUserLengths(user); auto sizes = fetchUserLengths(user);
auto params = insertUserValues(user, sizes); auto params = insertUserValues(user, sizes);
@@ -156,9 +161,9 @@ void UserRepository::saveUserRecord(const model::User& user)
mysql_close(conn); mysql_close(conn);
} }
void UserRepository::saveUserSalt(const model::PassSec& userSec) void UserRepository::saveUserSalt(const model::PassSec& userSec) {
{ std::cout << "inserting user salt record\n";
std::cout << "inserting user salt record" << std::endl;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -180,8 +185,7 @@ void UserRepository::saveUserSalt(const model::PassSec& userSec)
std::shared_ptr<MYSQL_BIND> UserRepository::insertUserValues(const model::User& user, std::shared_ptr<MYSQL_BIND> UserRepository::insertUserValues(const model::User& user,
std::shared_ptr<UserRepository::UserLengths> lengths) std::shared_ptr<UserRepository::UserLengths> lengths) {
{
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(6, sizeof(MYSQL_BIND))); std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(6, sizeof(MYSQL_BIND)));
values.get()[0].buffer_type = MYSQL_TYPE_STRING; values.get()[0].buffer_type = MYSQL_TYPE_STRING;
@@ -218,8 +222,7 @@ std::shared_ptr<MYSQL_BIND> UserRepository::insertUserValues(const model::User&
} }
std::shared_ptr<MYSQL_BIND> UserRepository::insertSaltValues(const model::PassSec& passSec, std::shared_ptr<MYSQL_BIND> UserRepository::insertSaltValues(const model::PassSec& passSec,
std::shared_ptr<UserRepository::SaltLengths> lengths) std::shared_ptr<UserRepository::SaltLengths> lengths) {
{
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(6, sizeof(MYSQL_BIND))); std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(6, sizeof(MYSQL_BIND)));
values.get()[0].buffer_type = MYSQL_TYPE_STRING; values.get()[0].buffer_type = MYSQL_TYPE_STRING;
@@ -229,13 +232,11 @@ std::shared_ptr<MYSQL_BIND> UserRepository::insertSaltValues(const model::PassSe
values.get()[1].buffer_type = MYSQL_TYPE_LONG; values.get()[1].buffer_type = MYSQL_TYPE_LONG;
values.get()[1].buffer = (char*)&passSec.userId; values.get()[1].buffer = (char*)&passSec.userId;
return values; return values;
} }
std::shared_ptr<MYSQL_BIND> UserRepository::valueBind(model::User& user, std::shared_ptr<MYSQL_BIND> UserRepository::valueBind(model::User& user,
std::tuple<char*, char*, char*, char*, char*, char*>& us) std::tuple<char*, char*, char*, char*, char*, char*>& us) {
{
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(7, sizeof(MYSQL_BIND))); std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(7, sizeof(MYSQL_BIND)));
constexpr auto strLen = 1024; constexpr auto strLen = 1024;
@@ -269,8 +270,8 @@ std::shared_ptr<MYSQL_BIND> UserRepository::valueBind(model::User& user,
return values; return values;
} }
std::shared_ptr<MYSQL_BIND> UserRepository::saltValueBind(model::PassSec& userSalt, char *salt) std::shared_ptr<MYSQL_BIND> UserRepository::saltValueBind(model::PassSec& userSalt,
{ char *salt) {
std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(3, sizeof(MYSQL_BIND))); std::shared_ptr<MYSQL_BIND> values((MYSQL_BIND*) std::calloc(3, sizeof(MYSQL_BIND)));
constexpr auto strLen = 1024; constexpr auto strLen = 1024;
@@ -287,8 +288,8 @@ std::shared_ptr<MYSQL_BIND> UserRepository::saltValueBind(model::PassSec& userSa
return values; return values;
} }
std::shared_ptr<UserRepository::UserLengths> UserRepository::fetchUserLengths(const model::User& user) std::shared_ptr<UserRepository::UserLengths> UserRepository::fetchUserLengths(
{ const model::User& user) {
auto userLen = std::make_shared<UserLengths>(); auto userLen = std::make_shared<UserLengths>();
userLen->firstnameLength = user.firstname.size(); userLen->firstnameLength = user.firstname.size();
userLen->lastnameLength = user.lastname.size(); userLen->lastnameLength = user.lastname.size();
@@ -300,8 +301,8 @@ std::shared_ptr<UserRepository::UserLengths> UserRepository::fetchUserLengths(co
return userLen; return userLen;
} }
std::shared_ptr<UserRepository::SaltLengths> UserRepository::fetchSaltLengths(const model::PassSec& passSec) std::shared_ptr<UserRepository::SaltLengths> UserRepository::fetchSaltLengths(
{ const model::PassSec& passSec) {
auto saltLen = std::make_shared<SaltLengths>(); auto saltLen = std::make_shared<SaltLengths>();
saltLen->saltLength = passSec.salt.size(); saltLen->saltLength = passSec.salt.size();
@@ -309,8 +310,7 @@ std::shared_ptr<UserRepository::SaltLengths> UserRepository::fetchSaltLengths(co
} }
std::tuple<char*, char*, char*, char*, char*, char*> UserRepository::fetchUV() std::tuple<char*, char*, char*, char*, char*, char*> UserRepository::fetchUV() {
{
char firstname[1024]; char firstname[1024];
char lastname[1024]; char lastname[1024];
char phone[1024]; char phone[1024];
@@ -322,8 +322,7 @@ std::tuple<char*, char*, char*, char*, char*, char*> UserRepository::fetchUV()
} }
model::User UserRepository::parseRecord(MYSQL_STMT *stmt) model::User UserRepository::parseRecord(MYSQL_STMT *stmt) {
{
model::User user; model::User user;
auto usv = fetchUV(); auto usv = fetchUV();
@@ -341,8 +340,7 @@ model::User UserRepository::parseRecord(MYSQL_STMT *stmt)
return user; return user;
} }
model::PassSec UserRepository::parseSaltRecord(MYSQL_STMT* stmt) model::PassSec UserRepository::parseSaltRecord(MYSQL_STMT* stmt) {
{
model::PassSec userSalt; model::PassSec userSalt;
char saltKey[1024]; char saltKey[1024];
+107 -107
View File
@@ -6,14 +6,11 @@
#include <string> #include <string>
#include <cstring> #include <cstring>
namespace database {
database::YearRepository::YearRepository(const model::BinaryPath& bConf) YearRepository::YearRepository(const model::BinaryPath& bConf) : BaseRepository(bConf) { }
: BaseRepository(bConf)
{ }
std::vector<model::Year> database::YearRepository::retrieveRecords() std::vector<model::Year> YearRepository::retrieveRecords() {
{
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
const std::string query = "SELECT * FROM Year"; const std::string query = "SELECT * FROM Year";
@@ -29,9 +26,9 @@ std::vector<model::Year> database::YearRepository::retrieveRecords()
return yearRecs; return yearRecs;
} }
std::pair<model::Year, int> database::YearRepository::retrieveRecordWithSongCount(model::Year& year, type::YearFilter filter = type::YearFilter::id) std::pair<model::Year, int> YearRepository::retrieveRecordWithSongCount(model::Year& year,
{ type::YearFilter filter) {
std::cout << "retrieving year record with song count" << std::endl; std::cout << "retrieving year record with song count\n";
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -68,25 +65,37 @@ std::pair<model::Year, int> database::YearRepository::retrieveRecordWithSongCoun
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "retrieved year record with song count" << std::endl; std::cout << "retrieved year record with song count\n";
return yearWSC; return yearWSC;
} }
model::Year database::YearRepository::retrieveRecord(model::Year& year, type::YearFilter filter) model::Year YearRepository::retrieveRecord(model::Year& year, type::YearFilter filter) {
{ std::cout << "retrieving year record\n";
// TODO: switch to prepared statements
std::cout << "retrieving year record" << std::endl;
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn);
qry << "SELECT yr.* FROM Year yr WHERE "; qry << "SELECT yr.* FROM Year yr WHERE ";
MYSQL_BIND params[1];
std::memset(params, 0, sizeof(0));
switch (filter) { switch (filter) {
case type::YearFilter::id: case type::YearFilter::id:
qry << "yr.YearId = " << year.id; qry << "yr.YearId = ?";
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; break;
case type::YearFilter::year: case type::YearFilter::year:
qry << "yr.Year = " << year.year; qry << "yr.Year = ?";
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; break;
default: default:
break; break;
@@ -95,19 +104,23 @@ model::Year database::YearRepository::retrieveRecord(model::Year& year, type::Ye
qry << " ORDER BY yr.YearId DESC LIMIT 1"; qry << " ORDER BY yr.YearId DESC LIMIT 1";
const auto query = qry.str(); const auto query = qry.str();
auto results = performMysqlQuery(conn, query);
year = parseRecord(results); auto status = mysql_stmt_prepare(stmt, query.c_str(), query.size());
status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt);
year = parseRecord(stmt);
mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "retrieved record" << std::endl; std::cout << "retrieved record\n";
return year; return year;
} }
bool database::YearRepository::doesYearExist(const model::Year& year, type::YearFilter filter)
{ bool YearRepository::doesYearExist(const model::Year& year, type::YearFilter filter) {
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -145,7 +158,7 @@ bool database::YearRepository::doesYearExist(const model::Year& year, type::Year
status = mysql_stmt_bind_param(stmt, params); status = mysql_stmt_bind_param(stmt, params);
status = mysql_stmt_execute(stmt); status = mysql_stmt_execute(stmt);
std::cout << "the query has been performed" << std::endl; std::cout << "the query has been performed\n";
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
auto rowCount = mysql_stmt_num_rows(stmt); auto rowCount = mysql_stmt_num_rows(stmt);
@@ -156,9 +169,9 @@ bool database::YearRepository::doesYearExist(const model::Year& year, type::Year
return (rowCount > 0) ? true : false; return (rowCount > 0) ? true : false;
} }
void database::YearRepository::saveRecord(const model::Year& year)
{ void YearRepository::saveRecord(const model::Year& year) {
std::cout << "saving year record" << std::endl; std::cout << "saving year record\n";
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
MYSQL_STMT *stmt = mysql_stmt_init(conn); MYSQL_STMT *stmt = mysql_stmt_init(conn);
@@ -181,12 +194,12 @@ void database::YearRepository::saveRecord(const model::Year& year)
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "saved record" << std::endl; std::cout << "saved record\n";
} }
void database::YearRepository::deleteYear(const model::Year& year, type::YearFilter filter = type::YearFilter::id) void YearRepository::deleteYear(const model::Year& year,
{ type::YearFilter filter) {
std::cout << "deleting year record" << std::endl; std::cout << "deleting year record\n";
std::stringstream qry; std::stringstream qry;
auto conn = setupMysqlConnection(); auto conn = setupMysqlConnection();
auto stmt = mysql_stmt_init(conn); auto stmt = mysql_stmt_init(conn);
@@ -218,125 +231,112 @@ void database::YearRepository::deleteYear(const model::Year& year, type::YearFil
mysql_stmt_close(stmt); mysql_stmt_close(stmt);
mysql_close(conn); mysql_close(conn);
std::cout << "deleted year record" << std::endl; std::cout << "deleted year record\n";
} }
std::vector<model::Year> database::YearRepository::parseRecords(MYSQL_STMT *stmt)
{ std::vector<model::Year> YearRepository::parseRecords(MYSQL_STMT *stmt) {
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
const auto rowCount = mysql_stmt_num_rows(stmt);
std::vector<model::Year> yearRecs; std::vector<model::Year> yearRecs;
yearRecs.reserve(mysql_stmt_num_rows(stmt)); yearRecs.reserve(rowCount);
if (mysql_stmt_field_count(stmt) == 0) { if (mysql_stmt_field_count(stmt) == 0) {
std::cout << "field count is 0" << std::endl; std::cout << "field count is 0\n";
return yearRecs; return yearRecs;
} }
model::Year yearRec;
const auto valAmt = 2; const auto valAmt = 2;
unsigned long len[valAmt]; unsigned long len[valAmt];
my_bool nullRes[valAmt]; my_bool nullRes[valAmt];
auto res = mysql_stmt_result_metadata(stmt); for (auto status = 0; status == 0; status = mysql_stmt_next_result(stmt)) {
if (mysql_stmt_field_count(stmt) > 0) {
model::Year yearRec;
MYSQL_BIND val[valAmt]; std::cout << "fetching statement result\n";
memset(val, 0, sizeof(val)); auto bindedValues = valueBind(yearRec);
status = mysql_stmt_bind_result(stmt, bindedValues.get());
val[0].buffer_type = MYSQL_TYPE_LONG;
val[0].buffer = (char*)&yearRec.id;
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_LONG;
val[1].buffer = (char*)&yearRec.year;
val[1].length = &len[1];
val[1].is_null = &nullRes[1];
for (auto status = mysql_stmt_bind_result(stmt, val); status == 0;) {
std::cout << "fetching statement result" << std::endl;
status = mysql_stmt_fetch(stmt); status = mysql_stmt_fetch(stmt);
if (status == 0) { if (status == 1 || status == MYSQL_NO_DATA) break;
yearRecs.push_back(std::move(yearRec));
yearRecs.push_back(yearRec);
} }
std::cout << "fetching next result\n";
} }
return yearRecs; return yearRecs;
} }
std::pair<model::Year, int> database::YearRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) std::pair<model::Year, int> YearRepository::parseRecordWithSongCount(MYSQL_STMT *stmt) {
{ std::cout << "parsing year record\n";
std::cout << "parsing year record" << std::endl;
mysql_stmt_store_result(stmt); mysql_stmt_store_result(stmt);
constexpr auto valAmt = 3;
unsigned long len[valAmt];
my_bool nullRes[valAmt];
model::Year year; model::Year year;
int songCount = 0; int songCount = 0;
if (mysql_stmt_num_rows(stmt) == 0) { if (mysql_stmt_num_rows(stmt) == 0) {
std::cout << "no results" << std::endl; std::cout << "no results\n";
return std::make_pair(year, songCount); return std::make_pair(year, songCount);
} }
MYSQL_BIND val[valAmt]; auto val = valueBindWithSongCount(year, songCount);
std::memset(val, 0, sizeof(val));
val[0].buffer_type = MYSQL_TYPE_LONG; auto status = mysql_stmt_bind_result(stmt, val.get());
val[0].buffer = (char*)&year.id; status = mysql_stmt_fetch(stmt);
val[0].length = &len[0];
val[0].is_null = &nullRes[0];
val[1].buffer_type = MYSQL_TYPE_LONG; std::cout << "parsed year record from the database\n";
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); return std::make_pair(year, songCount);
} }
model::Year database::YearRepository::parseRecord(MYSQL_RES *results)
{ std::shared_ptr<MYSQL_BIND> YearRepository::valueBind(model::Year& year) {
std::cout << "parsing year record" << std::endl; 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; model::Year year;
auto bindedValues = valueBind(year);
auto status = mysql_stmt_bind_result(stmt, bindedValues.get());
status = mysql_stmt_fetch(stmt);
auto fieldNum = mysql_num_fields(results); std::cout << "done parsing year record\n";
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; 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;
} }
+34 -1
View File
@@ -1,7 +1,7 @@
#include "dto/conversion/DtoConversions.h" #include "dto/conversion/DtoConversions.h"
namespace dto { namespace conversion { namespace dto { namespace conversion {
dto::LoginResultDto::ObjectWrapper DtoConversions::toLoginResultDto(const model::User& user, LoginResultDto::ObjectWrapper DtoConversions::toLoginResultDto(const model::User& user,
const model::Token& token) { const model::Token& token) {
auto logRes = dto::LoginResultDto::createShared(); auto logRes = dto::LoginResultDto::createShared();
logRes->username = user.username.c_str(); logRes->username = user.username.c_str();
@@ -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 DtoConversions::toSong(dto::SongDto::ObjectWrapper& songDto) {
model::Song song; model::Song song;
song.id = (songDto->id.getPtr() == nullptr) ? 0 : songDto->id->getValue(); song.id = (songDto->id.getPtr() == nullptr) ? 0 : songDto->id->getValue();
song.title = (songDto->title == nullptr) ? "" : songDto->title->c_str(); song.title = (songDto->title == nullptr) ? "" : songDto->title->c_str();
song.album = (songDto->album == nullptr) ? "" : songDto->album->c_str(); song.album = (songDto->album == nullptr) ? "" : songDto->album->c_str();
song.artist = (songDto->artist == nullptr) ? "" : songDto->artist->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.genre = (songDto->genre == nullptr) ? "" : songDto->genre->c_str();
song.year = (songDto->year.getPtr() == nullptr) ? 0 : songDto->year->getValue(); song.year = (songDto->year.getPtr() == nullptr) ? 0 : songDto->year->getValue();
song.track = (songDto->track.getPtr() == nullptr) ? 0 : songDto->track->getValue(); song.track = (songDto->track.getPtr() == nullptr) ? 0 : songDto->track->getValue();
song.disc = (songDto->disc.getPtr() == nullptr) ? 0 : songDto->disc->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; return song;
} }
+21 -30
View File
@@ -6,76 +6,67 @@
#include "model/Models.h" #include "model/Models.h"
#include "type/AlbumFilter.h" #include "type/AlbumFilter.h"
manager::AlbumManager::AlbumManager(const model::BinaryPath& bConf) namespace manager {
: m_bConf(bConf) AlbumManager::AlbumManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
{ }
model::Album manager::AlbumManager::retrieveAlbum(model::Album& album) model::Album AlbumManager::retrieveAlbum(model::Album& album) {
{
database::AlbumRepository albRepo(m_bConf); database::AlbumRepository albRepo(m_bConf);
album = std::move(albRepo.retrieveRecord(album, type::AlbumFilter::title)); album = std::move(albRepo.retrieveRecord(album, type::AlbumFilter::title));
return album; return album;
} }
model::Album manager::AlbumManager::saveAlbum(const model::Song& song) model::Album AlbumManager::saveAlbum(const model::Song& song) {
{ model::Album album(song);
model::Album album;
album.title = song.album;
album.year = song.year;
database::AlbumRepository albRepo(m_bConf); database::AlbumRepository albRepo(m_bConf);
// TODO: check for existence with the title and the artist
if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) { if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) {
albRepo.saveAlbum(album); albRepo.saveAlbum(album);
} else { } else {
std::cout << "album record already exists in the database" << std::endl; std::cout << "album record already exists in the database\n";
} }
return album; return album;
} }
void manager::AlbumManager::deleteAlbum(const model::Song& song) void AlbumManager::deleteAlbum(const model::Song& song) {
{
model::Album album(song); model::Album album(song);
database::AlbumRepository albRepo(m_bConf); database::AlbumRepository albRepo(m_bConf);
auto albWSC = albRepo.retrieveRecordWithSongCount(album, type::AlbumFilter::id); auto albWSC = albRepo.retrieveRecordWithSongCount(album, type::AlbumFilter::id);
if (albWSC.second > 1) { if (albWSC.second > 1) {
std::cout << "album still contain songs related to it, will not delete" << std::endl; std::cout << "album still contain songs related to it, will not delete\n";
return; return;
} }
std::cout << "safe to delete the album record" << std::endl; std::cout << "safe to delete the album record\n";
albRepo.deleteAlbum(album, type::AlbumFilter::id); albRepo.deleteAlbum(album, type::AlbumFilter::id);
} }
void manager::AlbumManager::updateAlbum(model::Song& updatedSong, void AlbumManager::updateAlbum(model::Song& updatedSong,
const model::Song& currSong) const model::Song& currSong) {
{ model::Album album(updatedSong);
model::Album album;
album.title = updatedSong.album;
album.year = updatedSong.year;
database::AlbumRepository albRepo(m_bConf); database::AlbumRepository albRepo(m_bConf);
if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) { if (!albRepo.doesAlbumExists(album, type::AlbumFilter::title)) {
std::cout << "album record does not exist" << std::endl; std::cout << "album record does not exist\n";
albRepo.saveAlbum(album); albRepo.saveAlbum(album);
} else { } else {
std::cout << "album record already exists" << std::endl; std::cout << "album record already exists\n";
} }
album = albRepo.retrieveRecord(album, type::AlbumFilter::title); album = albRepo.retrieveRecord(album, type::AlbumFilter::title);
updatedSong.albumId = album.id; updatedSong.albumId = album.id;
} }
void manager::AlbumManager::printAlbum(const model::Album& album) void AlbumManager::printAlbum(const model::Album& album) {
{ std::cout << "\nalbum record\n";
std::cout << "\nalbum record" << std::endl; std::cout << "id: " << album.id << "\n";
std::cout << "id: " << album.id << std::endl; std::cout << "title: " << album.title << "\n";
std::cout << "title: " << album.title << std::endl; std::cout << "year: " << album.year << "\n";
std::cout << "year: " << album.year << std::endl; }
} }
+21 -25
View File
@@ -5,24 +5,22 @@
#include "database/ArtistRepository.h" #include "database/ArtistRepository.h"
#include "type/ArtistFilter.h" #include "type/ArtistFilter.h"
manager::ArtistManager::ArtistManager(const model::BinaryPath& bConf) namespace manager {
: m_bConf(bConf)
{ } ArtistManager::ArtistManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
model::Artist manager::ArtistManager::retrieveArtist(model::Artist& artist) model::Artist ArtistManager::retrieveArtist(model::Artist& artist) {
{ std::cout << "retrieving artist record\n";
std::cout << "retrieving artist record" << std::endl;
database::ArtistRepository artRepo(m_bConf); database::ArtistRepository artRepo(m_bConf);
std::cout << "initialized artist repo" << std::endl; std::cout << "initialized artist repo\n";
std::cout << artist.artist << std::endl; std::cout << artist.artist << "\n";
artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist); artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist);
return artist; return artist;
} }
model::Artist manager::ArtistManager::saveArtist(const model::Song& song) model::Artist ArtistManager::saveArtist(const model::Song& song) {
{
model::Artist artist; model::Artist artist;
artist.artist = song.artist; artist.artist = song.artist;
@@ -30,15 +28,14 @@ model::Artist manager::ArtistManager::saveArtist(const model::Song& song)
if (!artRepo.doesArtistExist(artist, type::ArtistFilter::artist)) { if (!artRepo.doesArtistExist(artist, type::ArtistFilter::artist)) {
artRepo.saveRecord(artist); artRepo.saveRecord(artist);
} else { } else {
std::cout << "artist already exists" << std::endl; std::cout << "artist already exists\n";
} }
return artist; return artist;
} }
void manager::ArtistManager::deleteArtist(const model::Song& song) void ArtistManager::deleteArtist(const model::Song& song) {
{
model::Artist artist(song); model::Artist artist(song);
database::ArtistRepository artRepo(m_bConf); database::ArtistRepository artRepo(m_bConf);
@@ -46,35 +43,34 @@ void manager::ArtistManager::deleteArtist(const model::Song& song)
if (artWSC.second > 1) { if (artWSC.second > 1) {
std::cout << "artist still contain songs related to it"; std::cout << "artist still contain songs related to it";
std::cout << ", not delete" << std::endl; std::cout << ", not delete\n";
return; return;
} }
std::cout << "safe to delete the artist record" << std::endl; std::cout << "safe to delete the artist record\n";
artRepo.deleteArtist(artist, type::ArtistFilter::id); artRepo.deleteArtist(artist, type::ArtistFilter::id);
} }
void manager::ArtistManager::updateArtist(model::Song& updatedSong, void ArtistManager::updateArtist(model::Song& updatedSong,
const model::Song& currSong) const model::Song& currSong) {
{
model::Artist artist; model::Artist artist;
artist.artist = updatedSong.artist; artist.artist = updatedSong.artist;
database::ArtistRepository artRepo(m_bConf); database::ArtistRepository artRepo(m_bConf);
if (!artRepo.doesArtistExist(artist, type::ArtistFilter::artist)) { if (!artRepo.doesArtistExist(artist, type::ArtistFilter::artist)) {
std::cout << "artist record does not exist" << std::endl; std::cout << "artist record does not exist\n";
artRepo.saveRecord(artist); artRepo.saveRecord(artist);
} else { } else {
std::cout << "artist record already exists" << std::endl; std::cout << "artist record already exists\n";
} }
artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist); artist = artRepo.retrieveRecord(artist, type::ArtistFilter::artist);
updatedSong.artistId = artist.id; updatedSong.artistId = artist.id;
} }
void manager::ArtistManager::printArtist(const model::Artist& artist) void ArtistManager::printArtist(const model::Artist& artist) {
{ std::cout << "\nartist record" << "\n";
std::cout << "\nartist record" << std::endl; std::cout << "id: " << artist.id << "\n";
std::cout << "id: " << artist.id << std::endl; std::cout << "artist: " << artist.artist << "\n";
std::cout << "artist: " << artist.artist << std::endl; }
} }
+22 -29
View File
@@ -11,17 +11,13 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
manager::CoverArtManager::CoverArtManager(const std::string& configPath) : path(configPath) namespace manager {
{ } CoverArtManager::CoverArtManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
manager::CoverArtManager::CoverArtManager(const model::BinaryPath& bConf) : m_bConf(bConf)
{ }
model::Cover manager::CoverArtManager::saveCover(const model::Song& song) model::Cover CoverArtManager::saveCover(const model::Song& song) {
{ auto pathConfigContent = DirectoryManager::pathConfigContent(m_bConf);
auto pathConfigContent = manager::DirectoryManager::pathConfigContent(m_bConf); auto stockCoverPath = DirectoryManager::configPath(m_bConf);
auto stockCoverPath = manager::DirectoryManager::configPath(m_bConf);
stockCoverPath.append("/CoverArt.png"); stockCoverPath.append("/CoverArt.png");
utility::MetadataRetriever meta; utility::MetadataRetriever meta;
@@ -38,25 +34,25 @@ model::Cover manager::CoverArtManager::saveCover(const model::Song& song)
database::CoverArtRepository covRepo(m_bConf); database::CoverArtRepository covRepo(m_bConf);
if (!covRepo.doesCoverArtExist(cov, type::CoverFilter::songTitle)) { if (!covRepo.doesCoverArtExist(cov, type::CoverFilter::songTitle)) {
std::cout << "saving image record to the database" << std::endl; std::cout << "saving image record to the database\n";
covRepo.saveRecord(cov); covRepo.saveRecord(cov);
} else { } else {
std::cout << "cover art record already exists" << std::endl; std::cout << "cover art record already exists\n";
} }
std::cout << "retrieving image record from database" << std::endl; std::cout << "retrieving image record from database\n";
cov = covRepo.retrieveRecord(cov, type::CoverFilter::songTitle); cov = covRepo.retrieveRecord(cov, type::CoverFilter::songTitle);
return cov; return cov;
} }
std::pair<bool, std::string> manager::CoverArtManager::defaultCover( std::pair<bool, std::string> CoverArtManager::defaultCover(
const model::Cover& cover) { const model::Cover& cover) {
auto paths = manager::DirectoryManager::pathConfigContent(m_bConf); auto paths = DirectoryManager::pathConfigContent(m_bConf);
const auto coverArtPath = const auto coverArtPath =
paths[manager::DirectoryManager::retrievePathType( paths[DirectoryManager::retrievePathType(
type::PathType::coverArt)].get<std::string>(); type::PathType::coverArt)].get<std::string>();
auto stockCoverArtPath = coverArtPath; auto stockCoverArtPath = coverArtPath;
@@ -70,8 +66,7 @@ std::pair<bool, std::string> manager::CoverArtManager::defaultCover(
} }
void manager::CoverArtManager::deleteCover(const model::Song& song) void CoverArtManager::deleteCover(const model::Song& song) {
{
database::CoverArtRepository covRepo(m_bConf); database::CoverArtRepository covRepo(m_bConf);
model::Cover cov(song.coverArtId); model::Cover cov(song.coverArtId);
@@ -82,19 +77,18 @@ void manager::CoverArtManager::deleteCover(const model::Song& song)
auto result = defaultCover(cov); auto result = defaultCover(cov);
if (!result.first) { if (!result.first) {
fs::remove(cov.imagePath); fs::remove(cov.imagePath);
std::cout << "deleting cover art" << std::endl; std::cout << "deleting cover art\n";
const auto coverArtPath = result.second; const auto coverArtPath = result.second;
} else { } else {
std::cout << "song contains the stock cover art, will not delete" << std::endl; std::cout << "song contains the stock cover art, will not delete\n";
return; return;
} }
manager::DirectoryManager::deleteDirectories(song, result.second); DirectoryManager::deleteDirectories(song, result.second);
} }
void manager::CoverArtManager::updateCover(const model::Song& updatedSong, void CoverArtManager::updateCover(const model::Song& updatedSong,
const model::Song& currSong) const model::Song& currSong) {
{
database::CoverArtRepository covRepo(m_bConf); database::CoverArtRepository covRepo(m_bConf);
model::Cover cover(updatedSong.coverArtId); model::Cover cover(updatedSong.coverArtId);
cover = covRepo.retrieveRecord(cover, type::CoverFilter::id); cover = covRepo.retrieveRecord(cover, type::CoverFilter::id);
@@ -110,11 +104,10 @@ void manager::CoverArtManager::updateCover(const model::Song& updatedSong,
fs::copy(cover.imagePath, imagePath); fs::copy(cover.imagePath, imagePath);
fs::remove(cover.imagePath); fs::remove(cover.imagePath);
manager::DirectoryManager::deleteDirectories(currSong, result.second); DirectoryManager::deleteDirectories(currSong, result.second);
} }
void manager::CoverArtManager::updateCoverRecord(const model::Song& updatedSong) void CoverArtManager::updateCoverRecord(const model::Song& updatedSong) {
{
model::Cover updatedCover(updatedSong); model::Cover updatedCover(updatedSong);
auto updatedImagePath = createImagePath(updatedSong); auto updatedImagePath = createImagePath(updatedSong);
@@ -123,9 +116,8 @@ void manager::CoverArtManager::updateCoverRecord(const model::Song& updatedSong)
} }
std::string manager::CoverArtManager::createImagePath(const model::Song& song) std::string CoverArtManager::createImagePath(const model::Song& song) {
{ auto imagePath = DirectoryManager::createDirectoryProcess(
auto imagePath = manager::DirectoryManager::createDirectoryProcess(
song, m_bConf, type::PathType::coverArt); song, m_bConf, type::PathType::coverArt);
if (song.track != 0) { if (song.track != 0) {
@@ -140,3 +132,4 @@ std::string manager::CoverArtManager::createImagePath(const model::Song& song)
return imagePath; return imagePath;
} }
}
+103 -53
View File
@@ -7,82 +7,95 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace manager {
std::string manager::DirectoryManager::createDirectoryProcess(model::Song song, const std::string& rootPath) std::string DirectoryManager::createDirectoryProcess(const model::Song& song,
{ const std::string& rootPath) {
auto currPath = fs::path(rootPath); auto currPath = fs::path(rootPath);
if (fs::exists(currPath)) { if (fs::exists(currPath)) {
std::cout << "path exists" << std::endl; std::cout << "path exists\n";
} else { } else {
std::cout << "creating path" << std::endl; std::cout << "creating path\n";
fs::create_directory(currPath); fs::create_directory(currPath);
} }
auto artPath = fs::path(currPath.string() + song.artist); auto artPath = fs::path(currPath.string() + song.artist);
if (fs::exists(artPath)) { if (fs::exists(artPath)) {
std::cout << "artist path exists" << std::endl; std::cout << "artist path exists\n";
} else { } else {
std::cout << "creating artist path" << std::endl; std::cout << "creating artist path\n";
fs::create_directory(artPath); fs::create_directory(artPath);
} }
auto albPath = fs::path(artPath.string() + "/" + song.album); auto albPath = fs::path(artPath.string() + "/" + song.albumArtist);
if (fs::exists(albPath)) { if (fs::exists(albPath)) {
std::cout << "album path exists" << std::endl; std::cout << "album path exists\n";
} else { } else {
std::cout << "creating album path" << std::endl; std::cout << "creating album path\n";
fs::create_directory(albPath); fs::create_directory(albPath);
} }
return albPath.string() + "/"; 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);
} }
std::string manager::DirectoryManager::createDirectoryProcess(const model::Song& song, return discPath.string() + "/";
const model::BinaryPath& bConf, type::PathType pType) }
{
std::string DirectoryManager::createDirectoryProcess(const model::Song& song,
const model::BinaryPath& bConf, type::PathType pType) {
auto path = pathConfigContent(bConf)[retrievePathType(pType)]; auto path = pathConfigContent(bConf)[retrievePathType(pType)];
auto rootPath = path.get<std::string>(); auto rootPath = path.get<std::string>();
auto currPath = fs::path(rootPath); auto currPath = fs::path(rootPath);
if (fs::exists(currPath)) { if (fs::exists(currPath)) {
std::cout << "path exists" << std::endl; std::cout << "path exists\n";
} else { } else {
std::cout << "creating root music path" << std::endl; std::cout << "creating root music path\n";
fs::create_directory(currPath); fs::create_directory(currPath);
} }
auto artPath = fs::path(currPath.string() + song.artist); auto artPath = fs::path(currPath.string() + song.albumArtist);
if (fs::exists(artPath)) { if (fs::exists(artPath)) {
std::cout << "artist path exists" << std::endl; std::cout << "artist path exists\n";
} else { } else {
std::cout << "creating artist path" << std::endl; std::cout << "creating artist path\n";
fs::create_directory(artPath); fs::create_directory(artPath);
} }
auto albPath = fs::path(artPath.string() + "/" + song.album); auto albPath = fs::path(artPath.string() + "/" + song.album);
if (fs::exists(albPath)) { if (fs::exists(albPath)) {
std::cout << "album path exists" << std::endl; std::cout << "album path exists\n";
} else { } else {
std::cout << "creating album path" << std::endl; std::cout << "creating album path\n";
fs::create_directory(albPath); fs::create_directory(albPath);
} }
return albPath.string() + "/"; 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);
} }
std::string manager::DirectoryManager::configPath(std::string_view path) return discPath.string() + "/";
{ }
std::string DirectoryManager::configPath(std::string_view path) {
return fs::canonical(path).parent_path().string(); return fs::canonical(path).parent_path().string();
} }
std::string manager::DirectoryManager::configPath(const model::BinaryPath& bConf) std::string DirectoryManager::configPath(const model::BinaryPath& bConf) {
{
return fs::canonical(bConf.path).parent_path().string(); return fs::canonical(bConf.path).parent_path().string();
} }
std::string manager::DirectoryManager::contentOfPath(const std::string& path) std::string DirectoryManager::contentOfPath(const std::string& path) {
{
std::fstream a(path, std::ios::in); std::fstream a(path, std::ios::in);
std::stringstream s; std::stringstream s;
s << a.rdbuf(); s << a.rdbuf();
@@ -91,8 +104,7 @@ std::string manager::DirectoryManager::contentOfPath(const std::string& path)
return s.str(); return s.str();
} }
std::string manager::DirectoryManager::retrievePathType(type::PathType pType) std::string DirectoryManager::retrievePathType(type::PathType pType) {
{
std::string path; std::string path;
switch (pType) { switch (pType) {
case type::PathType::music: case type::PathType::music:
@@ -115,40 +127,46 @@ std::string manager::DirectoryManager::retrievePathType(type::PathType pType)
} }
nlohmann::json manager::DirectoryManager::credentialConfigContent(const model::BinaryPath& bConf) nlohmann::json DirectoryManager::credentialConfigContent(const model::BinaryPath& bConf) {
{
auto path = configPath(bConf); auto path = configPath(bConf);
path.append("/authcredentials.json"); path.append("/authcredentials.json");
return nlohmann::json::parse(contentOfPath(path)); return nlohmann::json::parse(contentOfPath(path));
} }
nlohmann::json manager::DirectoryManager::databaseConfigContent(const model::BinaryPath& bConf) nlohmann::json DirectoryManager::databaseConfigContent(const model::BinaryPath& bConf) {
{
auto path = configPath(bConf); auto path = configPath(bConf);
path.append("/database.json"); path.append("/database.json");
return nlohmann::json::parse(contentOfPath(path)); return nlohmann::json::parse(contentOfPath(path));
} }
nlohmann::json manager::DirectoryManager::pathConfigContent(const model::BinaryPath& bConf) nlohmann::json DirectoryManager::pathConfigContent(const model::BinaryPath& bConf) {
{
auto path = configPath(bConf); auto path = configPath(bConf);
path.append("/paths.json"); path.append("/paths.json");
return nlohmann::json::parse(contentOfPath(path)); return nlohmann::json::parse(contentOfPath(path));
} }
void manager::DirectoryManager::deleteDirectories(model::Song song, const std::string& rootPath)
{ void DirectoryManager::deleteDirectories(model::Song song, const std::string& rootPath) {
std::cout << "checking for empty directories to delete" << std::endl; std::cout << "checking for empty directories to delete\n";
const std::string art(rootPath + std::string("/") + song.artist); const std::string art(rootPath + std::string("/") + song.albumArtist);
const std::string alb(art + "/" + song.album); const std::string alb(art + "/" + song.album);
const std::string disc(alb + "/" + std::to_string(song.disc) + "/");
auto discPath = fs::path(disc);
if (fs::exists(discPath)) {
std::cout << "disc directory does not exist\n";
} else if (fs::is_empty(discPath)) {
fs::remove(discPath);
}
auto albPath = fs::path(alb); auto albPath = fs::path(alb);
if (!fs::exists(albPath)) { if (!fs::exists(albPath)) {
std::cout << "directory does not exists" << std::endl; std::cout << "directory does not exists\n";
} else if (fs::is_empty(albPath)) { } else if (fs::is_empty(albPath)) {
fs::remove(albPath); fs::remove(albPath);
} }
@@ -156,37 +174,69 @@ void manager::DirectoryManager::deleteDirectories(model::Song song, const std::s
auto artPath = fs::path(art); auto artPath = fs::path(art);
if (!fs::exists(artPath)) { if (!fs::exists(artPath)) {
std::cout << "directory does not exists" << std::endl; std::cout << "directory does not exists\n";
return; return;
} else if (fs::is_empty(artPath)) { } else if (fs::is_empty(artPath)) {
fs::remove(artPath); fs::remove(artPath);
} }
std::cout << "deleted empty directory or directories" << std::endl; std::cout << "deleted empty directory or directories\n";
} }
void manager::DirectoryManager::deleteCoverArtFile(const std::string& covPath, const std::string& stockCoverPath) void DirectoryManager::deleteCoverArtFile(const std::string& covPath,
{ const std::string& stockCoverPath) {
if (covPath.compare(stockCoverPath) == 0) { if (covPath.compare(stockCoverPath) == 0) {
std::cout << "cover has stock cover art, will not deleted" << std::endl; std::cout << "cover has stock cover art, will not deleted\n";
} else { } else {
std::cout << "deleting song path" << std::endl; std::cout << "deleting song path\n";
auto cov = fs::path(covPath); auto cov = fs::path(covPath);
fs::remove(cov); fs::remove(cov);
} }
} }
void manager::DirectoryManager::deleteSong(const model::Song song)
{ fs::path DirectoryManager::relativeDiscSongPathFilesystem(const fs::path& albPath,
std::cout << "deleting song" << std::endl; 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); auto songPath = fs::path(song.songPath);
if (!fs::exists(songPath)) { if (!fs::exists(songPath)) {
std::cout << "song does not exists" << std::endl; std::cout << "song does not exists\n";
return; return;
} }
fs::remove(songPath); fs::remove(songPath);
std::cout << "deleted song" << std::endl; std::cout << "deleted song" << "\n";
}
} }
+17 -22
View File
@@ -5,21 +5,18 @@
#include "database/GenreRepository.h" #include "database/GenreRepository.h"
#include "type/GenreFilter.h" #include "type/GenreFilter.h"
manager::GenreManager::GenreManager(const model::BinaryPath& bConf) namespace manager {
: m_bConf(bConf) GenreManager::GenreManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
{ }
model::Genre manager::GenreManager::retrieveGenre(model::Genre& genre) model::Genre GenreManager::retrieveGenre(model::Genre& genre) {
{
database::GenreRepository gnrRepo(m_bConf); database::GenreRepository gnrRepo(m_bConf);
genre = gnrRepo.retrieveRecord(genre, type::GenreFilter::category); genre = gnrRepo.retrieveRecord(genre, type::GenreFilter::category);
return genre; return genre;
} }
model::Genre manager::GenreManager::saveGenre(const model::Song& song) model::Genre GenreManager::saveGenre(const model::Song& song) {
{
model::Genre genre; model::Genre genre;
genre.category = song.genre; genre.category = song.genre;
@@ -27,15 +24,14 @@ model::Genre manager::GenreManager::saveGenre(const model::Song& song)
if (!gnrRepo.doesGenreExist(genre, type::GenreFilter::category)) { if (!gnrRepo.doesGenreExist(genre, type::GenreFilter::category)) {
gnrRepo.saveRecord(genre); gnrRepo.saveRecord(genre);
} else { } else {
std::cout << "genre record already exists" << std::endl; std::cout << "genre record already exists\n";
} }
return genre; return genre;
} }
void manager::GenreManager::deleteGenre(const model::Song& song) void GenreManager::deleteGenre(const model::Song& song) {
{
model::Genre genre(song); model::Genre genre(song);
database::GenreRepository gnrRepo(m_bConf); database::GenreRepository gnrRepo(m_bConf);
@@ -43,35 +39,34 @@ void manager::GenreManager::deleteGenre(const model::Song& song)
if (gnrWSC.second > 1) { if (gnrWSC.second > 1) {
std::cout << "genre still contain songs related to it"; std::cout << "genre still contain songs related to it";
std::cout << ", will not delete" << std::endl; std::cout << ", will not delete\n";
return; return;
} }
std::cout << "safe to delete the genre record" << std::endl; std::cout << "safe to delete the genre record\n";
gnrRepo.deleteRecord(genre, type::GenreFilter::id); gnrRepo.deleteRecord(genre, type::GenreFilter::id);
} }
void manager::GenreManager::updateGenre(model::Song& updatedSong, void GenreManager::updateGenre(model::Song& updatedSong,
const model::Song& currSong) const model::Song& currSong) {
{
model::Genre genre; model::Genre genre;
genre.category = updatedSong.genre; genre.category = updatedSong.genre;
database::GenreRepository gnrRepo(m_bConf); database::GenreRepository gnrRepo(m_bConf);
if (!gnrRepo.doesGenreExist(genre, type::GenreFilter::category)) { if (!gnrRepo.doesGenreExist(genre, type::GenreFilter::category)) {
std::cout << "genre record does not exist" << std::endl; std::cout << "genre record does not exist\n";
gnrRepo.saveRecord(genre); gnrRepo.saveRecord(genre);
} else { } else {
std::cout << "genre record already exists" << std::endl; std::cout << "genre record already exists\n";
} }
genre = gnrRepo.retrieveRecord(genre, type::GenreFilter::category); genre = gnrRepo.retrieveRecord(genre, type::GenreFilter::category);
updatedSong.genreId = genre.id; updatedSong.genreId = genre.id;
} }
void manager::GenreManager::printGenre(const model::Genre& genre) void GenreManager::printGenre(const model::Genre& genre) {
{ std::cout << "genre record\n";
std::cout << "genre record" << std::endl; std::cout << "id: " << genre.id << "\n";
std::cout << "id: " << genre.id << std::endl; std::cout << "category: " << genre.category << "\n";
std::cout << "category: " << genre.category << std::endl; }
} }
+117 -142
View File
@@ -5,7 +5,7 @@
#include <random> #include <random>
#include <nlohmann/json.hpp> #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 "oatpp/web/server/api/ApiController.hpp"
#include "database/CoverArtRepository.h" #include "database/CoverArtRepository.h"
@@ -21,18 +21,37 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
manager::SongManager::SongManager(std::string& x_path) namespace manager {
: exe_path(x_path) SongManager::SongManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
{ }
manager::SongManager::SongManager(const model::BinaryPath& bConf)
: m_bConf(bConf)
{ }
bool manager::SongManager::didSongChange(const model::Song& updatedSong, std::pair<bool, type::SongUpload> SongManager::saveSong(model::Song& song) {
const model::Song& currSong) 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);
}
bool SongManager::didSongChange(const model::Song& updatedSong,
const model::Song& currSong) {
if (!updatedSong.title.empty()) { if (!updatedSong.title.empty()) {
return true; return true;
} }
@@ -52,9 +71,8 @@ bool manager::SongManager::didSongChange(const model::Song& updatedSong,
return false; return false;
} }
bool manager::SongManager::requiresFilesystemChange(const model::Song& updatedSong, bool SongManager::requiresFilesystemChange(const model::Song& updatedSong,
const model::Song& currSong) const model::Song& currSong) {
{
if (updatedSong.title.compare(currSong.title) != 0) { if (updatedSong.title.compare(currSong.title) != 0) {
return true; return true;
} }
@@ -68,59 +86,39 @@ bool manager::SongManager::requiresFilesystemChange(const model::Song& updatedSo
return false; return false;
} }
bool SongManager::deleteSong(model::Song& song) {
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);
saveMisc(song);
printSong(song);
database::SongRepository songRepo(m_bConf);
songRepo.saveRecord(song);
}
void manager::SongManager::deleteSong(model::Song& song)
{
database::SongRepository songRepo(m_bConf); database::SongRepository songRepo(m_bConf);
if (!songRepo.doesSongExist(song, type::SongFilter::id)) { if (!songRepo.doesSongExist(song, type::SongFilter::id)) {
std::cout << "song does not exist" << std::endl; std::cout << "song does not exist\n";
return; return false;
} }
song = songRepo.retrieveRecord(song, type::SongFilter::id); song = songRepo.retrieveRecord(song, type::SongFilter::id);
auto paths = manager::DirectoryManager::pathConfigContent(m_bConf); auto paths = DirectoryManager::pathConfigContent(m_bConf);
auto deleted = songRepo.deleteRecord(song); auto deleted = songRepo.deleteRecord(song);
if (!deleted) { if (!deleted) {
std::cout << "song not deleted from databases" << std::endl; std::cout << "song not deleted from databases\n";
return; return deleted;
} }
deleteMisc(song); deleteMisc(song);
fs::remove(song.songPath); fs::remove(song.songPath);
manager::DirectoryManager::deleteDirectories(song, paths["root_music_path"].get<std::string>()); DirectoryManager::deleteDirectories(song, paths["root_music_path"].get<std::string>());
return deleted;
} }
void manager::SongManager::updateSong(model::Song& updatedSong) bool SongManager::updateSong(model::Song& updatedSong) {
{
database::SongRepository songRepo(m_bConf); database::SongRepository songRepo(m_bConf);
model::Song currSong(updatedSong.id); 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); currSong = songRepo.retrieveRecord(currSong, type::SongFilter::id);
if (!didSongChange(updatedSong, currSong)) { if (!didSongChange(updatedSong, currSong)) {
std::cout << "no change to the song" << std::endl; std::cout << "no change to the song\n";
return; return false;
} }
assignMiscId(updatedSong, currSong); assignMiscId(updatedSong, currSong);
@@ -139,48 +137,33 @@ void manager::SongManager::updateSong(model::Song& updatedSong)
printSong(currSong); printSong(currSong);
updateMisc(changes, updatedSong, currSong); updateMisc(changes, updatedSong, currSong);
}
model::Song manager::SongManager::songDtoConv(dto::SongDto::ObjectWrapper& songDto) return true;
{
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) void SongManager::printSong(const model::Song& song) {
{ std::cout << "\nsong" << "\n";
std::cout << "\nsong" << std::endl; std::cout << "title: " << song.title << "\n";
std::cout << "title: " << song.title << std::endl; std::cout << "artist: " << song.artist << "\n";
std::cout << "artist: " << song.artist << std::endl; std::cout << "album artist: " << song.albumArtist << "\n";
std::cout << "album: " << song.album << std::endl; std::cout << "album: " << song.album << "\n";
std::cout << "genre: " << song.genre << std::endl; std::cout << "genre: " << song.genre << "\n";
std::cout << "duration: " << song.duration << std::endl; std::cout << "duration: " << song.duration << "\n";
std::cout << "year: " << song.year << std::endl; std::cout << "year: " << song.year << "\n";
std::cout << "track: " << song.track << std::endl; std::cout << "track: " << song.track << "\n";
std::cout << "disc: " << song.disc << std::endl; std::cout << "disc: " << song.disc << "\n";
std::cout << "song path: " << song.songPath << std::endl; std::cout << "song path: " << song.songPath << "\n";
std::cout << "cover art id: " << song.coverArtId << std::endl; std::cout << "cover art id: " << song.coverArtId << "\n";
std::cout << "album id: " << song.albumId << std::endl; std::cout << "album id: " << song.albumId << "\n";
std::cout << "artist id: " << song.artistId << std::endl; std::cout << "artist id: " << song.artistId << "\n";
std::cout << "genre id: " << song.genreId << std::endl; std::cout << "genre id: " << song.genreId << "\n";
std::cout << "year id: " << song.yearId << std::endl; std::cout << "year id: " << song.yearId << "\n";
} }
std::map<type::SongChanged, bool> manager::SongManager::changesInSong( std::map<type::SongChanged, bool> SongManager::changesInSong(
const model::Song& updatedSong, const model::Song& currSong) const model::Song& updatedSong, const model::Song& currSong) {
{
std::map<type::SongChanged, bool> songChanges; std::map<type::SongChanged, bool> songChanges;
std::string_view updatedTitle = updatedSong.title; std::string_view updatedTitle = updatedSong.title;
@@ -211,9 +194,8 @@ std::map<type::SongChanged, bool> manager::SongManager::changesInSong(
} }
std::string manager::SongManager::createSongPath(const model::Song& song) std::string SongManager::createSongPath(const model::Song& song) {
{ auto songPath = DirectoryManager::createDirectoryProcess(
auto songPath = manager::DirectoryManager::createDirectoryProcess(
song, m_bConf, type::PathType::music); song, m_bConf, type::PathType::music);
if (song.track != 0) { if (song.track != 0) {
@@ -231,11 +213,10 @@ std::string manager::SongManager::createSongPath(const model::Song& song)
// used to prevent empty values to appear in the updated song // used to prevent empty values to appear in the updated song
void manager::SongManager::assignMiscFields( void SongManager::assignMiscFields(
std::map<type::SongChanged, bool>& songChanges, model::Song& updatedSong, std::map<type::SongChanged, bool>& songChanges, model::Song& updatedSong,
const model::Song& currSong) const model::Song& currSong) {
{ std::cout << "assigning miscellanes fields to updated song\n";
std::cout << "assigning miscellanes fields to updated song" << std::endl;
updatedSong.track = currSong.track; updatedSong.track = currSong.track;
for (auto scIter = songChanges.begin(); scIter != songChanges.end(); ++scIter) { for (auto scIter = songChanges.begin(); scIter != songChanges.end(); ++scIter) {
type::SongChanged key = scIter->first; type::SongChanged key = scIter->first;
@@ -245,23 +226,23 @@ void manager::SongManager::assignMiscFields(
switch (key) { switch (key) {
case type::SongChanged::title: case type::SongChanged::title:
updatedSong.title = currSong.title; updatedSong.title = currSong.title;
std::cout << "title has not been changed" << std::endl; std::cout << "title has not been changed\n";
break; break;
case type::SongChanged::artist: case type::SongChanged::artist:
updatedSong.artist = currSong.artist; updatedSong.artist = currSong.artist;
std::cout << "artist has not been changed" << std::endl; std::cout << "artist has not been changed\n";
break; break;
case type::SongChanged::album: case type::SongChanged::album:
updatedSong.album = currSong.album; updatedSong.album = currSong.album;
std::cout << "album has not been changed" << std::endl; std::cout << "album has not been changed\n";
break; break;
case type::SongChanged::genre: case type::SongChanged::genre:
updatedSong.genre = currSong.genre; updatedSong.genre = currSong.genre;
std::cout << "genre has not been changed" << std::endl; std::cout << "genre has not been changed\n";
break; break;
case::type::SongChanged::year: case::type::SongChanged::year:
updatedSong.year = currSong.year; updatedSong.year = currSong.year;
std::cout << "year has not been changed" << std::endl; std::cout << "year has not been changed\n";
default: default:
break; break;
} }
@@ -270,10 +251,9 @@ void manager::SongManager::assignMiscFields(
} }
// used to dump miscellaneous id to the updated song // used to dump miscellaneous id to the updated song
void manager::SongManager::assignMiscId(model::Song& updatedSong, void SongManager::assignMiscId(model::Song& updatedSong,
const model::Song& currSong) const model::Song& currSong) {
{ std::cout << "assigning miscellaneous Id's to updated song\n";
std::cout << "assigning miscellaneous Id's to updated song" << std::endl;
updatedSong.artistId = currSong.artistId; updatedSong.artistId = currSong.artistId;
updatedSong.albumId = currSong.albumId; updatedSong.albumId = currSong.albumId;
updatedSong.genreId = currSong.genreId; updatedSong.genreId = currSong.genreId;
@@ -282,9 +262,8 @@ void manager::SongManager::assignMiscId(model::Song& updatedSong,
} }
// saves song to a temporary path // saves song to a temporary path
void manager::SongManager::saveSongTemp(model::Song& song) void SongManager::saveSongTemp(model::Song& song) {
{ auto config = DirectoryManager::pathConfigContent(m_bConf);
auto config = manager::DirectoryManager::pathConfigContent(m_bConf);
auto tmpSongPath = config["temp_root_path"].get<std::string>(); auto tmpSongPath = config["temp_root_path"].get<std::string>();
std::random_device dev; std::random_device dev;
@@ -301,46 +280,45 @@ void manager::SongManager::saveSongTemp(model::Song& song)
song.songPath = tmpSongPath; song.songPath = tmpSongPath;
} }
void manager::SongManager::saveMisc(model::Song& song) void SongManager::saveMisc(model::Song& song) {
{
CoverArtManager covMgr(m_bConf); CoverArtManager covMgr(m_bConf);
auto pathConfigContent = manager::DirectoryManager::pathConfigContent(m_bConf); auto pathConfigContent = DirectoryManager::pathConfigContent(m_bConf);
auto musicRootPath = pathConfigContent["root_music_path"].get<std::string>(); auto musicRootPath = pathConfigContent["root_music_path"].get<std::string>();
auto cov = covMgr.saveCover(song); auto cov = covMgr.saveCover(song);
const auto songPath = createSongPath(song); const auto songPath = createSongPath(song);
if (fs::exists(songPath)) { if (fs::exists(songPath)) {
std::cout << "deleting old song with the same metadata" << std::endl; std::cout << "deleting old song with the same metadata\n";
fs::remove(songPath); fs::remove(songPath);
} }
std::cout << "copying song to the appropriate directory" << std::endl; std::cout << "copying song to the appropriate directory\n";
std::cout << song.songPath << std::endl; std::cout << song.songPath << "\n";
std::cout << songPath << std::endl; std::cout << songPath << "\n";
fs::copy(song.songPath, songPath); fs::copy(song.songPath, songPath);
fs::remove(song.songPath); fs::remove(song.songPath);
song.songPath = std::move(songPath); song.songPath = std::move(songPath);
std::cout << "copied song to the appropriate directory" << std::endl; std::cout << "copied song to the appropriate directory\n";
AlbumManager albMgr(m_bConf); AlbumManager albMgr(m_bConf);
auto album = albMgr.saveAlbum(song); auto album = albMgr.saveAlbum(song);
album = albMgr.retrieveAlbum(album); album = albMgr.retrieveAlbum(album);
manager::AlbumManager::printAlbum(album); AlbumManager::printAlbum(album);
ArtistManager artMgr(m_bConf); ArtistManager artMgr(m_bConf);
auto artist = artMgr.saveArtist(song); auto artist = artMgr.saveArtist(song);
artist = artMgr.retrieveArtist(artist); artist = artMgr.retrieveArtist(artist);
manager::ArtistManager::printArtist(artist); ArtistManager::printArtist(artist);
GenreManager gnrMgr(m_bConf); GenreManager gnrMgr(m_bConf);
auto genre = gnrMgr.saveGenre(song); auto genre = gnrMgr.saveGenre(song);
genre = gnrMgr.retrieveGenre(genre); genre = gnrMgr.retrieveGenre(genre);
manager::GenreManager::printGenre(genre); GenreManager::printGenre(genre);
YearManager yrMgr(m_bConf); YearManager yrMgr(m_bConf);
auto year = yrMgr.saveYear(song); auto year = yrMgr.saveYear(song);
year = yrMgr.retrieveYear(year); year = yrMgr.retrieveYear(year);
manager::YearManager::printYear(year); YearManager::printYear(year);
song.coverArtId = cov.id; song.coverArtId = cov.id;
song.albumId = album.id; song.albumId = album.id;
@@ -348,47 +326,44 @@ void manager::SongManager::saveMisc(model::Song& song)
song.genreId = genre.id; song.genreId = genre.id;
song.yearId = year.id; song.yearId = year.id;
std::cout << "done with miscellaneous database records" << std::endl; std::cout << "done with miscellaneous database records\n";
} }
void manager::SongManager::deleteMisc(const model::Song& song) void SongManager::deleteMisc(const model::Song& song) {
{ CoverArtManager covMgr(m_bConf);
manager::CoverArtManager covMgr(m_bConf);
covMgr.deleteCover(song); covMgr.deleteCover(song);
manager::AlbumManager albMgr(m_bConf); AlbumManager albMgr(m_bConf);
albMgr.deleteAlbum(song); albMgr.deleteAlbum(song);
manager::ArtistManager artMgr(m_bConf); ArtistManager artMgr(m_bConf);
artMgr.deleteArtist(song); artMgr.deleteArtist(song);
manager::GenreManager gnrMgr(m_bConf); GenreManager gnrMgr(m_bConf);
gnrMgr.deleteGenre(song); gnrMgr.deleteGenre(song);
manager::YearManager yrMgr(m_bConf); YearManager yrMgr(m_bConf);
yrMgr.deleteYear(song); yrMgr.deleteYear(song);
} }
// deletes miscellanes records // deletes miscellanes records
void manager::SongManager::deleteMiscExceptCoverArt(const model::Song& song) void SongManager::deleteMiscExceptCoverArt(const model::Song& song) {
{ AlbumManager albMgr(m_bConf);
manager::AlbumManager albMgr(m_bConf);
albMgr.deleteAlbum(song); albMgr.deleteAlbum(song);
manager::ArtistManager artMgr(m_bConf); ArtistManager artMgr(m_bConf);
artMgr.deleteArtist(song); artMgr.deleteArtist(song);
manager::GenreManager gnrMgr(m_bConf); GenreManager gnrMgr(m_bConf);
gnrMgr.deleteGenre(song); gnrMgr.deleteGenre(song);
manager::YearManager yrMgr(m_bConf); YearManager yrMgr(m_bConf);
yrMgr.deleteYear(song); yrMgr.deleteYear(song);
} }
void manager::SongManager::updateMisc( void SongManager::updateMisc(
const std::map<type::SongChanged, bool>& songChanges, const std::map<type::SongChanged, bool>& songChanges,
model::Song& updatedSong, const model::Song& currSong) model::Song& updatedSong, const model::Song& currSong) {
{
auto titleChange = songChanges.at(type::SongChanged::title); auto titleChange = songChanges.at(type::SongChanged::title);
auto artistChange = songChanges.at(type::SongChanged::artist); auto artistChange = songChanges.at(type::SongChanged::artist);
auto albumChange = songChanges.at(type::SongChanged::album); auto albumChange = songChanges.at(type::SongChanged::album);
@@ -396,25 +371,25 @@ void manager::SongManager::updateMisc(
auto yearChange = songChanges.at(type::SongChanged::year); auto yearChange = songChanges.at(type::SongChanged::year);
if (artistChange) { if (artistChange) {
manager::ArtistManager artMgr(m_bConf); ArtistManager artMgr(m_bConf);
artMgr.updateArtist(updatedSong, currSong); artMgr.updateArtist(updatedSong, currSong);
} }
if (albumChange) { if (albumChange) {
manager::AlbumManager albMgr(m_bConf); AlbumManager albMgr(m_bConf);
albMgr.updateAlbum(updatedSong, currSong); albMgr.updateAlbum(updatedSong, currSong);
} }
if (genreChange) { if (genreChange) {
manager::GenreManager gnrMgr(m_bConf); GenreManager gnrMgr(m_bConf);
gnrMgr.updateGenre(updatedSong, currSong); gnrMgr.updateGenre(updatedSong, currSong);
} }
if (yearChange) { if (yearChange) {
manager::YearManager yrMgr(m_bConf); YearManager yrMgr(m_bConf);
yrMgr.updateYear(updatedSong, currSong); yrMgr.updateYear(updatedSong, currSong);
} }
// determins to update the cover art record // determins to update the cover art record
if (titleChange || artistChange || albumChange) { if (titleChange || artistChange || albumChange) {
manager::CoverArtManager covMgr(m_bConf); CoverArtManager covMgr(m_bConf);
covMgr.updateCoverRecord(updatedSong); covMgr.updateCoverRecord(updatedSong);
} }
@@ -424,24 +399,24 @@ void manager::SongManager::updateMisc(
deleteMiscExceptCoverArt(currSong); deleteMiscExceptCoverArt(currSong);
} }
void manager::SongManager::modifySongOnFilesystem(model::Song& updatedSong, void SongManager::modifySongOnFilesystem(model::Song& updatedSong,
const model::Song& currSong) const model::Song& currSong) {
{ std::cout << "preparing to modify song\n";
std::cout << "preparing to modify song" << std::endl;
auto songPath = createSongPath(updatedSong); auto songPath = createSongPath(updatedSong);
updatedSong.songPath = std::move(songPath); updatedSong.songPath = std::move(songPath);
std::cout << "new path " << updatedSong.songPath << std::endl; std::cout << "new path " << updatedSong.songPath << "\n";
fs::copy(currSong.songPath, updatedSong.songPath); fs::copy(currSong.songPath, updatedSong.songPath);
fs::remove(currSong.songPath); fs::remove(currSong.songPath);
auto paths = manager::DirectoryManager::pathConfigContent(m_bConf); auto paths = DirectoryManager::pathConfigContent(m_bConf);
const auto musicRootPath = const auto musicRootPath =
paths[manager::DirectoryManager::retrievePathType( paths[DirectoryManager::retrievePathType(
type::PathType::music)].get<std::string>(); type::PathType::music)].get<std::string>();
manager::DirectoryManager::deleteDirectories(currSong, musicRootPath); DirectoryManager::deleteDirectories(currSong, musicRootPath);
manager::CoverArtManager covMgr(m_bConf); CoverArtManager covMgr(m_bConf);
covMgr.updateCover(updatedSong, currSong); covMgr.updateCover(updatedSong, currSong);
} }
}
+14 -46
View File
@@ -14,13 +14,7 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace manager { namespace manager {
TokenManager::TokenManager() model::Token TokenManager::retrieveToken(const model::BinaryPath& bConf) {
{
}
model::Token TokenManager::retrieveToken(const model::BinaryPath& bConf)
{
auto cred = parseAuthCredentials(bConf); auto cred = parseAuthCredentials(bConf);
auto reqObj = createTokenBody(cred); auto reqObj = createTokenBody(cred);
@@ -39,12 +33,11 @@ model::Token TokenManager::retrieveToken(const model::BinaryPath& bConf)
} }
bool TokenManager::isTokenValid(std::string& auth, type::Scope scope) bool TokenManager::isTokenValid(std::string& auth, type::Scope scope) {
{
auto authPair = fetchAuthHeader(auth); auto authPair = fetchAuthHeader(auth);
if (!std::get<0>(authPair)) { if (!std::get<0>(authPair)) {
std::cout << "no Bearer found" << std::endl; std::cout << "no Bearer found\n";
return std::get<0>(authPair); return std::get<0>(authPair);
} }
@@ -85,8 +78,7 @@ bool TokenManager::isTokenValid(std::string& auth, type::Scope scope)
return false; return false;
} }
bool TokenManager::testAuth(const model::BinaryPath& bConf) bool TokenManager::testAuth(const model::BinaryPath& bConf) {
{
auto cred = parseAuthCredentials(bConf); auto cred = parseAuthCredentials(bConf);
auto reqObj = createTokenBody(cred); auto reqObj = createTokenBody(cred);
@@ -100,8 +92,7 @@ bool TokenManager::testAuth(const model::BinaryPath& bConf)
} }
cpr::Response TokenManager::sendRequest(std::string_view uri, nlohmann::json& obj) cpr::Response TokenManager::sendRequest(std::string_view uri, nlohmann::json& obj) {
{
auto resp = cpr::Post(cpr::Url{uri}, cpr::Body{obj.dump()}, auto resp = cpr::Post(cpr::Url{uri}, cpr::Body{obj.dump()},
cpr::Header{{"Content-type", "application/json"}, cpr::Header{{"Content-type", "application/json"},
{"Connection", "keep-alive"}}); {"Connection", "keep-alive"}});
@@ -110,8 +101,7 @@ cpr::Response TokenManager::sendRequest(std::string_view uri, nlohmann::json& ob
} }
nlohmann::json TokenManager::createTokenBody(const model::AuthCredentials& auth) nlohmann::json TokenManager::createTokenBody(const model::AuthCredentials& auth) {
{
nlohmann::json obj; nlohmann::json obj;
obj["client_id"] = auth.clientId; obj["client_id"] = auth.clientId;
obj["client_secret"] = auth.clientSecret; obj["client_secret"] = auth.clientSecret;
@@ -122,26 +112,7 @@ nlohmann::json TokenManager::createTokenBody(const model::AuthCredentials& auth)
} }
[[depreacted("use the other function with the same name")]] model::AuthCredentials TokenManager::parseAuthCredentials(const model::BinaryPath& bConf) {
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); auto con = DirectoryManager::credentialConfigContent(bConf);
model::AuthCredentials auth; model::AuthCredentials auth;
@@ -155,13 +126,13 @@ model::AuthCredentials TokenManager::parseAuthCredentials(const model::BinaryPat
return auth; return auth;
} }
std::vector<std::string> TokenManager::extractScopes(const jwt::decoded_jwt&& decoded)
{ std::vector<std::string> TokenManager::extractScopes(const jwt::decoded_jwt&& decoded) {
std::vector<std::string> scopes; std::vector<std::string> scopes;
for (auto& d : decoded.get_payload_claims()) { for (auto& d : decoded.get_payload_claims()) {
if (d.first.compare("scope") == 0) { if (d.first.compare("scope") == 0) {
std::cout << "found scope" << std::endl; std::cout << "found scope\n";
std::string allScopes(d.second.to_json().get<std::string>()); std::string allScopes(d.second.to_json().get<std::string>());
std::istringstream iss(allScopes); std::istringstream iss(allScopes);
@@ -173,8 +144,7 @@ std::vector<std::string> TokenManager::extractScopes(const jwt::decoded_jwt&& de
return scopes; return scopes;
} }
std::pair<bool, std::vector<std::string>> TokenManager::fetchAuthHeader(const std::string& auth) std::pair<bool, std::vector<std::string>> TokenManager::fetchAuthHeader(const std::string& auth) {
{
std::istringstream iss(auth); std::istringstream iss(auth);
std::vector<std::string> authHeader{std::istream_iterator<std::string>(iss), std::vector<std::string> authHeader{std::istream_iterator<std::string>(iss),
std::istream_iterator<std::string>() std::istream_iterator<std::string>()
@@ -183,9 +153,8 @@ std::pair<bool, std::vector<std::string>> TokenManager::fetchAuthHeader(const st
bool foundBearer = false; bool foundBearer = false;
if (std::any_of(authHeader.begin(), authHeader.end(), if (std::any_of(authHeader.begin(), authHeader.end(),
[&](std::string_view word) { [&](std::string_view word) {
return (word.compare("Bearer") == 0); return (word.compare("Bearer") == 0); })) {
})) { std::cout << "Bearer found\n";
std::cout << "Bearer found" << std::endl;
foundBearer = true; foundBearer = true;
} }
@@ -194,8 +163,7 @@ std::pair<bool, std::vector<std::string>> TokenManager::fetchAuthHeader(const st
bool TokenManager::tokenSupportsScope(const std::vector<std::string>& scopes, bool TokenManager::tokenSupportsScope(const std::vector<std::string>& scopes,
const std::string&& scope) const std::string&& scope) {
{
return std::any_of(scopes.begin(), scopes.end(), return std::any_of(scopes.begin(), scopes.end(),
[&](std::string_view foundScope) { [&](std::string_view foundScope) {
return (foundScope.compare(scope) == 0); return (foundScope.compare(scope) == 0);
+9 -9
View File
@@ -25,7 +25,7 @@ model::RegisterResult UserManager::registerUser(model::User& user) {
model::User usr; model::User usr;
usr.username = user.username; usr.username = user.username;
std::cout << usr.username << std::endl; std::cout << usr.username << "\n";
usr = usrRepo.retrieveUserRecord(usr, type::UserFilter::username); usr = usrRepo.retrieveUserRecord(usr, type::UserFilter::username);
hashed.hashPassword = usr.password; hashed.hashPassword = usr.password;
hashed.userId = usr.id; hashed.userId = usr.id;
@@ -63,14 +63,14 @@ bool UserManager::validatePassword(const model::User& user) {
void UserManager::printUser(const model::User& user) { void UserManager::printUser(const model::User& user) {
std::cout << "\nuser info" << std::endl; std::cout << "\nuser info\n";
std::cout << "id: " << user.id << std::endl; std::cout << "id: " << user.id << "\n";
std::cout << "firstname: " << user.firstname << std::endl; std::cout << "firstname: " << user.firstname << "\n";
std::cout << "lastname: " << user.lastname << std::endl; std::cout << "lastname: " << user.lastname << "\n";
std::cout << "phone: " << user.phone << std::endl; std::cout << "phone: " << user.phone << "\n";
std::cout << "email: " << user.email << std::endl; std::cout << "email: " << user.email << "\n";
std::cout << "username: " << user.username << std::endl; std::cout << "username: " << user.username << "\n";
std::cout << "password: " << user.password<< std::endl; std::cout << "password: " << user.password<< "\n";
} }
} }
+17 -22
View File
@@ -5,21 +5,18 @@
#include "database/YearRepository.h" #include "database/YearRepository.h"
#include "type/YearFilter.h" #include "type/YearFilter.h"
manager::YearManager::YearManager(const model::BinaryPath& bConf) namespace manager {
: m_bConf(bConf) YearManager::YearManager(const model::BinaryPath& bConf) : m_bConf(bConf) { }
{ }
model::Year manager::YearManager::retrieveYear(model::Year& year) model::Year YearManager::retrieveYear(model::Year& year) {
{
database::YearRepository yearRepo(m_bConf); database::YearRepository yearRepo(m_bConf);
year = yearRepo.retrieveRecord(year, type::YearFilter::year); year = yearRepo.retrieveRecord(year, type::YearFilter::year);
return year; return year;
} }
model::Year manager::YearManager::saveYear(const model::Song& song) model::Year YearManager::saveYear(const model::Song& song) {
{
model::Year year; model::Year year;
year.year = song.year; year.year = song.year;
@@ -27,14 +24,13 @@ model::Year manager::YearManager::saveYear(const model::Song& song)
if (!yearRepo.doesYearExist(year, type::YearFilter::year)) { if (!yearRepo.doesYearExist(year, type::YearFilter::year)) {
yearRepo.saveRecord(year); yearRepo.saveRecord(year);
} else { } else {
std::cout << "year record already exists in the database" << std::endl; std::cout << "year record already exists in the database\n";
} }
return year; return year;
} }
void manager::YearManager::deleteYear(const model::Song& song) void YearManager::deleteYear(const model::Song& song) {
{
model::Year year(song); model::Year year(song);
database::YearRepository yrRepo(m_bConf); database::YearRepository yrRepo(m_bConf);
@@ -42,35 +38,34 @@ void manager::YearManager::deleteYear(const model::Song& song)
if (yrWSC.second > 1) { if (yrWSC.second > 1) {
std::cout << "year still contain songs related to it"; std::cout << "year still contain songs related to it";
std::cout << ", will not delete" << std::endl; std::cout << ", will not delete\n";
return; return;
} }
std::cout << "safe to delete the year record" << std::endl; std::cout << "safe to delete the year record\n";
yrRepo.deleteYear(year, type::YearFilter::id); yrRepo.deleteYear(year, type::YearFilter::id);
} }
void manager::YearManager::updateYear(model::Song& updatedSong, void YearManager::updateYear(model::Song& updatedSong,
const model::Song& currSong) const model::Song& currSong) {
{
model::Year year; model::Year year;
year.year = updatedSong.year; year.year = updatedSong.year;
database::YearRepository albRepo(m_bConf); database::YearRepository albRepo(m_bConf);
if (!albRepo.doesYearExist(year, type::YearFilter::year)) { if (!albRepo.doesYearExist(year, type::YearFilter::year)) {
std::cout << "year record does not exist" << std::endl; std::cout << "year record does not exist\n";
albRepo.saveRecord(year); albRepo.saveRecord(year);
} else { } else {
std::cout << "year record already exists" << std::endl; std::cout << "year record already exists\n";
} }
year = albRepo.retrieveRecord(year, type::YearFilter::year); year = albRepo.retrieveRecord(year, type::YearFilter::year);
updatedSong.yearId = year.id; updatedSong.yearId = year.id;
} }
void manager::YearManager::printYear(const model::Year& year) void YearManager::printYear(const model::Year& year) {
{ std::cout << "\nyear record\n";
std::cout << "\nyear record" << std::endl; std::cout << "id: " << year.id << "\n";
std::cout << "id: " << year.id << std::endl; std::cout << "year: " << year.year << "\n";
std::cout << "year: " << year.year << std::endl; }
} }
+4 -5
View File
@@ -1,10 +1,9 @@
#include "utility/ImageFile.h" #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() TagLib::ByteVector ImageFile::data() {
{
return readBlock(length()); return readBlock(length());
} }
}
+66 -46
View File
@@ -6,10 +6,6 @@
#include <sstream> #include <sstream>
#include <string.h> #include <string.h>
#include <attachedpictureframe.h>
#include <fileref.h>
#include <mpegfile.h>
#include <tag.h>
#include "manager/DirectoryManager.h" #include "manager/DirectoryManager.h"
#include "utility/ImageFile.h" #include "utility/ImageFile.h"
@@ -17,39 +13,51 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
model::Song utility::MetadataRetriever::retrieveMetadata(std::string& songPath) namespace utility {
{ model::Song MetadataRetriever::retrieveMetadata(model::Song& song) {
TagLib::FileRef file(songPath.c_str()); TagLib::MPEG::File sameFile(song.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;
// 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(); 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();
auto frame = tag->frameList("TPOS"); song.duration = sameFile.audioProperties()->lengthInSeconds();
if (frame.isEmpty()) {
song.disc = 1; constexpr auto id3DiscName = "TPOS";
// TODO: set default disc to 1 if none found 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 { } else {
song.disc = std::stoi(frame.front()->toString().toCString()); 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; return song;
} }
model::Cover utility::MetadataRetriever::updateCoverArt(const model::Song& song, model::Cover& cov, const std::string& stockCoverPath) model::Cover MetadataRetriever::updateCoverArt(const model::Song& song, model::Cover& cov,
{ const std::string& stockCoverPath) {
TagLib::MPEG::File sngF(song.songPath.c_str()); TagLib::MPEG::File sngF(song.songPath.c_str());
auto tag = sngF.ID3v2Tag(); auto tag = sngF.ID3v2Tag();
auto frameList = tag->frameListMap()["APIC"]; auto frameList = tag->frameListMap()["APIC"];
@@ -58,7 +66,7 @@ model::Cover utility::MetadataRetriever::updateCoverArt(const model::Song& song,
cov.imagePath.append("CoverArt.png"); cov.imagePath.append("CoverArt.png");
if (!fs::exists(cov.imagePath)) { if (!fs::exists(cov.imagePath)) {
std::cout << "copying stock cover path" << std::endl; std::cout << "copying stock cover path\n";
fs::copy(stockCoverPath, cov.imagePath); fs::copy(stockCoverPath, cov.imagePath);
} }
@@ -72,7 +80,7 @@ model::Cover utility::MetadataRetriever::updateCoverArt(const model::Song& song,
tag->addFrame(pic); tag->addFrame(pic);
sngF.save(); sngF.save();
std::cout << "applied stock cover art" << std::endl; std::cout << "applied stock cover art\n";
} else { } else {
auto frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>( auto frame = dynamic_cast<TagLib::ID3v2::AttachedPictureFrame*>(
frameList.front()); frameList.front());
@@ -86,21 +94,20 @@ model::Cover utility::MetadataRetriever::updateCoverArt(const model::Song& song,
std::ios::binary); std::ios::binary);
imgSave.write(frame->picture().data(), frame->picture().size()); imgSave.write(frame->picture().data(), frame->picture().size());
imgSave.close(); imgSave.close();
std::cout << "saved to " << cov.imagePath << std::endl; std::cout << "saved to " << cov.imagePath << "\n";
} }
return cov; return cov;
} }
// tags song with the stock cover art // tags song with the stock cover art
model::Cover utility::MetadataRetriever::applyStockCoverArt( model::Cover MetadataRetriever::applyStockCoverArt(
const model::Song& song, model::Cover& cov, const model::Song& song, model::Cover& cov,
const std::string& stockCoverPath) const std::string& stockCoverPath) {
{
TagLib::MPEG::File songFile(song.songPath.c_str()); TagLib::MPEG::File songFile(song.songPath.c_str());
auto tag = songFile.ID3v2Tag(); auto tag = songFile.ID3v2Tag();
utility::ImageFile stockImg(cov.imagePath.c_str()); ImageFile stockImg(cov.imagePath.c_str());
TagLib::ID3v2::AttachedPictureFrame *pic = TagLib::ID3v2::AttachedPictureFrame *pic =
new TagLib::ID3v2::AttachedPictureFrame; new TagLib::ID3v2::AttachedPictureFrame;
@@ -110,7 +117,7 @@ model::Cover utility::MetadataRetriever::applyStockCoverArt(
tag->addFrame(pic); tag->addFrame(pic);
songFile.save(); songFile.save();
std::cout << "applied stock cover art" << std::endl; std::cout << "applied stock cover art\n";
delete pic; delete pic;
@@ -119,9 +126,8 @@ model::Cover utility::MetadataRetriever::applyStockCoverArt(
// extracts cover art from the song and save it to the // extracts cover art from the song and save it to the
// appropriate directory // appropriate directory
model::Cover utility::MetadataRetriever::applyCoverArt(const model::Song& song, model::Cover MetadataRetriever::applyCoverArt(const model::Song& song,
model::Cover& cov) model::Cover& cov) {
{
TagLib::MPEG::File songFile(song.songPath.c_str()); TagLib::MPEG::File songFile(song.songPath.c_str());
auto tag = songFile.ID3v2Tag(); auto tag = songFile.ID3v2Tag();
auto frameList = tag->frameListMap()["APIC"]; auto frameList = tag->frameListMap()["APIC"];
@@ -134,14 +140,13 @@ model::Cover utility::MetadataRetriever::applyCoverArt(const model::Song& song,
imgSave.write(frame->picture().data(), frame->picture().size()); imgSave.write(frame->picture().data(), frame->picture().size());
imgSave.close(); imgSave.close();
std::cout << "saved to " << cov.imagePath << std::endl; std::cout << "saved to " << cov.imagePath << "\n";
return cov; return cov;
} }
bool utility::MetadataRetriever::songContainsCoverArt(const model::Song& song) bool MetadataRetriever::songContainsCoverArt(const model::Song& song) {
{
TagLib::MPEG::File songFile(song.songPath.c_str()); TagLib::MPEG::File songFile(song.songPath.c_str());
auto tag = songFile.ID3v2Tag(); auto tag = songFile.ID3v2Tag();
auto frameList = tag->frameListMap()["APIC"]; auto frameList = tag->frameListMap()["APIC"];
@@ -150,10 +155,10 @@ bool utility::MetadataRetriever::songContainsCoverArt(const model::Song& song)
} }
void utility::MetadataRetriever::updateMetadata(model::Song& sngUpdated, const model::Song& sngOld) void MetadataRetriever::updateMetadata(model::Song& sngUpdated, const model::Song& sngOld) {
{ std::cout << "updating metadata\n";
std::cout<<"updating metadata"<<std::endl; TagLib::MPEG::File file(sngOld.songPath.c_str());
TagLib::FileRef file(sngOld.songPath.c_str()); auto tag = file.ID3v2Tag();
if (sngUpdated.title.size() > 0) { if (sngUpdated.title.size() > 0) {
file.tag()->setTitle(sngUpdated.title); file.tag()->setTitle(sngUpdated.title);
@@ -161,6 +166,20 @@ void utility::MetadataRetriever::updateMetadata(model::Song& sngUpdated, const m
if (sngUpdated.artist.size() > 0) { if (sngUpdated.artist.size() > 0) {
file.tag()->setArtist(sngUpdated.artist); file.tag()->setArtist(sngUpdated.artist);
} }
if (sngUpdated.albumArtist.size() > 0) {
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());
}
file.save();
}
if (sngUpdated.album.size() > 0) { if (sngUpdated.album.size() > 0) {
file.tag()->setAlbum(sngUpdated.album); file.tag()->setAlbum(sngUpdated.album);
} }
@@ -175,3 +194,4 @@ void utility::MetadataRetriever::updateMetadata(model::Song& sngUpdated, const m
file.save(); file.save();
} }
}
+8 -14
View File
@@ -7,30 +7,29 @@
namespace utility { namespace utility {
model::PassSec PasswordEncryption::hashPassword(const model::User& user) model::PassSec PasswordEncryption::hashPassword(const model::User& user) {
{
model::PassSec passSec; model::PassSec passSec;
std::unique_ptr<char[]> salt(new char[BCRYPT_HASHSIZE]); std::unique_ptr<char[]> salt(new char[BCRYPT_HASHSIZE]);
std::unique_ptr<char[]> hash(new char[BCRYPT_HASHSIZE]); std::unique_ptr<char[]> hash(new char[BCRYPT_HASHSIZE]);
std::cout << "generating salt" << std::endl; std::cout << "generating salt\n";
bcrypt_gensalt(saltSize(), salt.get()); bcrypt_gensalt(saltSize(), salt.get());
std::cout << "hashing password" << std::endl; std::cout << "hashing password\n";
bcrypt_hashpw(user.password.c_str(), salt.get(), hash.get()); bcrypt_hashpw(user.password.c_str(), salt.get(), hash.get());
passSec.salt = salt.get(); passSec.salt = salt.get();
passSec.hashPassword = hash.get(); passSec.hashPassword = hash.get();
std::cout << "hash: " << passSec.hashPassword << std::endl; std::cout << "hash: " << passSec.hashPassword << "\n";
std::cout << "salt: " << passSec.salt << std::endl; std::cout << "salt: " << passSec.salt << "\n";
return passSec; return passSec;
} }
bool PasswordEncryption::isPasswordValid(const model::User& user, const model::PassSec& userSalt) bool PasswordEncryption::isPasswordValid(const model::User& user,
{ const model::PassSec& userSalt) {
std::unique_ptr<char[]> passwordHashed(new char[BCRYPT_HASHSIZE]); std::unique_ptr<char[]> passwordHashed(new char[BCRYPT_HASHSIZE]);
bcrypt_hashpw(user.password.c_str(), userSalt.salt.c_str(), passwordHashed.get()); bcrypt_hashpw(user.password.c_str(), userSalt.salt.c_str(), passwordHashed.get());
@@ -39,10 +38,5 @@ bool PasswordEncryption::isPasswordValid(const model::User& user, const model::P
} }
int PasswordEncryption::saltSize() constexpr int PasswordEncryption::saltSize() noexcept { return 10000; }
{
constexpr auto size = 10000;
return size;
}
} }
+19 -34
View File
@@ -11,91 +11,78 @@
namespace fs = std::filesystem; namespace fs = std::filesystem;
namespace verify { namespace verify {
bool Initialization::skipVerification(const std::string& argument) {
bool Initialization::skipVerification(const std::string& argument)
{
return argument.compare("--noverify") == 0; return argument.compare("--noverify") == 0;
} }
// verifies if the configuration settings are valid // verifies if the configuration settings are valid
void Initialization::checkIcarus(const model::BinaryPath& bConf) void Initialization::checkIcarus(const model::BinaryPath& bConf) {
{
auto auth = confirmConfigAuth(bConf); auto auth = confirmConfigAuth(bConf);
auto database = confirmConfigDatabase(bConf); auto database = confirmConfigDatabase(bConf);
auto path = confirmConfigPaths(bConf); auto path = confirmConfigPaths(bConf);
if ((auth && database && path) == false) { if ((!auth) && (!database) && (!path)) {
failedConfirmation(); failedConfirmation();
} }
std::cout << "icarus check passed" << std::endl; std::cout << "icarus check passed\n";
} }
// verifies that the authorization settings are not the default values // verifies that the authorization settings are not the default values
bool Initialization::confirmConfigAuth(const model::BinaryPath& bConf) bool Initialization::confirmConfigAuth(const model::BinaryPath& bConf) {
{
manager::TokenManager tokMgr; manager::TokenManager tokMgr;
return tokMgr.testAuth(bConf); return tokMgr.testAuth(bConf);
} }
// verifies if database connectivity can be established // verifies if database connectivity can be established
bool Initialization::confirmConfigDatabase(const model::BinaryPath& bConf) bool Initialization::confirmConfigDatabase(const model::BinaryPath& bConf) {
{
database::BaseRepository baseRepo(bConf); database::BaseRepository baseRepo(bConf);
return baseRepo.testConnection(); return baseRepo.testConnection();
} }
// verifies if the paths found in the config files exists // verifies if the paths found in the config files exists
bool Initialization::confirmConfigPaths(const model::BinaryPath& bConf) bool Initialization::confirmConfigPaths(const model::BinaryPath& bConf) {
{ using manager::DirectoryManager;
auto pathConfig = manager::DirectoryManager::pathConfigContent(bConf); auto pathConfig = DirectoryManager::pathConfigContent(bConf);
const auto rootMusicPath = const auto rootMusicPath =
pathConfig pathConfig
[manager:: [DirectoryManager::retrievePathType
DirectoryManager::
retrievePathType
(type::PathType::music)].get<std::string>(); (type::PathType::music)].get<std::string>();
const auto archiveRootPath = const auto archiveRootPath =
pathConfig pathConfig
[manager:: [DirectoryManager::retrievePathType
DirectoryManager::
retrievePathType
(type::PathType::archive)].get<std::string>(); (type::PathType::archive)].get<std::string>();
const auto tempRootPath = const auto tempRootPath =
pathConfig pathConfig
[manager:: [DirectoryManager::retrievePathType
DirectoryManager::
retrievePathType
(type::PathType::temp)].get<std::string>(); (type::PathType::temp)].get<std::string>();
const auto coverRootPath = const auto coverRootPath =
pathConfig pathConfig
[manager:: [DirectoryManager::retrievePathType
DirectoryManager::
retrievePathType
(type::PathType::coverArt)].get<std::string>(); (type::PathType::coverArt)].get<std::string>();
if (!fs::exists(rootMusicPath)) { if (!fs::exists(rootMusicPath)) {
std::cout << "root music path is not properly configured" << std::endl; std::cout << "root music path is not properly configured\n";
return false; return false;
} }
if (!fs::exists(archiveRootPath)) { if (!fs::exists(archiveRootPath)) {
std::cout << "archive root path is not properly configured" << std::endl; std::cout << "archive root path is not properly configured\n";
return false; return false;
} }
if (!fs::exists(tempRootPath)) { if (!fs::exists(tempRootPath)) {
std::cout << "temp root path is not properly configured" << std::endl; std::cout << "temp root path is not properly configured\n";
return false; return false;
} }
if (!fs::exists(coverRootPath)) { if (!fs::exists(coverRootPath)) {
std::cout << "cover art root path is not properly configured" << std::endl; std::cout << "cover art root path is not properly configured\n";
return false; return false;
} }
@@ -104,10 +91,8 @@ bool Initialization::confirmConfigPaths(const model::BinaryPath& bConf)
// confirmation failed // confirmation failed
void Initialization::failedConfirmation() void Initialization::failedConfirmation() {
{ std::cout << "configuration confirmation failed. check your settings\n";
std::cout << "configuration confirmation failed. check your settings" << std::endl;
std::exit(-1); std::exit(-1);
} }
} }