Compare commits

...

15 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
83 changed files with 4653 additions and 4984 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)
+1 -3
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>
@@ -151,8 +151,6 @@ 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
+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);
+50 -35
View File
@@ -9,13 +9,15 @@
#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"
@@ -27,37 +29,38 @@
#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);
@@ -65,16 +68,25 @@ 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;
}
}
auto songDto = dto::conversion::DtoConversions::toSongDto(sng);
return createDtoResponse(Status::CODE_200, songDto);
@@ -82,20 +94,19 @@ public:
// 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::conversion::DtoConversions::toSongDto(songDb);
@@ -121,7 +132,7 @@ public:
return songDoesNotExist();
}
std::cout << "song exists" << std::endl;
std::cout << "song exists\n";
songDb = songRepo.retrieveRecord(songDb, type::SongFilter::id);
auto song = dto::conversion::DtoConversions::toSongDto(songDb);
@@ -135,7 +146,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::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);
@@ -161,7 +173,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::updateSong), Status::CODE_403, "Not allowed");
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::updateSong), Status::CODE_403, "Not allowed");
auto updatedSong = dto::conversion::DtoConversions::toSong(songDto);
manager::SongManager songMgr(m_bConf);
@@ -180,7 +193,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::deleteSong), Status::CODE_403, "Not allowed");
OATPP_ASSERT_HTTP(tok.isTokenValid(auth,
type::Scope::deleteSong), Status::CODE_403, "Not allowed");
model::Song song(id);
@@ -200,7 +214,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::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);
@@ -210,10 +225,12 @@ public:
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);
@@ -223,18 +240,16 @@ public:
}
#include OATPP_CODEGEN_END(ApiController)
private:
private:
std::shared_ptr<oatpp::web::protocol::http::outgoing::Response>
songDoesNotExist() {
return createResponse(Status::CODE_404, "Song not found");
}
std::string m_exe_path;
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);
+3 -4
View File
@@ -6,17 +6,16 @@
#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);
+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);
+3
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,8 @@ 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&);
+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&);
+4 -6
View File
@@ -4,28 +4,27 @@
#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
{
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&);
bool deleteSong(model::Song&);
bool updateSong(model::Song&);
void saveSong(model::Song&);
static void printSong(const model::Song&);
private:
std::map<type::SongChanged, bool> changesInSong(const model::Song&, const model::Song&);
@@ -44,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;
}
}
+15 -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,12 +24,24 @@ 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;
@@ -47,6 +59,8 @@ namespace dto { namespace conversion {
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();
+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";
}
}
+129 -140
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,42 +84,40 @@ bool manager::SongManager::requiresFilesystemChange(const model::Song& updatedSo
}
return false;
}
}
bool 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;
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;
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;
}
}
bool manager::SongManager::updateSong(model::Song& updatedSong)
{
bool SongManager::updateSong(model::Song& updatedSong) {
database::SongRepository songRepo(m_bConf);
model::Song currSong(updatedSong.id);
currSong = songRepo.retrieveRecord(currSong, type::SongFilter::id);
if (!didSongChange(updatedSong, currSong)) {
std::cout << "no change to the song" << std::endl;
std::cout << "no change to the song\n";
return false;
}
@@ -123,50 +139,31 @@ bool manager::SongManager::updateSong(model::Song& updatedSong)
updateMisc(changes, updatedSong, currSong);
return true;
}
}
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);
song = songRepo.retrieveRecord(song, type::SongFilter::title);
}
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";
}
void manager::SongManager::printSong(const model::Song& song)
{
std::cout << "\nsong" << std::endl;
std::cout << "title: " << song.title << std::endl;
std::cout << "artist: " << song.artist << std::endl;
std::cout << "album: " << song.album << std::endl;
std::cout << "genre: " << song.genre << std::endl;
std::cout << "duration: " << song.duration << std::endl;
std::cout << "year: " << song.year << std::endl;
std::cout << "track: " << song.track << std::endl;
std::cout << "disc: " << song.disc << std::endl;
std::cout << "song path: " << song.songPath << std::endl;
std::cout << "cover art id: " << song.coverArtId << std::endl;
std::cout << "album id: " << song.albumId << std::endl;
std::cout << "artist id: " << song.artistId << std::endl;
std::cout << "genre id: " << song.genreId << std::endl;
std::cout << "year id: " << song.yearId << std::endl;
}
std::map<type::SongChanged, bool> manager::SongManager::changesInSong(
const model::Song& updatedSong, const model::Song& currSong)
{
std::map<type::SongChanged, bool> SongManager::changesInSong(
const model::Song& updatedSong, const model::Song& currSong) {
std::map<type::SongChanged, bool> songChanges;
std::string_view updatedTitle = updatedSong.title;
@@ -197,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) {
@@ -213,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;
@@ -231,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;
@@ -285,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;
@@ -334,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);
@@ -382,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);
}
@@ -408,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);
}
}
}