Skip to content

Commit 0162f61

Browse files
authored
Merge branch 'master' into feature/messages-via-ws
2 parents 5e5a2c8 + 2d1134f commit 0162f61

File tree

32 files changed

+399
-198
lines changed

32 files changed

+399
-198
lines changed

.github/prompts/update-user-messages.prompt.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ error_msg = user_message("Operation failed. Please try again later.")
1818

1919
## Guidelines for Updating User Messages
2020

21-
When modifying user messages, follow these rules:
21+
When modifying user messages, follow **as close as possible** these rules:
2222

2323
1. **Version Tracking**: Every modification to a user message must include an incremented `_version` parameter:
2424

@@ -43,7 +43,7 @@ When modifying user messages, follow these rules:
4343
user_message("Unable to load project.", _version=1)
4444
```
4545

46-
3. **Message Style**: Follow *strictly* the guidelines in `${workspaceFolder}/docs/user-messages-guidelines.md`
46+
3. **Message Style**: Follow **strictly** the guidelines in `${workspaceFolder}/docs/user-messages-guidelines.md`
4747

4848
4. **Preserve Context**: Ensure the modified message conveys the same meaning and context as the original.
4949

@@ -56,17 +56,19 @@ When modifying user messages, follow these rules:
5656
# After
5757
user_message("Your session has expired. Please log in again.", _version=3)
5858
```
59+
6. **Replace 'Study' by 'Project'**: If the message contains the word 'Study', replace it with 'Project' to align with our terminology.
60+
5961

6062
## Examples
6163

6264
### Example 1: Simple Message Update
6365

6466
```python
6567
# Before
66-
error_dialog(user_message("Failed to save changes."))
68+
error_dialog(user_message("Failed to save changes in this study."))
6769

6870
# After
69-
error_dialog(user_message("Unable to save your changes. Please try again.", _version=1))
71+
error_dialog(user_message("Unable to save your changes in this project.", _version=1))
7072
```
7173

7274
### Example 2: F-string Message Update

packages/service-library/src/servicelib/aiohttp/rest_middlewares.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
DEFAULT_API_VERSION = "v0"
3737
_FMSG_INTERNAL_ERROR_USER_FRIENDLY = user_message(
3838
"We apologize for the inconvenience. "
39-
"The issue has been recorded, please report it if it persists."
39+
"The issue has been recorded, please report it if it persists.",
40+
_version=1,
4041
)
4142

4243

services/docker-compose.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -888,10 +888,14 @@ services:
888888
- traefik.http.routers.${SWARM_STACK_NAME}_webserver_sticky.rule=Path(`/v0/projects`) ||
889889
Path(`/v0/projects:clone`) ||
890890
PathRegexp(`^/v0/projects/[0-9a-fA-F-]+/nodes/[0-9a-fA-F-]+:stop`) ||
891+
PathRegexp(`^/v0/projects/[0-9a-fA-F-]+/nodes/[0-9a-fA-F-]+:open`) ||
892+
PathRegexp(`^/v0/projects/[0-9a-fA-F-]+/nodes/[0-9a-fA-F-]+:close`) ||
891893
PathRegexp(`^/v0/storage/locations/[0-9]+/paths/.+:size`) ||
892894
PathRegexp(`^/v0/storage/locations/[0-9]+/-/paths:batchDelete`) ||
893895
PathRegexp(`^/v0/storage/locations/[0-9]+/export-data`) ||
894896
PathRegexp(`^/v0/tasks-legacy/.+`)
897+
# NOTE: the sticky router must have a higher priority than the webserver router but below dy-proxies
898+
- traefik.http.routers.${SWARM_STACK_NAME}_webserver_sticky.priority=8
895899
- traefik.http.routers.${SWARM_STACK_NAME}_webserver_sticky.entrypoints=http
896900
- traefik.http.routers.${SWARM_STACK_NAME}_webserver_sticky.service=${SWARM_STACK_NAME}_webserver_sticky
897901
- traefik.http.routers.${SWARM_STACK_NAME}_webserver_sticky.middlewares=${SWARM_STACK_NAME}_gzip@swarm, ${SWARM_STACK_NAME_NO_HYPHEN}_sslheader@swarm, ${SWARM_STACK_NAME}_webserver_retry

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

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

