update lambdas
This commit is contained in:
parent
438304cfce
commit
ab068cac8b
88
lambdas/get_location.py
Normal file
88
lambdas/get_location.py
Normal 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
50
lambdas/get_time.py
Normal 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)}"
|
||||
}
|
||||
79
lambdas/save_check_in_details.py
Normal file
79
lambdas/save_check_in_details.py
Normal 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
127
lambdas/send_email.py
Normal 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;">
|
||||
© 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'
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user