diff --git a/src/cloud/clouderrors.h b/src/cloud/clouderrors.h index 35979b7cf9..fb13edc7c1 100644 --- a/src/cloud/clouderrors.h +++ b/src/cloud/clouderrors.h @@ -34,9 +34,16 @@ enum class Err { UnknownError = int(Ret::Code::CloudFirst), AccessTokenIsEmpty, - AccountNotActivated, - Conflict, - NetworkError, /// < use cloudNetworkErrorUserDescription to retrieve user-readable description + Status400_InvalidRequest, + Status401_AuthorizationRequired, + Status403_AccountNotActivated, + Status403_NotOwner, + Status404_NotFound, + Status409_Conflict, + Status422_ValidationFailed, + Status500_InternalServerError, + UnknownStatusCode, + NetworkError, CouldNotReceiveSourceUrl, }; @@ -49,25 +56,21 @@ inline Ret make_ret(Err e) case Err::NoError: return Ret(retCode); case Err::UnknownError: return Ret(retCode); case Err::AccessTokenIsEmpty: return Ret(retCode, "Access token is empty"); - case Err::AccountNotActivated: return Ret(retCode, "Account not activated"); - case Err::Conflict: return Ret(retCode, "Conflict"); + case Err::Status400_InvalidRequest: return Ret(retCode, "Status 400: invalid request"); + case Err::Status401_AuthorizationRequired: return Ret(retCode, "Status 401: authorization required"); + case Err::Status403_AccountNotActivated: return Ret(retCode, "Status 403: account not activated"); + case Err::Status403_NotOwner: return Ret(retCode, "Status 403: not owner"); + case Err::Status404_NotFound: return Ret(retCode, "Status 404: not found"); + case Err::Status409_Conflict: return Ret(retCode, "Status 409: conflict"); + case Err::Status422_ValidationFailed: return Ret(retCode, "Status 422: validation failed"); + case Err::Status500_InternalServerError: return Ret(retCode, "Status 500: internal server error"); + case Err::UnknownStatusCode: return Ret(retCode, "Unknown status code"); case Err::NetworkError: return Ret(retCode, "Network error"); case Err::CouldNotReceiveSourceUrl: return Ret(retCode, "Could not receive source url"); + break; } - return Ret(static_cast(e)); -} - -inline std::string cloudNetworkErrorUserDescription(const Ret& ret) -{ - assert(ret.code() == int(Err::NetworkError)); - - auto userDescription = ret.data(CLOUD_NETWORK_ERROR_USER_DESCRIPTION_KEY); - if (userDescription.has_value()) { - return std::any_cast(userDescription); - } - - return {}; + return Ret(retCode); } } diff --git a/src/cloud/internal/abstractcloudservice.cpp b/src/cloud/internal/abstractcloudservice.cpp index 36ec6387df..a352347867 100644 --- a/src/cloud/internal/abstractcloudservice.cpp +++ b/src/cloud/internal/abstractcloudservice.cpp @@ -366,37 +366,38 @@ Ret AbstractCloudService::uploadingDownloadingRetFromRawRet(const Ret& rawRet, b return rawRet; // OK } - int code = statusCode(rawRet); - if (!code) { - return rawRet; + int status = statusCode(rawRet); + if (status) { + switch (status) { + case 400: return make_ret(Err::Status400_InvalidRequest); + case 401: return make_ret(Err::Status401_AuthorizationRequired); + case 403: + if (isAlreadyUploaded) { + return make_ret(Err::Status403_AccountNotActivated); + } else { + return make_ret(Err::Status403_NotOwner); + } + case 404: return make_ret(Err::Status404_NotFound); + case 409: return make_ret(Err::Status409_Conflict); + case 422: return make_ret(Err::Status422_ValidationFailed); + case 500: return make_ret(Err::Status500_InternalServerError); + default: break; + } + + Ret ret = make_ret(Err::UnknownStatusCode); + ret.setText("Unknown status code: " + std::to_string(status)); + ret.setData("status", status); + return ret; } - if (!isAlreadyUploaded && code == FORBIDDEN_CODE) { - return make_ret(cloud::Err::AccountNotActivated); + switch (rawRet.code()) { + case int(network::Err::NetworkError): + case int(network::Err::Timeout): + case int(network::Err::Abort): + return make_ret(Err::NetworkError); } - if (code == CONFLICT_STATUS_CODE) { - return make_ret(cloud::Err::Conflict); - } - - static const std::map codes { - { 400, mu::TranslatableString("cloud", "Invalid request") }, - { 401, mu::TranslatableString("cloud", "Authorization required") }, - { 403, mu::TranslatableString("cloud", "Forbidden. User is not owner of the score.") }, - { 422, mu::TranslatableString("cloud", "Validation failed") }, - { 500, mu::TranslatableString("cloud", "Internal server error") }, - }; - - std::string userDescription = qtrc("cloud", "Error %1: %2") - .arg(code) - .arg(mu::value(codes, code, TranslatableString("cloud", "Unknown error")).qTranslated()) - .toStdString(); - - Ret ret = make_ret(cloud::Err::NetworkError); - ret.setData(CLOUD_NETWORK_ERROR_USER_DESCRIPTION_KEY, userDescription); - ret.setData(STATUS_KEY, code); - - return ret; + return rawRet; } int AbstractCloudService::statusCode(const mu::Ret& ret) const diff --git a/src/cloud/musescorecom/musescorecomservice.cpp b/src/cloud/musescorecom/musescorecomservice.cpp index 66e51a5dfc..e3c327dfcb 100644 --- a/src/cloud/musescorecom/musescorecomservice.cpp +++ b/src/cloud/musescorecom/musescorecomservice.cpp @@ -215,7 +215,7 @@ mu::RetVal MuseScoreComService::downloadScoreInfo(int scoreId) if (!ret) { printServerReply(receivedData); - result.ret = ret; + result.ret = uploadingDownloadingRetFromRawRet(ret); return result; } diff --git a/src/project/internal/projectactionscontroller.cpp b/src/project/internal/projectactionscontroller.cpp index 3f81f6dd41..77543e3e21 100644 --- a/src/project/internal/projectactionscontroller.cpp +++ b/src/project/internal/projectactionscontroller.cpp @@ -455,8 +455,7 @@ Ret ProjectActionsController::openScoreFromMuseScoreCom(const QUrl& url) bool isOwner = true; RetVal scoreInfo = museScoreComService()->downloadScoreInfo(scoreId); if (!scoreInfo.ret) { - std::any status = scoreInfo.ret.data("status"); - if (status.has_value() && std::any_cast(status) == 403) { + if (scoreInfo.ret.code() == int(cloud::Err::Status403_NotOwner)) { LOGI() << "Downloading score info returned 403, so not owner"; isOwner = false; } else { @@ -1497,38 +1496,60 @@ void ProjectActionsController::showScoreDownloadError(const Ret& ret) message = trc("project", "This score is invalid."); break; case int(Err::FileOpenError): - message = trc("project", "The file could not be downloaded to your disk."); + message = trc("project/cloud", "The file could not be downloaded to your disk."); break; - case int(network::Err::NetworkError): { + case int(cloud::Err::Status400_InvalidRequest): + //: %1 will be replaced with the error code that MuseScore.com returned; this might contain english text + //: that is deliberately not translated + message = qtrc("project/cloud", "MuseScore.com returned an error code: %1.") + .arg("400 Invalid request").toStdString(); + break; + case int(cloud::Err::Status401_AuthorizationRequired): + //: %1 will be replaced with the error code that MuseScore.com returned; this might contain english text + //: that is deliberately not translated + message = qtrc("project/cloud", "MuseScore.com returned an error code: %1.") + .arg("401 Authorization required").toStdString(); + break; + case int(cloud::Err::Status403_AccountNotActivated): + message = trc("project/cloud", "Your musescore.com account needs to be verified first. " + "Please activate your account via the link in the activation email."); + break; + case int(cloud::Err::Status403_NotOwner): + message = trc("project/cloud", "This score does not belong to this account. To access this score, make sure you are logged in " + "to the desktop app with the account to which this score belongs."); + break; + case int(cloud::Err::Status404_NotFound): + message = trc("project/cloud", "The score could not be found, or cannot be accessed by your account."); + break; + case int(cloud::Err::Status422_ValidationFailed): + //: %1 will be replaced with the error code that MuseScore.com returned; this might contain english text + //: that is deliberately not translated + message = qtrc("project/cloud", "MuseScore.com returned an error code: %1.") + .arg("422 Validation failed").toStdString(); + break; + case int(cloud::Err::Status500_InternalServerError): + //: %1 will be replaced with the error code that MuseScore.com returned; this might contain english text + //: that is deliberately not translated + message = qtrc("project/cloud", "MuseScore.com returned an error code: %1.") + .arg("500 Internal server error").toStdString(); + break; + case int(cloud::Err::UnknownStatusCode): { std::any status = ret.data("status"); if (status.has_value()) { - int statusCode = std::any_cast(status); - switch (statusCode) { - case 404: - message = trc("project", "The score could not be found, or cannot be accessed by your account."); - break; - default: - message = qtrc("project", "musescore.com returned error code %1.") - .arg(statusCode).toStdString(); - } + //: %1 will be replaced with the error code that MuseScore.com returned, which is a number. + message = qtrc("project/cloud", "MuseScore.com returned an unknown error code: %1.") + .arg(std::any_cast(status)).toStdString(); } else { - message = trc("project", "Could not connect to musescore.com. " - "Please check your internet connection or try again later."); + message = trc("project/cloud", "MuseScore.com returned an unknown error code."); } } break; - case int(cloud::Err::AccountNotActivated): - message = trc("project", "Your musescore.com account needs to be verified first. " - "Please activate your account via the link in the activation email."); - break; + case int(cloud::Err::NetworkError): - message = cloud::cloudNetworkErrorUserDescription(ret); - if (!message.empty()) { - message += "\n\n" + trc("project/save", "Please try again later."); - break; - } - // FALLTHROUGH + message = trc("project/cloud", "Could not connect to musescore.com. " + "Please check your internet connection or try again later."); + break; default: - message = trc("project/save", "Please try again later."); + message = trc("project/cloud", "Please try again later."); break; } diff --git a/src/project/internal/saveprojectscenario.cpp b/src/project/internal/saveprojectscenario.cpp index 8f4ac60687..c6fdfbd163 100644 --- a/src/project/internal/saveprojectscenario.cpp +++ b/src/project/internal/saveprojectscenario.cpp @@ -246,12 +246,16 @@ RetVal SaveProjectScenario::doAskCloudLocation(INotationProjec } break; - case int(cloud::Err::AccountNotActivated): + case int(cloud::Err::Status400_InvalidRequest): + case int(cloud::Err::Status403_AccountNotActivated): + case int(cloud::Err::Status422_ValidationFailed): + case int(cloud::Err::Status500_InternalServerError): + case int(cloud::Err::UnknownStatusCode): case int(cloud::Err::NetworkError): return showCloudSaveError(scoreInfo.ret, project->cloudInfo(), isPublish, false); // It's possible the source URL is invalid or points to a score on a different user's account. - // In this situation we shouldn't see an error. + // In this situation we shouldn't show an error. default: break; } } @@ -422,12 +426,26 @@ Ret SaveProjectScenario::showCloudSaveError(const Ret& ret, const CloudProjectIn int defaultButtonCode = okBtn.btn; switch (ret.code()) { - case int(cloud::Err::AccountNotActivated): - msg = trc("project/save", "Your musescore.com account needs to be verified first. " - "Please activate your account via the link in the activation email."); + case int(cloud::Err::Status400_InvalidRequest): + //: %1 will be replaced with the error code that MuseScore.com returned; this might contain english text + //: that is deliberately not translated + msg = qtrc("project/cloud", "MuseScore.com returned an error code: %1.") + .arg("400 Invalid request").toStdString(); + msg += "\n\n" + trc("project/cloud", "Please try again later, or get help for this problem on musescore.org."); + break; + case int(cloud::Err::Status401_AuthorizationRequired): + //: %1 will be replaced with the error code that MuseScore.com returned; this might contain english text + //: that is deliberately not translated + msg = qtrc("project/cloud", "MuseScore.com returned an error code: %1.") + .arg("400 Authorization required").toStdString(); + msg += "\n\n" + trc("project/cloud", "Please try again later, or get help for this problem on musescore.org."); + break; + case int(cloud::Err::Status403_AccountNotActivated): + msg = trc("project/cloud", "Your musescore.com account needs to be verified first. " + "Please activate your account via the link in the activation email."); buttons = { okBtn }; break; - case int(cloud::Err::Conflict): + case int(cloud::Err::Status409_Conflict): title = trc("project/save", "There are conflicting changes in the online score"); if (isPublish) { msg = qtrc("project/save", "You can replace the online score, or publish this as a new score " @@ -453,15 +471,37 @@ Ret SaveProjectScenario::showCloudSaveError(const Ret& ret, const CloudProjectIn defaultButtonCode = replaceBtnCode; } break; - case int(cloud::Err::NetworkError): - msg = cloud::cloudNetworkErrorUserDescription(ret); - if (!msg.empty()) { - msg += "\n\n" + trc("project/save", "Please try again later, or get help for this problem on musescore.org."); - break; + case int(cloud::Err::Status422_ValidationFailed): + //: %1 will be replaced with the error code that MuseScore.com returned; this might contain english text + //: that is deliberately not translated + msg = qtrc("project/cloud", "MuseScore.com returned an error code: %1.") + .arg("422 Validation failed").toStdString(); + msg += "\n\n" + trc("project/cloud", "Please try again later, or get help for this problem on musescore.org."); + break; + case int(cloud::Err::Status500_InternalServerError): + //: %1 will be replaced with the error code that MuseScore.com returned; this might contain english text + //: that is deliberately not translated + msg = qtrc("project/cloud", "MuseScore.com returned an error code: %1.") + .arg("500 Internal server error").toStdString(); + msg += "\n\n" + trc("project/cloud", "Please try again later, or get help for this problem on musescore.org."); + break; + case int(cloud::Err::UnknownStatusCode): { + std::any status = ret.data("status"); + if (status.has_value()) { + //: %1 will be replaced with the error code that MuseScore.com returned, which is a number. + msg = qtrc("project/cloud", "MuseScore.com returned an unknown error code: %1.") + .arg(std::any_cast(status)).toStdString(); + } else { + msg = trc("project/cloud", "MuseScore.com returned an unknown error code."); } - // FALLTHROUGH + msg += "\n\n" + trc("project/cloud", "Please try again later, or get help for this problem on musescore.org."); + } break; + case int(cloud::Err::NetworkError): + msg = trc("project/cloud", "Could not connect to musescore.com. " + "Please check your internet connection or try again later."); + break; default: - msg = trc("project/save", "Please try again later, or get help for this problem on musescore.org."); + msg = trc("project/cloud", "Please try again later, or get help for this problem on musescore.org."); break; } @@ -485,26 +525,34 @@ Ret SaveProjectScenario::showCloudSaveError(const Ret& ret, const CloudProjectIn Ret SaveProjectScenario::showAudioCloudShareError(const Ret& ret) const { - std::string title= trc("project/save", "Your audio could not be shared"); + std::string title= trc("project/share", "Your audio could not be shared"); std::string msg; IInteractive::ButtonData okBtn = interactive()->buttonData(IInteractive::Button::Ok); IInteractive::ButtonDatas buttons = IInteractive::ButtonDatas { okBtn }; switch (ret.code()) { - case int(cloud::Err::AccountNotActivated): - msg = trc("project/save", "Your audio.com account needs to be verified first. " - "Please activate your account via the link in the activation email."); + case int(cloud::Err::Status403_AccountNotActivated): + msg = trc("project/share", "Your audio.com account needs to be verified first. " + "Please activate your account via the link in the activation email."); break; - case int(cloud::Err::NetworkError): - msg = cloud::cloudNetworkErrorUserDescription(ret); - if (!msg.empty()) { - msg += "\n\n" + trc("project/save", "Please try again later, or get help for this problem on audio.com."); - break; + case int(cloud::Err::UnknownStatusCode): { + std::any status = ret.data("status"); + if (status.has_value()) { + //: %1 will be replaced with the error code that audio.com returned, which is a number. + msg = qtrc("project/share", "Audio.com returned an unknown error code: %1.") + .arg(std::any_cast(status)).toStdString(); + } else { + msg = trc("project/share", "Audio.com returned an unknown error code."); } - // FALLTHROUGH + msg += "\n\n" + trc("project/share", "Please try again later, or get help for this problem on audio.com."); + } break; + case int(cloud::Err::NetworkError): + msg = trc("project/share", "Could not connect to audio.com. " + "Please check your internet connection or try again later."); + break; default: - msg = trc("project/save", "Please try again later, or get help for this problem on audio.com."); + msg = trc("project/share", "Please try again later, or get help for this problem on audio.com."); break; }