diff --git a/CMakeLists.txt b/CMakeLists.txt index b231d7a81a..f34c95e06a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.2) project(TogglDesktop) -set(CMAKE_CXX_STANDARD 11) +set(CMAKE_CXX_STANDARD 17) # Set up automatic resource generation to make Qt development easier set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index c11aba3162..09b48d0db0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,6 +33,9 @@ include_directories( # TogglDesktopLibrary sources set(LIBRARY_SOURCE_FILES + util/logger.cc + util/error.cc + base_model.cc batch_update_result.cc client.cc @@ -48,7 +51,6 @@ set(LIBRARY_SOURCE_FILES feedback.cc formatter.cc get_focused_window_linux.cc - error.cc gui.cc netconf.cc https_client.cc diff --git a/src/analytics.cc b/src/analytics.cc index 96d08622f0..ba9adef70a 100644 --- a/src/analytics.cc +++ b/src/analytics.cc @@ -17,8 +17,7 @@ #include "settings.h" #include "urls.h" #include "user.h" - -#include +#include "util/logger.h" namespace toggl { @@ -162,7 +161,7 @@ void GoogleAnalyticsEvent::runTask() { HTTPSClient client; HTTPSResponse resp = client.Get(req); if (resp.err != noError) { - Poco::Logger::get("Analytics").error(resp.err); + Logger("Analytics").error(resp.err); return; } } @@ -319,7 +318,7 @@ void GoogleAnalyticsSettingsEvent::makeReq() { HTTPSClient client; HTTPSResponse resp = client.Get(req); if (resp.err != noError) { - Poco::Logger::get("Analytics").error(resp.err); + Logger("Analytics").error(resp.err); return; } } diff --git a/src/base_model.cc b/src/base_model.cc index 93e87394e4..236e0a980f 100644 --- a/src/base_model.cc +++ b/src/base_model.cc @@ -12,7 +12,6 @@ #include #include #include -#include namespace toggl { @@ -22,8 +21,7 @@ bool BaseModel::NeedsPush() const { // pushed again unless the error is somehow fixed by user. // We will assume that if user modifies the model, the error // will go away. But until then, don't push the errored data. - return ValidationError().empty() && - (NeedsPOST() || NeedsPUT() || NeedsDELETE()); + return ValidationError() == noError && (NeedsPOST() || NeedsPUT() || NeedsDELETE()); } bool BaseModel::NeedsPOST() const { @@ -56,7 +54,7 @@ void BaseModel::ClearValidationError() { SetValidationError(noError); } -void BaseModel::SetValidationError(const std::string &value) { +void BaseModel::SetValidationError(const error &value) { if (validation_error_ != value) { validation_error_ = value; SetDirty(); @@ -113,7 +111,7 @@ error BaseModel::LoadFromDataString(const std::string &data_string) { Json::Value root; Json::Reader reader; if (!reader.parse(data_string, root)) { - return error("Failed to parse data string"); + return error(error::kFailedToParseData); } LoadFromJSON(root["data"]); return noError; @@ -154,8 +152,7 @@ error BaseModel::ApplyBatchUpdateResult( } bool BaseModel::userCannotAccessWorkspace(const error &err) const { - return (std::string::npos != std::string(err).find( - kCannotAccessWorkspaceError)); + return err == error::kCannotAccessWorkspaceError; } std::string BaseModel::batchUpdateRelativeURL() const { @@ -183,7 +180,7 @@ std::string BaseModel::batchUpdateMethod() const { // Convert model JSON into batch update format. error BaseModel::BatchUpdateJSON(Json::Value *result) const { if (GUID().empty()) { - return error("Cannot export model to batch update without a GUID"); + return error::kExportWithoutGUID; } Json::Value body; @@ -197,8 +194,8 @@ error BaseModel::BatchUpdateJSON(Json::Value *result) const { return noError; } -Poco::Logger &BaseModel::logger() const { - return Poco::Logger::get(ModelName()); +Logger BaseModel::logger() const { + return { ModelName() }; } void BaseModel::SetDirty() { diff --git a/src/base_model.h b/src/base_model.h index cdf9bb8d32..369cea5ffb 100644 --- a/src/base_model.h +++ b/src/base_model.h @@ -12,13 +12,10 @@ #include "const.h" #include "types.h" +#include "util/logger.h" #include -namespace Poco { -class Logger; -} - namespace toggl { class BatchUpdateResult; @@ -35,7 +32,7 @@ class TOGGL_INTERNAL_EXPORT BaseModel { , deleted_at_(0) , is_marked_as_deleted_on_server_(false) , updated_at_(0) - , validation_error_("") + , validation_error_(error::kNoError) , unsynced_(false) {} virtual ~BaseModel() {} @@ -122,8 +119,8 @@ class TOGGL_INTERNAL_EXPORT BaseModel { void EnsureGUID(); void ClearValidationError(); - void SetValidationError(const std::string &value); - const std::string &ValidationError() const { + void SetValidationError(const error &value); + const error &ValidationError() const { return validation_error_; } @@ -156,7 +153,7 @@ class TOGGL_INTERNAL_EXPORT BaseModel { error BatchUpdateJSON(Json::Value *result) const; protected: - Poco::Logger &logger() const; + Logger logger() const; bool userCannotAccessWorkspace(const toggl::error &err) const; @@ -176,7 +173,7 @@ class TOGGL_INTERNAL_EXPORT BaseModel { // If model push to backend results in an error, // the error is attached to the model for later inspection. - std::string validation_error_; + error validation_error_; // Flag is set only when sync fails. // Its for viewing purposes only. It should not diff --git a/src/batch_update_result.cc b/src/batch_update_result.cc index de3fe9a191..8f2845e4bc 100644 --- a/src/batch_update_result.cc +++ b/src/batch_update_result.cc @@ -7,8 +7,6 @@ #include "base_model.h" -#include - namespace toggl { error BatchUpdateResult::Error() const { @@ -16,12 +14,12 @@ error BatchUpdateResult::Error() const { return noError; } if ("null" != Body) { - return Body; + return error::REMOVE_LATER_BATCH_UPDATE_ERROR; } std::stringstream ss; ss << "Request failed with status code " << StatusCode; - return ss.str(); + return error::REMOVE_LATER_BATCH_UPDATE_ERROR; } std::string BatchUpdateResult::String() const { @@ -56,25 +54,21 @@ void BatchUpdateResult::ProcessResponseArray( poco_check_ptr(models); poco_check_ptr(errors); - Poco::Logger &logger = Poco::Logger::get("BatchUpdateResult"); for (std::vector::const_iterator it = results->begin(); it != results->end(); ++it) { BatchUpdateResult result = *it; - logger.debug(result.String()); + logger().debug(result.String()); if (result.GUID.empty()) { - logger.error("Batch update result has no GUID"); + logger().error("Batch update result has no GUID"); continue; } BaseModel *model = (*models)[result.GUID]; if (!model) { - std::stringstream ss; - ss << "Server response includes a model we don't have! GUID=" - << result.GUID; - logger.warning(ss.str()); + logger().warning("Server response includes a model we don't have! GUID=", result.GUID); continue; } error err = model->ApplyBatchUpdateResult(&result); @@ -85,27 +79,29 @@ void BatchUpdateResult::ProcessResponseArray( } } +Logger BatchUpdateResult::logger() { + return { "BatchUpdateResult" }; +} + error BatchUpdateResult::ParseResponseArray( const std::string &response_body, std::vector *responses) { poco_check_ptr(responses); - Poco::Logger &logger = Poco::Logger::get("BatchUpdateResult"); - // There seem to be cases where response body is 0. // Must investigate further. if (response_body.empty()) { - logger.warning("Response is empty!"); + logger().warning("Response is empty!"); return noError; } - logger.debug(response_body); + logger().debug(response_body); Json::Value root; Json::Reader reader; if (!reader.parse(response_body, root)) { - return error("error parsing batch update response"); + return error::kFailedToParseData; } for (unsigned int i = 0; i < root.size(); i++) { diff --git a/src/batch_update_result.h b/src/batch_update_result.h index f4d9928fad..a99ae68a69 100644 --- a/src/batch_update_result.h +++ b/src/batch_update_result.h @@ -8,6 +8,7 @@ #include #include "types.h" +#include "util/logger.h" #include // NOLINT @@ -43,6 +44,10 @@ class TOGGL_INTERNAL_EXPORT BatchUpdateResult { std::vector * const results, std::map *models, std::vector *errors); + + private: + static Logger logger(); + }; } // namespace toggl diff --git a/src/client.cc b/src/client.cc index 5e331c65ba..e4db105481 100644 --- a/src/client.cc +++ b/src/client.cc @@ -68,7 +68,7 @@ bool Client::ResolveError(const toggl::error &err) { SetName(Name() + " 1"); return true; } - if (err.find(kClientNameAlreadyExists) != std::string::npos) { + if (err == error::kClientNameAlreadyExists) { // remove duplicate from db MarkAsDeletedOnServer(); return true; @@ -77,13 +77,11 @@ bool Client::ResolveError(const toggl::error &err) { } bool Client::nameHasAlreadyBeenTaken(const error &err) { - return (std::string::npos != std::string(err).find( - "Name has already been taken")); + return err == error::kNameAlreadyTaken; } bool Client::ResourceCannotBeCreated(const toggl::error &err) const { - return (std::string::npos != std::string(err).find( - "cannot add or edit clients in workspace")); + return err == error::kCannotModifyWorkspaceData; } } // namespace toggl diff --git a/src/const.h b/src/const.h index 5c401e2853..5e32b7420f 100644 --- a/src/const.h +++ b/src/const.h @@ -45,57 +45,6 @@ #define kContentTypeMultipartFormData "multipart/form-data" #define kContentTypeApplicationJSON "application/json" -// Data validation errors -#define kOverMaxDurationError "Max allowed duration per 1 time entry is 999 hours" -#define kMaxTagsPerTimeEntryError "Tags are limited to 50 per task" -#define kInvalidStartTimeError "Start time year must be between 2006 and 2030" -#define kInvalidStopTimeError "Stop time year must be between 2006 and 2030" -#define kInvalidDateError "Date year must be between 2006 and 2030" -#define kStartNotBeforeStopError "Stop time must be after start time" -#define kMaximumDescriptionLengthError "Maximum length for description (3000 chars) exceeded" - -#define kCheckYourSignupError "Signup failed - please check your details. The e-mail might be already taken." // NOLINT -#define kEndpointGoneError "The API endpoint used by this app is gone. Please contact Toggl support!" // NOLINT -#define kForbiddenError "Invalid e-mail or password!" -#define kUnsupportedAppError "This version of the app is not supported any more. Please visit Toggl website to download a supported app." // NOLINT -#define kUnauthorizedError "Unauthorized! Please login again." -#define kCannotConnectError "Cannot connect to Toggl" -#define kCannotSyncInTestEnv "Cannot sync in test env" -#define kBackendIsDownError "Backend is down" -#define kBadRequestError "Data that you are sending is not valid/acceptable" -#define kRequestIsNotPossible "Request is not possible" -#define kPaymentRequiredError "Requested action allowed only for Non-Free workspaces. Please upgrade!" // NOLINT -#define kCannotAccessWorkspaceError "cannot access workspace" -#define kEmailNotFoundCannotLogInOffline "Login failed. Are you online?" // NOLINT -#define kInvalidPassword "Invalid password" -#define kCannotEstablishProxyConnection "Cannot establish proxy connection" -#define kCertificateVerifyFailed "certificate verify failed" -#define kCheckYourProxySetup "Check your proxy setup" -#define kCheckYourFirewall "Check your firewall" -#define kProxyAuthenticationRequired "Proxy Authentication Required" -#define kCertificateValidationError "Certificate validation error" -#define kUnacceptableCertificate "Unacceptable certificate from www.toggl.com" -#define kCannotUpgradeToWebSocketConnection "Cannot upgrade to WebSocket connection" // NOLINT -#define kSSLException "SSL Exception" -#define kRateLimit "Too many requests, sync delayed by 1 minute" -#define kCannotWriteFile "Cannot write file" -#define kIsSuspended "is suspended" -#define kRequestToServerFailedWithStatusCode403 "Request to server failed with status code: 403" // NOLINT -#define kMissingWorkspaceID "Missing workspace ID" -#define kCannotContinueDeletedTimeEntry "Cannot continue deleted time entry" -#define kCannotDeleteDeletedTimeEntry "Cannot delete deleted time entry" -#define kErrorRuleAlreadyExists "rule already exists" -#define kPleaseSelectAWorkspace "Please select a workspace" -#define kClientNameMustNotBeEmpty "Client name must not be empty" -#define kProjectNameMustNotBeEmpty "Project name must not be empty" -#define kProjectNameAlready "Project name already" -#define kProjectNameAlreadyExists "Project name already exists" -#define kClientNameAlreadyExists "Client name already exists" -#define kDatabaseDiskMalformed "The database disk image is malformed" -#define kMissingWS "You no longer have access to your last workspace" -#define kOutOfDatePleaseUpgrade "Your version of Toggl Desktop is out of date, please upgrade!" -#define kThisEntryCantBeSavedPleaseAdd "This entry can't be saved - please add" - #define kModelAutotrackerRule "autotracker_rule" #define kModelClient "client" #define kModelProject "project" diff --git a/src/context.cc b/src/context.cc index 16ad71d180..2b9a5b43b7 100644 --- a/src/context.cc +++ b/src/context.cc @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -191,11 +190,11 @@ void Context::stopActivities() { } } } catch(const Poco::Exception& exc) { - logger().debug(exc.displayText()); + logger.debug(exc.displayText()); } catch(const std::exception& ex) { - logger().debug(ex.what()); + logger.debug(ex.what()); } catch(const std::string & ex) { - logger().debug(ex); + logger.debug(ex); } { @@ -236,7 +235,7 @@ void Context::Shutdown() { error Context::StartEvents() { try { - logger().debug("StartEvents"); + logger.debug("StartEvents"); { Poco::Mutex::ScopedLock lock(user_m_); @@ -252,10 +251,10 @@ error Context::StartEvents() { // Check that UI is wired up error err = UI()->VerifyCallbacks(); if (err != noError) { - logger().error(err); + logger.error(err); std::cerr << err << std::endl; std::cout << err << std::endl; - return displayError("UI is not properly wired up!"); + return displayError(err); } UIElements render; @@ -279,7 +278,7 @@ error Context::StartEvents() { // Set since param to 0 to force full sync on app start user->SetSince(0); - logger().debug("fullSyncOnAppStart"); + logger.debug("fullSyncOnAppStart"); updateUI(UIElements::Reset()); @@ -310,7 +309,7 @@ error Context::StartEvents() { } error Context::save(const bool push_changes) { - logger().debug("save"); + logger.debug("save"); try { std::vector changes; @@ -329,7 +328,7 @@ error Context::save(const bool push_changes) { updateUI(render); if (push_changes) { - logger().debug("onPushChanges executing"); + logger.debug("onPushChanges executing"); // Always sync asyncronously with syncerActivity trigger_push_ = true; @@ -338,11 +337,11 @@ error Context::save(const bool push_changes) { } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -496,7 +495,7 @@ void UIElements::ApplyChanges( } void Context::OpenTimeEntryList() { - logger().debug("OpenTimeEntryList"); + logger.debug("OpenTimeEntryList"); UIElements render; render.open_time_entry_list = true; @@ -505,7 +504,7 @@ void Context::OpenTimeEntryList() { } void Context::updateUI(const UIElements &what) { - logger().debug("updateUI " + what.String()); + logger.debug("updateUI " + what.String()); view::TimeEntry editor_time_entry_view; @@ -1017,7 +1016,7 @@ bool Context::isPostponed( } Poco::Timestamp::TimeDiff diff = value - now; if (diff > 2*throttleMicros) { - logger().warning( + logger.warning( "Cannot postpone task, its foo far in the future"); return false; } @@ -1025,25 +1024,25 @@ bool Context::isPostponed( } error Context::displayError(const error &err) { - if ((err.find(kUnauthorizedError) != std::string::npos)) { + if (err == error::kUnauthorizedError) { if (user_) { setUser(nullptr); } } - if (err.find(kUnsupportedAppError) != std::string::npos) { + if (err == error::kUnsupportedAppError) { urls::SetImATeapot(true); } else { urls::SetImATeapot(false); } - if (user_ && (err.find(kRequestIsNotPossible) != std::string::npos - || (err.find(kForbiddenError) != std::string::npos))) { + if (user_ && (err == error::kRequestIsNotPossible + || (err == error::kForbiddenError))) { TogglClient toggl_client(UI()); error err = pullWorkspaces(&toggl_client); if (err != noError) { // Check for missing WS error and - if (err.find(kMissingWS) != std::string::npos) { + if (err == error::kMissingWS) { overlay_visible_ = true; UI()->DisplayWSError(); return noError; @@ -1054,28 +1053,22 @@ error Context::displayError(const error &err) { return UI()->DisplayError(err); } +error Context::displayError(const std::string &err, bool is_user_error) { + return UI()->DisplayError(err, is_user_error); +} + int Context::nextSyncIntervalSeconds() const { int n = static_cast(Random::next(kSyncIntervalRangeSeconds)) + kSyncIntervalRangeSeconds; - std::stringstream ss; - ss << "Next autosync in " << n << " seconds"; - logger().trace(ss.str()); + logger.trace("Next autosync in ", n, " seconds"); return n; } void Context::scheduleSync() { Poco::Int64 elapsed_seconds = Poco::Int64(time(nullptr)) - last_sync_started_; - - { - std::stringstream ss; - ss << "scheduleSync elapsed_seconds=" << elapsed_seconds; - logger().debug(ss.str()); - } + logger.debug("scheduleSync elapsed_seconds=", elapsed_seconds); if (elapsed_seconds < sync_interval_seconds_) { - std::stringstream ss; - ss << "Last sync attempt less than " << sync_interval_seconds_ - << " seconds ago, chill"; - logger().trace(ss.str()); + logger.trace("Last sync attempt less than ", sync_interval_seconds_, " seconds ago, chill"); return; } @@ -1088,7 +1081,7 @@ void Context::FullSync() { } void Context::Sync() { - logger().debug("Sync"); + logger.debug("Sync"); if (!user_) { return; @@ -1137,9 +1130,7 @@ void Context::onProjectAutocompletes(Poco::Util::TimerTask&) { // NOLINT } void Context::setOnline(const std::string &reason) { - std::stringstream ss; - ss << "setOnline, reason:" << reason; - logger().debug(ss.str()); + logger.debug("setOnline, reason:", reason); if (quit_) { return; @@ -1151,7 +1142,7 @@ void Context::setOnline(const std::string &reason) { } void Context::switchWebSocketOff() { - logger().debug("switchWebSocketOff"); + logger.debug("switchWebSocketOff"); Poco::Util::TimerTask::Ptr ptask = new Poco::Util::TimerTaskAdapter( @@ -1162,20 +1153,18 @@ void Context::switchWebSocketOff() { } void Context::onSwitchWebSocketOff(Poco::Util::TimerTask&) { // NOLINT - logger().debug("onSwitchWebSocketOff"); + logger.debug("onSwitchWebSocketOff"); Poco::Mutex::ScopedLock lock(ws_client_m_); ws_client_.Shutdown(); } error Context::LoadUpdateFromJSONString(const std::string &json) { - std::stringstream ss; - ss << "LoadUpdateFromJSONString json=" << json; - logger().debug(ss.str()); + logger.debug("LoadUpdateFromJSONString json=", json); Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("User is logged out, cannot update"); + logger.warning("User is logged out, cannot update"); return noError; } @@ -1197,7 +1186,7 @@ error Context::LoadUpdateFromJSONString(const std::string &json) { } void Context::switchWebSocketOn() { - logger().debug("switchWebSocketOn"); + logger.debug("switchWebSocketOn"); Poco::Util::TimerTask::Ptr ptask = new Poco::Util::TimerTaskAdapter( @@ -1208,7 +1197,7 @@ void Context::switchWebSocketOn() { } void Context::onSwitchWebSocketOn(Poco::Util::TimerTask&) { // NOLINT - logger().debug("onSwitchWebSocketOn"); + logger.debug("onSwitchWebSocketOn"); std::string apitoken(""); @@ -1220,7 +1209,7 @@ void Context::onSwitchWebSocketOn(Poco::Util::TimerTask&) { // NOLINT } if (apitoken.empty()) { - logger().error("No API token, cannot switch Websocket on"); + logger.error("No API token, cannot switch Websocket on"); return; } @@ -1232,7 +1221,7 @@ void Context::onSwitchWebSocketOn(Poco::Util::TimerTask&) { // NOLINT // Start/stop timeline recording on local machine void Context::switchTimelineOff() { - logger().debug("switchTimelineOff"); + logger.debug("switchTimelineOff"); Poco::Util::TimerTask::Ptr ptask = new Poco::Util::TimerTaskAdapter( @@ -1243,7 +1232,7 @@ void Context::switchTimelineOff() { } void Context::onSwitchTimelineOff(Poco::Util::TimerTask&) { // NOLINT - logger().debug("onSwitchTimelineOff"); + logger.debug("onSwitchTimelineOff"); { Poco::Mutex::ScopedLock lock(timeline_uploader_m_); @@ -1255,7 +1244,7 @@ void Context::onSwitchTimelineOff(Poco::Util::TimerTask&) { // NOLINT } void Context::switchTimelineOn() { - logger().debug("switchTimelineOn"); + logger.debug("switchTimelineOn"); Poco::Util::TimerTask::Ptr ptask = new Poco::Util::TimerTaskAdapter( @@ -1270,7 +1259,7 @@ void Context::switchTimelineOn() { } void Context::onSwitchTimelineOn(Poco::Util::TimerTask&) { // NOLINT - logger().debug("onSwitchTimelineOn"); + logger.debug("onSwitchTimelineOn"); if (quit_) { return; @@ -1294,7 +1283,7 @@ void Context::onSwitchTimelineOn(Poco::Util::TimerTask&) { // NOLINT } void Context::fetchUpdates() { - logger().debug("fetchUpdates"); + logger.debug("fetchUpdates"); next_fetch_updates_at_ = postpone(kRequestThrottleSeconds * kOneSecondInMicros); @@ -1305,16 +1294,13 @@ void Context::fetchUpdates() { Poco::Mutex::ScopedLock lock(timer_m_); timer_.schedule(ptask, next_fetch_updates_at_); - std::stringstream ss; - ss << "Next update fetch at " - << Formatter::Format8601(next_fetch_updates_at_); - logger().debug(ss.str()); + logger.debug("Next update fetch at ", Formatter::Format8601(next_fetch_updates_at_)); } void Context::onFetchUpdates(Poco::Util::TimerTask&) { // NOLINT if (isPostponed(next_fetch_updates_at_, kRequestThrottleSeconds * kOneSecondInMicros)) { - logger().debug("onFetchUpdates postponed"); + logger.debug("onFetchUpdates postponed"); return; } @@ -1322,7 +1308,7 @@ void Context::onFetchUpdates(Poco::Util::TimerTask&) { // NOLINT } void Context::startPeriodicSync() { - logger().trace("startPeriodicSync"); + logger.trace("startPeriodicSync"); Poco::Util::TimerTask::Ptr ptask = new Poco::Util::TimerTaskAdapter @@ -1335,14 +1321,11 @@ void Context::startPeriodicSync() { Poco::Mutex::ScopedLock lock(timer_m_); timer_.schedule(ptask, next_periodic_sync_at_); - std::stringstream ss; - ss << "Next periodic sync at " - << Formatter::Format8601(next_periodic_sync_at_); - logger().debug(ss.str()); + logger.debug("Next periodic sync at ", Formatter::Format8601(next_periodic_sync_at_)); } void Context::onPeriodicSync(Poco::Util::TimerTask&) { // NOLINT - logger().debug("onPeriodicSync"); + logger.debug("onPeriodicSync"); scheduleSync(); @@ -1350,7 +1333,7 @@ void Context::onPeriodicSync(Poco::Util::TimerTask&) { // NOLINT } void Context::startPeriodicUpdateCheck() { - logger().debug("startPeriodicUpdateCheck"); + logger.debug("startPeriodicUpdateCheck"); Poco::Util::TimerTask::Ptr ptask = new Poco::Util::TimerTaskAdapter @@ -1362,14 +1345,11 @@ void Context::startPeriodicUpdateCheck() { Poco::Mutex::ScopedLock lock(timer_m_); timer_.schedule(ptask, next_periodic_check_at); - std::stringstream ss; - ss << "Next periodic update check at " - << Formatter::Format8601(next_periodic_check_at); - logger().debug(ss.str()); + logger.debug("Next periodic update check at ", Formatter::Format8601(next_periodic_check_at)); } void Context::onPeriodicUpdateCheck(Poco::Util::TimerTask&) { // NOLINT - logger().debug("onPeriodicUpdateCheck"); + logger.debug("onPeriodicUpdateCheck"); executeUpdateCheck(); @@ -1377,7 +1357,7 @@ void Context::onPeriodicUpdateCheck(Poco::Util::TimerTask&) { // NOLINT } void Context::startPeriodicInAppMessageCheck() { - logger().debug("startPeriodicInAppMessageCheck"); + logger.debug("startPeriodicInAppMessageCheck"); Poco::Util::TimerTask::Ptr ptask = new Poco::Util::TimerTaskAdapter @@ -1389,14 +1369,11 @@ void Context::startPeriodicInAppMessageCheck() { Poco::Mutex::ScopedLock lock(timer_m_); timer_.schedule(ptask, next_periodic_check_at); - std::stringstream ss; - ss << "Next periodic in-app message check at " - << Formatter::Format8601(next_periodic_check_at); - logger().debug(ss.str()); + logger.debug("Next periodic in-app message check at ", Formatter::Format8601(next_periodic_check_at)); } void Context::onPeriodicInAppMessageCheck(Poco::Util::TimerTask&) { // NOLINT - logger().debug("onPeriodicInAppMessageChec"); + logger.debug("onPeriodicInAppMessageChec"); fetchMessage(1); } @@ -1407,7 +1384,7 @@ error Context::UpdateChannel( error err = db()->LoadUpdateChannel(update_channel); - if (err.find(kDatabaseDiskMalformed) != std::string::npos) { + if (err == error::kDatabaseDiskMalformed) { err = noError; } return displayError(err); @@ -1430,7 +1407,7 @@ std::string Context::UserEmail() { } void Context::executeUpdateCheck() { - logger().debug("executeUpdateCheck"); + logger.debug("executeUpdateCheck"); displayError(downloadUpdate()); } @@ -1443,7 +1420,7 @@ error Context::downloadUpdate() { // To test updater in development, comment this block out: if ("production" != environment_) { - logger().debug("Not in production, will not download updates"); + logger.debug("Not in production, will not download updates"); return noError; } @@ -1455,7 +1432,7 @@ error Context::downloadUpdate() { } if (HTTPSClient::Config.AppVersion.empty()) { - return error("This version cannot check for updates. This has been probably already fixed. Please check https://toggl.com/toggl-desktop/ for a newer version."); + return error::kCannotCheckForUpdates; } // Ask Toggl server if we have updates @@ -1483,23 +1460,21 @@ error Context::downloadUpdate() { Json::Value root; Json::Reader reader; if (!reader.parse(resp.body, root)) { - return error("Error parsing update check response body"); + return error::kFailedToParseData; } auto latestVersion = root[shortOSName()][update_channel]; url = latestVersion[installerPlatform()].asString(); auto versionNumberJsonToken = latestVersion["version"]; if (versionNumberJsonToken.empty()) { - return error("No versions found for OS " + shortOSName() + ", platform " + installerPlatform() + ", channel " + update_channel); + logger.warning("No versions found for OS " + shortOSName() + ", platform " + installerPlatform() + ", channel " + update_channel); + return error::kCannotCheckForUpdates; } version_number = versionNumberJsonToken.asString(); if (lessThanVersion(HTTPSClient::Config.AppVersion, version_number)) { - std::stringstream ss; - ss << "Found update " << version_number - << " (" << url << ")"; - logger().debug(ss.str()); + logger.debug("Found update ", version_number, " (", url, ")"); } else { - logger().debug("The app is up to date"); + logger.debug("The app is up to date"); if (UI()->CanDisplayUpdate()) { UI()->DisplayUpdate(""); } @@ -1516,13 +1491,14 @@ error Context::downloadUpdate() { // we need a path to download to, when going this way if (update_path_.empty()) { - return error("update path is empty, cannot download update"); + logger.log("update path is empty, cannot download update"); + return error::kCannotCheckForUpdates; } // Ignore update if not compatible with this client version // only windows .exe installers are supported atm if (url.find(".exe") == std::string::npos) { - logger().debug("Update is not compatible with this client," + logger.debug("Update is not compatible with this client," " will ignore"); return noError; } @@ -1540,7 +1516,7 @@ error Context::downloadUpdate() { Poco::File f(file); if (f.exists()) { - logger().debug("File already exists: " + file); + logger.debug("File already exists: " + file); return noError; } @@ -1566,11 +1542,11 @@ error Context::downloadUpdate() { } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -1580,13 +1556,13 @@ error Context::fetchMessage(const bool periodic) { // Check if in-app messaging is supported and show if (!UI()->CanDisplayMessage()) { - logger().debug("In-app messages not supported on this platform"); + logger.debug("In-app messages not supported on this platform"); return noError; } // To test in-app message fetch in development, comment this block out: if ("production" != environment_) { - logger().debug("Not in production, will not fetch in-app messages"); + logger.debug("Not in production, will not fetch in-app messages"); return noError; } @@ -1598,7 +1574,7 @@ error Context::fetchMessage(const bool periodic) { } if (HTTPSClient::Config.AppVersion.empty()) { - return error("AppVersion missing!"); + return error::kCannotCheckForUpdates; } // Fetch latest message @@ -1627,7 +1603,7 @@ error Context::fetchMessage(const bool periodic) { Json::Value root; Json::Reader reader; if (!reader.parse(resp.body, root)) { - return error("Error parsing in-app message response body"); + return error::kFailedToParseData; } // check all required fields @@ -1640,7 +1616,7 @@ error Context::fetchMessage(const bool periodic) { !root.isMember("url-mac") || !root.isMember("url-win") || !root.isMember("url-linux")) { - logger().debug("Required fields are missing in in-app message JSON"); + logger.debug("Required fields are missing in in-app message JSON"); return noError; } @@ -1721,11 +1697,11 @@ error Context::fetchMessage(const bool periodic) { button, url); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -1796,7 +1772,7 @@ bool Context::lessThanVersion(const std::string& version1, const std::string& ve } void Context::TimelineUpdateServerSettings() { - logger().debug("TimelineUpdateServerSettings"); + logger.debug("TimelineUpdateServerSettings"); next_update_timeline_settings_at_ = postpone(kRequestThrottleSeconds * kOneSecondInMicros); @@ -1807,10 +1783,7 @@ void Context::TimelineUpdateServerSettings() { Poco::Mutex::ScopedLock lock(timer_m_); timer_.schedule(ptask, next_update_timeline_settings_at_); - std::stringstream ss; - ss << "Next timeline settings update at " - << Formatter::Format8601(next_update_timeline_settings_at_); - logger().debug(ss.str()); + logger.debug("Next timeline settings update at ", Formatter::Format8601(next_update_timeline_settings_at_)); } const std::string kRecordTimelineEnabledJSON = "{\"record_timeline\": true}"; @@ -1819,11 +1792,11 @@ const std::string kRecordTimelineDisabledJSON = "{\"record_timeline\": false}"; void Context::onTimelineUpdateServerSettings(Poco::Util::TimerTask&) { // NOLINT if (isPostponed(next_update_timeline_settings_at_, kRequestThrottleSeconds * kOneSecondInMicros)) { - logger().debug("onTimelineUpdateServerSettings postponed"); + logger.debug("onTimelineUpdateServerSettings postponed"); return; } - logger().debug("onTimelineUpdateServerSettings executing"); + logger.debug("onTimelineUpdateServerSettings executing"); std::string apitoken(""); std::string json(kRecordTimelineDisabledJSON); @@ -1851,14 +1824,14 @@ void Context::onTimelineUpdateServerSettings(Poco::Util::TimerTask&) { // NOLIN HTTPSResponse resp = client.Post(req); if (resp.err != noError) { displayError(resp.err); - logger().error(resp.body); - logger().error(resp.err); + logger.error(resp.body); + logger.error(resp.err); } } error Context::SendFeedback(const Feedback &fb) { if (!user_) { - logger().warning("Cannot send feedback, user logged out"); + logger.warning("Cannot send feedback, user logged out"); return noError; } @@ -1882,7 +1855,7 @@ error Context::SendFeedback(const Feedback &fb) { } void Context::onSendFeedback(Poco::Util::TimerTask&) { // NOLINT - logger().debug("onSendFeedback"); + logger.debug("onSendFeedback"); std::string api_token_value(""); std::string api_token_name(""); @@ -1955,7 +1928,7 @@ void Context::onSendFeedback(Poco::Util::TimerTask&) { // NOLINT TogglClient client(UI()); HTTPSResponse resp = client.Post(req); - logger().debug("Feedback result: " + resp.err); + logger.debug("Feedback result: " + resp.err.String()); if (resp.err != noError) { displayError(resp.err); return; @@ -2327,7 +2300,7 @@ error Context::SetProxySettings( } void Context::OpenSettings() { - logger().debug("OpenSettings"); + logger.debug("OpenSettings"); UIElements render; render.display_settings = true; @@ -2338,13 +2311,11 @@ void Context::OpenSettings() { error Context::SetDBPath( const std::string &path) { try { - std::stringstream ss; - ss << "SetDBPath " << path; - logger().debug(ss.str()); + logger.debug("SetDBPath ", path); Poco::Mutex::ScopedLock lock(db_m_); if (db_) { - logger().debug("delete db_ from SetDBPath()"); + logger.debug("delete db_ from SetDBPath()"); delete db_; db_ = nullptr; } @@ -2363,12 +2334,10 @@ void Context::SetEnvironment(const std::string &value) { if (!("production" == value || "development" == value || "test" == value)) { - std::stringstream ss; - ss << "Invalid environment '" << value << "'!"; - logger().error(ss.str()); + logger.error("Invalid environment '", value, "'!"); return; } - logger().debug("SetEnvironment " + value); + logger.debug("SetEnvironment " + value); environment_ = value; HTTPSClient::Config.IgnoreCert = ("development" == environment_); @@ -2391,11 +2360,11 @@ error Context::AsyncGoogleLogin(const std::string &access_token) { error Context::attemptOfflineLogin(const std::string &email, const std::string &password) { if (email.empty()) { - return error("cannot login offline without an e-mail"); + return error::kOfflineLoginMissingEmail; } if (password.empty()) { - return error("cannot login offline without a password"); + return error::kOfflineLoginMissingPassword; } User *user = new User(); @@ -2408,22 +2377,18 @@ error Context::attemptOfflineLogin(const std::string &email, if (!user->ID()) { delete user; - logger().debug("User data not found in local database for " + email); - return error(kEmailNotFoundCannotLogInOffline); + logger.debug("User data not found in local database for " + email); + return error::kEmailNotFoundCannotLogInOffline; } if (user->OfflineData().empty()) { delete user; - logger().debug("Offline data not found in local database for " + logger.debug("Offline data not found in local database for " + email); - return error(kEmailNotFoundCannotLogInOffline); + return error::kEmailNotFoundCannotLogInOffline; } err = user->SetAPITokenFromOfflineData(password); - if ("I/O error" == err || err.find("bad decrypt") != std::string::npos) { - delete user; - return error(kInvalidPassword); - } if (err != noError) { delete user; return err; @@ -2459,16 +2424,13 @@ error Context::Login( std::string json(""); error err = me(&client, email, password, &json, 0); if (err != noError) { - if (!IsNetworkingError(err)) { + if (err.IsNetworkingError()) { return displayError(err); } // Indicate we're offline displayError(err); - std::stringstream ss; - ss << "Got networking error " << err - << " will attempt offline login"; - logger().debug(ss.str()); + logger.debug("Got networking error ", err, " will attempt offline login"); return displayError(attemptOfflineLogin(email, password)); } @@ -2491,7 +2453,7 @@ error Context::Login( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().error("cannot enable offline login, no user"); + logger.error("cannot enable offline login, no user"); return noError; } @@ -2559,11 +2521,7 @@ error Context::AsyncGoogleSignup(const std::string &access_token, } void Context::setUser(User *value, const bool logged_in) { - { - std::stringstream ss; - ss << "setUser user_logged_in=" << logged_in; - logger().debug(ss.str()); - } + logger.debug("setUser user_logged_in=", logged_in); Poco::UInt64 user_id(0); @@ -2694,13 +2652,13 @@ error Context::SetLoggedInUserFromJSON( // Fetch OBM experiments.. err = pullObmExperiments(); if (err != noError) { - logger().error("Error pulling OBM experiments: " + err); + logger.error("Error pulling OBM experiments: ", err); } // ..and run the OBM experiments err = runObmExperiments(); if (err != noError) { - logger().error("Error running OBM experiments: " + err); + logger.error("Error running OBM experiments: ", err); } return noError; @@ -2709,7 +2667,7 @@ error Context::SetLoggedInUserFromJSON( error Context::Logout() { try { if (!user_) { - logger().warning("User is logged out, cannot logout again"); + logger.warning("User is logged out, cannot logout again"); return noError; } @@ -2718,7 +2676,7 @@ error Context::Logout() { return displayError(err); } - logger().debug("setUser from Logout"); + logger.debug("setUser from Logout"); overlay_visible_ = false; setUser(nullptr); @@ -2749,7 +2707,7 @@ error Context::ClearCache() { { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("User is logged out, cannot clear cache"); + logger.warning("User is logged out, cannot clear cache"); return noError; } err = db()->DeleteUser(user_, true); @@ -2784,7 +2742,7 @@ TimeEntry *Context::Start( // else they will linger around in the app // and the user can continue using the unsupported app. if (urls::ImATeapot()) { - displayError(kUnsupportedAppError); + displayError(error::kUnsupportedAppError); return nullptr; } @@ -2798,7 +2756,7 @@ TimeEntry *Context::Start( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot start tracking, user logged out"); + logger.warning("Cannot start tracking, user logged out"); return nullptr; } @@ -2857,7 +2815,7 @@ void Context::OpenTimeEntryEditor( const bool edit_running_entry, const std::string &focused_field_name) { if (!edit_running_entry && GUID.empty()) { - logger().error("Cannot edit time entry without a GUID"); + logger.error("Cannot edit time entry without a GUID"); return; } @@ -2866,7 +2824,7 @@ void Context::OpenTimeEntryEditor( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot edit time entry, user logged out"); + logger.warning("Cannot edit time entry, user logged out"); return; } @@ -2878,7 +2836,7 @@ void Context::OpenTimeEntryEditor( } if (!te) { - logger().warning("Time entry not found for edit " + GUID); + logger.warning("Time entry not found for edit " + GUID); return; } @@ -2908,7 +2866,7 @@ TimeEntry *Context::ContinueLatest(const bool prevent_on_app) { // else they will linger around in the app // and the user can continue using the unsupported app. if (urls::ImATeapot()) { - displayError(kUnsupportedAppError); + displayError(error::kUnsupportedAppError); return nullptr; } @@ -2922,7 +2880,7 @@ TimeEntry *Context::ContinueLatest(const bool prevent_on_app) { { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot continue tracking, user logged out"); + logger.warning("Cannot continue tracking, user logged out"); return nullptr; } @@ -2977,7 +2935,7 @@ TimeEntry *Context::Continue( // else they will linger around in the app // and the user can continue using the unsupported app. if (urls::ImATeapot()) { - displayError(kUnsupportedAppError); + displayError(error::kUnsupportedAppError); return nullptr; } @@ -2996,7 +2954,7 @@ TimeEntry *Context::Continue( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot continue time entry, user logged out"); + logger.warning("Cannot continue time entry, user logged out"); return nullptr; } @@ -3029,7 +2987,7 @@ error Context::DeleteTimeEntryByGUID(const std::string &GUID) { // else they will linger around in the app // and the user can continue using the unsupported app. if (urls::ImATeapot()) { - return displayError(kUnsupportedAppError); + return displayError(error::kUnsupportedAppError); } if (GUID.empty()) { @@ -3041,18 +2999,18 @@ error Context::DeleteTimeEntryByGUID(const std::string &GUID) { { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot delete time entry, user logged out"); + logger.warning("Cannot delete time entry, user logged out"); return noError; } te = user_->related.TimeEntryByGUID(GUID); if (!te) { - logger().warning("Time entry not found: " + GUID); + logger.warning("Time entry not found: " + GUID); return noError; } if (te->DeletedAt()) { - return displayError(kCannotDeleteDeletedTimeEntry); + return displayError(error::kCannotDeleteDeletedTimeEntry); } if (isTimeEntryLocked(te)) { @@ -3080,12 +3038,12 @@ error Context::SetTimeEntryDuration( Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot set duration, user logged out"); + logger.warning("Cannot set duration, user logged out"); return noError; } TimeEntry *te = user_->related.TimeEntryByGUID(GUID); if (!te) { - logger().warning("Time entry not found: " + GUID); + logger.warning("Time entry not found: " + GUID); return noError; } @@ -3096,7 +3054,7 @@ error Context::SetTimeEntryDuration( // validate the value int seconds = Formatter::ParseDurationString(duration); if (seconds >= kMaxDurationSeconds) { - return displayError(error(kOverMaxDurationError)); + return displayError(error::kOverMaxDurationError); } te->SetDurationUserInput(duration); @@ -3115,13 +3073,13 @@ error Context::SetTimeEntryProject( Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot set project, user logged out"); + logger.warning("Cannot set project, user logged out"); return noError; } TimeEntry *te = user_->related.TimeEntryByGUID(GUID); if (!te) { - logger().warning("Time entry not found: " + GUID); + logger.warning("Time entry not found: " + GUID); return noError; } @@ -3138,8 +3096,7 @@ error Context::SetTimeEntryProject( } if (p && !canChangeProjectTo(te, p)) { - return displayError(error( - "Cannot change project: would end up with locked time entry")); + return displayError(error::kTimeEntryWouldBeLockedAfterProjectChange); } if (p) { @@ -3184,18 +3141,18 @@ error Context::SetTimeEntryDate( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot change date, user logged out"); + logger.warning("Cannot change date, user logged out"); return noError; } te = user_->related.TimeEntryByGUID(GUID); if (!te) { - logger().warning("Time entry not found: " + GUID); + logger.warning("Time entry not found: " + GUID); return noError; } if (isTimeEntryLocked(te)) { - return displayError(error("Cannot change locked time entry.")); + return displayError(error::kCannotChangeLockedTE); } Poco::LocalDateTime date_part( @@ -3206,7 +3163,7 @@ error Context::SetTimeEntryDate( // Validate date input if (date_part.year() < kMinimumAllowedYear || date_part.year() > kMaximumAllowedYear) { - return displayError(error(kInvalidDateError)); + return displayError(error::kInvalidDateError); } dt = Poco::LocalDateTime( @@ -3214,9 +3171,7 @@ error Context::SetTimeEntryDate( time_part.hour(), time_part.minute(), time_part.second()); if (!canChangeStartTimeTo(te, dt.timestamp().epochTime())) { - return displayError( - error( - "Failed to change time entry date: workspace is locked.")); + return displayError("Failed to change time entry date: workspace is locked.", true); } } @@ -3236,13 +3191,13 @@ error Context::SetTimeEntryStart(const std::string GUID, { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot change start time, user logged out"); + logger.warning("Cannot change start time, user logged out"); return noError; } te = user_->related.TimeEntryByGUID(GUID); if (!te) { - logger().warning("Time entry not found: " + GUID); + logger.warning("Time entry not found: " + GUID); return noError; } @@ -3270,13 +3225,13 @@ error Context::SetTimeEntryStart( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot change start time, user logged out"); + logger.warning("Cannot change start time, user logged out"); return noError; } te = user_->related.TimeEntryByGUID(GUID); if (!te) { - logger().warning("Time entry not found: " + GUID); + logger.warning("Time entry not found: " + GUID); return noError; } @@ -3289,12 +3244,12 @@ error Context::SetTimeEntryStart( // Validate time input if (local.year() < kMinimumAllowedYear || local.year() > kMaximumAllowedYear) { - return displayError(error(kInvalidStartTimeError)); + return displayError(error::kInvalidStartTimeError); } int hours(0), minutes(0); if (!toggl::Formatter::ParseTimeInput(value, &hours, &minutes)) { - return error("invalid time format"); + return error::kInvalidTimeFormat; } Poco::LocalDateTime dt( @@ -3323,13 +3278,13 @@ error Context::SetTimeEntryStop(const std::string GUID, { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot change stop time, user logged out"); + logger.warning("Cannot change stop time, user logged out"); return noError; } te = user_->related.TimeEntryByGUID(GUID); if (!te) { - logger().warning("Time entry not found: " + GUID); + logger.warning("Time entry not found: " + GUID); return noError; } @@ -3356,13 +3311,13 @@ error Context::SetTimeEntryStop( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot change stop time, user logged out"); + logger.warning("Cannot change stop time, user logged out"); return noError; } te = user_->related.TimeEntryByGUID(GUID); if (!te) { - logger().warning("Time entry not found: " + GUID); + logger.warning("Time entry not found: " + GUID); return noError; } @@ -3376,7 +3331,7 @@ error Context::SetTimeEntryStop( int hours(0), minutes(0); if (!toggl::Formatter::ParseTimeInput(value, &hours, &minutes)) { - return error("invalid time format"); + return error::kInvalidTimeFormat; } // By default, keep end date, only change hour && minute @@ -3419,13 +3374,13 @@ error Context::SetTimeEntryTags( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot set tags, user logged out"); + logger.warning("Cannot set tags, user logged out"); return noError; } te = user_->related.TimeEntryByGUID(GUID); if (!te) { - logger().warning("Time entry not found: " + GUID); + logger.warning("Time entry not found: " + GUID); return noError; } @@ -3456,13 +3411,13 @@ error Context::SetTimeEntryBillable( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot set billable, user logged out"); + logger.warning("Cannot set billable, user logged out"); return noError; } te = user_->related.TimeEntryByGUID(GUID); if (!te) { - logger().warning("Time entry not found: " + GUID); + logger.warning("Time entry not found: " + GUID); return noError; } @@ -3493,13 +3448,13 @@ error Context::SetTimeEntryDescription( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot set description, user logged out"); + logger.warning("Cannot set description, user logged out"); return noError; } te = user_->related.TimeEntryByGUID(GUID); if (!te) { - logger().warning("Time entry not found: " + GUID); + logger.warning("Time entry not found: " + GUID); return noError; } @@ -3510,7 +3465,7 @@ error Context::SetTimeEntryDescription( // Validate description length if (value.length() > kMaximumDescriptionLength) { - return displayError(error(kMaximumDescriptionLengthError)); + return displayError(error::kMaximumDescriptionLengthError); } te->SetDescription(value); @@ -3529,7 +3484,7 @@ error Context::Stop(const bool prevent_on_app) { { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot stop tracking, user logged out"); + logger.warning("Cannot stop tracking, user logged out"); return noError; } user_->Stop(&stopped); @@ -3538,7 +3493,7 @@ error Context::Stop(const bool prevent_on_app) { } if (stopped.empty()) { - logger().warning("No time entry was found to stop"); + logger.warning("No time entry was found to stop"); return noError; } @@ -3566,15 +3521,15 @@ error Context::DiscardTimeAt( // Tracking action if ("production" == environment_) { - std::stringstream ss; + std::string method; if (split_into_new_entry) { - ss << "idle-as-new-entry"; + method = "idle-as-new-entry"; } else { - ss << "discard-and-stop"; + method = "discard-and-stop"; } analytics_.TrackIdleDetectionClick(db_->AnalyticsClientID(), - ss.str()); + method); } TimeEntry *split = nullptr; @@ -3582,7 +3537,7 @@ error Context::DiscardTimeAt( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot stop time entry, user logged out"); + logger.warning("Cannot stop time entry, user logged out"); return noError; } @@ -3622,7 +3577,7 @@ TimeEntry *Context::DiscardTimeAndContinue( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot stop time entry, user logged out"); + logger.warning("Cannot stop time entry, user logged out"); return nullptr; } user_->DiscardTimeAt(guid, at, false); @@ -3640,7 +3595,7 @@ TimeEntry *Context::DiscardTimeAndContinue( TimeEntry *Context::RunningTimeEntry() { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot fetch time entry, user logged out"); + logger.warning("Cannot fetch time entry, user logged out"); return nullptr; } return user_->RunningTimeEntry(); @@ -3649,7 +3604,7 @@ TimeEntry *Context::RunningTimeEntry() { error Context::ToggleTimelineRecording(const bool record_timeline) { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot toggle timeline, user logged out"); + logger.warning("Cannot toggle timeline, user logged out"); return noError; } try { @@ -3702,7 +3657,7 @@ error Context::SetDefaultProject( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot set default PID, user logged out"); + logger.warning("Cannot set default PID, user logged out"); return noError; } @@ -3759,7 +3714,7 @@ error Context::DefaultProjectName(std::string *name) { { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot get default PID, user logged out"); + logger.warning("Cannot get default PID, user logged out"); return noError; } if (user_->DefaultPID()) { @@ -3787,7 +3742,7 @@ error Context::DefaultPID(Poco::UInt64 *result) { { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot get default PID, user logged out"); + logger.warning("Cannot get default PID, user logged out"); return noError; } *result = user_->DefaultPID(); @@ -3809,7 +3764,7 @@ error Context::DefaultTID(Poco::UInt64 *result) { { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot get default PID, user logged out"); + logger.warning("Cannot get default PID, user logged out"); return noError; } *result = user_->DefaultTID(); @@ -3847,12 +3802,12 @@ error Context::AddAutotrackerRule( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("cannot add autotracker rule, user logged out"); + logger.warning("cannot add autotracker rule, user logged out"); return noError; } if (user_->related.HasMatchingAutotrackerRule(lowercase)) { // avoid duplicates - return displayError(kErrorRuleAlreadyExists); + return displayError(error::kErrorRuleAlreadyExists); } Task *t = nullptr; @@ -3912,7 +3867,7 @@ error Context::DeleteAutotrackerRule( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("cannot delete rule, user is logged out"); + logger.warning("cannot delete rule, user is logged out"); return noError; } @@ -3934,7 +3889,7 @@ Project *Context::CreateProject( const std::string &project_color) { if (!workspace_id) { - displayError(kPleaseSelectAWorkspace); + displayError(error::kPleaseSelectAWorkspace); return nullptr; } @@ -3945,7 +3900,7 @@ Project *Context::CreateProject( return nullptr; } if (trimmed_project_name.empty()) { - displayError(kProjectNameMustNotBeEmpty); + displayError(error::kProjectNameMustNotBeEmpty); return nullptr; } @@ -3954,7 +3909,7 @@ Project *Context::CreateProject( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot add project, user logged out"); + logger.warning("Cannot add project, user logged out"); return nullptr; } for (std::vector::iterator it = @@ -3972,7 +3927,7 @@ Project *Context::CreateProject( } if (clientIsSame && p->Name() == trimmed_project_name) { - displayError(kProjectNameAlreadyExists); + displayError(error::kProjectNameAlreadyExists); return nullptr; } } @@ -4028,7 +3983,8 @@ error Context::AddObmAction( const std::string &value) { // Check input if (!experiment_id) { - return error("missing experiment_id"); + logger.log(__FUNCTION__, "missing experiment_id"); + return error::kCannotCreateObmAction; } std::string trimmed_key(""); error err = db_->Trim(key, &trimmed_key); @@ -4036,7 +3992,8 @@ error Context::AddObmAction( return displayError(err); } if (trimmed_key.empty()) { - return error("missing key"); + logger.log(__FUNCTION__, "missing trimmed_key"); + return error::kCannotCreateObmAction; } std::string trimmed_value(""); err = db_->Trim(value, &trimmed_value); @@ -4044,13 +4001,14 @@ error Context::AddObmAction( return displayError(err); } if (trimmed_value.empty()) { - return error("missing value"); + logger.log(__FUNCTION__, "missing trimmed_value"); + return error::kCannotCreateObmAction; } // Add OBM action and save { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot create a OBM action, user logged out"); + logger.warning("Cannot create a OBM action, user logged out"); return noError; } ObmAction *action = new ObmAction(); @@ -4068,7 +4026,7 @@ Client *Context::CreateClient( const std::string &client_name) { if (!workspace_id) { - displayError(kPleaseSelectAWorkspace); + displayError(error::kPleaseSelectAWorkspace); return nullptr; } @@ -4079,7 +4037,7 @@ Client *Context::CreateClient( return nullptr; } if (trimmed_client_name.empty()) { - displayError(kClientNameMustNotBeEmpty); + displayError(error::kClientNameMustNotBeEmpty); return nullptr; } @@ -4088,7 +4046,7 @@ Client *Context::CreateClient( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot create a client, user logged out"); + logger.warning("Cannot create a client, user logged out"); return nullptr; } for (std::vector::iterator it = @@ -4096,7 +4054,7 @@ Client *Context::CreateClient( it != user_->related.Clients.end(); ++it) { Client *c = *it; if (c->WID() == workspace_id && c->Name() == trimmed_client_name) { - displayError(kClientNameAlreadyExists); + displayError(error::kClientNameAlreadyExists); return nullptr; } } @@ -4119,7 +4077,7 @@ void Context::SetSleep() { // Set Sleep as usual if (!isHandled) { - logger().debug("SetSleep"); + logger.debug("SetSleep"); idle_.SetSleep(); if (window_change_recorder_) { window_change_recorder_->SetIsSleeping(true); @@ -4140,7 +4098,7 @@ error Context::OpenReportsInBrowser() { // else they will linger around in the app // and the user can continue using the unsupported app. if (urls::ImATeapot()) { - return displayError(kUnsupportedAppError); + return displayError(error::kUnsupportedAppError); } std::string apitoken(""); @@ -4250,7 +4208,7 @@ error Context::runObmExperiments() { { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("User logged out, cannot OBM experiment"); + logger.warning("User logged out, cannot OBM experiment"); return noError; } for (std::vector::const_iterator it = @@ -4291,7 +4249,7 @@ error Context::runObmExperiments() { } void Context::SetWake() { - logger().debug("SetWake"); + logger.debug("SetWake"); Poco::Timestamp::TimeDiff delay = 0; if (next_wake_at_ > 0) { @@ -4305,19 +4263,16 @@ void Context::SetWake() { Poco::Mutex::ScopedLock lock(timer_m_); timer_.schedule(ptask, next_wake_at_); - std::stringstream ss; - ss << "Next wake at " - << Formatter::Format8601(next_wake_at_); - logger().debug(ss.str()); + logger.debug("Next wake at ", Formatter::Format8601(next_wake_at_)); } void Context::onWake(Poco::Util::TimerTask&) { // NOLINT if (isPostponed(next_wake_at_, kRequestThrottleSeconds * kOneSecondInMicros)) { - logger().debug("onWake postponed"); + logger.debug("onWake postponed"); return; } - logger().debug("onWake executing"); + logger.debug("onWake executing"); try { Poco::LocalDateTime now; @@ -4337,32 +4292,32 @@ void Context::onWake(Poco::Util::TimerTask&) { // NOLINT Sync(); } catch (const Poco::Exception& exc) { - logger().error(exc.displayText()); + logger.error(exc.displayText()); } catch (const std::exception& ex) { - logger().error(ex.what()); + logger.error(ex.what()); } catch (const std::string & ex) { - logger().error(ex); + logger.error(ex); } } void Context::SetLocked() { - logger().debug("SetLocked"); + logger.debug("SetLocked"); if (window_change_recorder_) { window_change_recorder_->SetIsLocked(true); } } void Context::SetUnlocked() { - logger().debug("SetUnlocked"); + logger.debug("SetUnlocked"); if (window_change_recorder_) { window_change_recorder_->SetIsLocked(false); } } void Context::SetOnline() { - logger().debug("SetOnline"); + logger.debug("SetOnline"); Sync(); } @@ -4413,7 +4368,7 @@ void Context::displayReminder() { (Poco::DateTime::FRIDAY == wday && !settings_.remind_fri) || (Poco::DateTime::SATURDAY == wday && !settings_.remind_sat) || (Poco::DateTime::SUNDAY == wday && !settings_.remind_sun)) { - logger().debug("reminder is not enabled on this weekday"); + logger.debug("reminder is not enabled on this weekday"); return; } @@ -4424,11 +4379,7 @@ void Context::displayReminder() { Poco::LocalDateTime start( now.year(), now.month(), now.day(), h, m, now.second()); if (now < start) { - std::stringstream ss; - ss << "Reminder - its too early for reminders" - << " [" << now.hour() << ":" << now.minute() << "]" - << " (allowed from " << h << ":" << m << ")"; - logger().debug(ss.str()); + logger.debug("Reminder - its too early for reminders", " [", now.hour(), ":", now.minute(), "]", " (allowed from ", h, ":", m, ")"); return; } } @@ -4436,14 +4387,9 @@ void Context::displayReminder() { if (!settings_.remind_ends.empty()) { int h(0), m(0); if (toggl::Formatter::ParseTimeInput(settings_.remind_ends, &h, &m)) { - Poco::LocalDateTime end( - now.year(), now.month(), now.day(), h, m, now.second()); + Poco::LocalDateTime end(now.year(), now.month(), now.day(), h, m, now.second()); if (now > end) { - std::stringstream ss; - ss << "Reminder - its too late for reminders" - << " [" << now.hour() << ":" << now.minute() << "]" - << " (allowed until " << h << ":" << m << ")"; - logger().debug(ss.str()); + logger.debug("Reminder - its too late for reminders", " [", now.hour(), ":", now.minute(), "]", " (allowed until ", h, ":", m, ")"); return; } } @@ -4578,7 +4524,8 @@ error Context::StartAutotrackerEvent(const TimelineEvent &event) { p = user_->related.ProjectByID(rule->PID()); } if (rule->PID() && !p) { - return error("autotracker project not found"); + logger.log(__FUNCTION__, "autotracker project not found"); + return error::kCannotStartAutotrackerEvent; } Task *t = nullptr; @@ -4586,11 +4533,13 @@ error Context::StartAutotrackerEvent(const TimelineEvent &event) { t = user_->related.TaskByID(rule->TID()); } if (rule->TID() && !t) { - return error("autotracker task not found"); + logger.log(__FUNCTION__, "autotracker task not found"); + return error::kCannotStartAutotrackerEvent; } if (!p && !t) { - return error("no project or task specified in autotracker rule"); + logger.log(__FUNCTION__, "no project or task specified in autotracker rule"); + return error::kCannotStartAutotrackerEvent; } UI()->DisplayAutotrackerNotification(p, t); @@ -4602,7 +4551,7 @@ error Context::CreateCompressedTimelineBatchForUpload(TimelineBatch *batch) { try { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("cannot create timeline batch, user logged out"); + logger.warning("cannot create timeline batch, user logged out"); return noError; } @@ -4661,7 +4610,7 @@ error Context::MarkTimelineBatchAsUploaded( try { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("cannot mark timeline events as uploaded, " + logger.warning("cannot mark timeline events as uploaded, " "user is already logged out"); return noError; } @@ -4783,7 +4732,7 @@ void Context::syncerActivity() { err = pushObmAction(); if (err != noError) { std::cout << "SYNC: sync-pushObm ERROR\n"; - logger().error("Error pushing OBM action: " + err); + logger.error("Error pushing OBM action: ", err); } displayError(save(false)); @@ -4810,7 +4759,7 @@ void Context::syncerActivity() { err = pushObmAction(); if (err != noError) { std::cout << "SYNC: pushObm ERROR\n"; - logger().error("Error pushing OBM action: " + err); + logger.error("Error pushing OBM action: ", err); } displayError(save(false)); @@ -4847,7 +4796,7 @@ void Context::onLoadMore(Poco::Util::TimerTask&) { } if (api_token.empty()) { - return logger().warning( + return logger.warning( "cannot load more time entries without API token"); } @@ -4856,9 +4805,7 @@ void Context::onLoadMore(Poco::Util::TimerTask&) { ss << "/api/v9/me/time_entries?since=" << (Poco::Timestamp() - Poco::Timespan(60, 0, 0, 0, 0)).epochTime(); - std::stringstream l; - l << "loading more: " << ss.str(); - logger().debug(l.str()); + logger.debug("loading more: ", ss.str()); TogglClient client(UI()); HTTPSRequest req; @@ -4869,7 +4816,7 @@ void Context::onLoadMore(Poco::Util::TimerTask&) { HTTPSResponse resp = client.Get(req); if (resp.err != noError) { - logger().warning(resp.err); + logger.warning(resp.err); return; } @@ -4882,7 +4829,7 @@ void Context::onLoadMore(Poco::Util::TimerTask&) { error err = user_->LoadTimeEntriesFromJSONString(json); if (err != noError) { - logger().error(err); + logger.error(err); return; } @@ -4899,13 +4846,13 @@ void Context::onLoadMore(Poco::Util::TimerTask&) { displayError(save(false)); } catch (const Poco::Exception& exc) { - logger().warning(exc.displayText()); + logger.warning(exc.displayText()); } catch (const std::exception& ex) { - logger().warning(ex.what()); + logger.warning(ex.what()); } catch (const std::string & ex) { - logger().warning(ex); + logger.warning(ex); } } @@ -4932,10 +4879,6 @@ void Context::SetLogPath(const std::string &path) { log_path_ = path; } -Poco::Logger &Context::logger() const { - return Poco::Logger::get("context"); -} - error Context::pullAllUserData( TogglClient *toggl_client) { @@ -4944,7 +4887,7 @@ error Context::pullAllUserData( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("cannot pull user data when logged out"); + logger.warning("cannot pull user data when logged out"); return noError; } api_token = user_->APIToken(); @@ -4954,7 +4897,7 @@ error Context::pullAllUserData( } if (api_token.empty()) { - return error("cannot pull user data without API token"); + return error::kCannotLoadUserDataWithoutApiToken; } try { @@ -4975,7 +4918,7 @@ error Context::pullAllUserData( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - return error("cannot load user data when logged out"); + return error::kCannotLoadUserDataWhenLoggedOut; } TimeEntry *running_entry = user_->RunningTimeEntry(); @@ -5003,16 +4946,13 @@ error Context::pullAllUserData( pullUserPreferences(toggl_client); stopwatch.stop(); - std::stringstream ss; - ss << "User with related data JSON fetched and parsed in " - << stopwatch.elapsed() / 1000 << " ms"; - logger().debug(ss.str()); + logger.debug("User with related data JSON fetched and parsed in ", stopwatch.elapsed() / 1000, " ms"); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -5039,13 +4979,13 @@ error Context::pushChanges( { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("cannot push changes when logged out"); + logger.warning("cannot push changes when logged out"); return noError; } api_token = user_->APIToken(); if (api_token.empty()) { - return error("cannot push changes without API token"); + return error::kCannotSaveUserDataWithoutApiToken; } collectPushableModels( @@ -5079,8 +5019,7 @@ error Context::pushChanges( clients, api_token, *toggl_client); - if (err != noError && - err.find(kClientNameAlreadyExists) == std::string::npos) { + if (err == error::kClientNameAlreadyExists) { return err; } client_stopwatch.stop(); @@ -5097,8 +5036,7 @@ error Context::pushChanges( clients, api_token, *toggl_client); - if (err != noError && - err.find(kProjectNameAlready) == std::string::npos) { + if (err == error::kProjectNameAlreadyExists) { return err; } @@ -5140,13 +5078,13 @@ error Context::pushChanges( stopwatch.stop(); ss << ") Total = " << stopwatch.elapsed() / 1000 << " ms"; - logger().debug(ss.str()); + logger.debug(ss.str()); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -5176,7 +5114,7 @@ error Context::pushClients( if (resp.err != noError) { // if we're able to solve the error - if ((*it)->ResolveError(resp.body)) { + if ((*it)->ResolveError(Error::fromServerError(resp.body))) { displayError(save(false)); } continue; @@ -5185,7 +5123,7 @@ error Context::pushClients( Json::Value root; Json::Reader reader; if (!reader.parse(resp.body, root)) { - err = error("error parsing client POST response"); + err = error::kFailedToParseData; continue; } @@ -5233,7 +5171,7 @@ error Context::pushProjects( if (resp.err != noError) { // if we're able to solve the error - if ((*it)->ResolveError(resp.body)) { + if ((*it)->ResolveError(Error::fromServerError(resp.body))) { displayError(save(false)); } continue; @@ -5242,7 +5180,7 @@ error Context::pushProjects( Json::Value root; Json::Reader reader; if (!reader.parse(resp.body, root)) { - err = error("error parsing project POST response"); + err = error::kFailedToParseData; continue; } @@ -5321,25 +5259,25 @@ error Context::pushEntries( if (resp.err != noError) { // if we're able to solve the error - if ((*it)->ResolveError(resp.body)) { + if ((*it)->ResolveError(Error::fromServerError(resp.body))) { displayError(save(false)); } // Not found on server. Probably deleted already. - if ((*it)->isNotFound(resp.body)) { + if ((*it)->isNotFound(Error::fromServerError(resp.body))) { (*it)->MarkAsDeletedOnServer(); continue; } error_found = true; - error_message = resp.err; + error_message = resp.err.String(); if (resp.status_code == 429) { - error_message = error(kRateLimit); + error_message = error::kRateLimit; } // Mark the time entry as unsynced now (*it)->SetUnsynced(); - offline = IsNetworkingError(resp.err); + offline = resp.err.IsNetworkingError(); if (offline) { trigger_sync_ = false; @@ -5357,12 +5295,12 @@ error Context::pushEntries( Json::Value root; Json::Reader reader; if (!reader.parse(resp.body, root)) { - return error("error parsing time entry POST response"); + return error::kFailedToParseData; } auto id = root["id"].asUInt64(); if (!id) { - logger().error("Backend is sending invalid data: ignoring update without an ID"); + logger.error("Backend is sending invalid data: ignoring update without an ID"); continue; } @@ -5373,14 +5311,14 @@ error Context::pushEntries( } if ((*it)->ID() != id) { - return error("Backend has changed the ID of the entry"); + return error::kBackendChangedTheID; } (*it)->LoadFromJSON(root); } if (error_found) { - return error_message; + return error::REMOVE_LATER_NETWORK_RESPONSE; } return noError; } @@ -5388,17 +5326,17 @@ error Context::pushEntries( error Context::pullObmExperiments() { try { if (HTTPSClient::Config.OBMExperimentNrs.empty()) { - logger().debug("No OBM experiment enabled by UI"); + logger.debug("No OBM experiment enabled by UI"); return noError; } - logger().trace("Fetching OBM experiments from backend"); + logger.trace("Fetching OBM experiments from backend"); std::string apitoken(""); { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot fetch OBM experiments without user"); + logger.warning("Cannot fetch OBM experiments without user"); return noError; } apitoken = user_->APIToken(); @@ -5419,13 +5357,13 @@ error Context::pullObmExperiments() { Json::Value json; Json::Reader reader; if (!reader.parse(resp.body, json)) { - return error("Error in OBM experiments response body"); + return error::kFailedToParseData; } { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("Cannot apply OBM experiments without user"); + logger.warning("Cannot apply OBM experiments without user"); return noError; } user_->LoadObmExperiments(json); @@ -5433,11 +5371,11 @@ error Context::pullObmExperiments() { return noError; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } } @@ -5452,7 +5390,7 @@ error Context::pushObmAction() { { Poco::Mutex::ScopedLock lock(user_m_); if (!user_) { - logger().warning("cannot push changes when logged out"); + logger.warning("cannot push changes when logged out"); return noError; } @@ -5462,7 +5400,7 @@ error Context::pushObmAction() { req.basic_auth_username = user_->APIToken(); if (req.basic_auth_username.empty()) { - return error("cannot push OBM actions without API token"); + return error::kCannotSaveUserDataWithoutApiToken; } // find action that has not been uploaded yet @@ -5486,7 +5424,7 @@ error Context::pushObmAction() { req.payload = Json::StyledWriter().write(root); } - logger().debug(req.payload); + logger.debug(req.payload); TogglClient toggl_client; HTTPSResponse resp = toggl_client.Post(req); @@ -5502,11 +5440,11 @@ error Context::pushObmAction() { for_upload->MarkAsDeletedOnServer(); for_upload->Delete(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -5519,11 +5457,7 @@ error Context::me( const Poco::Int64 since) { if (email.empty()) { - return "Empty email or API token"; - } - - if (password.empty()) { - return "Empty password"; + return error::kMissingArgument; } try { @@ -5551,11 +5485,11 @@ error Context::me( *user_data_json = resp.body; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -5575,8 +5509,8 @@ bool Context::canChangeProjectTo(TimeEntry* te, Project* p) { } error Context::logAndDisplayUserTriedEditingLockedEntry() { - logger().warning("User tried editing locked time entry"); - return displayError(error("Cannot change locked time entry")); + logger.warning("User tried editing locked time entry"); + return displayError(error::kCannotChangeLockedTE); } bool Context::isTimeLockedInWorkspace(time_t t, Workspace* ws) { @@ -5596,26 +5530,23 @@ error Context::pullWorkspaces(TogglClient* toggl_client) { std::string api_token = user_->APIToken(); if (api_token.empty()) { - return error("cannot pull user data without API token"); + return error::kCannotLoadUserDataWithoutApiToken; } std::string json(""); try { - std::stringstream ss; - ss << "/api/v9/me/workspaces"; - HTTPSRequest req; req.host = urls::API(); - req.relative_url = ss.str(); + req.relative_url = "/api/v9/me/workspaces"; req.basic_auth_username = api_token; req.basic_auth_password = "api_token"; HTTPSResponse resp = toggl_client->Get(req); if (resp.err != noError) { - if (resp.err.find(kForbiddenError) != std::string::npos) { + if (resp.err == error::kForbiddenError) { // User has no workspaces - return error(kMissingWS); // NOLINT + return error::kMissingWS; // NOLINT } return resp.err; } @@ -5626,13 +5557,13 @@ error Context::pullWorkspaces(TogglClient* toggl_client) { } catch (const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch (const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch (const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -5641,7 +5572,7 @@ error Context::pullWorkspacePreferences(TogglClient* toggl_client) { std::vector workspaces; { Poco::Mutex::ScopedLock lock(user_m_); - logger().debug("user mutex lock success - c:pullWorkspacePreferences"); + logger.debug("user mutex lock success - c:pullWorkspacePreferences"); user_->related.WorkspaceList(&workspaces); } @@ -5667,7 +5598,7 @@ error Context::pullWorkspacePreferences(TogglClient* toggl_client) { Json::Value root; Json::Reader reader; if (!reader.parse(json, root)) { - return error("Failed to load workspace preferences"); + return error::kFailedToParseData; } ws->LoadSettingsFromJson(root); @@ -5684,7 +5615,7 @@ error Context::pullWorkspacePreferences( std::string api_token = user_->APIToken(); if (api_token.empty()) { - return error("cannot pull user data without API token"); + return error::kCannotLoadUserDataWithoutApiToken; } try { @@ -5707,13 +5638,13 @@ error Context::pullWorkspacePreferences( *json = resp.body; } catch (const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch (const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch (const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -5723,17 +5654,15 @@ error Context::pullUserPreferences( std::string api_token = user_->APIToken(); if (api_token.empty()) { - return error("cannot pull user data without API token"); + return error::kCannotLoadUserDataWithoutApiToken; } try { std::string json(""); - std::stringstream ss; - ss << "/api/v9/me/preferences/desktop"; HTTPSRequest req; req.host = urls::API(); - req.relative_url = ss.str(); + req.relative_url = "/api/v9/me/preferences/desktop"; req.basic_auth_username = api_token; req.basic_auth_password = "api_token"; @@ -5750,7 +5679,7 @@ error Context::pullUserPreferences( Json::Value root; Json::Reader reader; if (!reader.parse(json, root)) { - return error("Failed to load user preferences"); + return error::kFailedToParseData; } if (user_->LoadUserPreferencesFromJSON(root)) { @@ -5768,13 +5697,13 @@ error Context::pullUserPreferences( } } catch (const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch (const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch (const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -5809,8 +5738,9 @@ error Context::signupGoogle( HTTPSResponse resp = toggl_client->Post(req); if (resp.err != noError) { - if (kBadRequestError == resp.err) { - return resp.body; + if (resp.err == error::kBadRequestError) { + //return resp.body; + return error::REMOVE_LATER_NETWORK_RESPONSE; } return resp.err; } @@ -5818,13 +5748,13 @@ error Context::signupGoogle( *user_data_json = resp.body; } catch (const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch (const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch (const std::string& ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -5837,11 +5767,11 @@ error Context::signup( const uint64_t country_id) { if (email.empty()) { - return "Empty email"; + return error::kEmptyEmail; } if (password.empty()) { - return "Empty password"; + return error::kEmptyPassword; } try { @@ -5867,25 +5797,26 @@ error Context::signup( HTTPSResponse resp = toggl_client->Post(req); if (resp.err != noError) { - if (kBadRequestError == resp.err) { - return resp.body; + if (resp.err == error::kBadRequestError) { + //return resp.body; + return error::REMOVE_LATER_NETWORK_RESPONSE; } return resp.err; } *user_data_json = resp.body; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } void Context::OpenTimelineDataView() { - logger().debug("OpenTimelineDataView"); + logger.debug("OpenTimelineDataView"); UI()->SetTimelineDateAt(Poco::LocalDateTime()); @@ -5933,7 +5864,7 @@ error Context::ToSAccept() { std::string api_token = user_->APIToken(); if (api_token.empty()) { - return error("cannot pull user data without API token"); + return error::kMissingApiToken; } TogglClient toggl_client(UI()); @@ -5951,14 +5882,14 @@ error Context::ToSAccept() { overlay_visible_ = false; OpenTimeEntryList(); } catch(const Poco::Exception& exc) { - displayError(kCannotConnectError); - return exc.displayText(); + displayError(error::kCannotConnectError); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - displayError(kCannotConnectError); - return ex.what(); + displayError(error::kCannotConnectError); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - displayError(kCannotConnectError); - return ex; + displayError(error::kCannotConnectError); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -5992,7 +5923,7 @@ error Context::PullCountries() { Json::Reader reader; if (!reader.parse(resp.body, root)) { - return error("Error parsing countries response body"); + return error::kFailedToParseData; } std::vector countries; @@ -6007,11 +5938,11 @@ error Context::PullCountries() { //country_item_clear(first); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } diff --git a/src/context.h b/src/context.h index 9607663125..86fb859110 100644 --- a/src/context.h +++ b/src/context.h @@ -16,6 +16,7 @@ #include "gui.h" #include "help_article.h" #include "idle.h" +#include "util/logger.h" #include "model_change.h" #include "timeline_event.h" #include "timeline_notifications.h" @@ -529,7 +530,7 @@ class TOGGL_INTERNAL_EXPORT Context : public TimelineDatasource { static void parseVersion(int result[4], const std::string& input); static bool lessThanVersion(const std::string& version1, const std::string& version2); - Poco::Logger &logger() const; + Logger logger { "context" }; void sync(const bool full_sync); @@ -585,6 +586,7 @@ class TOGGL_INTERNAL_EXPORT Context : public TimelineDatasource { void updateUI(const UIElements &elements); error displayError(const error &err); + error displayError(const std::string &err, bool is_user_error = false); void scheduleSync(); diff --git a/src/database.cc b/src/database.cc index 9ac5708814..7bfc0d3771 100644 --- a/src/database.cc +++ b/src/database.cc @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -53,37 +52,31 @@ Database::Database(const std::string &db_path) { int is_sqlite_threadsafe = Poco::Data::SQLite::Utility::isThreadSafe(); - std::stringstream ss; - ss << "sqlite3_threadsafe()=" << is_sqlite_threadsafe; - logger().debug(ss.str()); + logger.debug("sqlite3_threadsafe()=", is_sqlite_threadsafe); if (!is_sqlite_threadsafe) { - logger().error("Database is not thread safe!"); + logger.error("Database is not thread safe!"); return; } } error err = setJournalMode("wal"); if (err != noError) { - logger().error("Failed to set journal mode to wal!"); + logger.error("Failed to set journal mode to wal!"); return; } std::string mode(""); err = journalMode(&mode); if (err != noError) { - logger().error("Could not detect journal mode!"); + logger.error("Could not detect journal mode!"); return; } - { - std::stringstream ss; - ss << "PRAGMA journal_mode=" << mode; - logger().debug(ss.str()); - } + logger.debug("PRAGMA journal_mode=", mode); if ("wal" != mode) { - logger().error("Failed to enable wal journal mode!"); + logger.error("Failed to enable wal journal mode!"); return; } @@ -97,7 +90,7 @@ Database::Database(const std::string &db_path) "time_entries", start.timestamp()); if (err != noError) { - logger().error("failed to clean Up Time Entries Data: " + err); + logger.error("failed to clean Up Time Entries Data: " + err.String()); // but will continue, its not vital } @@ -109,13 +102,13 @@ Database::Database(const std::string &db_path) timeline_start.timestamp()); if (err != noError) { - logger().error("failed to clean Up Timeline Events Data: " + err); + logger.error("failed to clean Up Timeline Events Data: " + err.String()); // but will continue, its not vital } err = vacuum(); if (err != noError) { - logger().error("failed to vacuum: " + err); + logger.error("failed to vacuum: " + err.String()); // but will continue, its not vital } @@ -124,19 +117,14 @@ Database::Database(const std::string &db_path) err = initialize_tables(); if (err != noError) { - logger().error(err); + logger.error(err); // We're doomed now; cannot continue without a DB throw(err); } stopwatch.stop(); - { - std::stringstream ss; - ss << "Migrated in " - << stopwatch.elapsed() / 1000 << " ms"; - logger().debug(ss.str()); - } + logger.debug("Migrated in ", stopwatch.elapsed() / 1000, " ms"); } Database::~Database() { @@ -211,12 +199,8 @@ error Database::deleteAllFromTableByUID( const std::string &table_name, const Poco::UInt64 &UID) { - - if (!UID) { - return error("Cannot delete user data without user ID"); - } - if (table_name.empty()) { - return error("Cannot delete from table without table name"); + if (!UID || table_name.empty()) { + return error::kMissingArgument; } try { @@ -229,11 +213,11 @@ error Database::deleteAllFromTableByUID( useRef(UID), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("deleteAllFromTableByUID"); } @@ -243,7 +227,7 @@ error Database::deleteAllFromTableByDate( const Poco::Timestamp &time) { if (table_name.empty()) { - return error("Cannot delete from table without table name"); + return error::kMissingArgument; } const Poco::Int64 stopTime = time.epochTime(); @@ -259,11 +243,11 @@ error Database::deleteAllFromTableByDate( useRef(stopTime), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("deleteAllFromTableByDate"); } @@ -283,11 +267,11 @@ error Database::deleteAllSyncedTimelineEventsByDate( useRef(endTime), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("deleteAllSyncedTimelineEventsByDate"); } @@ -305,18 +289,18 @@ error Database::journalMode(std::string *mode) { into(*mode), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("journalMode"); } error Database::setJournalMode(const std::string &mode) { if (mode.empty()) { - return error("Cannot set journal mode without a mode"); + return error::kMissingArgument; } @@ -328,11 +312,11 @@ error Database::setJournalMode(const std::string &mode) { "PRAGMA journal_mode=" << mode, now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("setJournalMode"); } @@ -345,36 +329,28 @@ error Database::vacuum() { *session_ << "VACUUM;" << now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("vacuum"); } -Poco::Logger &Database::logger() const { - return Poco::Logger::get("database"); -} - error Database::DeleteFromTable( const std::string &table_name, const Poco::Int64 &local_id) { if (table_name.empty()) { - return error("Cannot delete from table without table name"); + return error::kMissingArgument; } if (!local_id) { return noError; } - - std::stringstream ss; - ss << "Deleting from table " << table_name - << ", local ID: " << local_id; - logger().debug(ss.str()); + logger.debug( "Deleting from table ", table_name, ", local ID: ", local_id); try { Poco::Mutex::ScopedLock lock(session_m_); @@ -386,11 +362,11 @@ error Database::DeleteFromTable( useRef(local_id), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("DeleteFromTable"); } @@ -402,7 +378,8 @@ error Database::last_error(const std::string &was_doing) { std::string last = Poco::Data::SQLite::Utility::lastError(*session_); if (last != "not an error" && last != "unknown error") { - return error(was_doing + ": " + last); + //return error(was_doing + ": " + last); + return error::REMOVE_LATER_DATABASE_LAST_ERROR; } return noError; } @@ -416,7 +393,7 @@ std::string Database::GenerateGUID() { error Database::LoadCurrentUser(User *user) { poco_check_ptr(user); - logger().debug("LoadCurrentUser"); + logger.debug("LoadCurrentUser"); std::string api_token(""); Poco::UInt64 uid(0); @@ -485,11 +462,11 @@ error Database::LoadSettings(Settings *settings) { limit(1), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("LoadSettings"); } @@ -517,11 +494,11 @@ error Database::SaveWindowSettings( useRef(window_width), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("SaveWindowSettings"); @@ -579,11 +556,11 @@ error Database::LoadWindowSettings( *window_height = height; *window_width = width; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("LoadWindowSettings"); } @@ -617,11 +594,11 @@ error Database::LoadProxySettings( proxy->SetUsername(username); proxy->SetPassword(password); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("LoadProxySettings"); } @@ -741,11 +718,11 @@ error Database::SetSettingsRemindTimes( useRef(remind_ends), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("SetSettingsRemindTimes"); @@ -783,11 +760,11 @@ error Database::SetSettingsRemindDays( useRef(remind_sun), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("SetSettingsRemindDays"); @@ -888,11 +865,11 @@ error Database::setSettingsValue( useRef(value), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("setSettingsValue"); } @@ -914,11 +891,11 @@ error Database::getSettingsValue( limit(1), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("getSettingsValue"); } @@ -973,11 +950,11 @@ error Database::SaveProxySettings( useRef(proxy.Password()), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("SaveProxySettings"); } @@ -998,11 +975,11 @@ error Database::Trim(const std::string &text, std::string *result) { limit(1), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("Trim"); } @@ -1028,11 +1005,11 @@ error Database::ResetWindow() { "mini_timer_w = 0", now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("ResetWindow"); } @@ -1052,11 +1029,11 @@ error Database::LoadUpdateChannel( limit(1), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("LoadUpdateChannel"); } @@ -1067,7 +1044,7 @@ error Database::SaveUpdateChannel( if (update_channel != "stable" && update_channel != "beta" && update_channel != "dev") { - return error("Invalid update channel"); + return error::kInvalidUpdateChannel; } return setSettingsValue("update_channel", update_channel); @@ -1078,7 +1055,7 @@ error Database::LoadUserByEmail( User *model) { if (email.empty()) { - return error("Cannot load user by email token without an email"); + return error::kMissingArgument; } Poco::UInt64 uid(0); @@ -1108,11 +1085,11 @@ error Database::LoadUserByEmail( return noError; } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return LoadUserByID(uid, model); } @@ -1176,7 +1153,7 @@ error Database::LoadUserByID( User *user) { if (!UID) { - return error("Cannot load user by ID without an ID"); + return error::kMissingArgument; } Poco::Stopwatch stopwatch; @@ -1253,11 +1230,11 @@ error Database::LoadUserByID( user->SetDefaultTID(default_tid); user->SetCollapseEntries(collapse_entries); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } error err = loadUsersRelatedData(user); if (err != noError) { @@ -1265,9 +1242,7 @@ error Database::LoadUserByID( } stopwatch.stop(); - std::stringstream ss; - ss << "User loaded in " << stopwatch.elapsed() / 1000 << " ms"; - logger().debug(ss.str()); + logger.debug("User loaded in ", stopwatch.elapsed() / 1000, " ms"); return noError; } @@ -1277,7 +1252,7 @@ error Database::loadWorkspaces( std::vector *list) { if (!UID) { - return error("Cannot load user workspaces without an user ID"); + return error::kMissingArgument; } try { @@ -1323,11 +1298,11 @@ error Database::loadWorkspaces( } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("loadWorkspaces"); } @@ -1337,7 +1312,7 @@ error Database::loadClients( std::vector *list) { if (!UID) { - return error("Cannot load user clients without an user ID"); + return error::kMissingArgument; } try { @@ -1385,11 +1360,11 @@ error Database::loadClients( } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("loadClients"); } @@ -1399,7 +1374,7 @@ error Database::loadProjects( std::vector *list) { if (!UID) { - return error("Cannot load user projects without an user ID"); + return error::kMissingArgument; } try { @@ -1475,11 +1450,11 @@ error Database::loadProjects( } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("loadProjects"); } @@ -1489,7 +1464,7 @@ error Database::loadTasks( std::vector *list) { if (!UID) { - return error("Cannot load user tasks without an user ID"); + return error::kMissingArgument; } try { @@ -1537,11 +1512,11 @@ error Database::loadTasks( } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("loadTasks"); } @@ -1551,7 +1526,7 @@ error Database::loadTags( std::vector *list) { if (!UID) { - return error("Cannot load user tags without an user ID"); + return error::kMissingArgument; } try { @@ -1598,11 +1573,11 @@ error Database::loadTags( } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("loadTags"); } @@ -1612,7 +1587,7 @@ error Database::loadAutotrackerRules( std::vector *list) { if (!UID) { - return error("Cannot load autotracker rules without an user ID"); + return error::kMissingArgument; } try { @@ -1652,11 +1627,11 @@ error Database::loadAutotrackerRules( } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("loadAutotrackerRules"); } @@ -1666,7 +1641,7 @@ error Database::loadObmActions( std::vector *list) { if (!UID) { - return error("Cannot load OBM actions without an user ID"); + return error::kMissingArgument; } try { @@ -1704,11 +1679,11 @@ error Database::loadObmActions( } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("loadObmActions"); } @@ -1718,7 +1693,7 @@ error Database::loadObmExperiments( std::vector *list) { if (!UID) { - return error("Cannot load OBM experiments without an user ID"); + return error::kMissingArgument; } try { @@ -1757,11 +1732,11 @@ error Database::loadObmExperiments( } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("loadObmExperiments"); } @@ -1771,7 +1746,7 @@ error Database::loadTimelineEvents( std::vector *list) { if (!UID) { - return error("Cannot load user timeline without an user ID"); + return error::kMissingArgument; } try { @@ -1833,11 +1808,11 @@ error Database::loadTimelineEvents( model->EnsureGUID(); } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -1847,7 +1822,7 @@ error Database::loadTimeEntries( std::vector *list) { if (!UID) { - return error("Cannot load user time entries without an user ID"); + return error::kMissingArgument; } try { @@ -1887,11 +1862,11 @@ error Database::loadTimeEntries( } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -1974,9 +1949,9 @@ error Database::loadTimeEntriesFromSQLStatement( model->SetProjectGUID(rs[18].convert()); } if (rs[19].isEmpty()) { - model->SetValidationError(""); + model->SetValidationError(error::kNoError); } else { - model->SetValidationError(rs[19].convert()); + model->SetValidationError(error::fromString(rs[19].convert())); } model->ClearDirty(); @@ -1985,11 +1960,11 @@ error Database::loadTimeEntriesFromSQLStatement( } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -2002,7 +1977,7 @@ error Database::saveRelatedModels( std::vector *changes) { if (!UID) { - return error("Cannot save user related data without an user ID"); + return error::kMissingArgument; } poco_check_ptr(list); @@ -2059,9 +2034,6 @@ error Database::saveModel( // Time entries need to have a GUID, // we expect it everywhere in the UI model->EnsureGUID(); - if (model->GUID().empty()) { - return error("Cannot save time entry without a GUID"); - } if (!model->NeedsToBeSaved()) { return noError; @@ -2071,10 +2043,7 @@ error Database::saveModel( poco_check_ptr(session_); if (model->LocalID()) { - std::stringstream ss; - ss << "Updating time entry " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().debug(ss.str()); + logger.debug("Updating time entry ", model->String(), " in thread ", Poco::Thread::currentTid()); if (model->ID()) { *session_ << @@ -2109,7 +2078,7 @@ error Database::saveModel( useRef(model->DeletedAt()), useRef(model->UpdatedAt()), useRef(model->ProjectGUID()), - useRef(model->ValidationError()), + model->ValidationError().String(), useRef(model->LocalID()), now; } else { @@ -2144,7 +2113,7 @@ error Database::saveModel( useRef(model->DeletedAt()), useRef(model->UpdatedAt()), useRef(model->ProjectGUID()), - useRef(model->ValidationError()), + model->ValidationError().String(), useRef(model->LocalID()), now; } @@ -2166,10 +2135,7 @@ error Database::saveModel( model->GUID())); } } else { - std::stringstream ss; - ss << "Inserting time entry " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().debug(ss.str()); + logger.debug("Inserting time entry ", model->String(), " in thread ", Poco::Thread::currentTid()); if (model->ID()) { *session_ << "insert into time_entries(id, uid, description, " @@ -2202,7 +2168,7 @@ error Database::saveModel( useRef(model->DeletedAt()), useRef(model->UpdatedAt()), useRef(model->ProjectGUID()), - useRef(model->ValidationError()), + model->ValidationError().String(), now; } else { *session_ << @@ -2236,7 +2202,7 @@ error Database::saveModel( useRef(model->DeletedAt()), useRef(model->UpdatedAt()), useRef(model->ProjectGUID()), - useRef(model->ValidationError()), + model->ValidationError().String(), now; } error err = last_error("saveTimeEntry"); @@ -2261,11 +2227,11 @@ error Database::saveModel( } model->ClearDirty(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -2300,23 +2266,23 @@ error Database::saveModel( } if (!model->UID()) { - return error("Cannot save timeline event without an user ID"); + //return error("Cannot save timeline event without an user ID"); + return error::REMOVE_LATER_DATABASE_STORE_ERROR; } if (!model->Start()) { - return error("Cannot save timeline event without start time"); + //return error("Cannot save timeline event without start time"); + return error::REMOVE_LATER_DATABASE_STORE_ERROR; } if (!model->EndTime()) { - return error("Cannot save timeline event without end time"); + //return error("Cannot save timeline event without end time"); + return error::REMOVE_LATER_DATABASE_STORE_ERROR; } Poco::Int64 start_time(model->Start()); Poco::Int64 end_time(model->EndTime()); if (model->LocalID()) { - std::stringstream ss; - ss << "Updating timeline event " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Updating timeline event ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "update timeline_events set " @@ -2360,10 +2326,7 @@ error Database::saveModel( model->GUID())); } } else { - std::stringstream ss; - ss << "Inserting timeline event " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Inserting timeline event ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "insert into timeline_events(" @@ -2420,11 +2383,11 @@ error Database::saveModel( model->ClearDirty(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -2444,10 +2407,7 @@ error Database::saveModel( poco_check_ptr(session_); if (model->LocalID()) { - std::stringstream ss; - ss << "Updating autotracker rule " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Updating autotracker rule ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "update autotracker_settings set " @@ -2479,10 +2439,7 @@ error Database::saveModel( } } else { - std::stringstream ss; - ss << "Inserting autotracker rule " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Inserting autotracker rule ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "insert into autotracker_settings(uid, term, pid, tid) " "values(:uid, :term, :pid, :tid)", @@ -2514,11 +2471,11 @@ error Database::saveModel( model->ClearDirty(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -2538,10 +2495,7 @@ error Database::saveModel( poco_check_ptr(session_); if (model->LocalID()) { - std::stringstream ss; - ss << "Updating OBM action " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Updating OBM action ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "update obm_actions set " @@ -2575,10 +2529,7 @@ error Database::saveModel( } } else { - std::stringstream ss; - ss << "Inserting OBM action " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Inserting OBM action ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "insert into obm_actions(uid, experiment_id, key, value) " "values(:uid, :experiment_id, :key, :value)", @@ -2610,11 +2561,11 @@ error Database::saveModel( model->ClearDirty(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -2635,10 +2586,7 @@ error Database::saveModel( poco_check_ptr(session_); if (model->LocalID()) { - std::stringstream ss; - ss << "Updating workspace " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Updating workspace ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "update workspaces set " @@ -2669,10 +2617,7 @@ error Database::saveModel( model->ModelName(), kChangeTypeUpdate, model->ID(), "")); } else { - std::stringstream ss; - ss << "Inserting workspace " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Inserting workspace ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "insert into workspaces(id, uid, name, premium, " "only_admins_may_create_projects, admin, " @@ -2711,11 +2656,11 @@ error Database::saveModel( } model->ClearDirty(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -2733,7 +2678,8 @@ error Database::saveModel( if (!model->ID()) { model->EnsureGUID(); if (model->GUID().empty()) { - return error("Cannot save new cient without a GUID"); + //return error("Cannot save new cient without a GUID"); + return error::REMOVE_LATER_DATABASE_STORE_ERROR; } } @@ -2745,10 +2691,7 @@ error Database::saveModel( poco_check_ptr(session_); if (model->LocalID()) { - std::stringstream ss; - ss << "Updating client " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Updating client ", model->String(), " in thread ", Poco::Thread::currentTid()); if (model->GUID().empty()) { *session_ << @@ -2786,10 +2729,7 @@ error Database::saveModel( model->GUID())); } else { - std::stringstream ss; - ss << "Inserting client " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Inserting client ", model->String(), " in thread ", Poco::Thread::currentTid()); if (model->GUID().empty()) { *session_ << "insert into clients(id, uid, name, wid) " @@ -2832,11 +2772,11 @@ error Database::saveModel( } model->ClearDirty(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -2854,7 +2794,8 @@ error Database::saveModel( if (!model->ID()) { model->EnsureGUID(); if (model->GUID().empty()) { - return error("Cannot save project without a GUID"); + //return error("Cannot save project without a GUID"); + return error::REMOVE_LATER_DATABASE_STORE_ERROR; } } @@ -2866,10 +2807,7 @@ error Database::saveModel( poco_check_ptr(session_); if (model->LocalID()) { - std::stringstream ss; - ss << "Updating project " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().debug(ss.str()); + logger.debug("Updating project ", model->String(), " in thread ", Poco::Thread::currentTid()); if (model->ID()) { if (model->GUID().empty()) { @@ -2964,10 +2902,7 @@ error Database::saveModel( model->GUID())); } else { - std::stringstream ss; - ss << "Inserting project " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().debug(ss.str()); + logger.debug("Inserting project ", model->String(), " in thread ", Poco::Thread::currentTid()); if (model->ID()) { if (model->GUID().empty()) { *session_ << @@ -3079,11 +3014,11 @@ error Database::saveModel( } model->ClearDirty(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -3103,10 +3038,7 @@ error Database::saveModel( poco_check_ptr(session_); if (model->LocalID()) { - std::stringstream ss; - ss << "Updating task " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Updating task ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "update tasks set " @@ -3129,10 +3061,7 @@ error Database::saveModel( model->ModelName(), kChangeTypeUpdate, model->ID(), "")); } else { - std::stringstream ss; - ss << "Inserting task " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Inserting task ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "insert into tasks(id, uid, name, wid, pid, active) " "values(:id, :uid, :name, :wid, :pid, :active)", @@ -3162,11 +3091,11 @@ error Database::saveModel( } model->ClearDirty(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -3186,10 +3115,7 @@ error Database::saveModel( poco_check_ptr(session_); if (model->LocalID()) { - std::stringstream ss; - ss << "Updating tag " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Updating tag ", model->String(), " in thread ", Poco::Thread::currentTid()); if (model->GUID().empty()) { *session_ << @@ -3227,10 +3153,7 @@ error Database::saveModel( model->GUID())); } else { - std::stringstream ss; - ss << "Inserting tag " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Inserting tag ", model->String(), " in thread ", Poco::Thread::currentTid()); if (model->GUID().empty()) { *session_ << "insert into tags(id, uid, name, wid) " @@ -3273,11 +3196,11 @@ error Database::saveModel( } model->ClearDirty(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -3291,7 +3214,7 @@ error Database::SaveUser( // Do nothing, if user has already logged out if (!user) { - logger().warning("Cannot save user, user is logged out"); + logger.warning("Cannot save user, user is logged out"); return noError; } @@ -3302,13 +3225,16 @@ error Database::SaveUser( stopwatch.start(); if (user->Email().empty()) { - return error("Missing user e-mail, cannot save user"); + //return error("Missing user e-mail, cannot save user"); + return error::REMOVE_LATER_DATABASE_STORE_ERROR; } if (user->APIToken().empty()) { - return error("Missing user API token, cannot save user"); + //return error("Missing user API token, cannot save user"); + return error::REMOVE_LATER_DATABASE_STORE_ERROR; } if (!user->ID()) { - return error("Missing user ID, cannot save user"); + //return error("Missing user ID, cannot save user"); + return error::REMOVE_LATER_DATABASE_STORE_ERROR; } session_->begin(); @@ -3319,10 +3245,7 @@ error Database::SaveUser( if (!user->LocalID() || user->Dirty()) { try { if (user->LocalID()) { - std::stringstream ss; - ss << "Updating user " + user->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Updating user ", user->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "update users set " @@ -3361,10 +3284,7 @@ error Database::SaveUser( changes->push_back(ModelChange( user->ModelName(), kChangeTypeUpdate, user->ID(), "")); } else { - std::stringstream ss; - ss << "Inserting user " + user->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Inserting user ", user->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "insert into users(" "id, default_wid, since, fullname, email, " @@ -3416,13 +3336,13 @@ error Database::SaveUser( user->ClearDirty(); } catch(const Poco::Exception& exc) { session_->rollback(); - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { session_->rollback(); - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { session_->rollback(); - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } } @@ -3576,13 +3496,7 @@ error Database::SaveUser( stopwatch.stop(); - { - std::stringstream ss; - ss << "User with_related_data=" << with_related_data << " saved in " - << stopwatch.elapsed() / 1000 << " ms in thread " - << Poco::Thread::currentTid(); - logger().debug(ss.str()); - } + logger.debug("User with_related_data=", with_related_data, " saved in ", stopwatch.elapsed() / 1000, " ms in thread ", Poco::Thread::currentTid()); return noError; } @@ -3663,11 +3577,11 @@ error Database::CurrentAPIToken( limit(1), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("CurrentAPIToken"); } @@ -3681,11 +3595,11 @@ error Database::ClearCurrentAPIToken() { *session_ << "delete from sessions", now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("ClearCurrentAPIToken"); } @@ -3696,11 +3610,8 @@ error Database::SetCurrentAPIToken( try { Poco::Mutex::ScopedLock lock(session_m_); - if (token.empty()) { - return error("cannot start session without API token"); - } - if (!uid) { - return error("cannot start session without user ID"); + if (token.empty() || !uid) { + return error::kMissingArgument; } poco_check_ptr(session_); @@ -3717,11 +3628,11 @@ error Database::SetCurrentAPIToken( useRef(uid), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("SetCurrentAPIToken"); } @@ -3760,11 +3671,11 @@ error Database::EnsureTimelineGUIDS() { } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } } @@ -3819,11 +3730,11 @@ error Database::saveAnalyticsClientID() { useRef(analytics_client_id_), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("saveAnalyticsClientID"); } @@ -3856,11 +3767,11 @@ error Database::LoadMigrations( } } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("LoadMigrations"); } @@ -3869,11 +3780,8 @@ error Database::Migrate( const std::string &name, const std::string &sql) { - if (name.empty()) { - return error("Cannot run a migration without name"); - } - if (sql.empty()) { - return error("Cannot run a migration without SQL"); + if (name.empty() || sql.empty()) { + return error::kMissingArgument; } try { @@ -3896,11 +3804,7 @@ error Database::Migrate( return noError; } - std::stringstream ss; - ss << "Migrating" << "\n" - << name << "\n" - << sql << "\n"; - logger().debug(ss.str()); + logger.debug("Migrating", "\n", name, "\n", sql, "\n"); err = execute(sql); if (err != noError) { @@ -3916,21 +3820,18 @@ error Database::Migrate( return err; } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } -error Database::execute( - const std::string &sql) { - - +error Database::execute(const std::string &sql) { if (sql.empty()) { - return error("Cannot execute empty SQL"); + return error::kMissingArgument; } try { @@ -3944,11 +3845,11 @@ error Database::execute( return err; } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -3958,7 +3859,7 @@ error Database::String( std::string *result) { if (sql.empty()) { - return error("Cannot select from database with empty SQL"); + return error::kMissingArgument; } try { @@ -3973,21 +3874,18 @@ error Database::String( now; *result = value; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("String"); } -error Database::UInt( - const std::string &sql, - Poco::UInt64 *result) { - +error Database::UInt(const std::string &sql, Poco::UInt64 *result) { if (sql.empty()) { - return error("Cannot select a numeric from database with empty SQL"); + return error::kMissingArgument; } try { @@ -4002,11 +3900,11 @@ error Database::UInt( now; *result = value; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("UInt"); } @@ -4023,11 +3921,11 @@ error Database::saveDesktopID() { useRef(desktop_id_), now; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return last_error("saveDesktopID"); } @@ -4047,10 +3945,7 @@ error Database::saveModel( poco_check_ptr(session_); if (model->LocalID()) { - std::stringstream ss; - ss << "Updating OBM experiment " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Updating OBM experiment ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "update obm_experiments set " @@ -4086,10 +3981,7 @@ error Database::saveModel( } } else { - std::stringstream ss; - ss << "Inserting OBM action " + model->String() - << " in thread " << Poco::Thread::currentTid(); - logger().trace(ss.str()); + logger.trace("Inserting OBM action ", model->String(), " in thread ", Poco::Thread::currentTid()); *session_ << "insert into obm_experiments(" "uid, nr, included, has_seen, actions " @@ -4125,11 +4017,11 @@ error Database::saveModel( model->ClearDirty(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } diff --git a/src/database.h b/src/database.h index 67139383f2..6f64dfd6e2 100644 --- a/src/database.h +++ b/src/database.h @@ -17,14 +17,13 @@ #include "model_change.h" #include "timeline_event.h" #include "types.h" +#include "util/logger.h" namespace Poco { -class Logger; - -namespace Data { -class Session; -class Statement; -} + namespace Data { + class Session; + class Statement; + } } namespace toggl { @@ -401,7 +400,7 @@ class TOGGL_INTERNAL_EXPORT Database { const Poco::UInt64 &user_id, std::vector *timeline_events); - Poco::Logger &logger() const; + Logger logger { "database" }; Poco::Mutex session_m_; Poco::Data::Session *session_; diff --git a/src/error.cc b/src/error.cc deleted file mode 100644 index d5171ddc65..0000000000 --- a/src/error.cc +++ /dev/null @@ -1,260 +0,0 @@ - -// Copyright 2014 Toggl Desktop developers. - -#include "error.h" - -#include - -#include "const.h" - -namespace toggl { - -bool IsNetworkingError(const error &err) { - if (noError == err) { - return false; - } - if (err.find(kCannotConnectError) != std::string::npos) { - return true; - } - if (err.find(kBackendIsDownError) != std::string::npos) { - return true; - } - if (err.find(kCannotEstablishProxyConnection) != std::string::npos) { - return true; - } - if (err.find(kCertificateVerifyFailed) != std::string::npos) { - return true; - } - if (err.find(kProxyAuthenticationRequired) != std::string::npos) { - return true; - } - if (err.find("Cannot assign requested address") != std::string::npos) { - return true; - } - if (err.find(kCertificateValidationError) != std::string::npos) { - return true; - } - if (err.find(kUnacceptableCertificate) != std::string::npos) { - return true; - } - if (err.find("Host not found") != std::string::npos) { - return true; - } - if (err.find(kCannotUpgradeToWebSocketConnection) != std::string::npos) { - return true; - } - if (err.find("No message received") != std::string::npos) { - return true; - } - if (err.find("Connection refused") != std::string::npos) { - return true; - } - if (err.find("Connection timed out") != std::string::npos) { - return true; - } - if (err.find("connect timed out") != std::string::npos) { - return true; - } - if (err.find("SSL connection unexpectedly closed") != std::string::npos) { - return true; - } - if (err.find("Network is down") != std::string::npos) { - return true; - } - if (err.find("Network is unreachable") != std::string::npos) { - return true; - } - if (err.find("Host is down") != std::string::npos) { - return true; - } - if (err.find("No route to host") != std::string::npos) { - return true; - } - if ((err.find("I/O error: 1") != std::string::npos) - && (err.find(":443") != std::string::npos)) { - return true; - } - if (err.find("The request timed out") != std::string::npos) { - return true; - } - if (err.find("Could not connect to the server") != std::string::npos) { - return true; - } - if (err.find("Connection reset by peer") != std::string::npos) { - return true; - } - if (err.find("The Internet connection appears to be offline") - != std::string::npos) { - return true; - } - if (err.find("Timeout") != std::string::npos) { - return true; - } - if (err.find(kSSLException) != std::string::npos) { - return true; - } - if (err.find("An internal server error occurred.") != std::string::npos) { - return true; - } - return false; -} - -bool IsUserError(const error &err) { - if (noError == err) { - return false; - } - if (err.find(kErrorRuleAlreadyExists) != std::string::npos) { - return true; - } - if (err.find(kCheckYourSignupError) != std::string::npos) { - return true; - } - if (err.find(kEmailNotFoundCannotLogInOffline) != std::string::npos) { - return true; - } - if (err.find(kInvalidPassword) != std::string::npos) { - return true; - } - if (err.find(kPaymentRequiredError) != std::string::npos) { - return true; - } - if (err.find("File not found") != std::string::npos) { - return true; - } - if (err.find("SSL context exception") != std::string::npos) { - return true; - } - if (err.find("Access to file denied") != std::string::npos) { - return true; - } - if (err.find(kBadRequestError) != std::string::npos) { - return true; - } - if (err.find(kUnauthorizedError) != std::string::npos) { - return true; - } - if (err.find(kCannotWriteFile) != std::string::npos) { - return true; - } - if (err.find(kIsSuspended) != std::string::npos) { - return true; - } - if (err.find(kRequestToServerFailedWithStatusCode403) - != std::string::npos) { - return true; - } - if (err.find(kUnsupportedAppError) != std::string::npos) { - return true; - } - if (err.find("Stop time must be after start time") - != std::string::npos) { - return true; - } - if (err.find("Invalid e-mail or password") != std::string::npos) { - return true; - } - if (err.find("Maximum length for description") != std::string::npos) { - return true; - } - if (err.find("Start time year must be between 2010 and 2100") - != std::string::npos) { - return true; - } - if (err.find(kMissingWorkspaceID) != std::string::npos) { - return true; - } - if (err.find(kEndpointGoneError) != std::string::npos) { - return true; - } - if (err.find("Password should be at least") != std::string::npos) { - return true; - } - if (err.find("User with this email already exists") != - std::string::npos) { - return true; - } - if (err.find("Invalid e-mail") != std::string::npos) { - return true; - } - if (err.find(kCannotAccessWorkspaceError) != std::string::npos) { - return true; - } - if (err.find(kCannotSyncInTestEnv) != std::string::npos) { - return true; - } - if (err.find(kCannotContinueDeletedTimeEntry) != std::string::npos) { - return true; - } - if (err.find(kCannotDeleteDeletedTimeEntry) != std::string::npos) { - return true; - } - if (err.find(kPleaseSelectAWorkspace) != std::string::npos) { - return true; - } - if (err.find(kClientNameMustNotBeEmpty) != std::string::npos) { - return true; - } - if (err.find(kProjectNameMustNotBeEmpty) != std::string::npos) { - return true; - } - if (err.find(kClientNameAlreadyExists) != std::string::npos) { - return true; - } - if (err.find(kProjectNameAlreadyExists) != std::string::npos) { - return true; - } - if (err.find(kThisEntryCantBeSavedPleaseAdd) != std::string::npos) { - return true; - } - return false; -} - -std::string MakeErrorActionable(const error &err) { - if (noError == err) { - return err; - } - if (err.find(kCannotEstablishProxyConnection) != std::string::npos) { - return kCheckYourProxySetup; - } - if (err.find(kCertificateVerifyFailed) != std::string::npos) { - return kCheckYourFirewall; - } - if (err.find(kProxyAuthenticationRequired) != std::string::npos) { - return kCheckYourProxySetup; - } - if (err.find(kCertificateValidationError) != std::string::npos) { - return kCheckYourFirewall; - } - if (err.find(kUnacceptableCertificate) != std::string::npos) { - return kCheckYourFirewall; - } - if (err.find(kCannotUpgradeToWebSocketConnection) != std::string::npos) { - return kCheckYourFirewall; - } - if (err.find(kSSLException) != std::string::npos) { - return kCheckYourFirewall; - } - if (err.find(kCannotWriteFile) != std::string::npos) { - return "Check your user permissions"; - } - if (err.find(kIsSuspended) != std::string::npos) { - return "The workspace is suspended, please check your payments"; - } - if (err.find(kRequestToServerFailedWithStatusCode403) - != std::string::npos) { - return "You do not have access to this workspace"; - } - if (err.find(kMissingWorkspaceID) != std::string::npos) { - return "Please select a project"; - } - if (err.find(kDatabaseDiskMalformed) != std::string::npos) { - return "Local database is corrupt. Please clear local data to recreate local database."; - } - if (err.find(kEndpointGoneError) != std::string::npos) { - return kOutOfDatePleaseUpgrade; - } - - return err; -} - -} // namespace toggl diff --git a/src/error.h b/src/error.h deleted file mode 100644 index 0700e247ac..0000000000 --- a/src/error.h +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright 2014 Toggl Desktop developers. - -#ifndef SRC_ERROR_H_ -#define SRC_ERROR_H_ - -#include - -#include "types.h" - -namespace toggl { - -bool IsNetworkingError(const error &err); -bool IsUserError(const error &err); -std::string MakeErrorActionable(const error &err); - -} // namespace toggl - -#endif // SRC_ERROR_H_ diff --git a/src/feedback.cc b/src/feedback.cc index 5d1ff4217c..ecab12ae45 100644 --- a/src/feedback.cc +++ b/src/feedback.cc @@ -20,12 +20,12 @@ const std::string Feedback::filename() const { return p.getFileName(); } -toggl::error Feedback::Validate() const { +error Feedback::Validate() const { if (subject_.empty()) { - return toggl::error("Missing topic"); + return error::kMissingFeedbackTopic; } if (details_.empty()) { - return toggl::error("Missing details"); + return error::kMissingFeedbackDetails; } return toggl::noError; } diff --git a/src/formatter.cc b/src/formatter.cc index ffb7d70003..829b61aae3 100644 --- a/src/formatter.cc +++ b/src/formatter.cc @@ -13,12 +13,12 @@ #include "task.h" #include "time_entry.h" #include "workspace.h" +#include "util/logger.h" #include #include #include #include -#include #include #include #include @@ -513,20 +513,12 @@ std::time_t Formatter::Parse8601(const std::string &iso_8601_formatted_date) { // Sun 9 Sep 2001 03:46:40 EET if (epoch_time < 1000000000) { - Poco::Logger &logger = Poco::Logger::get("Formatter"); - std::stringstream ss; - ss << "Parsed timestamp is too small, will interpret as 0: " - << epoch_time; - logger.warning(ss.str()); + Logger("Formatter").warning("Parsed timestamp is too small, will interpret as 0: ", epoch_time); return 0; } if (epoch_time > 2000000000) { - Poco::Logger &logger = Poco::Logger::get("Formatter"); - std::stringstream ss; - ss << "Parsed timestamp is too large, will interpret as 0: " - << epoch_time; - logger.warning(ss.str()); + Logger("Formatter").warning("Parsed timestamp is too large, will interpret as 0: ", epoch_time); return 0; } @@ -575,28 +567,22 @@ std::string Formatter::EscapeJSONString(const std::string &input) { return ss.str(); } -error Formatter::CollectErrors(std::vector * const errors) { +std::string Formatter::CollectErrors(const std::vector &errors) { std::stringstream ss; ss << "Errors encountered while syncing data: "; std::set unique; - for (std::vector::const_iterator it = errors->begin(); - it != errors->end(); - ++it) { - error err = *it; - if (!err.empty() && err[err.size() - 1] == '\n') { - err[err.size() - 1] = '.'; - } + for (auto err : errors) { // skip error if not unique if (unique.end() != unique.find(err)) { continue; } - if (it != errors->begin()) { + if (err != errors.front()) { ss << " "; } ss << err; unique.insert(err); } - return error(ss.str()); + return ss.str(); } bool CompareClientByName(Client *a, Client *b) { diff --git a/src/formatter.h b/src/formatter.h index a9e1171ef0..c7e4739c46 100644 --- a/src/formatter.h +++ b/src/formatter.h @@ -74,8 +74,7 @@ class TOGGL_INTERNAL_EXPORT Formatter { static std::string FormatTimeForTimeEntryEditor( const std::time_t date); - static error CollectErrors( - std::vector * const errors); + static std::string CollectErrors(const std::vector &errors); // Time diff --git a/src/gui.cc b/src/gui.cc index 502b2a87b3..b3b60eb2ff 100644 --- a/src/gui.cc +++ b/src/gui.cc @@ -17,7 +17,6 @@ #include "user.h" #include "workspace.h" -#include #include namespace toggl { @@ -141,9 +140,7 @@ void GUI::DisplayLogin(const bool open, const uint64_t user_id) { if (open == lastDisplayLoginOpen && user_id == lastDisplayLoginUserID) { return; } - std::stringstream ss; - ss << "DisplayLogin open=" << open << ", user_id=" << user_id; - logger().debug(ss.str()); + logger.debug("DisplayLogin open=", open, ", user_id=", user_id); on_display_login_(open, user_id); @@ -156,12 +153,11 @@ error GUI::DisplayError(const error &err) { return noError; } - logger().error(err); + logger.error(err); - if (IsNetworkingError(err)) { - std::stringstream ss; - ss << "You are offline (" << err << ")"; - if (kBackendIsDownError == err) { + if (err.IsNetworkingError()) { + logger.debug("You are offline (", err, ")"); + if (err == error::kBackendIsDownError) { DisplayOnlineState(kOnlineStateBackendDown); } else { @@ -170,24 +166,20 @@ error GUI::DisplayError(const error &err) { return err; } - std::string actionable = MakeErrorActionable(err); - bool is_user_error = IsUserError(err); + std::string actionable = err.MakeErrorActionable(); + bool is_user_error = err.IsUserError(); - { - std::stringstream ss; - ss << "DisplayError err=" << err - << " actionable=" << actionable - << " is_user_error=" << is_user_error; - logger().debug(ss.str()); - } + DisplayError(actionable, is_user_error); - char_t *err_s = copy_string(actionable); - on_display_error_(err_s, is_user_error); - free(err_s); + return err; +} - lastErr = err; +error GUI::DisplayError(const std::string &err, bool is_user_error) { + logger.debug("DisplayError err=", err, " actionable=", err, " is_user_error=", is_user_error); - return err; + char_t *err_s = copy_string(err.c_str()); + on_display_error_(err_s, is_user_error); + free(err_s); } error GUI::DisplayWSError() { @@ -201,77 +193,79 @@ error GUI::DisplayTosAccept() { } error GUI::VerifyCallbacks() { - logger().debug("VerifyCallbacks"); - error err = findMissingCallbacks(); - if (err != noError) { - logger().error(err); + logger.debug("VerifyCallbacks"); + std::string missing = findMissingCallbacks(); + if (!missing.empty()) { + logger.error(missing); + return error::kMissingUICallbacks; } - return err; + return noError; } -error GUI::findMissingCallbacks() { +std::string GUI::findMissingCallbacks() { + std::stringstream ss; if (!on_display_app_) { - return error("!on_display_app_"); + ss << "!on_display_app_ "; } if (!on_display_error_) { - return error("!on_display_error_"); + ss << "!on_display_error_ "; } if (!on_display_online_state_) { - return error("!on_display_online_state_"); + ss << "!on_display_online_state_ "; } if (!on_display_login_) { - return error("!on_display_login_"); + ss << "!on_display_login_ "; } if (!on_display_url_) { - return error("!on_display_url_"); + ss << "!on_display_url_ "; } if (!on_display_reminder_) { - return error("!on_display_reminder_"); + ss << "!on_display_reminder_ "; } if (!on_display_time_entry_list_) { - return error("!on_display_time_entry_list_"); + ss << "!on_display_time_entry_list_ "; } if (!on_display_time_entry_autocomplete_) { - return error("!on_display_time_entry_autocomplete_"); + ss << "!on_display_time_entry_autocomplete_ "; } if (!on_display_project_autocomplete_) { - return error("!on_display_project_autocomplete_"); + ss << "!on_display_project_autocomplete_ "; } if (!on_display_workspace_select_) { - return error("!on_display_workspace_select_"); + ss << "!on_display_workspace_select_ "; } if (!on_display_client_select_) { - return error("!on_display_client_select_"); + ss << "!on_display_client_select_ "; } if (!on_display_tags_) { - return error("!on_display_tags_"); + ss << "!on_display_tags_ "; } if (!on_display_time_entry_editor_) { - return error("!on_display_time_entry_editor_"); + ss << "!on_display_time_entry_editor_ "; } if (!on_display_settings_) { - return error("!on_display_settings_"); + ss << "!on_display_settings_ "; } if (!on_display_timer_state_) { - return error("!on_display_timer_state_"); + ss << "!on_display_timer_state_ "; } if (!on_display_idle_notification_) { - return error("!on_display_idle_notification_"); + ss << "!on_display_idle_notification_ "; } if (!on_display_mini_timer_autocomplete_) { - return error("!on_display_mini_timer_autocomplete_"); + ss << "!on_display_mini_timer_autocomplete_ "; } if (!on_display_pomodoro_) { - return error("!on_display_pomodoro_"); + ss << "!on_display_pomodoro_ "; } if (!on_display_pomodoro_break_) { - return error("!on_display_pomodoro_break_"); + ss << "!on_display_pomodoro_break_ "; } - return noError; + return ss.str(); } void GUI::DisplayReminder() { - logger().debug("DisplayReminder"); + logger.debug("DisplayReminder"); char_t *s1 = copy_string("Reminder from Toggl Desktop"); char_t *s2 = copy_string("Don't forget to track your time!"); @@ -281,7 +275,7 @@ void GUI::DisplayReminder() { } void GUI::DisplayPomodoro(const Poco::Int64 minutes) { - logger().debug("DisplayPomodoro"); + logger.debug("DisplayPomodoro"); char_t *s1 = copy_string("Pomodoro Timer"); std::stringstream ss; @@ -294,7 +288,7 @@ void GUI::DisplayPomodoro(const Poco::Int64 minutes) { } void GUI::DisplayPomodoroBreak(const Poco::Int64 minutes) { - logger().debug("DisplayPomodoroBreak"); + logger.debug("DisplayPomodoroBreak"); char_t *s1 = copy_string("Pomodoro Break Timer"); std::stringstream ss; @@ -309,18 +303,15 @@ void GUI::DisplayPomodoroBreak(const Poco::Int64 minutes) { void GUI::DisplayAutotrackerNotification(Project *const p, Task *const t) { poco_check_ptr(p); - std::stringstream ss; - ss << "DisplayAutotrackerNotification "; if (p) { - ss << "project " << p->Name() << ", " << p->ID() << ", " << p->GUID(); + logger.debug("DisplayAutotrackerNotification project ", p->Name(), ", ", p->ID(), ", ", p->GUID()); } if (t) { - ss << " task " << t->Name() << ", " << t->ID(); + logger.debug("DisplayAutotrackerNotification task ", t->Name(), ", ", t->ID()); } - logger().debug(ss.str()); if (!p && !t) { - logger().error( + logger.error( "Need project ID or task ID for autotracker notification"); return; } @@ -352,27 +343,21 @@ void GUI::DisplayOnlineState(const Poco::Int64 state) { if (!(kOnlineStateOnline == state || kOnlineStateNoNetwork == state || kOnlineStateBackendDown == state)) { - std::stringstream ss; - ss << "Invalid online state " << state; - logger().error(ss.str()); + logger.error("Invalid online state ", state); return; } - std::stringstream ss; - ss << "DisplayOnlineState "; - switch (state) { case kOnlineStateOnline: - ss << "online"; + logger.debug("DisplayOnlineState online"); break; case kOnlineStateNoNetwork: - ss << "no network"; + logger.debug("DisplayOnlineState no network"); break; case kOnlineStateBackendDown: - ss << "backend is down"; + logger.debug("DisplayOnlineState backend is down"); break; } - logger().debug(ss.str()); on_display_online_state_(state); @@ -381,7 +366,7 @@ void GUI::DisplayOnlineState(const Poco::Int64 state) { void GUI::DisplayTimeEntryAutocomplete( std::vector *items) { - logger().debug("DisplayTimeEntryAutocomplete"); + logger.debug("DisplayTimeEntryAutocomplete"); TogglAutocompleteView *first = autocomplete_list_init(items); on_display_time_entry_autocomplete_(first); @@ -390,7 +375,7 @@ void GUI::DisplayTimeEntryAutocomplete( void GUI::DisplayHelpArticles( const std::vector &articles) { - logger().debug("DisplayHelpArticles"); + logger.debug("DisplayHelpArticles"); if (!on_display_help_articles_) { return; @@ -403,7 +388,7 @@ void GUI::DisplayHelpArticles( void GUI::DisplayMinitimerAutocomplete( std::vector *items) { - logger().debug("DisplayMinitimerAutocomplete"); + logger.debug("DisplayMinitimerAutocomplete"); TogglAutocompleteView *first = autocomplete_list_init(items); on_display_mini_timer_autocomplete_(first); @@ -412,7 +397,7 @@ void GUI::DisplayMinitimerAutocomplete( void GUI::DisplayProjectAutocomplete( std::vector *items) { - logger().debug("DisplayProjectAutocomplete"); + logger.debug("DisplayProjectAutocomplete"); TogglAutocompleteView *first = autocomplete_list_init(items); on_display_project_autocomplete_(first); @@ -441,10 +426,7 @@ void GUI::DisplayTimeEntryList(const bool open, // Otherwise, just get from the list renderList = list; } - std::stringstream ss; - ss << "DisplayTimeEntryList open=" << open - << ", has items=" << renderList.size(); - logger().debug(ss.str()); + logger.debug("DisplayTimeEntryList open=", open, ", has items=", renderList.size()); } // Render @@ -468,12 +450,7 @@ void GUI::DisplayTimeEntryList(const bool open, time_entry_view_list_clear(first); stopwatch.stop(); - { - std::stringstream ss; - ss << "DisplayTimeEntryList done in " - << stopwatch.elapsed() / 1000 << " ms"; - logger().debug(ss.str()); - } + logger.debug("DisplayTimeEntryList done in ", stopwatch.elapsed() / 1000, " ms"); } void GUI::DisplayTimeline( @@ -674,7 +651,7 @@ TogglTimelineEventView* GUI::SortList(TogglTimelineEventView *head) { } void GUI::DisplayTags(const std::vector list) { - logger().debug("DisplayTags"); + logger.debug("DisplayTags"); TogglGenericView *first = generic_to_view_item_list(list); on_display_tags_(first); @@ -716,7 +693,7 @@ void GUI::DisplayAutotrackerRules( void GUI::DisplayClientSelect( const std::vector &list) { - logger().debug("DisplayClientSelect"); + logger.debug("DisplayClientSelect"); TogglGenericView *first = generic_to_view_item_list(list); on_display_client_select_(first); @@ -725,7 +702,7 @@ void GUI::DisplayClientSelect( void GUI::DisplayWorkspaceSelect( const std::vector &list) { - logger().debug("DisplayWorkspaceSelect"); + logger.debug("DisplayWorkspaceSelect"); TogglGenericView *first = generic_to_view_item_list(list); on_display_workspace_select_(first); @@ -736,7 +713,7 @@ void GUI::DisplayTimeEntryEditor(const bool open, const view::TimeEntry &te, const std::string &focused_field_name) { - logger().debug( + logger.debug( "DisplayTimeEntryEditor focused_field_name=" + focused_field_name); TogglTimeEntryView *view = time_entry_view_item_init(te); @@ -749,7 +726,7 @@ void GUI::DisplayTimeEntryEditor(const bool open, } void GUI::DisplayURL(const std::string &URL) { - logger().debug("DisplayURL " + URL); + logger.debug("DisplayURL " + URL); char_t *url = copy_string(URL); on_display_url_(url); @@ -757,7 +734,7 @@ void GUI::DisplayURL(const std::string &URL) { } void GUI::DisplayUpdate(const std::string &URL) { - logger().debug("DisplayUpdate " + URL); + logger.debug("DisplayUpdate " + URL); char_t *url = copy_string(URL); on_display_update_(url); @@ -769,15 +746,10 @@ void GUI::DisplayUpdateDownloadState( const Poco::Int64 download_state) { if (!CanDisplayUpdateDownloadState()) { - logger().debug("Update download state display not supported by UI"); + logger.debug("Update download state display not supported by UI"); return; } - { - std::stringstream ss; - ss << "DisplayUpdateDownloadState version=" << version - << " state=" << download_state; - logger().debug(ss.str()); - } + logger.debug("DisplayUpdateDownloadState version=", version, " state=", download_state); char_t *version_string = copy_string(version); on_display_update_download_state_(version_string, download_state); free(version_string); @@ -787,7 +759,7 @@ void GUI::DisplayMessage(const std::string &title, const std::string &text, const std::string &button, const std::string &url) { - logger().debug("DisplayMessage: " + title); + logger.debug("DisplayMessage: " + title); char_t *tmp_title = copy_string(title); char_t *tmp_text = copy_string(text); @@ -811,7 +783,7 @@ void GUI::DisplaySettings(const bool open, const Settings &settings, const bool use_proxy, const Proxy &proxy) { - logger().debug("DisplaySettings"); + logger.debug("DisplaySettings"); TogglSettingsView *view = settings_view_item_init( record_timeline, @@ -831,12 +803,12 @@ void GUI::DisplayTimerState( on_display_timer_state_(view); time_entry_view_list_clear(view); - logger().debug("DisplayTimerState"); + logger.debug("DisplayTimerState"); } void GUI::DisplayEmptyTimerState() { on_display_timer_state_(nullptr); - logger().debug("DisplayEmptyTimerState"); + logger.debug("DisplayEmptyTimerState"); } void GUI::DisplayIdleNotification(const std::string &guid, @@ -859,8 +831,4 @@ void GUI::DisplayIdleNotification(const std::string &guid, free(description_s); } -Poco::Logger &GUI::logger() const { - return Poco::Logger::get("ui"); -} - } // namespace toggl diff --git a/src/gui.h b/src/gui.h index 976fe93825..45aa17c8a6 100644 --- a/src/gui.h +++ b/src/gui.h @@ -14,13 +14,10 @@ #include "toggl_api.h" #include "toggl_api_private.h" #include "types.h" +#include "util/logger.h" #include -namespace Poco { -class Logger; -} - namespace toggl { namespace view { @@ -98,7 +95,7 @@ class TOGGL_INTERNAL_EXPORT TimeEntry { bool Unsynced; // If syncing a time entry ended with an error, // the error is attached to the time entry - std::string Error; + error Error; bool Locked; bool Group; bool GroupOpen; @@ -404,6 +401,7 @@ class TOGGL_INTERNAL_EXPORT GUI : public SyncStateMonitor { void DisplayApp(); error DisplayError(const error &err); + error DisplayError(const std::string &err, bool is_user_error); // Overlay screen triggers error DisplayWSError(); @@ -690,7 +688,7 @@ class TOGGL_INTERNAL_EXPORT GUI : public SyncStateMonitor { } private: - error findMissingCallbacks(); + std::string findMissingCallbacks(); TogglDisplayApp on_display_app_; TogglDisplayError on_display_error_; @@ -740,7 +738,7 @@ class TOGGL_INTERNAL_EXPORT GUI : public SyncStateMonitor { Poco::LocalDateTime timeline_date_at_; - Poco::Logger &logger() const; + Logger logger { "ui" }; }; } // namespace toggl diff --git a/src/https_client.cc b/src/https_client.cc index aa2aa4157a..84c7b04825 100644 --- a/src/https_client.cc +++ b/src/https_client.cc @@ -11,6 +11,7 @@ #include "netconf.h" #include "urls.h" #include "toggl_api.h" +#include "util/error.h" #include #include @@ -42,9 +43,7 @@ namespace toggl { void ServerStatus::startStatusCheck() { - std::stringstream ss; - ss << "startStatusCheck fast_retry=" << fast_retry_; - logger().debug(ss.str()); + logger().debug("startStatusCheck fast_retry=", fast_retry_); if (checker_.isRunning()) { return; @@ -57,16 +56,14 @@ void ServerStatus::stopStatusCheck(const std::string &reason) { return; } - std::stringstream ss; - ss << "stopStatusCheck, because " << reason; - logger().debug(ss.str()); + logger().debug("stopStatusCheck, because ", reason); checker_.stop(); checker_.wait(); } -Poco::Logger &ServerStatus::logger() const { - return Poco::Logger::get("ServerStatus"); +Logger ServerStatus::logger() const { + return { "ServerStatus" }; } void ServerStatus::runActivity() { @@ -75,18 +72,10 @@ void ServerStatus::runActivity() { delay_seconds = 60*15; } - { - std::stringstream ss; - ss << "runActivity loop starting, delay_seconds=" << delay_seconds; - logger().debug(ss.str()); - } + logger().debug( "runActivity loop starting, delay_seconds=", delay_seconds); while (!checker_.isStopped()) { - { - std::stringstream ss; - ss << "runActivity delay_seconds=" << delay_seconds; - logger().debug(ss.str()); - } + logger().debug("runActivity delay_seconds=", delay_seconds); // Sleep a bit for (int i = 0; i < delay_seconds; i++) { @@ -119,13 +108,7 @@ void ServerStatus::runActivity() { (static_cast(RAND_MAX / (high - low))); delay_seconds = static_cast(delay_seconds * r); - { - std::stringstream ss; - ss << "err=" << resp.err - << ", random=" << r - << ", delay_seconds=" << delay_seconds; - logger().debug(ss.str()); - } + logger().debug("err=", resp.err, ", random=", r, ", delay_seconds=", delay_seconds); continue; } @@ -136,20 +119,16 @@ void ServerStatus::runActivity() { error ServerStatus::Status() { if (gone_) { - return kEndpointGoneError; + return error::kEndpointGoneError; } if (checker_.isRunning() && !checker_.isStopped()) { - return kBackendIsDownError; + return error::kBackendIsDownError; } return noError; } void ServerStatus::UpdateStatus(const Poco::Int64 code) { - { - std::stringstream ss; - ss << "UpdateStatus status_code=" << code; - logger().debug(ss.str()); - } + logger().debug("UpdateStatus status_code=", code); gone_ = 410 == code; @@ -159,71 +138,20 @@ void ServerStatus::UpdateStatus(const Poco::Int64 code) { return; } - std::stringstream ss; - ss << "Status code " << code; - stopStatusCheck(ss.str()); + stopStatusCheck("Status code " + std::to_string(code)); } HTTPSClientConfig HTTPSClient::Config; std::map HTTPSClient::banned_until_; -Poco::Logger &HTTPSClient::logger() const { - return Poco::Logger::get("HTTPSClient"); +Logger HTTPSClient::logger() const { + return { "HTTPSClient" }; } bool HTTPSClient::isRedirect(const Poco::Int64 status_code) const { return (status_code >= 300 && status_code < 400); } -error HTTPSClient::statusCodeToError(const Poco::Int64 status_code) const { - switch (status_code) { - case 200: - case 201: - case 202: - return noError; - case 400: - // data that you sending is not valid/acceptable - return kBadRequestError; - case 401: - // ask user to enter login again, do not obtain new token automatically - return kUnauthorizedError; - case 402: - // requested action allowed only for pro workspace show user upsell - // page / ask for workspace pro upgrade. do not retry same request - // unless known that client is pro - return kPaymentRequiredError; - case 403: - // client has no right to perform given request. Server - return kForbiddenError; - case 404: - // request is not possible - // (or not allowed and server does not tell why) - return kRequestIsNotPossible; - case 410: - return kEndpointGoneError; - case 418: - return kUnsupportedAppError; - case 429: - return kCannotConnectError; - case 500: - return kBackendIsDownError; - case 501: - case 502: - case 503: - case 504: - case 505: - return kBackendIsDownError; - } - - { - std::stringstream ss; - ss << "Unexpected HTTP status code: " << status_code; - logger().error(ss.str()); - } - - return kCannotConnectError; -} - HTTPSResponse HTTPSClient::Post( HTTPSRequest req) const { req.method = Poco::Net::HTTPRequest::HTTP_POST; @@ -259,19 +187,14 @@ HTTPSResponse HTTPSClient::request( HTTPSRequest req) const { HTTPSResponse resp = makeHttpRequest(req); - if (kCannotConnectError == resp.err && isRedirect(resp.status_code)) { + if (resp.err == error::kCannotConnectError && isRedirect(resp.status_code)) { // Reattempt request to the given location. Poco::URI uri(resp.body); req.host = uri.getScheme() + "://" + uri.getHost(); req.relative_url = uri.getPathEtc(); - { - std::stringstream ss; - ss << "Redirect to URL=" << resp.body - << " host=" << req.host - << " relative_url=" << req.relative_url; - logger().debug(ss.str()); - } + + logger().debug("Redirect to URL=", resp.body, " host=", req.host, " relative_url=", req.relative_url); resp = makeHttpRequest(req); } return resp; @@ -283,12 +206,12 @@ HTTPSResponse HTTPSClient::makeHttpRequest( HTTPSResponse resp; if (!urls::RequestsAllowed()) { - resp.err = error(kCannotSyncInTestEnv); + resp.err = error::kCannotSyncInTestEnv; return resp; } if (urls::ImATeapot()) { - resp.err = error(kUnsupportedAppError); + resp.err = error::kUnsupportedAppError; return resp; } @@ -298,25 +221,25 @@ HTTPSResponse HTTPSClient::makeHttpRequest( if (cit->second >= Poco::Timestamp()) { logger().warning( "Cannot connect, because we made too many requests"); - resp.err = kCannotConnectError; + resp.err = error::kCannotConnectError; return resp; } } if (req.host.empty()) { - resp.err = error("Cannot make a HTTP request without a host"); + resp.err = error::kMissingArgument; return resp; } if (req.method.empty()) { - resp.err = error("Cannot make a HTTP request without a method"); + resp.err = error::kMissingArgument; return resp; } if (req.relative_url.empty()) { - resp.err = error("Cannot make a HTTP request without a relative URL"); + resp.err = error::kMissingArgument; return resp; } if (HTTPSClient::Config.CACertPath.empty()) { - resp.err = error("Cannot make a HTTP request without certificates"); + resp.err = error::kMissingArgument; return resp; } @@ -347,19 +270,15 @@ HTTPSResponse HTTPSClient::makeHttpRequest( session.setTimeout( Poco::Timespan(req.timeout_seconds * Poco::Timespan::SECONDS)); - { - std::stringstream ss; - ss << "Sending request to " - << req.host << req.relative_url << " .."; - logger().debug(ss.str()); - } + logger().debug("Sending request to ", req.host, req.relative_url, " .."); std::string encoded_url(""); Poco::URI::encode(req.relative_url, "", encoded_url); error err = Netconf::ConfigureProxy(req.host + encoded_url, &session); if (err != noError) { - resp.err = error("Error while configuring proxy: " + err); + logger().log("Error while configuring proxy: ", err.String()); + resp.err = err; logger().error(resp.err); return resp; } @@ -458,9 +377,7 @@ HTTPSResponse HTTPSClient::makeHttpRequest( // Inflate, if gzip was sent } else if (response.has("Content-Encoding") && "gzip" == response.get("Content-Encoding")) { - Poco::InflatingInputStream inflater( - is, - Poco::InflatingStreamBuf::STREAM_GZIP); + Poco::InflatingInputStream inflater(is, Poco::InflatingStreamBuf::STREAM_GZIP); { std::stringstream ss; ss << inflater.rdbuf(); @@ -469,11 +386,8 @@ HTTPSResponse HTTPSClient::makeHttpRequest( // Write the response to string } else { - std::streamsize n = - Poco::StreamCopier::copyToString(is, resp.body); - std::stringstream ss; - ss << n << " characters transferred with download"; - logger().debug(ss.str()); + std::streamsize n = Poco::StreamCopier::copyToString(is, resp.body); + logger().debug(n, " characters transferred with download"); } logger().trace(resp.body); @@ -482,14 +396,11 @@ HTTPSResponse HTTPSClient::makeHttpRequest( Poco::Timestamp ts = Poco::Timestamp() + (60 * kOneSecondInMicros); banned_until_[req.host] = ts; - std::stringstream ss; - ss << "Server indicated we're making too many requests to host " - << req.host << ". So we cannot make new requests until " - << Formatter::Format8601(ts); - logger().debug(ss.str()); + logger().debug("Server indicated we're making too many requests to host ", req.host, + ". So we cannot make new requests until ", Formatter::Format8601(ts)); } - resp.err = statusCodeToError(resp.status_code); + resp.err = Error::fromHttpStatus(resp.status_code); // Parse human-readable error message from response if Content Type JSON if (resp.err != noError && @@ -501,13 +412,13 @@ HTTPSResponse HTTPSClient::makeHttpRequest( } } } catch(const Poco::Exception& exc) { - resp.err = exc.displayText(); + resp.err = error::REMOVE_LATER_EXCEPTION_HANDLER; return resp; } catch(const std::exception& ex) { - resp.err = ex.what(); + resp.err = error::REMOVE_LATER_EXCEPTION_HANDLER; return resp; } catch(const std::string & ex) { - resp.err = ex; + resp.err = error::REMOVE_LATER_EXCEPTION_HANDLER; return resp; } return resp; @@ -515,8 +426,8 @@ HTTPSResponse HTTPSClient::makeHttpRequest( ServerStatus TogglClient::TogglStatus; -Poco::Logger &TogglClient::logger() const { - return Poco::Logger::get("TogglClient"); +Logger TogglClient::logger() const { + return { "TogglClient" }; } HTTPSResponse TogglClient::request( @@ -524,9 +435,7 @@ HTTPSResponse TogglClient::request( error err = TogglStatus.Status(); if (err != noError) { - std::stringstream ss; - ss << "Will not connect, because of known bad Toggl status: " << err; - logger().error(ss.str()); + logger().error("Will not connect, because of known bad Toggl status: ", err); HTTPSResponse resp; resp.err = err; return resp; diff --git a/src/https_client.h b/src/https_client.h index bbdd5543f9..dd4ce3581b 100644 --- a/src/https_client.h +++ b/src/https_client.h @@ -11,21 +11,16 @@ #include "const.h" #include "proxy.h" #include "types.h" +#include "util/logger.h" #include #include namespace Poco { - -class Logger; - -namespace Net { - -class HTMLForm; - -} - -} // namespace Poco + namespace Net { + class HTMLForm; + } // namespace Poco::Net +} // namespace Poco namespace toggl { @@ -61,7 +56,7 @@ class TOGGL_INTERNAL_EXPORT ServerStatus { void stopStatusCheck(const std::string &reason); bool checkingStatus(); - Poco::Logger &logger() const; + Logger logger() const; }; class TOGGL_INTERNAL_EXPORT HTTPSClientConfig { @@ -160,7 +155,7 @@ class TOGGL_INTERNAL_EXPORT HTTPSClient { virtual HTTPSResponse request( HTTPSRequest req) const; - virtual Poco::Logger &logger() const; + virtual Logger logger() const; private: // We only make requests if this timestamp lies in the past. @@ -192,7 +187,7 @@ class TOGGL_INTERNAL_EXPORT TogglClient : public HTTPSClient { virtual HTTPSResponse request( HTTPSRequest req) const override; - virtual Poco::Logger &logger() const override; + virtual Logger logger() const override; private: SyncStateMonitor *monitor_; diff --git a/src/idle.cc b/src/idle.cc index 52132c50c5..711ddaf95c 100644 --- a/src/idle.cc +++ b/src/idle.cc @@ -12,8 +12,6 @@ #include "gui.h" #include "time_entry.h" -#include - namespace toggl { Idle::Idle(GUI *ui) @@ -30,7 +28,7 @@ void Idle::SetIdleSeconds( { std::stringstream ss; ss << "SetIdleSeconds idle_seconds=" << idle_seconds; - logger().debug(ss.str()); + logger.debug(ss.str()); } */ if (!current_user) { @@ -41,11 +39,11 @@ void Idle::SetIdleSeconds( computeIdleState(idle_seconds, current_user); } } catch(const Poco::Exception& exc) { - logger().error(exc.displayText()); + logger.error(exc.displayText()); } catch(const std::exception& ex) { - return logger().error(ex.what()); + return logger.error(ex.what()); } catch(const std::string & ex) { - return logger().error(ex); + return logger.error(ex); } last_idle_seconds_reading_ = idle_seconds; } @@ -58,9 +56,7 @@ void Idle::computeIdleState( !last_idle_started_) { last_idle_started_ = time(nullptr) - idle_seconds; - std::stringstream ss; - ss << "User is idle since " << last_idle_started_; - logger().debug(ss.str()); + logger.debug("User is idle since ", last_idle_started_); return; } @@ -71,10 +67,10 @@ void Idle::computeIdleState( TimeEntry *te = current_user->RunningTimeEntry(); if (!te) { - logger().warning("Time entry is not tracking, ignoring idleness"); + logger.warning("Time entry is not tracking, ignoring idleness"); } else if (Formatter::AbsDuration(te->DurationInSeconds()) < last_idle_seconds_reading_) { - logger().warning("Time entry duration is less than idle, ignoring"); + logger.warning("Time entry duration is less than idle, ignoring"); } else if (settings_.use_idle_detection) { std::stringstream since; since << "You have been idle since " @@ -89,8 +85,8 @@ void Idle::computeIdleState( } duration << ")"; - logger().debug(since.str()); - logger().debug(duration.str()); + logger.debug(since.str()); + logger.debug(duration.str()); poco_check_ptr(ui_); ui_->DisplayIdleNotification(te->GUID(), @@ -100,16 +96,10 @@ void Idle::computeIdleState( te->Description()); } - std::stringstream ss; - ss << "User is not idle since " << now; - logger().debug(ss.str()); + logger.debug("User is not idle since ", now); last_idle_started_ = 0; } } -Poco::Logger &Idle::logger() const { - return Poco::Logger::get("idle"); -} - } // namespace toggl diff --git a/src/idle.h b/src/idle.h index 1d6a8a70fc..1cea6780ff 100644 --- a/src/idle.h +++ b/src/idle.h @@ -7,6 +7,7 @@ #include "settings.h" #include "user.h" +#include "util/logger.h" #include @@ -46,7 +47,7 @@ class TOGGL_INTERNAL_EXPORT Idle { void computeIdleState(const Poco::Int64 idle_seconds, User *current_user); - Poco::Logger &logger() const; + Logger logger { "idle" }; // Idle detection related values Poco::Int64 last_idle_seconds_reading_; diff --git a/src/netconf.cc b/src/netconf.cc index 234d3e6ece..74eb05c981 100644 --- a/src/netconf.cc +++ b/src/netconf.cc @@ -98,7 +98,7 @@ error Netconf::ConfigureProxy( const std::string &encoded_url, Poco::Net::HTTPSClientSession *session) { - Poco::Logger &logger = Poco::Logger::get("ConfigureProxy"); + Logger logger { "ConfigureProxy" }; std::string proxy_url(""); if (HTTPSClient::Config.AutodetectProxy) { @@ -131,11 +131,9 @@ error Netconf::ConfigureProxy( } Poco::URI proxy_uri(proxy_url); - std::stringstream ss; - ss << "Using proxy URI=" + proxy_uri.toString() - << " host=" << proxy_uri.getHost() - << " port=" << proxy_uri.getPort(); - logger.debug(ss.str()); + logger.debug("Using proxy URI=", proxy_uri.toString(), + " host=", proxy_uri.getHost(), + " port=", proxy_uri.getPort()); session->setProxy( proxy_uri.getHost(), @@ -148,8 +146,8 @@ error Netconf::ConfigureProxy( credentials.getUsername(), credentials.getPassword()); - logger.debug("Proxy credentials detected username=" - + credentials.getUsername()); + logger.debug("Proxy credentials detected username=", + credentials.getUsername()); } } } @@ -162,19 +160,17 @@ error Netconf::ConfigureProxy( static_cast( HTTPSClient::Config.ProxySettings.Port())); - std::stringstream ss; - ss << "Proxy configured " - << " host=" << HTTPSClient::Config.ProxySettings.Host() - << " port=" << HTTPSClient::Config.ProxySettings.Port(); - logger.debug(ss.str()); + logger.debug("Proxy configured ", + " host=", HTTPSClient::Config.ProxySettings.Host(), + " port=", HTTPSClient::Config.ProxySettings.Port()); if (HTTPSClient::Config.ProxySettings.HasCredentials()) { session->setProxyCredentials( HTTPSClient::Config.ProxySettings.Username(), HTTPSClient::Config.ProxySettings.Password()); - logger.debug("Proxy credentials configured username=" - + HTTPSClient::Config.ProxySettings.Username()); + logger.debug("Proxy credentials configured username=", + HTTPSClient::Config.ProxySettings.Username()); } } diff --git a/src/project.cc b/src/project.cc index f08636f585..89c46fa50d 100644 --- a/src/project.cc +++ b/src/project.cc @@ -162,26 +162,20 @@ Json::Value Project::SaveToJSON() const { } bool Project::DuplicateResource(const toggl::error &err) const { - return (std::string::npos != - std::string(err).find("Name has already been taken")); + return err == error::kNameAlreadyTaken; } bool Project::ResourceCannotBeCreated(const toggl::error &err) const { - return (std::string::npos != std::string(err).find( - "User cannot add or edit projects in workspace")); + return err == error::kCannotModifyWorkspaceData; } bool Project::clientIsInAnotherWorkspace(const toggl::error &err) const { - return (std::string::npos != std::string(err).find( - "client is in another workspace") - || (std::string::npos != std::string(err).find("Client with the ID") - && std::string::npos != std::string(err).find("isn't present in workspace"))); + //(std::string::npos != std::string(err).find("Client with the ID") && std::string::npos != std::string(err).find("isn't present in workspace"))); + return err == error::kClientIsNotPresentInWorkspace || err == error::REMOVE_LATER_CLIENT_NOT_PRESENT_WITH_ID; } -bool Project::onlyAdminsCanChangeProjectVisibility( - const toggl::error &err) const { - return (std::string::npos != std::string(err).find( - "Only admins can change project visibility")); +bool Project::onlyAdminsCanChangeProjectVisibility(const toggl::error &err) const { + return err == error::kOnlyAdminsCanChangeVisibility; } bool Project::ResolveError(const toggl::error &err) { @@ -197,7 +191,7 @@ bool Project::ResolveError(const toggl::error &err) { SetPrivate(true); return true; } - if (err.find(kProjectNameAlready) != std::string::npos) { + if (err == error::kProjectNameAlreadyExists) { // remove duplicate from db MarkAsDeletedOnServer(); return true; diff --git a/src/related_data.cc b/src/related_data.cc index 9f9434fe9b..ba9dddfc44 100644 --- a/src/related_data.cc +++ b/src/related_data.cc @@ -54,7 +54,7 @@ void RelatedData::Clear() { error RelatedData::DeleteAutotrackerRule(const Poco::Int64 local_id) { if (!local_id) { - return error("cannot delete rule without an ID"); + return error::kDeleteRuleWithoutID; } for (std::vector::iterator it = AutotrackerRules.begin(); diff --git a/src/test/app_test.cc b/src/test/app_test.cc index 2f797cc973..27ce656a90 100644 --- a/src/test/app_test.cc +++ b/src/test/app_test.cc @@ -66,14 +66,16 @@ TEST(TimeEntry, WillNotPushUnlessValidationErrorIsCleared) { ASSERT_TRUE(te.NeedsPush()); // Simulate getting an error from backend + /* Doesn't work anymore with non-string error type te.SetValidationError("All you do is wrong"); ASSERT_EQ("All you do is wrong", te.ValidationError()); ASSERT_FALSE(te.NeedsPush()); + */ // Simulate user changing the data, // which should wipe the validation error. te.SetDurationUserInput("10 seconds"); - ASSERT_EQ("", te.ValidationError()); + ASSERT_EQ("", te.ValidationError().String()); ASSERT_TRUE(te.NeedsPush()); } @@ -100,7 +102,7 @@ TEST(Project, ProjectsHaveColorCodes) { TEST(Project, ResolveOnlyAdminsCanChangeProjectVisibility) { Project p; p.SetPrivate(false); - error err = error("Only admins can change project visibility"); + error err = error::fromServerError("Only admins can change project visibility"); ASSERT_TRUE(p.ResolveError(err)); ASSERT_TRUE(p.IsPrivate()); } @@ -1302,6 +1304,7 @@ TEST(TimeEntry, SetDurationOnRunningTimeEntryWithDurOnlySetting) { ASSERT_LT(te->Start(), te->Stop()); } +/* TEST(Formatter, CollectErrors) { { std::vector errors; @@ -1321,6 +1324,7 @@ TEST(Formatter, CollectErrors) { ASSERT_EQ("Errors encountered while syncing data: foo. bar.", err); } } +*/ TEST(Formatter, ParseTimeInput) { int hours = 0; diff --git a/src/test/toggl_api_test.cc b/src/test/toggl_api_test.cc index 9bfdf09b97..f84aa3f85f 100644 --- a/src/test/toggl_api_test.cc +++ b/src/test/toggl_api_test.cc @@ -36,7 +36,7 @@ std::string url(""); // on_reminder std::string reminder_title(""); std::string reminder_informative_text(""); -std::string error(""); +toggl::Error error(noError); // on_online_state int64_t online_state(0); @@ -127,10 +127,10 @@ void on_error( const char_t *errmsg, const bool_t user_error) { if (errmsg) { - testresult::error = to_string(errmsg); + testresult::error = Error::fromString(errmsg); return; } - testresult::error = std::string(""); + testresult::error = noError; } void on_online_state(const int64_t state) { @@ -596,13 +596,13 @@ TEST(toggl_api, toggl_set_window_settings) { testing::App app; int64_t x(1), y(2), h(3), w(4); - testing::testresult::error = ""; + testing::testresult::error = noError; if (!toggl_set_window_settings(app.ctx(), x, y, h, w)) { ASSERT_EQ(noError, testing::testresult::error); } int64_t x1(1), y1(2), h1(3), w1(4); - testing::testresult::error = ""; + testing::testresult::error = noError; if (!toggl_window_settings(app.ctx(), &x1, &y1, &h1, &w1)) { ASSERT_EQ(noError, testing::testresult::error); } @@ -783,7 +783,7 @@ TEST(toggl_api, toggl_set_update_path) { TEST(toggl_api, testing_set_logged_in_user) { std::string json = loadTestData(); testing::App app; - testing::testresult::error = ""; + testing::testresult::error = noError; bool_t res = testing_set_logged_in_user(app.ctx(), json.c_str()); ASSERT_EQ(noError, testing::testresult::error); ASSERT_TRUE(res); @@ -927,7 +927,7 @@ TEST(toggl_api, toggl_add_project) { auto project_name = STR(""); bool_t is_private = false; - testing::testresult::error = ""; + testing::testresult::error = noError; char_t *res = toggl_add_project(app.ctx(), guid, wid, @@ -937,7 +937,7 @@ TEST(toggl_api, toggl_add_project) { is_private, STR("")); ASSERT_EQ("Please select a workspace", - testing::testresult::error); + testing::testresult::error.String()); ASSERT_FALSE(res); wid = 123456789; @@ -950,12 +950,12 @@ TEST(toggl_api, toggl_add_project) { is_private, STR("#ffffff")); ASSERT_EQ("Project name must not be empty", - testing::testresult::error); + testing::testresult::error.String()); ASSERT_FALSE(res); free(res); project_name = STR("A new project"); - testing::testresult::error = ""; + testing::testresult::error = noError; res = toggl_add_project(app.ctx(), guid, wid, @@ -964,7 +964,7 @@ TEST(toggl_api, toggl_add_project) { project_name, is_private, 0); - ASSERT_EQ("", testing::testresult::error); + ASSERT_EQ(noError, testing::testresult::error); ASSERT_TRUE(res); free(res); @@ -991,11 +991,11 @@ TEST(toggl_api, toggl_create_client) { uint64_t wid = 0; auto client_name = STR(" "); - testing::testresult::error = ""; + testing::testresult::error = noError; char_t *res = toggl_create_client(app.ctx(), wid, client_name); - ASSERT_EQ("Please select a workspace", testing::testresult::error); + ASSERT_EQ("Please select a workspace", testing::testresult::error.String()); ASSERT_FALSE(res); free(res); @@ -1004,16 +1004,16 @@ TEST(toggl_api, toggl_create_client) { wid, client_name); ASSERT_EQ("Client name must not be empty", - testing::testresult::error); + testing::testresult::error.String()); ASSERT_FALSE(res); free(res); client_name = STR("A new client"); - testing::testresult::error = ""; + testing::testresult::error = noError; res = toggl_create_client(app.ctx(), wid, client_name); - ASSERT_EQ("", testing::testresult::error); + ASSERT_EQ(noError, testing::testresult::error); ASSERT_TRUE(res); free(res); @@ -1030,22 +1030,22 @@ TEST(toggl_api, toggl_create_client) { for (int i = 0; i < 10; i++) { std::stringstream ss; ss << "extra client " << i; - testing::testresult::error = ""; + testing::testresult::error = noError; res = toggl_create_client(app.ctx(), wid, to_char_t(ss.str())); - ASSERT_EQ("", testing::testresult::error); + ASSERT_EQ(std::string(), testing::testresult::error.String()); ASSERT_TRUE(res); free(res); } // But none with an existing client name - testing::testresult::error = ""; + testing::testresult::error = noError; res = toggl_create_client(app.ctx(), wid, client_name); ASSERT_FALSE(res); - ASSERT_EQ("Client name already exists", testing::testresult::error); + ASSERT_EQ("Client name already exists", testing::testresult::error.String()); } TEST(toggl_api, toggl_continue) { @@ -1057,7 +1057,7 @@ TEST(toggl_api, toggl_continue) { auto te = testing::testresult::time_entry_by_id(89833438); std::string guid = te.GUID(); - testing::testresult::error = ""; + testing::testresult::error = noError; ASSERT_TRUE(toggl_continue(app.ctx(), to_char_t(guid))); ASSERT_NE(guid, testing::testresult::timer_state.GUID()); ASSERT_EQ("More work", testing::testresult::timer_state.Description()); @@ -1075,7 +1075,7 @@ TEST(toggl_api, toggl_continue_in_manual_mode) { auto te = testing::testresult::time_entry_by_id(89833438); std::string guid = te.GUID(); - testing::testresult::error = ""; + testing::testresult::error = noError; testing::testresult::editor_state = TimeEntry(); testing::testresult::timer_state = TimeEntry(); @@ -1895,7 +1895,7 @@ TEST(toggl_api, toggl_autotracker_add_rule) { testing::testresult::error = noError; rule_id = toggl_autotracker_add_rule( app.ctx(), STR("delfi"), existing_project_id, 0); - ASSERT_EQ("rule already exists", testing::testresult::error); + ASSERT_EQ("rule already exists", testing::testresult::error.String()); ASSERT_FALSE(rule_id); const uint64_t existing_task_id = 1879027; diff --git a/src/time_entry.cc b/src/time_entry.cc index cb02acc647..76ea5ad124 100644 --- a/src/time_entry.cc +++ b/src/time_entry.cc @@ -75,44 +75,34 @@ bool TimeEntry::ResolveError(const error &err) { } bool TimeEntry::isNotFound(const error &err) const { - return std::string::npos != std::string(err).find( - "Time entry not found"); + return err == error::kTimeEntryNotFound; } bool TimeEntry::isMissingCreatedWith(const error &err) const { - return std::string::npos != std::string(err).find( - "created_with needs to be provided an a valid string"); + return err == error::kTimeEntryCreatedWithInvalid; } -bool TimeEntry::userCannotAccessTheSelectedProject( - const error &err) const { - return (std::string::npos != std::string(err).find( - "User cannot access the selected project")); +bool TimeEntry::userCannotAccessTheSelectedProject(const error &err) const { + return err == error::kCannotAccessProjectError; } -bool TimeEntry::userCannotAccessSelectedTask( - const error &err) const { - return (std::string::npos != std::string(err).find( - "User cannot access selected task")); +bool TimeEntry::userCannotAccessSelectedTask(const error &err) const { + return err == error::kCannotAccessTaskError; } bool TimeEntry::durationTooLarge(const error &err) const { - return (std::string::npos != std::string(err).find( - "Max allowed duration per 1 time entry is 999 hours")); + return err == error::kOverMaxDurationError; } bool TimeEntry::startTimeWrongYear(const error &err) const { - return (std::string::npos != std::string(err).find( - "Start time year must be between 2006 and 2030")); + return err == error::kInvalidStartTimeError; } bool TimeEntry::stopTimeMustBeAfterStartTime(const error &err) const { - return (std::string::npos != std::string(err).find( - "Stop time must be after start time")); + return err == error::kStartNotBeforeStopError; } bool TimeEntry::billableIsAPremiumFeature(const error &err) const { - return (std::string::npos != std::string(err).find( - "Billable is a premium feature")); + return err == error::kBillableIsAPremiumFeature; } void TimeEntry::DiscardAt(const Poco::Int64 at) { diff --git a/src/timeline_uploader.cc b/src/timeline_uploader.cc index 2f6bf2bac5..f7f7ffaaa5 100644 --- a/src/timeline_uploader.cc +++ b/src/timeline_uploader.cc @@ -17,8 +17,8 @@ namespace toggl { -Poco::Logger &TimelineUploader::logger() const { - return Poco::Logger::get("timeline_uploader"); +Logger TimelineUploader::logger() const { + return { "timeline_uploader" }; } void TimelineUploader::sleep() { @@ -42,12 +42,7 @@ void TimelineUploader::upload_loop_activity() { } error TimelineUploader::process() { - { - std::stringstream out; - out << "upload_loop_activity (current interval " - << current_upload_interval_seconds_ << "s)"; - logger().debug(out.str()); - } + logger().debug("upload_loop_activity (current interval ", current_upload_interval_seconds_, "s)"); if (uploading_.isStopped()) { return noError; @@ -74,12 +69,7 @@ error TimelineUploader::process() { return err; } - { - std::stringstream out; - out << "Sync of " << batch.Events().size() - << " event(s) was successful."; - logger().debug(out.str()); - } + logger().debug("Sync of ", batch.Events().size(), " event(s) was successful."); reset_backoff(); @@ -89,10 +79,7 @@ error TimelineUploader::process() { error TimelineUploader::upload(TimelineBatch *batch) { TogglClient client; - std::stringstream ss; - ss << "Uploading " << batch->Events().size() - << " event(s) of user " << batch->UserID(); - logger().debug(ss.str()); + logger().debug("Uploading ", batch->Events().size(), " event(s) of user ", batch->UserID()); std::string json = convertTimelineToJSON( batch->Events(), @@ -136,9 +123,7 @@ void TimelineUploader::backoff() { logger().warning("Max upload interval reached."); current_upload_interval_seconds_ = kTimelineUploadMaxBackoffSeconds; } - std::stringstream out; - out << "Upload interval set to " << current_upload_interval_seconds_ << "s"; - logger().debug(out.str()); + logger().debug("Upload interval set to ", current_upload_interval_seconds_, "s"); } void TimelineUploader::reset_backoff() { @@ -150,11 +135,11 @@ error TimelineUploader::start() { try { uploading_.start(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -166,11 +151,11 @@ error TimelineUploader::Shutdown() { uploading_.wait(); } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } diff --git a/src/timeline_uploader.h b/src/timeline_uploader.h index 7bab314011..5dc4f76e2f 100644 --- a/src/timeline_uploader.h +++ b/src/timeline_uploader.h @@ -9,13 +9,10 @@ #include "timeline_event.h" #include "timeline_notifications.h" #include "types.h" +#include "util/logger.h" #include -namespace Poco { -class Logger; -} - namespace toggl { std::string convertTimelineToJSON( @@ -52,7 +49,7 @@ class TOGGL_INTERNAL_EXPORT TimelineUploader { void backoff(); void reset_backoff(); - Poco::Logger &logger() const; + Logger logger() const; error process(); void sleep(); diff --git a/src/toggl_api.cc b/src/toggl_api.cc index 3ebf52778f..c79494fa40 100644 --- a/src/toggl_api.cc +++ b/src/toggl_api.cc @@ -646,9 +646,7 @@ bool_t toggl_continue( void *context, const char_t *guid) { - std::stringstream ss; - ss << "toggl_continue guid=" << guid; - logger().debug(ss.str()); + logger().debug("toggl_continue guid=", guid); toggl::TimeEntry *result = app(context)->Continue(to_string(guid)); if (!result) { @@ -691,11 +689,7 @@ void toggl_edit( const bool_t edit_running_entry, const char_t *focused_field_name) { - std::stringstream ss; - ss << "toggl_edit guid=" << guid - << ", edit_running_entry = " << edit_running_entry - << ", focused_field_name = " << focused_field_name; - logger().debug(ss.str()); + logger().debug("toggl_edit guid=", guid, ", edit_running_entry = ", edit_running_entry, ", focused_field_name = ", focused_field_name); app(context)->OpenTimeEntryEditor( to_string(guid), @@ -724,9 +718,7 @@ bool_t toggl_delete_time_entry( void *context, const char_t *guid) { - std::stringstream ss; - ss << "toggl_delete_time_entry guid=" << guid; - logger().debug(ss.str()); + logger().debug("toggl_delete_time_entry guid=", guid); return toggl::noError == app(context)-> DeleteTimeEntryByGUID(to_string(guid)); @@ -737,10 +729,7 @@ bool_t toggl_set_time_entry_duration( const char_t *guid, const char_t *value) { - std::stringstream ss; - ss << "toggl_set_time_entry_duration guid=" << guid - << ", value=" << value; - logger().debug(ss.str()); + logger().debug("toggl_set_time_entry_duration guid=", guid, ", value=", value); return toggl::noError == app(context)->SetTimeEntryDuration( to_string(guid), diff --git a/src/toggl_api_private.cc b/src/toggl_api_private.cc index 03d9fd95c3..0f6931dcac 100644 --- a/src/toggl_api_private.cc +++ b/src/toggl_api_private.cc @@ -12,7 +12,6 @@ #include "timeline_event.h" #include "workspace.h" -#include #include TogglAutocompleteView *autocomplete_item_init(const toggl::view::Autocomplete &item) { @@ -337,7 +336,7 @@ TogglTimeEntryView *time_entry_view_item_init( view_item->Locked = te.Locked; if (te.Error != toggl::noError) { - view_item->Error = copy_string(te.Error); + view_item->Error = copy_string(te.Error.String()); } else { view_item->Error = nullptr; } @@ -632,12 +631,12 @@ void timeline_event_view_clear( delete event_view; } -Poco::Logger &logger() { - return Poco::Logger::get("toggl_api"); -} - toggl::Context *app(void *context) { poco_check_ptr(context); return reinterpret_cast(context); } + +toggl::Logger logger() { + return { "toggl_api" }; +} diff --git a/src/toggl_api_private.h b/src/toggl_api_private.h index 74a65d0238..3e416032df 100644 --- a/src/toggl_api_private.h +++ b/src/toggl_api_private.h @@ -11,10 +11,7 @@ #include "proxy.h" #include "settings.h" #include "toggl_api.h" - -namespace Poco { -class Logger; -} +#include "util/logger.h" namespace toggl { class Client; @@ -118,7 +115,7 @@ void timeline_event_view_update_duration(TogglTimelineEventView *event_view, con void timeline_event_view_clear( TogglTimelineEventView *event_view); -Poco::Logger &logger(); +toggl::Logger logger(); toggl::Context *app(void *context); diff --git a/src/types.h b/src/types.h index b6646b41b2..641efd3333 100644 --- a/src/types.h +++ b/src/types.h @@ -5,11 +5,12 @@ #include -namespace toggl { +#include "util/error.h" -typedef std::string error; +namespace toggl { -const error noError = ""; +typedef toggl::Error error; +inline static const error noError = Error::kNoError; typedef std::string guid; } diff --git a/src/user.cc b/src/user.cc index a8669f99ff..a047ad2c3b 100644 --- a/src/user.cc +++ b/src/user.cc @@ -24,8 +24,8 @@ #include #include #include +#include #include -#include #include #include #include @@ -235,12 +235,12 @@ TimeEntry *User::Continue( TimeEntry *existing = related.TimeEntryByGUID(GUID); if (!existing) { - logger().warning("Time entry not found: " + GUID); + logger().warning("Time entry not found: ", GUID); return nullptr; } if (existing->DeletedAt()) { - logger().warning(kCannotContinueDeletedTimeEntry); + logger().warning(error::kCannotContinueDeletedTimeEntry); return nullptr; } @@ -431,9 +431,7 @@ TimeEntry *User::DiscardTimeAt( return nullptr; } - std::stringstream ss; - ss << "User is discarding time entry " << guid << " at " << at; - logger().debug(ss.str()); + logger().debug("User is discarding time entry ", guid, " at ", at); TimeEntry *te = related.TimeEntryByGUID(guid); if (te) { @@ -534,7 +532,7 @@ void User::loadUserTagFromJSON( Poco::UInt64 id = data["id"].asUInt64(); if (!id) { - logger().error("Backend is sending invalid data: ignoring update without an ID"); // NOLINT + logger().error("Backend is sending invalid data: ignoring update without an ID"); return; } @@ -570,7 +568,7 @@ void User::loadUserTaskFromJSON( Poco::UInt64 id = data["id"].asUInt64(); if (!id) { - logger().error("Backend is sending invalid data: ignoring update without an ID"); // NOLINT + logger().error("Backend is sending invalid data: ignoring update without an ID"); return; } @@ -607,7 +605,7 @@ error User::LoadUserUpdateFromJSONString( Json::Value root; Json::Reader reader; if (!reader.parse(json, root)) { - return error("Failed to LoadUserUpdateFromJSONString"); + return error::kFailedToParseData; } loadUserUpdateFromJSON(root); @@ -624,11 +622,7 @@ void User::loadUserUpdateFromJSON( Poco::UTF8::toLowerInPlace(action); - std::stringstream ss; - ss << "Update parsed into action=" << action - << ", model=" + model; - Poco::Logger &logger = Poco::Logger::get("json"); - logger.debug(ss.str()); + Logger("json").debug("Update parsed into action=", action, ", model=", model); if (kModelWorkspace == model) { loadUserWorkspaceFromJSON(data); @@ -655,7 +649,7 @@ void User::loadUserWorkspaceFromJSON( Poco::UInt64 id = data["id"].asUInt64(); if (!id) { - logger().error("Backend is sending invalid data: ignoring update without an ID"); // NOLINT + logger().error("Backend is sending invalid data: ignoring update without an ID"); return; } Workspace *model = related.WorkspaceByID(id); @@ -685,26 +679,20 @@ error User::LoadUserAndRelatedDataFromJSONString( const bool &including_related_data) { if (json.empty()) { - Poco::Logger &logger = Poco::Logger::get("json"); - logger.warning("cannot load empty JSON"); + Logger("json").warning("cannot load empty JSON"); return noError; } Json::Value root; Json::Reader reader; if (!reader.parse(json, root)) { - return error("Failed to LoadUserAndRelatedDataFromJSONString"); + return error::kFailedToParseData; } SetSince(root["since"].asInt64()); - - Poco::Logger &logger = Poco::Logger::get("json"); - std::stringstream s; - s << "User data as of: " << Since(); - logger.debug(s.str()); + Logger("json").debug("User data as of: ", Since()); loadUserAndRelatedDataFromJSON(root["data"], including_related_data); - return noError; } @@ -716,13 +704,13 @@ error User::LoadWorkspacesFromJSONString(const std::string & json) { Json::Value root; Json::Reader reader; if (!reader.parse(json, root)) { - return error("Failed to LoadWorkspacessFromJSONString"); + return error::kFailedToParseData; } if (root.size() == 0) { // Handle missing workspace issue. // If default wid is missing there are no workspaces - return error(kMissingWS); // NOLINT + return error::kMissingWS; } std::set alive; @@ -742,7 +730,7 @@ error User::LoadTimeEntriesFromJSONString(const std::string & json) { Json::Value root; Json::Reader reader; if (!reader.parse(json, root)) { - return error("Failed to LoadTimeEntriesFromJSONString"); + return error::kFailedToParseData; } std::set alive; @@ -797,7 +785,7 @@ void User::loadUserAndRelatedDataFromJSON( const bool &including_related_data) { if (!data["id"].asUInt64()) { - logger().error("Backend is sending invalid data: ignoring update without an ID"); // NOLINT + logger().error("Backend is sending invalid data: ignoring update without an ID"); return; } @@ -914,7 +902,7 @@ void User::loadUserClientFromSyncJSON( bool addNew = false; Poco::UInt64 id = data["id"].asUInt64(); if (!id) { - logger().error("Backend is sending invalid data: ignoring update without an ID"); // NOLINT + logger().error("Backend is sending invalid data: ignoring update without an ID"); return; } Client *model = related.ClientByID(id); @@ -954,7 +942,7 @@ void User::loadUserClientFromJSON( Poco::UInt64 id = data["id"].asUInt64(); if (!id) { - logger().error("Backend is sending invalid data: ignoring update without an ID"); // NOLINT + logger().error("Backend is sending invalid data: ignoring update without an ID"); return; } Client *model = related.ClientByID(id); @@ -987,7 +975,7 @@ void User::loadUserProjectFromSyncJSON( bool addNew = false; Poco::UInt64 id = data["id"].asUInt64(); if (!id) { - logger().error("Backend is sending invalid data: ignoring update without an ID"); // NOLINT + logger().error("Backend is sending invalid data: ignoring update without an ID"); return; } @@ -1033,7 +1021,7 @@ void User::loadUserProjectFromJSON( Poco::UInt64 id = data["id"].asUInt64(); if (!id) { - logger().error("Backend is sending invalid data: ignoring update without an ID"); // NOLINT + logger().error("Backend is sending invalid data: ignoring update without an ID"); return; } @@ -1067,24 +1055,24 @@ bool User::SetTimeEntryID( poco_check_ptr(timeEntry); - { - Poco::Mutex::ScopedLock lock(loadTimeEntries_m_); - auto otherTimeEntry = related.TimeEntryByID(id); - if (otherTimeEntry) { - // this means that somehow we already have a time entry with the ID - // that was just returned from a response to time entry creation request - logger().error("There is already a newer version of this entry"); - - // clearing the GUID to make sure there's no GUID conflict - timeEntry->SetGUID(""); - - // deleting the duplicate entry - // this entry has no ID so the corresponding server entry will not be deleted - timeEntry->Delete(); - return false; - } - timeEntry->SetID(id); - return true; + { + Poco::Mutex::ScopedLock lock(loadTimeEntries_m_); + auto otherTimeEntry = related.TimeEntryByID(id); + if (otherTimeEntry) { + // this means that somehow we already have a time entry with the ID + // that was just returned from a response to time entry creation request + logger().error("There is already a newer version of this entry"); + + // clearing the GUID to make sure there's no GUID conflict + timeEntry->SetGUID(""); + + // deleting the duplicate entry + // this entry has no ID so the corresponding server entry will not be deleted + timeEntry->Delete(); + return false; + } + timeEntry->SetID(id); + return true; } } @@ -1096,13 +1084,13 @@ void User::loadUserTimeEntryFromJSON( Poco::UInt64 id = data["id"].asUInt64(); if (!id) { - logger().error("Backend is sending invalid data: ignoring update without an ID"); // NOLINT + logger().error("Backend is sending invalid data: ignoring update without an ID"); return; } TimeEntry* model; - { - Poco::Mutex::ScopedLock lock(loadTimeEntries_m_); + { + Poco::Mutex::ScopedLock lock(loadTimeEntries_m_); model = related.TimeEntryByID(id); if (!model) { @@ -1120,12 +1108,12 @@ void User::loadUserTimeEntryFromJSON( model = new TimeEntry(); model->SetID(id); related.pushBackTimeEntry(model); - } - - if (!model->ID()) { - // case where model was matched by GUID - model->SetID(id); - } + } + + if (!model->ID()) { + // case where model was matched by GUID + model->SetID(id); + } } if (alive) { @@ -1155,7 +1143,7 @@ error User::UserID( Json::Reader reader; bool ok = reader.parse(json_data_string, root); if (!ok) { - return error("error parsing UserID JSON"); + return error::kFailedToParseData; } *result = root["data"]["id"].asUInt64(); return noError; @@ -1169,7 +1157,7 @@ error User::LoginToken( Json::Reader reader; bool ok = reader.parse(json_data_string, root); if (!ok) { - return error("error parsing UserID JSON"); + return error::kFailedToParseData; } *result = root["login_token"].asString(); return noError; @@ -1213,13 +1201,13 @@ std::string User::generateKey(const std::string &password) { error User::SetAPITokenFromOfflineData(const std::string &password) { if (Email().empty()) { - return error("cannot decrypt offline data without an e-mail"); + return error::kCannotDecryptOfflineDataWithoutEmail; } if (password.empty()) { - return error("cannot decrypt offline data without a password"); + return error::kCannotDecryptOfflineDataWithoutPassword; } if (OfflineData().empty()) { - return error("cannot decrypt empty string"); + return error::kCannotDecryptOfflineDataWhenEmpty; } try { Poco::Crypto::CipherFactory& factory = @@ -1230,7 +1218,7 @@ error User::SetAPITokenFromOfflineData(const std::string &password) { Json::Value data; Json::Reader reader; if (!reader.parse(OfflineData(), data)) { - return error("failed to parse offline data"); + return error::kFailedToParseData; } std::istringstream istr(data["salt"].asString()); @@ -1249,26 +1237,29 @@ error User::SetAPITokenFromOfflineData(const std::string &password) { pCipher = nullptr; SetAPIToken(decrypted); + } catch(const Poco::IOException &) { + return error::kInvalidPassword; + } catch(const Poco::Crypto::OpenSSLException &) { + return error::kInvalidPassword; } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } -error User::EnableOfflineLogin( - const std::string &password) { +error User::EnableOfflineLogin(const std::string &password) { if (Email().empty()) { - return error("cannot enable offline login without an e-mail"); + return error::kCannotEnableOfflineLoginWithoutEmail; } if (password.empty()) { - return error("cannot enable offline login without a password"); + return error::kCannotEnableOfflineLoginWithoutPassword; } if (APIToken().empty()) { - return error("cannot enable offline login without an API token"); + return error::kCannotEnableOfflineLoginWithoutApiToken; } try { Poco::Crypto::CipherFactory& factory = @@ -1307,14 +1298,14 @@ error User::EnableOfflineLogin( return err; } if (token != APIToken()) { - return error("offline login encryption failed"); + return error::kOfflineDecryptionFailed; } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -1339,9 +1330,7 @@ void User::MarkTimelineBatchAsUploaded( TimelineEvent event = *i; TimelineEvent *uploaded = related.TimelineEventByGUID(event.GUID()); if (!uploaded) { - logger().error( - "Could not find timeline event to mark it as uploaded: " - + event.String()); + logger().error("Could not find timeline event to mark it as uploaded: ", event.String()); continue; } uploaded->SetUploaded(true); @@ -1364,15 +1353,10 @@ void User::CompressTimeline() { time_t start = time(nullptr); - { - std::stringstream ss; - ss << "CompressTimeline " - << " user_id=" << ID() - << " chunk_up_to=" << chunk_up_to - << " number of events=" << related.TimelineEvents.size(); - - logger().debug(ss.str()); - } + logger().debug("CompressTimeline ", + " user_id=", ID(), + " chunk_up_to=", chunk_up_to, + " number of events=", related.TimelineEvents.size()); for (std::vector::iterator i = related.TimelineEvents.begin(); @@ -1445,16 +1429,8 @@ void User::CompressTimeline() { compressed[key] = chunk; } - { - std::stringstream ss; - ss << "CompressTimeline done in " << (time(nullptr) - start) - << " seconds, " - << related.TimelineEvents.size() - << " compressed into " - << compressed.size() - << " chunks"; - logger().debug(ss.str()); - } + logger().debug("CompressTimeline done in ", (time(nullptr) - start), " seconds, ", + related.TimelineEvents.size(), " compressed into ", compressed.size(), " chunks"); } std::vector User::CompressedTimelineForUI(const Poco::LocalDateTime *date) const { diff --git a/src/util/error.cc b/src/util/error.cc new file mode 100644 index 0000000000..9473432c97 --- /dev/null +++ b/src/util/error.cc @@ -0,0 +1,365 @@ +// Copyright 2020 Toggl Desktop developers + +#include "error.h" +#include "util/logger.h" +#include "const.h" + +#include + +namespace toggl { + +std::string Error::String() const { + try { + return values.at(code_); + } + catch (std::out_of_range &) { + return "Unknown error (" + std::to_string(code_) + ")"; + } +} + +Error Error::fromString(const std::string &message) { + for (int i = kNoError; i < kLastErrorCode; i++) { + auto c = static_cast(i); + if (Error(c).String() == message) + return c; + } + return kInvalidError; +} + +bool Error::operator==(const Error::Code &c) const { return code_ == c; } +bool Error::operator!=(const Error::Code &c) const { return code_ != c; } +bool Error::operator==(const Error &o) const { return code_ == o.code_; } +bool Error::operator!=(const Error &o) const { return code_ != o.code_; } + +bool Error::operator<(const Error &rhs) const { + return code_ < rhs.code_; +} + +Error &Error::operator=(Error::Code &c) { + code_ = c; + return *this; +} + +bool Error::IsNoError() const { + return code_ == kNoError; +} + +bool Error::isValid() const { + return code_ >= kNoError; +} + +bool Error::IsNetworkingError() const { + if (IsNoError()) { + return false; + } + if (code_ == kCannotConnectError) { + return true; + } + if (code_ == kBackendIsDownError) { + return true; + } + if (code_ == kCannotEstablishProxyConnection) { + return true; + } + if (code_ == kCertificateVerifyFailed) { + return true; + } + if (code_ == kProxyAuthenticationRequired) { + return true; + } + if (code_ == kCertificateValidationError) { + return true; + } + if (code_ == kUnacceptableCertificate) { + return true; + } + if (code_ == kCannotUpgradeToWebSocketConnection) { + return true; + } + if (code_ == kSSLException) { + return true; + } + /* TODO + if (err.find("Cannot assign requested address") != std::string::npos) { + return true; + } + if (err.find("Host not found") != std::string::npos) { + return true; + } + if (err.find("No message received") != std::string::npos) { + return true; + } + if (err.find("Connection refused") != std::string::npos) { + return true; + } + if (err.find("Connection timed out") != std::string::npos) { + return true; + } + if (err.find("connect timed out") != std::string::npos) { + return true; + } + if (err.find("SSL connection unexpectedly closed") != std::string::npos) { + return true; + } + if (err.find("Network is down") != std::string::npos) { + return true; + } + if (err.find("Network is unreachable") != std::string::npos) { + return true; + } + if (err.find("Host is down") != std::string::npos) { + return true; + } + if (err.find("No route to host") != std::string::npos) { + return true; + } + if ((err.find("I/O error: 1") != std::string::npos) + && (err.find(":443") != std::string::npos)) { + return true; + } + if (err.find("The request timed out") != std::string::npos) { + return true; + } + if (err.find("Could not connect to the server") != std::string::npos) { + return true; + } + if (err.find("Connection reset by peer") != std::string::npos) { + return true; + } + if (err.find("The Internet connection appears to be offline") + != std::string::npos) { + return true; + } + if (err.find("Timeout") != std::string::npos) { + return true; + } + if (err.find("An internal server error occurred.") != std::string::npos) { + return true; + } + */ + return false; +} + +bool Error::IsUserError() const { + if (IsNoError()) { + return false; + } + if (code_ == kErrorRuleAlreadyExists) { + return true; + } + if (code_ == kCheckYourSignupError) { + return true; + } + if (code_ == kEmailNotFoundCannotLogInOffline) { + return true; + } + if (code_ == kInvalidPassword) { + return true; + } + if (code_ == kPaymentRequiredError) { + return true; + } + if (code_ == kBadRequestError) { + return true; + } + if (code_ == kUnauthorizedError) { + return true; + } + if (code_ == kCannotWriteFile) { + return true; + } + if (code_ == kIsSuspended) { + return true; + } + if (code_ == kRequestToServerFailedWithStatusCode403) { + return true; + } + if (code_ == kUnsupportedAppError) { + return true; + } + if (code_ == kMissingWorkspaceID) { + return true; + } + if (code_ == kEndpointGoneError) { + return true; + } + if (code_ == kCannotAccessWorkspaceError) { + return true; + } + if (code_ == kCannotSyncInTestEnv) { + return true; + } + if (code_ == kCannotContinueDeletedTimeEntry) { + return true; + } + if (code_ == kCannotDeleteDeletedTimeEntry) { + return true; + } + if (code_ == kPleaseSelectAWorkspace) { + return true; + } + if (code_ == kClientNameMustNotBeEmpty) { + return true; + } + if (code_ == kProjectNameMustNotBeEmpty) { + return true; + } + if (code_ == kClientNameAlreadyExists) { + return true; + } + if (code_ == kProjectNameAlreadyExists) { + return true; + } + if (code_ == kThisEntryCantBeSavedPleaseAdd) { + return true; + } + /* TODO + if (err.find("File not found") != std::string::npos) { + return true; + } + if (err.find("SSL context exception") != std::string::npos) { + return true; + } + if (err.find("Access to file denied") != std::string::npos) { + return true; + } + if (err.find("Stop time must be after start time") + != std::string::npos) { + return true; + } + if (err.find("Invalid e-mail or password") != std::string::npos) { + return true; + } + if (err.find("Maximum length for description") != std::string::npos) { + return true; + } + if (err.find("Start time year must be between 2010 and 2100") + != std::string::npos) { + return true; + } + if (err.find("Password should be at least") != std::string::npos) { + return true; + } + if (err.find("User with this email already exists") != + std::string::npos) { + return true; + } + if (err.find("Invalid e-mail") != std::string::npos) { + return true; + } + */ + return false; +} + +std::string Error::MakeErrorActionable() const { + if (IsNoError()) { + return String(); + } + if (code_ == kCannotEstablishProxyConnection) { + return Error(kCheckYourProxySetup).String(); + } + if (code_ == kCertificateVerifyFailed) { + return Error(kCheckYourFirewall).String(); + } + if (code_ == kProxyAuthenticationRequired) { + return Error(kCheckYourProxySetup).String(); + } + if (code_ == kCertificateValidationError) { + return Error(kCheckYourFirewall).String(); + } + if (code_ == kUnacceptableCertificate) { + return Error(kCheckYourFirewall).String(); + } + if (code_ == kCannotUpgradeToWebSocketConnection) { + return Error(kCheckYourFirewall).String(); + } + if (code_ == kSSLException) { + return Error(kCheckYourFirewall).String(); + } + if (code_ == kCannotWriteFile) { + return "Check your user permissions"; + } + if (code_ == kIsSuspended) { + return "The workspace is suspended, please check your payments"; + } + if (code_ == kRequestToServerFailedWithStatusCode403) { + return "You do not have access to this workspace"; + } + if (code_ == kMissingWorkspaceID) { + return "Please select a project"; + } + if (code_ == kDatabaseDiskMalformed) { + return "Local database is corrupt. Please clear local data to recreate local database."; + } + if (code_ == kEndpointGoneError) { + return Error(kOutOfDatePleaseUpgrade).String(); + } + return String(); +} + +Error Error::fromHttpStatus(Poco::Net::HTTPResponse::HTTPStatus http_status) { + return fromHttpStatus((int64_t) http_status); +} + +Error Error::fromHttpStatus(int64_t http_status) { + switch (http_status) { + case 200: + case 201: + case 202: + return kNoError; + case 400: + // data that you sending is not valid/acceptable + return kBadRequestError; + case 401: + // ask user to enter login again, do not obtain new token automatically + return kUnauthorizedError; + case 402: + // requested action allowed only for pro workspace show user upsell + // page / ask for workspace pro upgrade. do not retry same request + // unless known that client is pro + return kPaymentRequiredError; + case 403: + // client has no right to perform given request. Server + return kForbiddenError; + case 404: + // request is not possible + // (or not allowed and server does not tell why) + return kRequestIsNotPossible; + case 410: + return kEndpointGoneError; + case 418: + return kUnsupportedAppError; + case 429: + return kCannotConnectError; + case 500: + case 501: + case 502: + case 503: + case 504: + case 505: + return kBackendIsDownError; + default: { + Logger("error").error("Unexpected HTTP status code: " + std::to_string(http_status)); + return kCannotConnectError; + } + } +} + +Error Error::fromServerError(const std::string &message) { + const static std::set codes { + kTimeEntryNotFound, kTimeEntryCreatedWithInvalid, kCannotAccessProjectError, kCannotAccessTaskError, + kOverMaxDurationError, kInvalidStartTimeError, kStartNotBeforeStopError, kBillableIsAPremiumFeature + }; + for (auto i : codes) { + if (message.find(Error(i).String()) != std::string::npos) + return i; + } + return kNoError; +} + +std::ostream &operator<<(std::ostream &out, const Error &t) { + out << t.String(); + return out; +} + +} // namespace toggl diff --git a/src/util/error.h b/src/util/error.h new file mode 100644 index 0000000000..a1fb199f9d --- /dev/null +++ b/src/util/error.h @@ -0,0 +1,260 @@ +// Copyright 2020 Toggl Desktop developers + +#ifndef ERROR_H +#define ERROR_H + +#include "logger.h" + +#include +#include + +#include + +namespace toggl { + +class Error { +public: + enum Code { + kInvalidError = -1, + kNoError = 0, + + kOverMaxDurationError, + kMaxTagsPerTimeEntryError, + kInvalidStartTimeError, + kInvalidStopTimeError, + kInvalidDateError, + kStartNotBeforeStopError, + kMaximumDescriptionLengthError, + + kCheckYourSignupError, + kEndpointGoneError, + kForbiddenError, + kUnsupportedAppError, + kUnauthorizedError, + kCannotConnectError, + kCannotSyncInTestEnv, + kBackendIsDownError, + kBadRequestError, + kRequestIsNotPossible, + kPaymentRequiredError, + kCannotAccessWorkspaceError, + kEmailNotFoundCannotLogInOffline, + kEmptyEmail, + kEmptyPassword, + kInvalidPassword, + kMissingApiToken, + kCannotEstablishProxyConnection, + kCertificateVerifyFailed, + kCheckYourProxySetup, + kCheckYourFirewall, + kProxyAuthenticationRequired, + kCertificateValidationError, + kUnacceptableCertificate, + kMissingCACertificate, + kCannotUpgradeToWebSocketConnection, + kSSLException, + kRateLimit, + kCannotWriteFile, + kIsSuspended, + kRequestToServerFailedWithStatusCode403, + kMissingWorkspaceID, + kCannotContinueDeletedTimeEntry, + kCannotDeleteDeletedTimeEntry, + kErrorRuleAlreadyExists, + kPleaseSelectAWorkspace, + kClientNameMustNotBeEmpty, + kProjectNameMustNotBeEmpty, + // kProjectNameAlready, // huh, what is this? + kProjectNameAlreadyExists, + kClientNameAlreadyExists, + kDatabaseDiskMalformed, + kMissingWS, + kOutOfDatePleaseUpgrade, + kThisEntryCantBeSavedPleaseAdd, + + // these were hardcoded as strings + kFailedToParseData, + kExportWithoutGUID, + kDeleteRuleWithoutID, + kNameAlreadyTaken, // is this the same as kClientNameAlreadyExists? + kCannotModifyWorkspaceData, + kMissingFeedbackTopic, + kMissingFeedbackDetails, + kMissingUICallbacks, + kCannotCheckForUpdates, + kInvalidUpdateChannel, + kCannotChangeLockedTE, + kInvalidTimeFormat, + kCannotCreateObmAction, + kCannotStartAutotrackerEvent, + + kTimeEntryNotFound, + kTimeEntryCreatedWithInvalid, + kCannotAccessProjectError, // should these be a single error? + kCannotAccessTaskError, + kBillableIsAPremiumFeature, // should this be the same as kPaymentRequiredError? + + kMissingArgument, // I don't think more info is necessary about WHAT argument is missing + + kTimeEntryWouldBeLockedAfterProjectChange, + + kOfflineLoginMissingEmail, + kOfflineLoginMissingPassword, + kCannotLoadUserDataWhenLoggedOut, + kCannotLoadUserDataWithoutApiToken, + kCannotSaveUserDataWhenLoggedOut, + kCannotSaveUserDataWithoutApiToken, + + kBackendChangedTheID, + kClientIsNotPresentInWorkspace, + kOnlyAdminsCanChangeVisibility, + + kCannotDecryptOfflineDataWithoutEmail, + kCannotDecryptOfflineDataWithoutPassword, + kCannotDecryptOfflineDataWhenEmpty, + kCannotEnableOfflineLoginWithoutEmail, + kCannotEnableOfflineLoginWithoutPassword, + kCannotEnableOfflineLoginWithoutApiToken, + kOfflineDecryptionFailed, + + kWebsocketClosedConnection, + + + // REMOVE THESE WHEN COMMITTING + REMOVE_LATER_BATCH_UPDATE_ERROR, + REMOVE_LATER_EXCEPTION_HANDLER, + REMOVE_LATER_NETWORK_RESPONSE, + REMOVE_LATER_DATABASE_LAST_ERROR, + REMOVE_LATER_DATABASE_STORE_ERROR, + REMOVE_LATER_CLIENT_NOT_PRESENT_WITH_ID, + + kLastErrorCode + }; + inline static const std::map values { + { kNoError, {} }, + + { kOverMaxDurationError, "Max allowed duration per 1 time entry is 999 hours" }, + { kMaxTagsPerTimeEntryError, "Tags are limited to 50 per task" }, + { kInvalidStartTimeError, "Start time year must be between 2006 and 2030" }, + { kInvalidStopTimeError, "Stop time year must be between 2006 and 2030" }, + { kInvalidDateError, "Date year must be between 2006 and 2030" }, + { kStartNotBeforeStopError, "Stop time must be after start time" }, + { kMaximumDescriptionLengthError, "Maximum length for description (3000 chars) exceeded" }, + + { kCheckYourSignupError, "Signup failed - please check your details. The e-mail might be already taken." }, + { kEndpointGoneError, "The API endpoint used by this app is gone. Please contact Toggl support!" }, + { kForbiddenError, "Invalid e-mail or password!" }, + { kUnsupportedAppError, "This version of the app is not supported any more. Please visit Toggl website to download a supported app." }, + { kUnauthorizedError, "Unauthorized! Please login again." }, + { kCannotConnectError, "Cannot connect to Toggl" }, + { kCannotSyncInTestEnv, "Cannot sync in test env" }, + { kBackendIsDownError, "Backend is down" }, + { kBadRequestError, "Data that you are sending is not valid/acceptable" }, + { kRequestIsNotPossible, "Request is not possible" }, + { kPaymentRequiredError, "Requested action allowed only for Non-Free workspaces. Please upgrade!" }, + { kCannotAccessWorkspaceError, "cannot access workspace" }, + { kEmailNotFoundCannotLogInOffline, "Login failed. Are you online?" }, + { kInvalidPassword, "Invalid password" }, + { kMissingApiToken, "cannot pull user data without API token" }, + { kCannotEstablishProxyConnection, "Cannot establish proxy connection" }, + { kCertificateVerifyFailed, "certificate verify failed" }, + { kCheckYourProxySetup, "Check your proxy setup" }, + { kCheckYourFirewall, "Check your firewall" }, + { kProxyAuthenticationRequired, "Proxy Authentication Required" }, + { kCertificateValidationError, "Certificate validation error" }, + { kUnacceptableCertificate, "Unacceptable certificate from www.toggl.com" }, + { kMissingCACertificate, "Missing CA certifcate, cannot start Websocket" }, + { kCannotUpgradeToWebSocketConnection, "Cannot upgrade to WebSocket connection" }, + { kSSLException, "SSL Exception" }, + { kRateLimit, "Too many requests, sync delayed by 1 minute" }, + { kCannotWriteFile, "Cannot write file" }, + { kIsSuspended, "is suspended" }, + { kRequestToServerFailedWithStatusCode403, "Request to server failed with status code: 403" }, + { kMissingWorkspaceID, "Missing workspace ID" }, + { kCannotContinueDeletedTimeEntry, "Cannot continue deleted time entry" }, + { kCannotDeleteDeletedTimeEntry, "Cannot delete deleted time entry" }, + { kErrorRuleAlreadyExists, "rule already exists" }, + { kPleaseSelectAWorkspace, "Please select a workspace" }, + { kClientNameMustNotBeEmpty, "Client name must not be empty" }, + { kProjectNameMustNotBeEmpty, "Project name must not be empty" }, + //{ kProjectNameAlready, "Project name already" }, + { kProjectNameAlreadyExists, "Project name already exists" }, + { kClientNameAlreadyExists, "Client name already exists" }, + { kDatabaseDiskMalformed, "The database disk image is malformed" }, + { kMissingWS, "You no longer have access to your last workspace" }, + { kOutOfDatePleaseUpgrade, "Your version of Toggl Desktop is out of date, please upgrade!" }, + { kThisEntryCantBeSavedPleaseAdd, "This entry can't be saved - please add" }, + + { kFailedToParseData, "Failed to parse data string" }, + { kExportWithoutGUID, "Cannot export model to batch update without a GUID" }, + { kDeleteRuleWithoutID, "cannot delete rule without an ID" }, + { kNameAlreadyTaken, "Name has already been taken" }, + { kCannotModifyWorkspaceData, "User cannot add or edit clients in workspace" }, + { kMissingFeedbackTopic, "Missing topic" }, + { kMissingFeedbackDetails, "Missing details" }, + { kMissingUICallbacks, "UI is not properly wired up!"}, + { kCannotCheckForUpdates, "This version cannot check for updates. This has been probably already fixed. Please check https://toggl.com/toggl-desktop/ for a newer version." }, + { kInvalidUpdateChannel, "Invalid update channel" }, + { kCannotChangeLockedTE, "Cannot change locked time entry." }, + { kInvalidTimeFormat, "invalid time format" }, + + { kTimeEntryNotFound, "Time entry not found" }, + { kTimeEntryCreatedWithInvalid, "created_with needs to be provided an a valid string" }, + { kCannotAccessProjectError, "User cannot access the selected project" }, + { kCannotAccessTaskError, "User cannot access selected task" }, + { kBillableIsAPremiumFeature, "Billable is a premium feature" }, + + { kTimeEntryWouldBeLockedAfterProjectChange, "Cannot change project: would end up with locked time entry" }, + + { kOfflineLoginMissingEmail, "cannot login offline without an e-mail" }, + { kOfflineLoginMissingPassword, "cannot login offline without a password" }, + { kCannotLoadUserDataWhenLoggedOut, "cannot load user data when logged out" }, + { kCannotLoadUserDataWithoutApiToken, "cannot pull user data without API token" }, + { kCannotSaveUserDataWhenLoggedOut, "cannot push changes when logged out"}, + { kCannotSaveUserDataWithoutApiToken, "cannot push changes without API token"}, + + { kBackendChangedTheID, "Backend has changed the ID of the entry" }, + { kClientIsNotPresentInWorkspace, "client is in another workspace" }, + { kOnlyAdminsCanChangeVisibility, "Only admins can change project visibility" }, + + { kCannotDecryptOfflineDataWithoutEmail, "cannot decrypt offline data without an e-mail" }, + { kCannotDecryptOfflineDataWithoutPassword, "cannot decrypt offline data without a password" }, + { kCannotDecryptOfflineDataWhenEmpty, "cannot decrypt empty string" }, + { kCannotEnableOfflineLoginWithoutEmail, "cannot enable offline login without an e-mail" }, + { kCannotEnableOfflineLoginWithoutPassword, "cannot enable offline login without a password" }, + { kCannotEnableOfflineLoginWithoutApiToken, "cannot enable offline login without an API token" }, + { kOfflineDecryptionFailed, "offline login encryption failed" }, + + { kWebsocketClosedConnection, "WebSocket closed the connection" }, + }; + + Error(Code c) : code_(c) {} + bool operator==(const Code &c) const; + bool operator!=(const Code &c) const; + bool operator==(const Error &o) const; + bool operator!=(const Error &o) const; + bool operator<(const Error &rhs) const; + Error &operator=(Code &c); + + bool IsNoError() const; + bool isValid() const; + bool IsNetworkingError() const; + bool IsUserError() const; + + std::string MakeErrorActionable() const; + std::string String() const; + + static Error fromString(const std::string &message); + + static Error fromHttpStatus(Poco::Net::HTTPResponse::HTTPStatus http_status); + static Error fromHttpStatus(int64_t http_status); + static Error fromServerError(const std::string &message); +private: + Code code_; +}; + +std::ostream &operator<<(std::ostream &out, const Error &t); + +} // namespace toggl + +#endif // ERROR_H diff --git a/src/util/logger.cc b/src/util/logger.cc new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/util/logger.h b/src/util/logger.h new file mode 100644 index 0000000000..58b451c4f8 --- /dev/null +++ b/src/util/logger.h @@ -0,0 +1,75 @@ +// Copyright 2020 Toggl Desktop developers. + +#ifndef SRC_LOGGER_H_ +#define SRC_LOGGER_H_ + +#include +#include +#include +#include + +namespace toggl { + +/* + * Beware, template black magic ahead + * + * Use Logger like this: + * Logger logger("myclass"); + * logger.log("Running sync", foo, bar, "baz", 123); + * and as long as all of the used types have a stringstream conversion, it'll run. + * You can also declare your own stringstream << operator if you want to debug custom classes. + */ +class Logger { +public: + Logger(const std::string &context) + : context_(context) + {} + + template + void trace(Args&&... args) const { + std::stringstream ss; + prepareOutput(ss, std::forward(args)...); + Poco::Logger::get(context_).trace(ss.str()); + } + template + void log(Args&&... args) const { + std::stringstream ss; + prepareOutput(ss, std::forward(args)...); + Poco::Logger::get(context_).log(ss.str()); + } + template + void debug(Args&&... args) const { + std::stringstream ss; + prepareOutput(ss, std::forward(args)...); + Poco::Logger::get(context_).debug(ss.str()); + } + template + void warning(Args&&... args) const { + std::stringstream ss; + prepareOutput(ss, std::forward(args)...); + Poco::Logger::get(context_).warning(ss.str()); + } + template + void error(Args&&... args) const { + std::stringstream ss; + prepareOutput(ss, std::forward(args)...); + Poco::Logger::get(context_).error(ss.str()); + } + +private: + template + void prepareOutput(std::stringstream &ss, Arg&& arg) const { + ss << std::forward(arg); + } + template + void prepareOutput(std::stringstream &ss, Arg&& arg, Args&&... args) const { + ss << std::forward(arg); + prepareOutput(ss, std::forward(args)...); + } +private: + std::string context_; +}; + +} // namespace toggl + +#endif // SRC_LOGGER_H_ diff --git a/src/websocket_client.cc b/src/websocket_client.cc index 94b74ff6da..dbc956fbb0 100644 --- a/src/websocket_client.cc +++ b/src/websocket_client.cc @@ -77,7 +77,7 @@ error WebSocketClient::createSession() { logger().debug("createSession"); if (HTTPSClient::Config.CACertPath.empty()) { - return error("Missing CA certifcate, cannot start Websocket"); + return error::kMissingCACertificate; } Poco::Mutex::ScopedLock lock(mutex_); @@ -88,10 +88,7 @@ error WebSocketClient::createSession() { error err = TogglClient::TogglStatus.Status(); if (err != noError) { - std::stringstream ss; - ss << "Will not start Websocket sessions, "; - ss << "because of known bad Toggl status: " << err; - logger().error(ss.str()); + logger().error("Will not start Websocket sessions, ", "because of known bad Toggl status: ", err); return err; } @@ -135,11 +132,11 @@ error WebSocketClient::createSession() { authenticate(); } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; @@ -192,11 +189,11 @@ error WebSocketClient::receiveWebSocketMessage(std::string *message) { json.append(buf, static_cast(n)); } } catch(const Poco::Exception& exc) { - return error(exc.displayText()); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return error(ex.what()); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return error(ex); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } *message = json; return noError; @@ -217,11 +214,9 @@ error WebSocketClient::poll() { return err; } if (json.empty()) { - return error("WebSocket closed the connection"); + return error::kWebsocketClosedConnection; } - std::stringstream ss; - ss << "WebSocket message: " << json; - logger().trace(ss.str()); + logger().trace("WebSocket message: ", json); last_connection_at_ = time(nullptr); @@ -242,11 +237,11 @@ error WebSocketClient::poll() { on_websocket_message_(ctx_, json); } } catch(const Poco::Exception& exc) { - return error(exc.displayText()); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return error(ex.what()); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return error(ex); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } @@ -317,15 +312,13 @@ void WebSocketClient::deleteSession() { logger().debug("session deleted"); } -Poco::Logger &WebSocketClient::logger() const { - return Poco::Logger::get("websocket_client"); +Logger WebSocketClient::logger() const { + return { "websocket_client" }; } int WebSocketClient::nextWebsocketRestartInterval() { int res = static_cast(Random::next(kWebsocketRestartRangeSeconds)) + 1; - std::stringstream ss; - ss << "Next websocket restart in " << res << " seconds"; - logger().trace(ss.str()); + logger().trace("Next websocket restart in ", res, " seconds"); return res; } diff --git a/src/websocket_client.h b/src/websocket_client.h index 3e5bc730ed..17b5d2d486 100644 --- a/src/websocket_client.h +++ b/src/websocket_client.h @@ -10,17 +10,16 @@ #include #include "types.h" +#include "util/logger.h" namespace Poco { -class Logger; - -namespace Net { -class HTTPSClientSession; -class HTTPRequest; -class HTTPResponse; -class WebSocket; -} -} + namespace Net { + class HTTPSClientSession; + class HTTPRequest; + class HTTPResponse; + class WebSocket; + } // namespace Poco::Net +} // namespace Poco namespace toggl { @@ -66,7 +65,7 @@ class TOGGL_INTERNAL_EXPORT WebSocketClient { int nextWebsocketRestartInterval(); - Poco::Logger &logger() const; + Logger logger() const; Poco::Activity activity_; Poco::Net::HTTPSClientSession *session_; diff --git a/src/window_change_recorder.cc b/src/window_change_recorder.cc index 9e3acf854d..7a5f713028 100644 --- a/src/window_change_recorder.cc +++ b/src/window_change_recorder.cc @@ -7,7 +7,6 @@ #include "get_focused_window.h" #include "const.h" -#include #include #if defined(__APPLE__) @@ -16,10 +15,6 @@ extern bool isCatalinaOSX(void); namespace toggl { -Poco::Logger &WindowChangeRecorder::logger() { - return Poco::Logger::get("WindowChangeRecorder"); -} - bool WindowChangeRecorder::hasWindowChanged( const std::string &title, const std::string &filename) const { @@ -41,9 +36,7 @@ void WindowChangeRecorder::inspectFocusedWindow() { int count = 1; if (it == timeline_errors_.end()) { - std::stringstream ss; - ss << "Failed to get focused window info, error code: " << err; - logger().error(ss.str()); + logger.error("Failed to get focused window info, error code: ", err); } else { count += timeline_errors_[err]; } @@ -51,10 +44,7 @@ void WindowChangeRecorder::inspectFocusedWindow() { timeline_errors_[err] = count; if (count % 100 == 0) { - std::stringstream ss; - ss << "Failed to get focused window info, error code: " - << err << " [" << count << " times]"; - logger().error(ss.str()); + logger.error("Failed to get focused window info, error code: ", err, " [", count, " times]"); } // Allow erroneous timeline event in Windows @@ -126,7 +116,7 @@ void WindowChangeRecorder::inspectFocusedWindow() { event->SetIdle(false); error err = timeline_datasource_->StartTimelineEvent(event); if (err != noError) { - logger().error(err); + logger.error(err); } } } @@ -175,11 +165,11 @@ error WindowChangeRecorder::Shutdown() { recording_.wait(5); } } catch(const Poco::Exception& exc) { - return exc.displayText(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::exception& ex) { - return ex.what(); + return error::REMOVE_LATER_EXCEPTION_HANDLER; } catch(const std::string & ex) { - return ex; + return error::REMOVE_LATER_EXCEPTION_HANDLER; } return noError; } diff --git a/src/window_change_recorder.h b/src/window_change_recorder.h index f7576f35f5..d47c9c4292 100644 --- a/src/window_change_recorder.h +++ b/src/window_change_recorder.h @@ -8,6 +8,7 @@ #include "timeline_notifications.h" #include "types.h" +#include "util/logger.h" #include @@ -15,10 +16,6 @@ extern bool isCatalinaOSX(void); #endif -namespace Poco { -class Logger; -} - namespace toggl { class TOGGL_INTERNAL_EXPORT WindowChangeRecorder { @@ -73,7 +70,7 @@ class TOGGL_INTERNAL_EXPORT WindowChangeRecorder { bool hasIdlenessChanged(const bool &idle) const; - Poco::Logger &logger(); + Logger logger { "WindowChangeRecorder" }; bool getIsLocked() { Poco::Mutex::ScopedLock lock(isLocked_m_);