diff --git a/api/bcd_request.py b/api/bcd_request.py index c2a7f8d52a91a8d40f84dac2e1bef1c38e0266b8..b64fc54f41e9d56164bb52d13e46bc992d2d9b66 100644 --- a/api/bcd_request.py +++ b/api/bcd_request.py @@ -1,10 +1,15 @@ +import html +import pathlib + from fastapi import APIRouter, Depends, HTTPException from starlette import status -from api import get_conn +from api import db, get_conn from model.bcd_request import BCDRequestModel, BCDProtectionRequirements, BCDSystemType, IPAddressVersion +from model.settings import settings from model.wapi.cntl import APIToken, Mgr from util.auth import check_auth +from util.util import render_jinja_template, send_email from util.wapi_util import execute_wapi_function router = APIRouter( @@ -72,8 +77,10 @@ async def handle_request(bcd_request: BCDRequestModel, token: APIToken = Depends ) if validate_bcd_request(bcd_request): - # TODO: Send e-mail - return {'result': 'success'} + mailstatus = send_bcd_request(bcd_request=bcd_request, mgr=user) + if mailstatus: + send_bcd_request_confirmation(bcd_request=bcd_request, mgr=user, receiver=user.email) + return {'result': 'success'} raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR) @@ -220,3 +227,68 @@ def validate_bcd_request(bcd_request: BCDRequestModel) -> bool: ) return True + + +def send_bcd_request(bcd_request: BCDRequestModel, mgr: Mgr, receiver=settings.bcd_request_email_receivers) -> bool: + try: + host_mode = db.host_omdl.OP_ENV_MODE.upper() + + path = pathlib.Path(__file__).parent.parent.resolve() + TEMPLATE = 'templates/bcd_request_template.j2' + + body = render_jinja_template(path, TEMPLATE, + bcd_request=bcd_request, + mgr=mgr, + host_mode=host_mode, + ) + + subject = f'BCD Request for {html.escape(bcd_request.oe)} by {html.escape(mgr.first_name)} {html.escape(mgr.last_name)}' + if host_mode: + subject = f'[{host_mode}] {subject}' + + # hacky way to intercept mails for development. In production, the assignment should be used + if settings.bcd_request_email_receivers is not None: + receiver = settings.bcd_request_email_receivers + + send_email(to=receiver, + sender=settings.patch_request_email_sender, + reply_to=mgr.email, + subject=subject, + body=body, + ) + return True + except Exception as e: + raise e + + +def send_bcd_request_confirmation(bcd_request: BCDRequestModel, mgr: Mgr, receiver) -> bool: + try: + host_mode = db.host_omdl.OP_ENV_MODE.upper() + + path = pathlib.Path(__file__).parent.parent.resolve() + TEMPLATE = 'templates/bcd_request_template.j2' + + body = render_jinja_template(path, TEMPLATE, + bcd_request=bcd_request, + mgr=mgr, + host_mode=host_mode, + confirmation=True + ) + + subject = f'Confirmation for BCD Request for {html.escape(bcd_request.oe)}' + if host_mode: + subject = f'[{host_mode}] {subject}' + + # hacky way to intercept mails for development. In production, the assignment should be used + if settings.patch_request_email_receivers is not None: + receiver = settings.patch_request_email_receivers + + send_email(to=receiver, + sender=settings.bcd_request_email_sender, + reply_to=settings.bcd_request_email_sender, + subject=subject, + body=body + ) + return True + except Exception as e: + raise e diff --git a/model/settings.py b/model/settings.py index d3a62aff74230ff93e941b21cc1531d0b2fa41f2..93bc110fad6817608f8aa3eda475afe98917686a 100644 --- a/model/settings.py +++ b/model/settings.py @@ -49,6 +49,9 @@ class Settings(BaseSettings): patch_request_email_sender: str = '' patch_request_assignment: dict[str, str] = {} + bcd_request_email_receivers: Optional[str] = None + bcd_request_email_sender: str = '' + mail_smarthost: str = 'smarthost.kit.edu' ip_contact_send_mail: bool = True diff --git a/templates/bcd_request_template.j2 b/templates/bcd_request_template.j2 new file mode 100644 index 0000000000000000000000000000000000000000..1aace940da4cbffb4235adcaddce217ec0962c4a --- /dev/null +++ b/templates/bcd_request_template.j2 @@ -0,0 +1,45 @@ +<body> +<h1>BCD Request</h1> +{% if host_mode != 'PROD' %} + <h2 style="color: red">This BCD request was sent from a development or testing instance of NETVS and is probably + just a test!</h2> +{% endif %} +{% if confirmation is defined %} +{% else %} +<p>{{ mgr.first_name }} {{ mgr.last_name }} ({{ mgr.email|urlize }}) would like you to fulfill + the following BCD request:</p> +{% endif %} + +<table style="width: 100%; border: 1px solid black; border-collapse: collapse;"> + <tr> + <th style="border: 1px solid black; border-collapse: collapse;">Organizational unit</th> + <td style="border: 1px solid black; border-collapse: collapse;">{{ bcd_request.oe }}</td> + </tr> + <tr> + <th style="border: 1px solid black; border-collapse: collapse;">Group</th> + <td style="border: 1px solid black; border-collapse: collapse;">{{ bcd_request.group }}</td> + </tr> + <tr> + <th style="border: 1px solid black; border-collapse: collapse;">Protection Requirements</th> + <td style="border: 1px solid black; border-collapse: collapse;">{{ bcd_request.protection_requirement }}</td> + </tr> + {% if bcd_request.protection_requirement_note is not None %} + <tr> + <th style="border: 1px solid black; border-collapse: collapse;">Special Protection Requirements Note</th> + <td style="border: 1px solid black; border-collapse: collapse;">{{ bcd_request.protection_requirement_note }}</td> + </tr> + {% endif %} + <tr> + <th style="border: 1px solid black; border-collapse: collapse;">Type of Systems</th> + <td style="border: 1px solid black; border-collapse: collapse;">{{ bcd_request.type_of_system }}</td> + </tr> + {% if bcd_request.type_of_system_note is not None%} + <tr> + <th style="border: 1px solid black; border-collapse: collapse;">Special Type of Systems Note</th> + <td style="border: 1px solid black; border-collapse: collapse;">{{ bcd_request.type_of_system_note }}</td> + </tr> + {% endif %} +</table> + +<p>Have a nice day!</p> +</body> \ No newline at end of file