update lambdas

This commit is contained in:
King Matthew Ochoa 2025-07-05 21:24:53 +08:00
parent 438304cfce
commit ab068cac8b
4 changed files with 344 additions and 0 deletions

88
lambdas/get_location.py Normal file
View File

@ -0,0 +1,88 @@
import logging
import json
from typing import Dict, Any
from http import HTTPStatus
import urllib.request
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
"""
AWS Lambda handler for processing Bedrock agent requests and geocoding location names using Nominatim.
Args:
event (Dict[str, Any]): The Lambda event containing action details
context (Any): The Lambda context object
Returns:
Dict[str, Any]: Response formatted for Bedrock Agents
"""
try:
action_group = event['actionGroup']
function = event['function']
message_version = event.get('messageVersion', 1)
parameters = event.get('parameters', [])
print(parameters)
parameters_dict ={parameter["name"]:parameter["value"] for parameter in parameters}
location_name = parameters_dict.get('location_name')
if not location_name:
raise KeyError("Missing required parameter: 'location_name'")
# Call Nominatim API to geocode the location
query = urllib.parse.urlencode({
"q": location_name,
"format": "json",
"limit": 1
})
headers = {
"User-Agent": "aws-lambda-geocoder/1.0"
}
url = f"https://nominatim.openstreetmap.org/search?{query}"
req = urllib.request.Request(url, headers=headers)
with urllib.request.urlopen(req) as response:
response_data = response.read()
print(response_data)
results = json.loads(response_data)
if not results:
raise ValueError(f"No coordinates found for '{location_name}'")
lat = float(results[0]["lat"])
lon = float(results[0]["lon"])
# Prepare Bedrock-compatible response
response_body = {
'TEXT': {
'body': f"Coordinates for '{location_name}': Latitude {lat}, Longitude {lon}"
}
}
action_response = {
'actionGroup': action_group,
'function': function,
'functionResponse': {
'responseBody': response_body
}
}
final_response = {
'response': action_response,
'messageVersion': message_version
}
logger.info('Success: %s', final_response)
return final_response
except KeyError as e:
logger.error('Missing required field: %s', str(e))
return {
'statusCode': HTTPStatus.BAD_REQUEST,
'body': f'Error: {str(e)}'
}
except Exception as e:
logger.error('Unexpected error: %s', str(e))
return {
'statusCode': HTTPStatus.INTERNAL_SERVER_ERROR,
'body': f'Internal server error: {str(e)}'
}

50
lambdas/get_time.py Normal file
View File

@ -0,0 +1,50 @@
import json
import logging
from datetime import datetime, timedelta, timezone
from typing import Dict, Any
from http import HTTPStatus
logger = logging.getLogger()
logger.setLevel(logging.INFO)
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
try:
action_group = event.get("actionGroup")
function = event.get("function")
message_version = event.get("messageVersion", 1)
# Get current UTC time
utc_now = datetime.now(timezone.utc)
# Assume CET is UTC+2 for summer (CEST)
# Use UTC+1 if you want standard time
cet_offset = timezone(timedelta(hours=2)) # Change to +1 in winter
cet_now = utc_now.astimezone(cet_offset)
response_body = {
"TEXT": {
"body": (
f"Current time:\n"
f"- UTC: {utc_now.strftime('%Y-%m-%d %H:%M:%S %Z')}\n"
f"- CET (UTC+2): {cet_now.strftime('%Y-%m-%d %H:%M:%S %Z')}"
)
}
}
return {
"response": {
"actionGroup": action_group,
"function": function,
"functionResponse": {
"responseBody": response_body
}
},
"messageVersion": message_version
}
except Exception as e:
logger.error("Unexpected error: %s", str(e))
return {
"statusCode": HTTPStatus.INTERNAL_SERVER_ERROR,
"body": f"Internal server error: {str(e)}"
}

View File

@ -0,0 +1,79 @@
import json
import logging
import boto3
from typing import Dict, Any
from http import HTTPStatus
logger = logging.getLogger()
logger.setLevel(logging.INFO)
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('checkin_table')
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
try:
action_group = event.get('actionGroup')
function = event.get('function')
message_version = event.get('messageVersion', 1)
parameters = event.get('parameters', [])
# Extract 'data' parameter (stringified JSON)
data_param = next((p for p in parameters if p["name"] == "data"), None)
if not data_param:
raise KeyError("Missing 'data' parameter.")
data = json.loads(data_param["value"])
required_fields = [
"CheckInDate", "UserID", "CheckInTime", "LocationGps",
"LocationLink", "LocationName", "Organization", "Position"
]
missing = [f for f in required_fields if f not in data]
if missing:
raise KeyError(f"Missing fields in data: {missing}")
# Prepare item for DynamoDB
item = {
"CheckInDate": data["CheckInDate"],
"UserID": data["UserID"],
"Position": data["Position"],
"Organization": data["Organization"],
"CheckInTime": data["CheckInTime"],
"LocationGps": data["LocationGps"],
"LocationName": data["LocationName"],
"LocationLink": data["LocationLink"],
"Notes": data.get("Notes", "")
}
table.put_item(Item=item)
response_body = {
"TEXT": {
"body": f"Check-in recorded successfully for {item['UserID']}."
}
}
action_response = {
"actionGroup": action_group,
"function": function,
"functionResponse": {
"responseBody": response_body
}
}
return {
"response": action_response,
"messageVersion": message_version
}
except KeyError as e:
logger.error("Missing required field: %s", str(e))
return {
"statusCode": HTTPStatus.BAD_REQUEST,
"body": f"Error: {str(e)}"
}
except Exception as e:
logger.error("Unexpected error: %s", str(e))
return {
"statusCode": HTTPStatus.INTERNAL_SERVER_ERROR,
"body": f"Internal server error: {str(e)}"
}

