Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,9 @@
from .typing_extension import Handler, Middleware

DEFAULT_API_VERSION = "v0"
_FMSG_INTERNAL_ERROR_USER_FRIENDLY_WITH_OEC = (
_FMSG_INTERNAL_ERROR_USER_FRIENDLY = (
"We apologize for the inconvenience. "
"Our team has recorded the issue [SupportID={error_code}]. "
"If the issue persists please report it."
"The issue has been recorded, please report it if it persists."
)


Expand All @@ -52,7 +51,7 @@ def _process_and_raise_unexpected_error(request: web.BaseRequest, err: Exception
"request.path": f"{request.path}",
}

user_error_msg = _FMSG_INTERNAL_ERROR_USER_FRIENDLY_WITH_OEC.format(
user_error_msg = _FMSG_INTERNAL_ERROR_USER_FRIENDLY.format(
error_code=error_code
)
http_error = create_http_error(
Expand Down
10 changes: 0 additions & 10 deletions packages/service-library/tests/aiohttp/test_rest_middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,9 @@
import pytest
from aiohttp import web
from aiohttp.test_utils import TestClient
from common_library.error_codes import parse_error_codes
from common_library.json_serialization import json_dumps
from servicelib.aiohttp import status
from servicelib.aiohttp.rest_middlewares import (
_FMSG_INTERNAL_ERROR_USER_FRIENDLY_WITH_OEC,
envelope_middleware_factory,
error_middleware_factory,
)
Expand Down Expand Up @@ -234,14 +232,6 @@ async def test_raised_unhandled_exception(
assert not data
assert error

# user friendly message with OEC reference
assert "OEC" in error["message"]
parsed_oec = parse_error_codes(error["message"]).pop()
assert (
_FMSG_INTERNAL_ERROR_USER_FRIENDLY_WITH_OEC.format(error_code=parsed_oec)
== error["message"]
)

# avoids details
assert not error.get("errors")
assert not error.get("logs")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,35 @@ qx.Class.define("osparc.FlashMessenger", {
console.error(error);
}
const msg = this.extractMessage(error, defaultMessage);
return this.getInstance().logAs(msg, "ERROR", duration);
const flashMessage = this.getInstance().logAs(msg, "ERROR", duration);
if (error && error["supportId"]) {
flashMessage.addWidget(this.__createCopyOECWidget(msg, error["supportId"]));
flashMessage.setDuration(flashMessage.getDuration()*2);
}
return flashMessage;
},

__createCopyOECWidget: function(message, supportId) {
const errorLabel = new qx.ui.basic.Atom().set({
label: supportId,
icon: "@FontAwesome5Solid/copy/10",
iconPosition: "right",
gap: 8,
cursor: "pointer",
alignX: "center",
allowGrowX: false,
});
errorLabel.addListener("tap", () => {
const dataToClipboard = {
message,
supportId,
timestamp: new Date().toString(),
url: window.location.href,
studyId: osparc.store.Store.getInstance().getCurrentStudy() || "",
}
osparc.utils.Utils.copyTextToClipboard(JSON.stringify(dataToClipboard));
});
return errorLabel;
},
},

Expand Down Expand Up @@ -143,14 +171,9 @@ qx.Class.define("osparc.FlashMessenger", {
}
this.__displayedMessagesCount++;

let duration = flashMessage.getDuration();
if (duration === null) {
const message = flashMessage.getMessage();
const wordCount = message.split(" ").length;
duration = Math.max(5500, wordCount*500); // An average reader takes 300ms to read a word
}
const duration = flashMessage.getDuration();
if (duration !== 0) {
qx.event.Timer.once(() => this.removeMessage(flashMessage), this, duration);
flashMessage.timer = setTimeout(() => this.removeMessage(flashMessage), duration);
}
},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ qx.Class.define("osparc.ui.message.FlashMessage", {
*/
construct: function(message, level, duration) {
this.base(arguments);
this._setLayout(new qx.ui.layout.VBox(15));
this._setLayout(new qx.ui.layout.VBox(10));

this.set({
padding: 18,
Expand All @@ -48,14 +48,13 @@ qx.Class.define("osparc.ui.message.FlashMessage", {
textColor: this.self().LOG_LEVEL_COLOR_MAP[level].color
});

if (message) {
this.setMessage(message);
}
this.setMessage(message);

// also support duration 0: the message won't be automatically removed
if (duration != null) {
this.setDuration(duration);
if ([null, undefined].includes(duration)) {
const wordCount = message.split(" ").length;
duration = Math.max(5500, wordCount*500); // An average reader takes 300ms to read a word
}
this.setDuration(duration);

this.getChildControl("closebutton");
},
Expand All @@ -68,13 +67,14 @@ qx.Class.define("osparc.ui.message.FlashMessage", {

message: {
check: "String",
nullable: true,
apply: "__applyMessage"
nullable: false,
apply: "__applyMessage",
},

duration: {
check: "Number",
nullable: true
init: null,
nullable: true,
}
},

Expand Down Expand Up @@ -142,10 +142,7 @@ qx.Class.define("osparc.ui.message.FlashMessage", {
},

__applyMessage: function(value) {
const label = this.getChildControl("message");
if (label) {
label.setValue(value);
}
this.getChildControl("message").setValue(value);
},

addWidget: function(widget) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
from typing import Final

MSG_2FA_CODE_SENT: Final[str] = "A code was sent by SMS to {phone_number}."
MSG_2FA_UNAVAILABLE_OEC: Final[str] = (
"Two-factor authentication is temporarily unavailable. Please try again later. ({error_code})"
)
MSG_2FA_UNAVAILABLE: Final[str] = "Two-factor authentication is temporarily unavailable"
MSG_ACTIVATED: Final[str] = "Your account has been activated."
MSG_ACTIVATION_REQUIRED: Final[str] = (
"Please activate your account via the email we sent before logging in."
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
""" Core functionality and tools for user's registration
"""Core functionality and tools for user's registration

- registration code
- invitation code
- registration code
- invitation code
"""

import logging
Expand Down Expand Up @@ -214,9 +214,7 @@ def _invitations_request_context(invitation_code: str) -> Iterator[URL]:

except (ValidationError, InvalidInvitationError) as err:
error_code = create_error_code(err)
user_error_msg = (
f"Invalid invitation. {MSG_INVITATIONS_CONTACT_SUFFIX} [{error_code}]"
)
user_error_msg = f"Invalid invitation. {MSG_INVITATIONS_CONTACT_SUFFIX}"

_logger.exception(
**create_troubleshotting_log_kwargs(
Expand All @@ -233,7 +231,7 @@ def _invitations_request_context(invitation_code: str) -> Iterator[URL]:

except InvitationsServiceUnavailableError as err:
error_code = create_error_code(err)
user_error_msg = f"Unable to process your invitation since the invitations service is currently unavailable [{error_code}]"
user_error_msg = "Unable to process your invitation since the invitations service is currently unavailable"

_logger.exception(
**create_troubleshotting_log_kwargs(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@
from servicelib.mimetype_constants import MIMETYPE_APPLICATION_JSON

from ..errors import WebServerBaseError
from ._constants import MSG_2FA_UNAVAILABLE_OEC
from ._constants import MSG_2FA_UNAVAILABLE

_logger = logging.getLogger(__name__)


class LoginError(WebServerBaseError, ValueError):
...
class LoginError(WebServerBaseError, ValueError): ...


class SendingVerificationSmsError(LoginError):
Expand All @@ -32,7 +31,7 @@ async def wrapper(request: web.Request) -> web.StreamResponse:

except (SendingVerificationSmsError, SendingVerificationEmailError) as exc:
error_code = exc.error_code()
front_end_msg = MSG_2FA_UNAVAILABLE_OEC.format(error_code=error_code)
front_end_msg = MSG_2FA_UNAVAILABLE
# in these cases I want to log the cause
_logger.exception(
**create_troubleshotting_log_kwargs(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,7 @@ async def validate_confirmation_and_redirect(request: web.Request):
error_code = create_error_code(err)
user_error_msg = (
f"Sorry, we cannot confirm your {action}."
"Please try again in a few moments. "
f"If the problem persist please contact support attaching this code ({error_code})"
"Please try again in a few moments."
)

_logger.exception(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ async def register(request: web.Request):
)
except Exception as err: # pylint: disable=broad-except
error_code = create_error_code(err)
user_error_msg = f"{MSG_CANT_SEND_MAIL} [{error_code}]"
user_error_msg = MSG_CANT_SEND_MAIL

_logger.exception(
**create_troubleshotting_log_kwargs(
Expand Down Expand Up @@ -416,7 +416,7 @@ async def register_phone(request: web.Request):
except Exception as err: # pylint: disable=broad-except
# Unhandled errors -> 503
error_code = create_error_code(err)
user_error_msg = f"Currently we cannot register phone numbers [{error_code}]"
user_error_msg = "Currently we cannot register phone numbers"

_logger.exception(
**create_troubleshotting_log_kwargs(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,7 @@
MissingGroupExtraPropertiesForProductError: HttpErrorInfo(
status.HTTP_503_SERVICE_UNAVAILABLE,
"The product is not ready for use until the configuration is fully completed. "
"Please wait and try again. "
"If this issue persists, contact support indicating this support code: {error_code}.",
"Please wait and try again. ",
),
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ async def wrapper(request: web.Request) -> web.StreamResponse:
except BillingDetailsNotFoundError as exc:

error_code = create_error_code(exc)
user_error_msg = f"{MSG_BILLING_DETAILS_NOT_DEFINED_ERROR} [{error_code}]"
user_error_msg = MSG_BILLING_DETAILS_NOT_DEFINED_ERROR

_logger.exception(
**create_troubleshotting_log_kwargs(
Expand Down Expand Up @@ -155,10 +155,10 @@ async def create_wallet(request: web.Request):
async def list_wallets(request: web.Request):
req_ctx = WalletsRequestContext.model_validate(request)

wallets: list[
WalletGetWithAvailableCredits
] = await _api.list_wallets_with_available_credits_for_user(
app=request.app, user_id=req_ctx.user_id, product_name=req_ctx.product_name
wallets: list[WalletGetWithAvailableCredits] = (
await _api.list_wallets_with_available_credits_for_user(
app=request.app, user_id=req_ctx.user_id, product_name=req_ctx.product_name
)
)

return envelope_json_response(wallets)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
)
from simcore_service_webserver.login._constants import (
CODE_2FA_SMS_CODE_REQUIRED,
MSG_2FA_UNAVAILABLE_OEC,
MSG_2FA_UNAVAILABLE,
)
from simcore_service_webserver.login.storage import AsyncpgStorage
from simcore_service_webserver.products import products_web
Expand Down Expand Up @@ -456,9 +456,7 @@ async def test_2fa_sms_failure_during_login(
response, status.HTTP_503_SERVICE_UNAVAILABLE
)
assert not data
assert error["errors"][0]["message"].startswith(
MSG_2FA_UNAVAILABLE_OEC[:10]
)
assert error["errors"][0]["message"].startswith(MSG_2FA_UNAVAILABLE[:10])

# Expects logs like 'Failed while setting up 2FA code and sending SMS to 157XXXXXXXX3 [OEC:140392495277888]'
assert f"{fake_user_phone_number[:3]}" in caplog.text
Loading