Compare commits

...

19 Commits

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