Skip to content

Commit

Permalink
Adding UpdateClientFunction
Browse files Browse the repository at this point in the history
  • Loading branch information
enrique committed May 21, 2024
1 parent 3c03f64 commit f16199a
Show file tree
Hide file tree
Showing 5 changed files with 171 additions and 6 deletions.
13 changes: 13 additions & 0 deletions src/clients/client_modules/dao/client_dao.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,16 @@ def create_client(self, item: dict) -> dict:
"""
response = self.clients_db.insert_record(item)
return response

def update_client(self, item: dict) -> dict:
"""
Attempts to update an existing record for a client in the DynamoDB table.
If the client does not exist, a new record will be created.
:param item: Client representation.
:type item: dict
:return: A dictionary that contains the response object.
:rtype: dict
"""
response = self.clients_db.update_record(item)
return response
8 changes: 4 additions & 4 deletions src/clients/client_modules/data_mapper/client_mapper.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ def get_geolocation_data(
return geolocation

def build_client(self, username: str) -> Dict[str, Any]:
"""This function will create a dictionary to send to DynamoDB to create a new record
"""This function will create a dictionary to send to DynamoDB to create/update a new record
Arguments:
username -- who is sending the request
Returns:
Object needed by DynamoDB to create a record
Object needed by DynamoDB to create/update a record
"""
client_errors = []

Expand Down Expand Up @@ -109,7 +109,7 @@ def build_client(self, username: str) -> Dict[str, Any]:
"discount": self.client_data["discount"],
"email": self.client_data["email"],
"errors": client_errors,
"created_by": username,
"created_at": datetime.now().isoformat(),
"last_modified_by": username,
"last_modified_at": datetime.now().isoformat(),
}
return data
4 changes: 4 additions & 0 deletions src/clients/client_modules/models/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,8 @@ class HIBerryBaseClient(BaseModel):


class HIBerryClient(HIBerryBaseClient):
pass


class HIBerryClientUpdate(HIBerryBaseClient):
pass
81 changes: 80 additions & 1 deletion src/clients/lambda_function.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# Own's modules
from client_modules.dao.client_dao import ClientDAO
from client_modules.models.client import HIBerryClient
from client_modules.models.client import HIBerryClient, HIBerryClientUpdate
from client_modules.utils.doorman import DoormanUtil
from client_modules.errors.auth_error import AuthError
from client_modules.data_mapper.client_mapper import ClientHelper
Expand Down Expand Up @@ -93,3 +93,82 @@ def create_client(event: Dict[str, Any], context: LambdaContext) -> Dict[str, An
payload={"message": error_details}, status_code=500
)



def update_client(event: Dict[str, Any], context: LambdaContext) -> Dict[str, Any]:
"""
This function is the entry point of the process that will receive a payload as an input
and will attempt to update an existing client entry in DynamoDB.
:param event: Custom object that can come from an APIGateway or EventBridge.
:type event: Dict
:param context: Regular lambda function context.
:type context: LambdaContext
:return: Custom object with the response from the lambda, it could be a 200 if the update was successful,
or >= 400 if there was an error.
:rtype: Dict
"""

logger = Logger()
logger.info("Initializing Update Client function")
doorman = DoormanUtil(event, logger)

try:
username = doorman.get_username_from_context()
is_auth = doorman.auth_user()
if not is_auth:
raise AuthError(f"User {username} is not authorized to update a client")

body = doorman.get_body_from_request()

logger.debug(f"Incoming data is {body=} and {username=}")

updated_client_data = HIBerryClientUpdate(**body)
builder = ClientHelper(updated_client_data.model_dump())
client_db_data = builder.build_client(username=username)
logger.info(f"Updating client with phone: {updated_client_data.phone_number}")

dao = ClientDAO()
update_response = dao.update_client(client_db_data)

if update_response.get("status") == "success":
logger.info("Client data received and updated")
output_data = {
"address_latitude": client_db_data["address_latitude"],
"address_longitude": client_db_data["address_longitude"],
"second_address_latitude": client_db_data["second_address_latitude"],
"second_address_longitude": client_db_data["second_address_longitude"],
"errors": client_db_data["errors"]
}

logger.debug(f"Outgoing data is {output_data=}")
return doorman.build_response(
payload=output_data,
status_code=update_response["status_code"],
)
else:
return doorman.build_response(
payload={"message": update_response.get("message", "Update failed")},
status_code=update_response.get("status_code", 500),
)

except ValidationError as validation_error:
error_details = "Some fields failed validation: " + str(validation_error)
logger.error(error_details)
return doorman.build_response(
payload={"message": error_details}, status_code=400
)

except AuthError as auth_error:
error_details = str(auth_error)
logger.error(error_details)
return doorman.build_response(
payload={"message": error_details}, status_code=403
)

except Exception as e:
error_details = f"Error updating the client: {e}"
logger.error(error_details, exc_info=True)
return doorman.build_response(
payload={"message": error_details}, status_code=500
)
71 changes: 70 additions & 1 deletion src/clients/template.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,29 @@ Resources:
Authorizer: HiBerryCognitoAuthorizer
Role: !GetAtt CreateClientRole.Arn

UpdateClientFunction:
Type: AWS::Serverless::Function
Properties:
FunctionName: !Sub "UpdateClientFunction-${StageName}"
CodeUri: .
Handler: lambda_function.update_client
Runtime: python3.11
Environment:
Variables:
POWERTOOLS_SERVICE_NAME: update-client
POWERTOOLS_LOG_LEVEL: !Ref LogLevel
APP_ENVIRONMENT: !Ref StageName
Events:
HttpPut:
Type: Api
Properties:
RestApiId: !Ref ApiGateway
Path: /clients
Method: put
Auth:
Authorizer: HiBerryCognitoAuthorizer
Role: !GetAtt UpdateClientsRole.Arn

ApiGateway:
Type: AWS::Serverless::Api
Properties:
Expand Down Expand Up @@ -118,7 +141,6 @@ Resources:
- Effect: Allow
Action:
- geo:SearchPlaceIndexForText
#Resource: !GetAtt HiBerrySearchLocationIndex.Arn
Resource: !ImportValue HiBerryLocationIndexArn
- PolicyName: CloudWatchLogsPolicy
PolicyDocument:
Expand All @@ -130,10 +152,57 @@ Resources:
- logs:CreateLogStream
- logs:PutLogEvents
Resource: "*"

UpdateClientsRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub "UpdateClientsRole-${StageName}"
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
Policies:
- PolicyName: DynamoDBUpdateItemPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- dynamodb:PutItem
- dynamodb:Query
- dynamodb:DeleteItem
Resource: !GetAtt ClientsTable.Arn
- PolicyName: LocationServiceAccess
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- geo:SearchPlaceIndexForText
Resource: !ImportValue HiBerryLocationIndexArn
- PolicyName: CloudWatchLogsPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource: "*"

Outputs:
CreateClientFunction:
Description: "Lambda Function ARN"
Value: !GetAtt CreateClientFunction.Arn
UpdateClientFunction:
Description: "Lambda Function ARN"
Value: !GetAtt UpdateClientFunction.Arn
HttpApiEndpoint:
Description: The default endpoint ApiGateway.
Value: !Sub "https://${ApiGateway}.execute-api.${AWS::Region}.amazonaws.com/${StageName}/"

0 comments on commit f16199a

Please sign in to comment.