3+
from common_library.user_messages import user_message
4+
35
from ..constants import MSG_TRY_AGAIN_OR_SUPPORT
46

5-
MSG_CATALOG_SERVICE_UNAVAILABLE: Final[str] = (
7+
MSG_CATALOG_SERVICE_UNAVAILABLE: Final[str] = user_message(
68
# 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+
"The catalog service is currently unavailable. This issue has been logged and will be investigated. "
10+
+ MSG_TRY_AGAIN_OR_SUPPORT,
11+
_version=1,
912
)
1013

1114

services/web/server/src/simcore_service_webserver/constants.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# pylint:disable=unused-import
22

3+
from sys import version
34
from typing import Final
45

56
from common_library.user_messages import user_message
@@ -39,7 +40,7 @@
3940
# main index route name = front-end
4041
INDEX_RESOURCE_NAME: Final[str] = "get_cached_frontend_index"
4142

42-
MSG_UNDER_DEVELOPMENT: Final[str] = (
43+
MSG_UNDER_DEVELOPMENT: Final[str] = user_message(
4344
"Under development. Use WEBSERVER_DEV_FEATURES_ENABLED=1 to enable current implementation"
4445
)
4546

@@ -48,7 +49,7 @@
4849

4950

5051
MSG_TRY_AGAIN_OR_SUPPORT: Final[str] = user_message(
51-
"Please try again shortly. If the issue persists, contact support."
52+
"Please try again shortly. If the issue persists, contact support.", _version=1
5253
)
5354

5455
__all__: tuple[str, ...] = (

services/web/server/src/simcore_service_webserver/conversations/_conversation_message_service.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ async def update_message(
111111
async def delete_message(
112112
app: web.Application,
113113
*,
114+
user_id: UserID,
114115
project_id: ProjectID,
115116
conversation_id: ConversationID,
116117
message_id: ConversationMessageID,
@@ -121,9 +122,12 @@ async def delete_message(
121122
message_id=message_id,
122123
)
123124

125+
_user_group_id = await get_user_primary_group_id(app, user_id=user_id)
126+
124127
await notify_conversation_message_deleted(
125128
app,
126129
recipients=await _get_recipients(app, project_id),
130+
user_group_id=_user_group_id,
127131
project_id=project_id,
128132
conversation_id=conversation_id,
129133
message_id=message_id,

services/web/server/src/simcore_service_webserver/conversations/_socketio.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,17 @@
66
ConversationID,
77
ConversationMessageGetDB,
88
ConversationMessageID,
9+
ConversationMessageType,
910
)
11+
from models_library.groups import GroupID
1012
from models_library.projects import ProjectID
1113
from models_library.socketio import SocketMessageDict
1214
from models_library.users import UserID
1315
from pydantic import AliasGenerator, BaseModel, ConfigDict
1416
from pydantic.alias_generators import to_camel
1517
from servicelib.utils import limited_as_completed
1618

17-
from ..socketio.messages import send_message_to_standard_group
19+
from ..socketio.messages import send_message_to_user
1820

1921
_MAX_CONCURRENT_SENDS: Final[int] = 3
2022

@@ -32,6 +34,8 @@
3234
class BaseConversationMessage(BaseModel):
3335
conversation_id: ConversationID
3436
message_id: ConversationMessageID
37+
user_group_id: GroupID
38+
type: ConversationMessageType
3539

3640
model_config = ConfigDict(
3741
populate_by_name=True,
@@ -42,13 +46,9 @@ class BaseConversationMessage(BaseModel):
4246
)
4347

4448

45-
class ConversationMessageCreated(BaseConversationMessage):
49+
class ConversationMessageCreatedOrUpdated(BaseConversationMessage):
4650
content: str
4751
created: datetime.datetime
48-
49-
50-
class ConversationMessageUpdated(BaseConversationMessage):
51-
content: str
5252
modified: datetime.datetime
5353

5454

@@ -62,7 +62,9 @@ async def _send_message_to_recipients(
6262
):
6363
async for _ in limited_as_completed(
6464
(
65-
send_message_to_standard_group(app, recipient, notification_message)
65+
send_message_to_user(
66+
app, recipient, notification_message, ignore_queue=True
67+
)
6668
for recipient in recipients
6769
),
6870
limit=_MAX_CONCURRENT_SENDS,
@@ -81,7 +83,7 @@ async def notify_conversation_message_created(
8183
event_type=SOCKET_IO_CONVERSATION_MESSAGE_CREATED_EVENT,
8284
data={
8385
"projectId": project_id,
84-
**ConversationMessageCreated(
86+
**ConversationMessageCreatedOrUpdated(
8587
**conversation_message.model_dump()
8688
).model_dump(mode="json", by_alias=True),
8789
},
@@ -102,7 +104,7 @@ async def notify_conversation_message_updated(
102104
event_type=SOCKET_IO_CONVERSATION_MESSAGE_UPDATED_EVENT,
103105
data={
104106
"projectId": project_id,
105-
**ConversationMessageUpdated(
107+
**ConversationMessageCreatedOrUpdated(
106108
**conversation_message.model_dump()
107109
).model_dump(mode="json", by_alias=True),
108110
},
@@ -115,6 +117,7 @@ async def notify_conversation_message_deleted(
115117
app: web.Application,
116118
*,
117119
recipients: set[UserID],
120+
user_group_id: GroupID,
118121
project_id: ProjectID,
119122
conversation_id: ConversationID,
120123
message_id: ConversationMessageID,
@@ -125,7 +128,10 @@ async def notify_conversation_message_deleted(
125128
data={
126129
"projectId": project_id,
127130
**ConversationMessageDeleted(
128-
conversation_id=conversation_id, message_id=message_id
131+
conversation_id=conversation_id,
132+
message_id=message_id,
133+
user_group_id=user_group_id,
134+
type=ConversationMessageType.MESSAGE,
129135
).model_dump(mode="json", by_alias=True),
130136
},
131137
)

services/web/server/src/simcore_service_webserver/director_v2/_controller/_rest_exceptions.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,11 +87,17 @@ async def _handler_director_service_error_as_503_or_4xx(
8787
_TO_HTTP_ERROR_MAP: ExceptionToHttpErrorMap = {
8888
UserDefaultWalletNotFoundError: HttpErrorInfo(
8989
status.HTTP_404_NOT_FOUND,
90-
user_message("Default wallet not found but necessary for computations"),
90+
user_message(
91+
"A default wallet is required for running computations but could not be found.",
92+
_version=1,
93+
),
9194
),
9295
WalletNotEnoughCreditsError: HttpErrorInfo(
9396
status.HTTP_402_PAYMENT_REQUIRED,
94-
user_message("Wallet does not have enough credits for computations. {reason}"),
97+
user_message(
98+
"Your wallet does not have sufficient credits to run this computation. {reason}",
99+
_version=1,
100+
),
95101
),
96102
}
97103

services/web/server/src/simcore_service_webserver/folders/_common/exceptions_handlers.py

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,49 +32,56 @@
3232
_TO_HTTP_ERROR_MAP: ExceptionToHttpErrorMap = {
3333
FolderNotFoundError: HttpErrorInfo(
3434
status.HTTP_404_NOT_FOUND,
35-
user_message("Folder was not found"),
35+
user_message("The requested folder could not be found.", _version=1),
3636
),
3737
WorkspaceNotFoundError: HttpErrorInfo(
3838
status.HTTP_404_NOT_FOUND,
39-
user_message("Workspace was not found"),
39+
user_message("The requested workspace could not be found.", _version=1),
4040
),
4141
FolderAccessForbiddenError: HttpErrorInfo(
4242
status.HTTP_403_FORBIDDEN,
43-
user_message("Does not have access to this folder"),
43+
user_message("You do not have permission to access this folder.", _version=1),
4444
),
4545
WorkspaceAccessForbiddenError: HttpErrorInfo(
4646
status.HTTP_403_FORBIDDEN,
47-
user_message("Does not have access to this workspace"),
47+
user_message(
48+
"You do not have permission to access this workspace.", _version=1
49+
),
4850
),
4951
WorkspaceFolderInconsistencyError: HttpErrorInfo(
5052
status.HTTP_403_FORBIDDEN,
51-
user_message("This folder does not exist in this workspace"),
53+
user_message(
54+
"This folder is not available in the selected workspace.", _version=1
55+
),
5256
),
5357
FolderValueNotPermittedError: HttpErrorInfo(
5458
status.HTTP_409_CONFLICT,
55-
user_message("Provided folder value is not permitted: {reason}"),
59+
user_message("The folder operation cannot be completed: {reason}", _version=1),
5660
),
5761
FoldersValueError: HttpErrorInfo(
5862
status.HTTP_409_CONFLICT,
59-
user_message("Invalid folder value set: {reason}"),
63+
user_message("The folder configuration is invalid: {reason}", _version=1),
6064
),
6165
ProjectInvalidRightsError: HttpErrorInfo(
6266
status.HTTP_403_FORBIDDEN,
6367
user_message(
64-
"Access Denied: You do not have permission to move the project with UUID: {project_uuid}. Tip: Copy and paste the UUID into the search bar to locate the project."
68+
"You do not have permission to move the project with UUID: {project_uuid}. To locate this project, copy and paste the UUID into the search bar.",
69+
_version=1,
6570
),
6671
),
6772
# Trashing
6873
ProjectRunningConflictError: HttpErrorInfo(
6974
status.HTTP_409_CONFLICT,
7075
user_message(
71-
"One or more studies in this folder are in use and cannot be trashed. Please stop all services first and try again"
76+
"Cannot move folder to trash because it contains projects that are currently running. Please stop all running services first and try again.",
77+
_version=2,
7278
),
7379
),
7480
ProjectStoppingError: HttpErrorInfo(
7581
status.HTTP_503_SERVICE_UNAVAILABLE,
7682
user_message(
77-
"Something went wrong while stopping running services in studies within this folder before trashing. Aborting trash."
83+
"Something went wrong while stopping running services in projects within this folder before trashing. Aborting trash.",
84+
_version=2,
7885
),
7986
),
8087
}

services/web/server/src/simcore_service_webserver/groups/_common/exceptions_handlers.py

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,32 +24,40 @@
2424
_TO_HTTP_ERROR_MAP: ExceptionToHttpErrorMap = {
2525
UserNotFoundError: HttpErrorInfo(
2626
status.HTTP_404_NOT_FOUND,
27-
user_message("User {uid} or {email} not found"),
27+
user_message(
28+
"The user with ID {uid} or email {email} could not be found.", _version=1
29+
),
2830
),
2931
GroupNotFoundError: HttpErrorInfo(
3032
status.HTTP_404_NOT_FOUND,
31-
user_message("Group {gid} not found"),
33+
user_message("The group with ID {gid} could not be found.", _version=1),
3234
),
3335
UserInGroupNotFoundError: HttpErrorInfo(
3436
status.HTTP_404_NOT_FOUND,
35-
user_message("User not found in group {gid}"),
37+
user_message("The user is not a member of group {gid}.", _version=1),
3638
),
3739
UserAlreadyInGroupError: HttpErrorInfo(
3840
status.HTTP_409_CONFLICT,
39-
user_message("User is already in group {gid}"),
41+
user_message("The user is already a member of group {gid}.", _version=1),
4042
),
4143
UserInsufficientRightsError: HttpErrorInfo(
4244
status.HTTP_403_FORBIDDEN,
43-
user_message("Insufficient rights for {permission} access to group {gid}"),
45+
user_message(
46+
"You do not have sufficient rights for {permission} access to group {gid}.",
47+
_version=1,
48+
),
4449
),
4550
# scicrunch
4651
InvalidRRIDError: HttpErrorInfo(
4752
status.HTTP_409_CONFLICT,
48-
user_message("Invalid RRID {rrid}"),
53+
user_message("The RRID {rrid} is not valid.", _version=1),
4954
),
5055
ScicrunchError: HttpErrorInfo(
5156
status.HTTP_409_CONFLICT,
52-
user_message("Cannot get RRID since scicrunch.org service is not reachable."),
57+
user_message(
58+
"Unable to retrieve RRID information because the scicrunch.org service is currently unavailable.",
59+
_version=1,
60+
),
5361
),
5462
}
5563

0 commit comments

Comments
 (0)