From cb393b0c0d6c1585babc549ba07afac72de461e5 Mon Sep 17 00:00:00 2001 From: Kevin Whitaker Date: Sat, 18 Feb 2017 14:25:52 -0500 Subject: [PATCH] Uncomment user actions and fix by finding active DB object instead of converting dead one. Use font-awesome to make icons for buttons. Implement rest of basic logic for login page. Some style fixings. Start adding skip controls. --- src/GroovePlayer.cpp | 44 +++++++++++------------ src/WebInterface.cpp | 4 ++- src/ui/LoginInterface.cpp | 72 ++++++++++++++++++++++++++++++++------ src/ui/LoginInterface.h | 5 +-- src/ui/PlayerInterface.cpp | 20 ++++++++--- src/ui/PlayerInterface.h | 2 ++ src/ui/TrackDetails.cpp | 8 +++-- 7 files changed, 113 insertions(+), 42 deletions(-) diff --git a/src/GroovePlayer.cpp b/src/GroovePlayer.cpp index 106b5ef..a927ab6 100644 --- a/src/GroovePlayer.cpp +++ b/src/GroovePlayer.cpp @@ -355,8 +355,8 @@ void GroovePlayerMgr::grooveEventLoop() Wt::Dbo::Transaction voteTransaction(sqlSession); UserAction* action = new UserAction(); action->action = UserAction::UAction::VoteTrack; - action->user = Wt::Dbo::ptr(&event.userInvolved); - action->trackInvolved = Wt::Dbo::ptr(&event.tracksInvolved.front()); + action->user = sqlSession.find().where("username = ?").bind(event.userInvolved.username); + action->trackInvolved = sqlSession.find().where("fingerprint = ?").bind(event.tracksInvolved.front().trackFingerprint); action->datetime = Wt::WDateTime::currentDateTime(); sqlSession.add(action); voteTransaction.commit(); @@ -383,15 +383,15 @@ void GroovePlayerMgr::grooveEventLoop() } else if(event.eventType == PLAYING_PAUSED) { - //Add action to DB TODO -// Wt::Dbo::Transaction pauseTransaction(sqlSession); -// UserAction* action = new UserAction(); -// action->action = UserAction::UAction::PlayPause; -// action->user = Wt::Dbo::ptr(&event.userInvolved); -// action->trackInvolved = Wt::Dbo::ptr(&event.tracksInvolved.front()); -// action->datetime = Wt::WDateTime::currentDateTime(); -// sqlSession.add(action); -// pauseTransaction.commit(); + //Add action to DB + Wt::Dbo::Transaction pauseTransaction(sqlSession); + UserAction* action = new UserAction(); + action->action = UserAction::UAction::PlayPause; + action->user = sqlSession.find().where("username = ?").bind(event.userInvolved.username); + action->trackInvolved = sqlSession.find().where("fingerprint = ?").bind(event.tracksInvolved.front().trackFingerprint); + action->datetime = Wt::WDateTime::currentDateTime(); + sqlSession.add(action); + pauseTransaction.commit(); groove_playlist_pause(currentPlaylist); @@ -407,15 +407,15 @@ void GroovePlayerMgr::grooveEventLoop() } else if(event.eventType == PLAYING_RESUMED) { - //Add action to DB TODO -// Wt::Dbo::Transaction playTransaction(sqlSession); -// UserAction* action = new UserAction(); -// action->action = UserAction::UAction::PlayPause; -// action->user = Wt::Dbo::ptr(&event.userInvolved); -// action->trackInvolved = Wt::Dbo::ptr(&event.tracksInvolved.front()); -// action->datetime = Wt::WDateTime::currentDateTime(); -// sqlSession.add(action); -// playTransaction.commit(); + //Add action to DB + Wt::Dbo::Transaction playTransaction(sqlSession); + UserAction* action = new UserAction(); + action->action = UserAction::UAction::PlayPause; + action->user = sqlSession.find().where("username = ?").bind(event.userInvolved.username); + action->trackInvolved = sqlSession.find().where("fingerprint = ?").bind(event.tracksInvolved.front().trackFingerprint); + action->datetime = Wt::WDateTime::currentDateTime(); + sqlSession.add(action); + playTransaction.commit(); groove_playlist_play(currentPlaylist); @@ -439,8 +439,8 @@ void GroovePlayerMgr::grooveEventLoop() Wt::Dbo::Transaction skipTransaction(sqlSession); UserAction* action = new UserAction(); action->action = UserAction::UAction::RequestSkip; - action->user = Wt::Dbo::ptr(&event.userInvolved); - action->trackInvolved = Wt::Dbo::ptr(&event.tracksInvolved.front()); + action->user = sqlSession.find().where("username = ?").bind(event.userInvolved.username); + action->trackInvolved = sqlSession.find().where("fingerprint = ?").bind(event.tracksInvolved.front().trackFingerprint); action->datetime = Wt::WDateTime::currentDateTime(); sqlSession.add(action); skipTransaction.commit(); diff --git a/src/WebInterface.cpp b/src/WebInterface.cpp index a01539b..efbb044 100644 --- a/src/WebInterface.cpp +++ b/src/WebInterface.cpp @@ -32,14 +32,16 @@ struct WebInterface::internal WebInterface::WebInterface(const Wt::WEnvironment& env) : Wt::WApplication(env) { priv_int = new internal; + this->useStyleSheet(Wt::WLink("/resources/font-awesome/css/font-awesome.min.css")); setTitle("Arbitrateor - Audio Jukebox"); enableUpdates(true); priv_int->playerUI = new PlayerInterface(this); priv_int->playerUI->hide(); priv_int->loginUI = new LoginInterface(this); - priv_int->loginUI->animateShow(Wt::WAnimation(Wt::WAnimation::AnimationEffect::SlideInFromTop)); root()->addWidget(priv_int->playerUI); root()->addWidget(priv_int->loginUI); + priv_int->loginUI->animateShow(Wt::WAnimation(Wt::WAnimation::AnimationEffect::SlideInFromTop)); + priv_int->loginUI->checkSessionValidity(); } WebInterface::~WebInterface() diff --git a/src/ui/LoginInterface.cpp b/src/ui/LoginInterface.cpp index 804a72a..97b811b 100644 --- a/src/ui/LoginInterface.cpp +++ b/src/ui/LoginInterface.cpp @@ -19,11 +19,15 @@ #include "LoginInterface.h" #include "../db/UserAction.h" +#include +#include +#include +#include +#include LoginInterface::LoginInterface(WebInterface* app) { this->app = app; - //TODO: First check if cookie is set and if is a valid user. Skip login if valid. loginContainer = new Wt::WContainerWidget(); loginLayout = new Wt::WVBoxLayout(); loginMessage = new Wt::WText("Please Login to access."); @@ -52,6 +56,24 @@ LoginInterface::LoginInterface(WebInterface* app) loginContainer->setWidth(Wt::WLength(50, Wt::WLength::Percentage)); } +void LoginInterface::checkSessionValidity() +{ + Wt::Dbo::Session sqlSession; + sqlSession.setConnectionPool(*GroovePlayerMgr::getInstance()->connectionPool); + sqlSession.mapClass("user"); + sqlSession.mapClass("tracks"); + sqlSession.mapClass("actions"); + //First check if cookie is set and if is a valid user. Skip login if valid. + try{ + if(Wt::WApplication::instance()->environment().getCookieValue("arbitrateor_user") != nullptr && getUserForLoginCookie(&sqlSession, *Wt::WApplication::instance()->environment().getCookieValue("arbitrateor_user")).username != User().username) + { + app->currentUser = getUserForLoginCookie(&sqlSession, *Wt::WApplication::instance()->environment().getCookieValue("arbitrateor_user")); + app->loginCompleted(); + } + } + catch(std::runtime_error e){} +} + void LoginInterface::loginCheck() { //Reset message in case of success. @@ -78,9 +100,10 @@ void LoginInterface::loginCheck() createUser(&sqlSession, usernameField->text().toUTF8(),passwordField->text().toUTF8(), true); } //Check if the credentials match anything in the DB. If so, store cookie to skip login. - if(getUserForLoginAuth(&sqlSession, usernameField->text().toUTF8(),passwordField->text().toUTF8()) != nullptr) + if(getUserForLoginAuth(&sqlSession, usernameField->text().toUTF8(),passwordField->text().toUTF8()).username != User().username && !getUserForLoginAuth(&sqlSession, usernameField->text().toUTF8(),passwordField->text().toUTF8()).isDisabled) { - app->currentUser = *getUserForLoginAuth(&sqlSession, usernameField->text().toUTF8(),passwordField->text().toUTF8()); + app->currentUser = getUserForLoginAuth(&sqlSession, usernameField->text().toUTF8(),passwordField->text().toUTF8()); + Wt::log("info") << "login by "<< app->currentUser.username << " happened."; setLocalCookieForUser(app->currentUser); app->loginCompleted(); } @@ -94,25 +117,54 @@ void LoginInterface::loginCheck() void LoginInterface::createUser(Wt::Dbo::Session* session, std::string username, std::string rawPassword, bool isAdmin) { - //TODO + Wt::Dbo::Transaction transaction(*session); + Wt::Auth::BCryptHashFunction hasher; + User* user = new User(); + user->isAdmin = isAdmin; + user->username = username; + user->isDisabled = false; + user->passwordSalt = Wt::WRandom::generateId(); + user->passwordHash = hasher.compute(rawPassword, user->passwordSalt); + user->loginCookieToken = Wt::WRandom::generateId(); + session->add(user); + transaction.commit(); } int LoginInterface::getUserCount(Wt::Dbo::Session* session) { - //TODO + Wt::Dbo::Transaction transaction(*session); + int userCount = session->query("select count(username) from user"); + transaction.commit(); + return userCount; } -User* LoginInterface::getUserForLoginCookie(Wt::Dbo::Session* session, std::string cookie) +User LoginInterface::getUserForLoginCookie(Wt::Dbo::Session* session, std::string cookie) { - //TODO + Wt::Dbo::Transaction transaction(*session); + Wt::Dbo::ptr user = session->find().where("cookie = ?").bind(cookie); + transaction.commit(); + if(user.get() != nullptr) + { + return (*user); + } + return User(); } -User* LoginInterface::getUserForLoginAuth(Wt::Dbo::Session* session, std::string username, std::string rawPassword) +User LoginInterface::getUserForLoginAuth(Wt::Dbo::Session* session, std::string username, std::string rawPassword) { - //TODO + Wt::Dbo::Transaction transaction(*session); + Wt::Auth::BCryptHashFunction hasher; + Wt::Dbo::ptr user = session->find().where("username = ?").bind(username); + if(user.get() != nullptr && hasher.compute(rawPassword,(*user).passwordSalt) == (*user).passwordHash) + { + transaction.commit(); + return (*user); + } + transaction.commit(); + return User(); } void LoginInterface::setLocalCookieForUser(User user) { - //TODO + this->app->setCookie("arbitrateor_user", user.loginCookieToken,2628000); } diff --git a/src/ui/LoginInterface.h b/src/ui/LoginInterface.h index f9d8aca..6ac4e03 100644 --- a/src/ui/LoginInterface.h +++ b/src/ui/LoginInterface.h @@ -33,6 +33,7 @@ class LoginInterface : public Wt::WContainerWidget { public: LoginInterface(WebInterface* app); + void checkSessionValidity(); private: Wt::WPushButton* loginButton; Wt::WVBoxLayout* loginLayout; @@ -48,8 +49,8 @@ private: void loginCheck(); void createUser(Wt::Dbo::Session* session, std::string username, std::string rawPassword, bool isAdmin); int getUserCount(Wt::Dbo::Session* session); - User* getUserForLoginCookie(Wt::Dbo::Session* session, std::string cookie); - User* getUserForLoginAuth(Wt::Dbo::Session* session, std::string username, std::string rawPassword); + User getUserForLoginCookie(Wt::Dbo::Session* session, std::string cookie); + User getUserForLoginAuth(Wt::Dbo::Session* session, std::string username, std::string rawPassword); void setLocalCookieForUser(User user); }; diff --git a/src/ui/PlayerInterface.cpp b/src/ui/PlayerInterface.cpp index b5b8e0b..e2a0ad3 100644 --- a/src/ui/PlayerInterface.cpp +++ b/src/ui/PlayerInterface.cpp @@ -24,6 +24,7 @@ #include #include #include +#include PlayerInterface::PlayerInterface(WebInterface* app) { @@ -33,6 +34,7 @@ PlayerInterface::PlayerInterface(WebInterface* app) playControlLayout = new Wt::WHBoxLayout(); voteControlLayout = new Wt::WVBoxLayout(); playControlWidget = new Wt::WContainerWidget(); + skipControls = new Wt::WContainerWidget(); playControlWidget->setLayout(playControlLayout); currentTrackProgress = new Wt::WProgressBar(); @@ -43,10 +45,17 @@ PlayerInterface::PlayerInterface(WebInterface* app) trackProgress->timeout().connect(this,&PlayerInterface::updateProgressFromTimer); currentTrackDetails = new TrackDetails(); playpause = new Wt::WPushButton(); - playpause->setText(groove_playlist_playing(GroovePlayerMgr::getInstance()->currentPlaylist)==1?"Pause":"Resume"); + playpause->setTextFormat(Wt::XHTMLText); + playpause->decorationStyle().font().setFamily(Wt::WFont::Default,"FontAwesome"); + playpause->setText(groove_playlist_playing(GroovePlayerMgr::getInstance()->currentPlaylist)==1?Wt::WString::fromUTF8(""):Wt::WString::fromUTF8("")); playpause->setMaximumSize(Wt::WLength(60,Wt::WLength::Point),Wt::WLength(30,Wt::WLength::Point)); isPaused = groove_playlist_playing(GroovePlayerMgr::getInstance()->currentPlaylist)==0; playpause->clicked().connect(this, &PlayerInterface::playpauseClicked); + skipRequest = new Wt::WPushButton(); + skipRequest->setTextFormat(Wt::XHTMLText); + skipRequest->decorationStyle().font().setFamily(Wt::WFont::Default,"FontAwesome"); + skipRequest->setText(""); //cancel skip?  + skipControls->addWidget(skipRequest); interfaceLayout->addWidget(playControlWidget); interfaceLayout->addWidget(currentTrackProgress); @@ -55,17 +64,18 @@ PlayerInterface::PlayerInterface(WebInterface* app) playControlWidget->decorationStyle().setBackgroundColor(Wt::WColor("#00B200")); playControlLayout->addWidget(playpause,0,Wt::AlignmentFlag::AlignLeft | Wt::AlignmentFlag::AlignMiddle); playControlLayout->addWidget(currentTrackDetails); + playControlLayout->addWidget(skipControls,0,Wt::AlignmentFlag::AlignRight | Wt::AlignmentFlag::AlignMiddle); } void PlayerInterface::playpauseClicked() { if(!isPaused) { - GroovePlayerMgr::getInstance()->lastInternalEvents.push_back(GroovePlayerMgr::PlayerEvent() = {GroovePlayerMgr::PlayerEventType::PLAYING_PAUSED, app->currentUser}); + GroovePlayerMgr::getInstance()->lastInternalEvents.push_back(GroovePlayerMgr::PlayerEvent() = {GroovePlayerMgr::PlayerEventType::PLAYING_PAUSED, app->currentUser, std::list{GroovePlayerMgr::getInstance()->currentTrack}}); } else { - GroovePlayerMgr::getInstance()->lastInternalEvents.push_back(GroovePlayerMgr::PlayerEvent() = {GroovePlayerMgr::PlayerEventType::PLAYING_RESUMED, app->currentUser}); + GroovePlayerMgr::getInstance()->lastInternalEvents.push_back(GroovePlayerMgr::PlayerEvent() = {GroovePlayerMgr::PlayerEventType::PLAYING_RESUMED, app->currentUser, std::list{GroovePlayerMgr::getInstance()->currentTrack}}); } } @@ -73,11 +83,11 @@ void PlayerInterface::playpauseUpdated() { if(isPaused) { - playpause->setText("Resume"); + playpause->setText(Wt::WString::fromUTF8("")); } else { - playpause->setText("Pause"); + playpause->setText(Wt::WString::fromUTF8("")); } } diff --git a/src/ui/PlayerInterface.h b/src/ui/PlayerInterface.h index e672a58..4f8e13e 100644 --- a/src/ui/PlayerInterface.h +++ b/src/ui/PlayerInterface.h @@ -48,6 +48,8 @@ public: Wt::WHBoxLayout* currentTrackLayout; Wt::WContainerWidget* currentTrackContainer; Wt::WPushButton* playpause; + Wt::WContainerWidget* skipControls; + Wt::WPushButton* skipRequest; bool isPaused = false; //TODO:put in controls for requesting/admin skip and adding users as admin. diff --git a/src/ui/TrackDetails.cpp b/src/ui/TrackDetails.cpp index f74754a..537c9c7 100644 --- a/src/ui/TrackDetails.cpp +++ b/src/ui/TrackDetails.cpp @@ -23,7 +23,7 @@ TrackDetails::TrackDetails() { - this->setMaximumSize(Wt::WLength(600, Wt::WLength::Pixel),Wt::WLength(200, Wt::WLength::Pixel)); + this->setMaximumSize(Wt::WLength::Auto,Wt::WLength(200, Wt::WLength::Pixel)); this->decorationStyle().setBorder(Wt::WBorder::Ridge); this->decorationStyle().setBackgroundColor(Wt::WColor("#6FFF6F")); mainLayout = new Wt::WHBoxLayout(); @@ -34,14 +34,18 @@ TrackDetails::TrackDetails() albumCover->setMinimumSize(Wt::WLength(100,Wt::WLength::Pixel),Wt::WLength(100,Wt::WLength::Pixel)); albumCover->setMaximumSize(Wt::WLength(200,Wt::WLength::Pixel),Wt::WLength(200,Wt::WLength::Pixel)); mainLayout->addWidget(albumCover); - mainLayout->addSpacing(Wt::WLength(20, Wt::WLength::Pixel)); + mainLayout->addSpacing(Wt::WLength(10, Wt::WLength::Pixel)); mainLayout->addLayout(metaLayout); + mainLayout->addSpacing(Wt::WLength(10, Wt::WLength::Pixel)); trackTitle = new Wt::WText(); + trackTitle->setWordWrap(false); trackTitle->decorationStyle().setTextDecoration(Wt::WCssDecorationStyle::Underline); trackTitle->decorationStyle().font().setSize(Wt::WFont::Size::Large); trackTitle->decorationStyle().font().setWeight(Wt::WFont::Weight::Bold); trackArtist = new Wt::WText(); + trackArtist->setWordWrap(false); trackAlbum = new Wt::WText(); + trackAlbum->setWordWrap(false); metaLayout->addWidget(trackTitle,2); metaLayout->addWidget(trackAlbum,1,Wt::AlignmentFlag::AlignBottom); metaLayout->addWidget(trackArtist,1,Wt::AlignmentFlag::AlignBottom); -- GitLab