Skip to content

Commit 37de58e

Browse files
send email to fogbugz
1 parent d296fbe commit 37de58e

File tree

8 files changed

+137
-23
lines changed

8 files changed

+137
-23
lines changed

services/web/server/src/simcore_service_webserver/conversations/_controller/_conversations_messages_rest.py

Lines changed: 52 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@
2727
from servicelib.rest_constants import RESPONSE_MODEL_POLICY
2828

2929
from ..._meta import API_VTAG as VTAG
30+
from ...email import email_service
3031
from ...login.decorators import login_required
3132
from ...models import AuthenticatedRequestContext
33+
from ...products import products_web
3234
from ...users import users_service
3335
from ...utils_aiohttp import envelope_json_response
3436
from .. import _conversation_message_service, _conversation_service
@@ -70,27 +72,66 @@ async def create_conversation_message(request: web.Request):
7072
_ConversationMessageCreateBodyParams, request
7173
)
7274

73-
user_primary_gid = await users_service.get_user_primary_group_id(
74-
request.app, user_id=req_ctx.user_id
75-
)
75+
user = await users_service.get_user(request.app, user_id=req_ctx.user_id)
7676
conversation = await _conversation_service.get_conversation_for_user(
7777
app=request.app,
7878
conversation_id=path_params.conversation_id,
79-
user_group_id=user_primary_gid,
79+
user_group_id=user["primary_gid"],
8080
)
8181
# Ensure only support conversations are allowed
8282
if conversation.type != ConversationType.SUPPORT:
8383
raise_unsupported_type(conversation.type)
8484

