Skip to content

Commit 5064cab

Browse files
authored
Merge branch 'master' into pr-osparc-revert7809
2 parents 55dd3f9 + bfb0c98 commit 5064cab

File tree

10 files changed

+129
-33
lines changed

10 files changed

+129
-33
lines changed

services/static-webserver/client/source/class/osparc/editor/HtmlEditor.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ qx.Class.define("osparc.editor.HtmlEditor", {
2626

2727
this.getChildControl("preview-html");
2828
this.getChildControl("subtitle").set({
29-
value: this.tr("Supports HTML")
29+
value: this.tr("Supports HTML"),
30+
url: "https://en.wikipedia.org/wiki/HTML",
3031
});
3132
},
3233

services/static-webserver/client/source/class/osparc/editor/MarkdownEditor.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ qx.Class.define("osparc.editor.MarkdownEditor", {
3131

3232
this.getChildControl("preview-markdown");
3333
this.getChildControl("subtitle").set({
34-
value: this.tr("Markdown supported")
34+
value: this.tr("Markdown supported"),
35+
url: "https://en.wikipedia.org/wiki/Markdown",
3536
});
3637
},
3738

services/static-webserver/client/source/class/osparc/editor/TextEditor.js

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,15 +81,13 @@ qx.Class.define("osparc.editor.TextEditor", {
8181
writePage.add(control, {
8282
flex: 1
8383
});
84-
const subtitle = this.getChildControl("subtitle").set({
85-
value: this.tr("Supports HTML")
86-
});
84+
const subtitle = this.getChildControl("subtitle");
8785
writePage.add(subtitle);
8886
tabs.add(writePage);
8987
break;
9088
}
9189
case "subtitle":
92-
control = new qx.ui.basic.Label().set({
90+
control = new osparc.ui.basic.LinkLabel().set({
9391
font: "text-12"
9492
});
9593
this._add(control);

services/static-webserver/client/source/class/osparc/info/CommentUI.js

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,8 @@ qx.Class.define("osparc.info.CommentUI", {
113113

114114
__buildLayout: function() {
115115
const thumbnail = this.getChildControl("thumbnail");
116-
thumbnail.setSource(osparc.utils.Avatar.emailToThumbnail("", "", 32));
117116

118117
const userName = this.getChildControl("user-name");
119-
userName.setValue("Unknown");
120118

121119
const date = new Date(this.__comment["modified"]);
122120
const date2 = osparc.utils.Utils.formatDateAndTime(date);
@@ -131,7 +129,14 @@ qx.Class.define("osparc.info.CommentUI", {
131129
if (user) {
132130
thumbnail.setSource(user.getThumbnail());
133131
userName.setValue(user.getLabel());
132+
} else {
133+
thumbnail.setSource(osparc.utils.Avatar.emailToThumbnail());
134+
userName.setValue("Unknown user");
134135
}
136+
})
137+
.catch(() => {
138+
thumbnail.setSource(osparc.utils.Avatar.emailToThumbnail());
139+
userName.setValue("Unknown user");
135140
});
136141

137142
this.getChildControl("spacer");

services/static-webserver/client/source/class/osparc/utils/Avatar.js

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,7 @@ qx.Class.define("osparc.utils.Avatar", {
3434
type: "static",
3535

3636
statics: {
37-
emailToThumbnail: function(email, username) {
38-
return this.__getUrl(email, username, 32);
39-
},
40-
41-
__getUrl: function(email, username, size = 100) {
42-
email = email || "";
37+
emailToThumbnail: function(email = "", username = "??", size = 32) {
4338
// MD5 (Message-Digest Algorithm) by WebToolkit
4439
const MD5 = function(s) {
4540
function L(k, d) {

services/static-webserver/client/source/resource/osparc/ui_config.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,11 @@
156156
"title": "${replace_me_product_name}",
157157
"newStudyLabel": "New Project",
158158
"idToWidget": "startS4LButton"
159+
}, {
160+
"resourceType": "service",
161+
"expectedKey": "simcore/services/dynamic/s4l-ui-framework",
162+
"title": "Sim4Life.framework",
163+
"newStudyLabel": "Sim4Life.framework"
159164
}]
160165
}
161166
},

services/web/server/src/simcore_service_webserver/catalog/_catalog_rest_client_service.py

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,15 @@
2121
from models_library.services_types import ServiceKey, ServiceVersion
2222
from models_library.users import UserID
2323
from pydantic import TypeAdapter
24-
from servicelib.aiohttp import status
2524
from servicelib.aiohttp.client_session import get_client_session
2625
from servicelib.rest_constants import X_PRODUCT_NAME_HEADER
26+
from simcore_service_webserver.catalog.errors import (
27+
CatalogConnectionError,
28+
CatalogResponseError,
29+
)
2730
from yarl import URL
2831

2932
from .._meta import api_version_prefix
30-
from ._constants import MSG_CATALOG_SERVICE_NOT_FOUND, MSG_CATALOG_SERVICE_UNAVAILABLE
3133
from .settings import CatalogSettings, get_plugin_settings
3234

3335
_logger = logging.getLogger(__name__)
@@ -51,16 +53,17 @@ def _handle_client_exceptions(app: web.Application) -> Iterator[ClientSession]:
5153
yield session
5254

5355
except ClientResponseError as err:
54-
if err.status == status.HTTP_404_NOT_FOUND:
55-
raise web.HTTPNotFound(text=MSG_CATALOG_SERVICE_NOT_FOUND) from err
56-
raise web.HTTPServiceUnavailable(
57-
reason=MSG_CATALOG_SERVICE_UNAVAILABLE
56+
raise CatalogResponseError(
57+
status=err.status,
58+
message=err.message,
59+
headers=err.headers,
60+
request_info=err.request_info,
5861
) from err
5962

6063
except (TimeoutError, ClientConnectionError) as err:
61-
_logger.debug("Request to catalog service failed: %s", err)
62-
raise web.HTTPServiceUnavailable(
63-
reason=MSG_CATALOG_SERVICE_UNAVAILABLE
64+
raise CatalogConnectionError(
65+
message=str(err),
66+
request_info=getattr(err, "request_info", None),
6467
) from err
6568

6669

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
from typing import Final
22

3-
MSG_CATALOG_SERVICE_UNAVAILABLE: Final[
4-
str
5-
] = "Currently catalog service is unavailable, please try again later"
3+
from ..constants import MSG_TRY_AGAIN_OR_SUPPORT
4+
5+
MSG_CATALOG_SERVICE_UNAVAILABLE: Final[str] = (
6+
# Most likely the director service is down or misconfigured so the user is asked to try again later.
7+
"This service is temporarily unavailable. The incident was logged and will be investigated. "
8+
+ MSG_TRY_AGAIN_OR_SUPPORT
9+
)
10+
611

712
MSG_CATALOG_SERVICE_NOT_FOUND: Final[str] = "Not Found"

services/web/server/src/simcore_service_webserver/catalog/_controller_rest_exceptions.py

Lines changed: 79 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,96 @@
11
"""Defines the different exceptions that may arise in the catalog subpackage"""
22

3+
import logging
4+
5+
from aiohttp import web
6+
from common_library.error_codes import create_error_code
7+
from models_library.rest_error import ErrorGet
38
from servicelib.aiohttp import status
9+
from servicelib.logging_errors import create_troubleshotting_log_kwargs
10+
from servicelib.rabbitmq._errors import RemoteMethodNotRegisteredError
411
from servicelib.rabbitmq.rpc_interfaces.catalog.errors import (
512
CatalogForbiddenError,
613
CatalogItemNotFoundError,
714
)
815

916
from ..exception_handling import (
17+
ExceptionHandlersMap,
1018
ExceptionToHttpErrorMap,
1119
HttpErrorInfo,
20+
create_error_context_from_request,
21+
create_error_response,
1222
exception_handling_decorator,
1323
to_exceptions_handlers_map,
1424
)
1525
from ..resource_usage.errors import DefaultPricingPlanNotFoundError
16-
from .errors import DefaultPricingUnitForServiceNotFoundError
26+
from ._constants import MSG_CATALOG_SERVICE_NOT_FOUND, MSG_CATALOG_SERVICE_UNAVAILABLE
27+
from .errors import (
28+
CatalogConnectionError,
29+
CatalogResponseError,
30+
DefaultPricingUnitForServiceNotFoundError,
31+
)
1732

1833
# mypy: disable-error-code=truthy-function
1934
assert CatalogForbiddenError # nosec
2035
assert CatalogItemNotFoundError # nosec
2136

2237

38+
_logger = logging.getLogger(__name__)
39+
40+
41+
async def _handler_catalog_client_errors(
42+
request: web.Request, exception: Exception
43+
) -> web.Response:
44+
45+
assert isinstance( # nosec
46+
exception, CatalogResponseError | CatalogConnectionError
47+
), f"check mapping, got {exception=}"
48+
49+
if (
50+
isinstance(exception, CatalogResponseError)
51+
and exception.status == status.HTTP_404_NOT_FOUND
52+
):
53+
error = ErrorGet(
54+
status=status.HTTP_404_NOT_FOUND,
55+
message=MSG_CATALOG_SERVICE_NOT_FOUND,
56+
)
57+
58+
else:
59+
# NOTE: The remaining errors are mapped to 503
60+
status_code = status.HTTP_503_SERVICE_UNAVAILABLE
61+
user_msg = MSG_CATALOG_SERVICE_UNAVAILABLE
62+
63+
# Log for further investigation
64+
oec = create_error_code(exception)
65+
_logger.exception(
66+
**create_troubleshotting_log_kwargs(
67+
user_msg,
68+
error=exception,
69+
error_code=oec,
70+
error_context={
71+
**create_error_context_from_request(request),
72+
"error_code": oec,
73+
},
74+
)
75+
)
76+
error = ErrorGet.model_construct(
77+
message=user_msg,
78+
support_id=oec,
79+
status=status_code,
80+
)
81+
82+
return create_error_response(error, status_code=error.status)
83+
84+
2385
_TO_HTTP_ERROR_MAP: ExceptionToHttpErrorMap = {
86+
RemoteMethodNotRegisteredError: HttpErrorInfo(
87+
status.HTTP_503_SERVICE_UNAVAILABLE,
88+
MSG_CATALOG_SERVICE_UNAVAILABLE,
89+
),
90+
CatalogForbiddenError: HttpErrorInfo(
91+
status.HTTP_403_FORBIDDEN,
92+
"Forbidden catalog access",
93+
),
2494
CatalogItemNotFoundError: HttpErrorInfo(
2595
status.HTTP_404_NOT_FOUND,
2696
"Catalog item not found",
@@ -32,13 +102,17 @@
32102
DefaultPricingUnitForServiceNotFoundError: HttpErrorInfo(
33103
status.HTTP_404_NOT_FOUND, "Default pricing unit not found"
34104
),
35-
CatalogForbiddenError: HttpErrorInfo(
36-
status.HTTP_403_FORBIDDEN, "Forbidden catalog access"
37-
),
38105
}
39106

107+
108+
_exceptions_handlers_map: ExceptionHandlersMap = {
109+
CatalogResponseError: _handler_catalog_client_errors,
110+
CatalogConnectionError: _handler_catalog_client_errors,
111+
}
112+
_exceptions_handlers_map.update(to_exceptions_handlers_map(_TO_HTTP_ERROR_MAP))
113+
40114
handle_plugin_requests_exceptions = exception_handling_decorator(
41-
to_exceptions_handlers_map(_TO_HTTP_ERROR_MAP)
115+
_exceptions_handlers_map
42116
)
43117

44118

services/web/server/src/simcore_service_webserver/catalog/errors.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
"""Defines the different exceptions that may arise in the catalog subpackage"""
2-
31
from ..errors import WebServerBaseError
42

53

@@ -23,3 +21,14 @@ def __init__(self, *, service_key: str, service_version: str, **ctxs):
2321
super().__init__(**ctxs)
2422
self.service_key = service_key
2523
self.service_version = service_version
24+
25+
26+
class CatalogResponseError(BaseCatalogError):
27+
msg_template = "Catalog response with error status {status} and message '{message}'"
28+
status: int
29+
message: str
30+
31+
32+
class CatalogConnectionError(BaseCatalogError):
33+
msg_template = "Catalog connection or timeout error: {message}"
34+
message: str

0 commit comments

Comments
 (0)