127
lambdas/send_email.py Normal file
View File

@ -0,0 +1,127 @@
import logging
import boto3
import json
from typing import Dict, Any
from http import HTTPStatus
logger = logging.getLogger()
logger.setLevel(logging.INFO)
ses_client = boto3.client('ses', region_name='us-east-1')
FROM_EMAIL = "xmatthewochoa@gmail.com" # Replace with verified SES sender
TO_EMAIL = ["xmatthewochoa@gmail.com"] # Replace with recipients or fallback list
def extract_parameters(parameter_list):
"""Convert parameter list of dicts into a key-value dictionary."""
return {param['name']: param.get('value', '') for param in parameter_list}
def parse_email_list(value: str) -> list[str]:
"""Safely parse the email list string."""
try:
if not value.strip().startswith("["):
return TO_EMAIL
formatted = "[" + ", ".join(f'"{email.strip()}"' for email in value.strip("[]").split(",")) + "]"
return json.loads(formatted)
except Exception as e:
logger.warning("Invalid email list; using default. Error: %s", str(e))
return TO_EMAIL
def send_email(subject: str, body: str, to_email: list[str]) -> None:
"""Send an email via Amazon SES."""
try:
response = ses_client.send_email(
Source=FROM_EMAIL,
Destination={'ToAddresses': to_email},
Message={
'Subject': {'Data': subject},
'Body': {
'Html': {'Data': body},
'Text': {'Data': 'Personnel check-in summary sent via SES.'}
}
}
)
logger.info("Email sent successfully: %s", response)
except Exception as e:
logger.error("Failed to send email: %s", str(e))
raise
def lambda_handler(event: Dict[str, Any], context: Any) -> Dict[str, Any]:
logger.info("Received event: %s", event)
try:
action_group = event['actionGroup']
function = event['function']
message_version = event.get('messageVersion', 1)
raw_params = event.get('parameters', [])
parameters = extract_parameters(raw_params)
# Parse emails
email_list = parse_email_list(parameters.get('list_of_emails_address', ''))
# Parse JSON Data string
try:
data_dict = json.loads(parameters.get('Data', '{}'))
except json.JSONDecodeError as e:
logger.warning("Invalid JSON in Data; using empty dict. Error: %s", str(e))
data_dict = {}
email_subject = f'✅ Check-In Notification: {function}'
param_html_rows = ''.join([
f"<tr style='border-bottom: 1px solid #eee;'>"
f"<td style='padding: 12px 10px; font-weight: bold; color: #333;'>{k.replace('_', ' ')}</td>"
f"<td style='padding: 12px 10px; color: #555;'>{v}</td>"
f"</tr>"
for k, v in data_dict.items()
])
email_body = f'''
<html>
<body style="font-family: Arial, sans-serif; background-color: #f9f9f9; padding: 20px; margin: 0;">
<div style="max-width: 700px; margin: auto; background-color: #ffffff; border-radius: 10px; box-shadow: 0 4px 12px rgba(0,0,0,0.05); overflow: hidden;">
<div style="background-color: #28a745; color: white; padding: 20px; text-align: center;">
<h2 style="margin: 0;">Personnel Check-In Submission</h2>
</div>
<div style="padding: 30px;">
<p style="font-size: 16px; color: #333;">A personnel check-in has been submitted with the following details:</p>
<table style="width: 100%; border-collapse: collapse; margin-top: 20px;">
<tbody>
{param_html_rows}
</tbody>
</table>
</div>
<div style="background-color: #f0f0f0; padding: 15px; text-align: center; font-size: 12px; color: #888;">
&copy; 2025 Security Operations Team. All rights reserved.
</div>
</div>
</body>
</html>
'''
send_email(email_subject, email_body, email_list)
return {
'response': {
'actionGroup': action_group,
'function': function,
'functionResponse': {
'responseBody': {
'TEXT': {'body': f'Check-in email sent to {email_list}.'}
}
}
},
'messageVersion': message_version
}
except KeyError as e:
logger.error('Missing required field: %s', str(e))
return {
'statusCode': HTTPStatus.BAD_REQUEST,
'body': f'Error: {str(e)}'
}
except Exception as e:
logger.error('Unexpected error: %s', str(e))
return {
'statusCode': HTTPStatus.INTERNAL_SERVER_ERROR,
'body': 'Internal server error'
}