85-
message = await _conversation_message_service.create_message(
86-
app=request.app,
87-
user_id=req_ctx.user_id,
88-
project_id=None, # Support conversations don't use project_id
89-
conversation_id=path_params.conversation_id,
90-
content=body_params.content,
91-
type_=body_params.type,
85+
message, is_first_message = (
86+
await _conversation_message_service.create_support_message_and_check_if_it_is_first_message(
87+
app=request.app,
88+
user_id=req_ctx.user_id,
89+
project_id=None, # Support conversations don't use project_id
90+
conversation_id=path_params.conversation_id,
91+
content=body_params.content,
92+
type_=body_params.type,
93+
)
9294
)
9395

96+
# NOTE: This is done here in the Controller layer, as the interface around email currently needs request
97+
if is_first_message:
98+
try:
99+
product = products_web.get_current_product(request)
100+
template_name = "request_support.jinja2"
101+
destination_email = product.support_email
102+
email_template_path = await products_web.get_product_template_path(
103+
request, template_name
104+
)
105+
_conversation_url = (
106+
f"{request.url}/#/conversations/{path_params.conversation_id}"
107+
)
108+
_extra_context = conversation.extra_context
109+
await email_service.send_email_from_template(
110+
request,
111+
from_=product.support_email,
112+
to=destination_email,
113+
template=email_template_path,
114+
context={
115+
"host": request.host,
116+
"product": product.model_dump(
117+
include={
118+
"display_name",
119+
}
120+
),
121+
"first_name": user["first_name"],
122+
"last_name": user["last_name"],
123+
"user_email": user["email"],
124+
"conversation_url": _conversation_url,
125+
"extra_context": _extra_context,
126+
},
127+
)
128+
except Exception: # pylint: disable=broad-except
129+
_logger.exception(
130+
"Failed while sending '%s' email to %s",
131+
template_name,
132+
user["email"],
133+
)
134+
94135
data = ConversationMessageRestGet.from_domain_model(message)
95136
return envelope_json_response(data, web.HTTPCreated)
96137

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,28 @@ async def create_message(
6060
return created_message
6161

6262

63+
async def create_support_message_and_check_if_it_is_first_message(
64+
app: web.Application,
65+
*,
66+
user_id: UserID,
67+
project_id: ProjectID | None,
68+
conversation_id: ConversationID,
69+
# Creation attributes
70+
content: str,
71+
type_: ConversationMessageType,
72+
) -> tuple[ConversationMessageGetDB, bool]:
73+
created_message = await create_message(
74+
app,
75+
user_id=user_id,
76+
project_id=project_id,
77+
conversation_id=conversation_id,
78+
content=content,
79+
type_=type_,
80+
)
81+
82+
return created_message, True
83+
84+
6385
async def get_message(
6486
app: web.Application,
6587
*,

services/web/server/src/simcore_service_webserver/email/_core.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
from aiohttp_jinja2 import render_string
1616
from settings_library.email import EmailProtocol, SMTPSettings
1717

18+
from ..products import products_web
1819
from .settings import get_plugin_settings
1920

2021
_logger = logging.getLogger(__name__)
@@ -225,6 +226,10 @@ def _render_template(
225226
return subject, html_body
226227

227228

229+
async def get_template_path(request: web.Request, filename: str) -> Path:
230+
return await products_web.get_product_template_path(request, filename)
231+
232+
228233
async def send_email_from_template(
229234
request: web.Request,
230235
*,
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import logging
2+
3+
from ._core import AttachmentTuple, get_template_path, send_email_from_template
4+
5+
log = logging.getLogger(__name__)
6+
7+
8+
# prevents auto-removal by pycln
9+
# mypy: disable-error-code=truthy-function
10+
assert AttachmentTuple # nosec
11+
assert send_email_from_template # nosec
12+
assert get_template_path # nosec
13+
14+
15+
__all__: tuple[str, ...] = (
16+
"AttachmentTuple",
17+
"send_email_from_template",
18+
"get_template_path",
19+
)

services/web/server/src/simcore_service_webserver/email/utils.py

Lines changed: 0 additions & 3 deletions
This file was deleted.
Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
import logging
22
from pathlib import Path
33

4-
from aiohttp import web
5-
64
from .._resources import webserver_resources
7-
from ..email.utils import AttachmentTuple, send_email_from_template
8-
from ..products import products_web
5+
from ..email.email_service import (
6+
AttachmentTuple,
7+
get_template_path,
8+
send_email_from_template,
9+
)
910

1011
log = logging.getLogger(__name__)
1112

@@ -15,17 +16,15 @@ def themed(dirname: str, template: str) -> Path:
1516
return path
1617

1718

18-
async def get_template_path(request: web.Request, filename: str) -> Path:
19-
return await products_web.get_product_template_path(request, filename)
20-
21-
2219
# prevents auto-removal by pycln
2320
# mypy: disable-error-code=truthy-function
2421
assert AttachmentTuple # nosec
2522
assert send_email_from_template # nosec
23+
assert get_template_path # nosec
2624

2725

2826
__all__: tuple[str, ...] = (
2927
"AttachmentTuple",
3028
"send_email_from_template",
29+
"get_template_path",
3130
)

services/web/server/src/simcore_service_webserver/login_accounts/_service.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
from pydantic import EmailStr, PositiveInt, TypeAdapter, ValidationError
1515
from servicelib.utils_secrets import generate_passcode
1616

17-
from ..email.utils import send_email_from_template
17+
from ..email.email_service import send_email_from_template
1818
from ..products import products_web
1919
from ..products.models import Product
2020
from ..users import _accounts_service
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
Request for Support on {{ host }}
2+
<!--
3+
NOTE: this header is only for testing purposes and is removed automatically before sending
4+
TEST host: {{ host }}
5+
TEST first_name: {{ first_name }}
6+
TEST last_name: {{ last_name }}
7+
TEST user_email: {{ user_email }}
8+
TEST product: {{ product }}
9+
TEST conversation_url: {{ conversation_url }}
10+
TEST extra_context: {{ extra_context }}
11+
-->
12+
<p>
13+
Dear Support Team,
14+
</p>
15+
16+
<p>
17+
We have received a support request from {{ first_name }} {{ last_name }} ({{ user_email }}) regarding an account in <b>{{ product.display_name }}</b> on <b>{{ host }}</b>.
18+
</p>
19+
20+
<p>
21+
All communication should take place in the Platform Support Center at the following link:
22+
<a href="{{ conversation_url }}">{{ conversation_url }}</a>
23+
</p>
24+
25+
<p>
26+
Additional Information:
27+
</p>
28+
29+
<pre>
30+
{{ dumps(extra_context) }}
31+
</pre>

0 commit comments

Comments
 (0)