Skip to content

Commit 55de9db

Browse files
formatting
1 parent bb32566 commit 55de9db

File tree

2 files changed

+98
-67
lines changed

2 files changed

+98
-67
lines changed

lambdas/icaseworks_api_ingestion/main.py

Lines changed: 59 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
11
import sys
22

3-
sys.path.append('./lib/')
43

5-
import pybase64
6-
import json
4+
sys.path.append("./lib/")
5+
6+
import datetime
77
import hashlib
88
import hmac
9+
import json
10+
import logging
911
import re
10-
import requests
1112
import time
13+
from os import getenv
14+
1215
import boto3
16+
import pybase64
17+
import requests
1318
from dotenv import load_dotenv
14-
from os import getenv
15-
import datetime
16-
import logging
19+
1720

1821
logger = logging.getLogger()
1922
logger.setLevel(logging.INFO)
2023

2124

2225
def remove_illegal_characters(string):
2326
"""Removes illegal characters from string"""
24-
regex_list = [['=', ""], ['\/', "_"], ['+', "-"]]
27+
regex_list = [["=", ""], ["\/", "_"], ["+", "-"]]
2528
for r in regex_list:
26-
string = re.sub(string=string,
27-
pattern="[{}]".format(r[0]),
28-
repl=r[1])
29+
string = re.sub(string=string, pattern="[{}]".format(r[0]), repl=r[1])
2930
return string
3031

3132

@@ -44,37 +45,39 @@ def dictionary_to_string(dictionary):
4445
def create_signature(header, payload, secret):
4546
"""Encode JSON string"""
4647
# hashed header, hashed payload, string secret
47-
unsigned_token = header + '.' + payload
48-
key_bytes = bytes(secret, 'utf-8')
49-
string_to_sign_bytes = bytes(unsigned_token, 'utf-8')
50-
signature_hash = hmac.new(key_bytes, string_to_sign_bytes, digestmod=hashlib.sha256).digest()
48+
unsigned_token = header + "." + payload
49+
key_bytes = bytes(secret, "utf-8")
50+
string_to_sign_bytes = bytes(unsigned_token, "utf-8")
51+
signature_hash = hmac.new(
52+
key_bytes, string_to_sign_bytes, digestmod=hashlib.sha256
53+
).digest()
5154
encoded_signature = pybase64.b64encode(signature_hash)
52-
encoded_signature = encoded_signature.decode('utf-8')
55+
encoded_signature = encoded_signature.decode("utf-8")
5356
encoded_signature = remove_illegal_characters(encoded_signature)
5457
return encoded_signature
5558

5659

5760
def get_token(url, encoded_header, encoded_payload, signature, headers):
5861
"""Get token"""
5962
assertion = encoded_header + "." + encoded_payload + "." + signature
60-
data = f'assertion={assertion}&grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer'
63+
data = f"assertion={assertion}&grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer"
6164
response = requests.post(url, headers=headers, data=data)
6265
response_json = response.json()
63-
auth_token = response_json.get('access_token')
66+
auth_token = response_json.get("access_token")
6467
return auth_token
6568

6669

6770
def get_icaseworks_report_from(report_id, from_date, auth_headers, auth_payload):
6871
report_url = "https://hackneyreports.icasework.com/getreport?"
69-
request_url = f'{report_url}ReportId={report_id}&Format=json&From={from_date}'
70-
logger.info(f'Request url: {request_url}')
72+
request_url = f"{report_url}ReportId={report_id}&Format=json&From={from_date}"
73+
logger.info(f"Request url: {request_url}")
7174
response = requests.get(request_url, headers=auth_headers, data=auth_payload)
72-
logger.info(f'Status Code: {response.status_code}')
75+
logger.info(f"Status Code: {response.status_code}")
7376
return response.content
7477

7578

7679
def write_dataframe_to_s3(s3_client, data, s3_bucket, output_folder, filename):
77-
filename = re.sub('[^a-zA-Z0-9]+', '-', filename).lower()
80+
filename = re.sub("[^a-zA-Z0-9]+", "-", filename).lower()
7881
current_date = datetime.datetime.now()
7982
day = single_digit_to_zero_prefixed_string(current_date.day)
8083
month = single_digit_to_zero_prefixed_string(current_date.month)
@@ -83,7 +86,7 @@ def write_dataframe_to_s3(s3_client, data, s3_bucket, output_folder, filename):
8386
return s3_client.put_object(
8487
Bucket=s3_bucket,
8588
Body=data,
86-
Key=f"{output_folder}/import_year={year}/import_month={month}/import_day={day}/import_date={date}/{filename}.json"
89+
Key=f"{output_folder}/import_year={year}/import_month={month}/import_day={day}/import_date={date}/{filename}.json",
8790
)
8891

8992

@@ -102,14 +105,16 @@ def lambda_handler(event, lambda_context):
102105
url = "https://hackney.icasework.com/token"
103106

104107
headers = {
105-
'Content-Type': 'application/x-www-form-urlencoded',
108+
"Content-Type": "application/x-www-form-urlencoded",
106109
}
107110

108111
# Get api api credentials from secrets manager
109112
secret_name = getenv("SECRET_NAME")
110-
secrets_manager_client = boto3.client('secretsmanager')
111-
api_credentials_response = retrieve_credentials_from_secrets_manager(secrets_manager_client, secret_name)
112-
api_credentials = json.loads(api_credentials_response['SecretString'])
113+
secrets_manager_client = boto3.client("secretsmanager")
114+
api_credentials_response = retrieve_credentials_from_secrets_manager(
115+
secrets_manager_client, secret_name
116+
)
117+
api_credentials = json.loads(api_credentials_response["SecretString"])
113118
api_key = api_credentials.get("api_key")
114119
secret = api_credentials.get("secret")
115120

@@ -122,11 +127,7 @@ def lambda_handler(event, lambda_context):
122127
# Create payload
123128
current_unix_time = int(time.time())
124129
str_time = str(current_unix_time)
125-
payload_object = {
126-
"iss": api_key,
127-
"aud": url,
128-
"iat": str_time
129-
}
130+
payload_object = {"iss": api_key, "aud": url, "iat": str_time}
130131

131132
payload_object = dictionary_to_string(payload_object)
132133

@@ -136,16 +137,21 @@ def lambda_handler(event, lambda_context):
136137
signature = create_signature(header, payload, secret)
137138

138139
# Get token from response
139-
auth_token = get_token(url=url, encoded_header=header, encoded_payload=payload, signature=signature,
140-
headers=headers)
140+
auth_token = get_token(
141+
url=url,
142+
encoded_header=header,
143+
encoded_payload=payload,
144+
signature=signature,
145+
headers=headers,
146+
)
141147

142148
# Create auth header for API Calls and auth payload
143-
authorization = f'Bearer {auth_token}'
149+
authorization = f"Bearer {auth_token}"
144150

145151
auth_payload = {}
146152

147153
auth_headers = {
148-
'Authorization': authorization,
154+
"Authorization": authorization,
149155
}
150156

151157
report_tables = [
@@ -164,22 +170,32 @@ def lambda_handler(event, lambda_context):
164170
date_to_track_from = today - datetime.timedelta(days=1)
165171
logger.info(f"Date to track from: {date_to_track_from}")
166172

167-
s3_client = boto3.client('s3')
173+
s3_client = boto3.client("s3")
168174

169175
for report_details in report_tables:
170-
logger.info(f'Pulling report for {report_details["name"]}')
176+
logger.info(f"Pulling report for {report_details['name']}")
171177
case_id_report_id = report_details["id"]
172-
case_id_list = get_icaseworks_report_from(case_id_report_id, date_to_track_from, auth_headers, auth_payload)
178+
case_id_list = get_icaseworks_report_from(
179+
case_id_report_id, date_to_track_from, auth_headers, auth_payload
180+
)
173181
report_details["data"] = case_id_list
174-
write_dataframe_to_s3(s3_client, report_details["data"], s3_bucket, output_folder_name, report_details["name"])
175-
logger.info(f'Finished writing report for {report_details["name"]} to S3')
182+
write_dataframe_to_s3(
183+
s3_client,
184+
report_details["data"],
185+
s3_bucket,
186+
output_folder_name,
187+
report_details["name"],
188+
)
189+
logger.info(f"Finished writing report for {report_details['name']} to S3")
176190

177191
# Trigger glue job to copy from landing to raw and convert to parquet
178-
glue_client = boto3.client('glue')
192+
glue_client = boto3.client("glue")
179193
start_glue_trigger(glue_client, glue_trigger_name)
180194

195+
181196
def single_digit_to_zero_prefixed_string(value):
182-
return str(value) if value > 9 else '0' + str(value)
197+
return str(value) if value > 9 else "0" + str(value)
198+
183199

184200
def start_glue_trigger(glue_client, trigger_name):
185201
trigger_details = glue_client.start_trigger(Name=trigger_name)

lambdas/sftp_to_s3/index.js

Lines changed: 39 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ const config = {
1616
host: process.env.SFTP_HOST,
1717
username: process.env.SFTP_USERNAME,
1818
password: process.env.SFTP_PASSWORD,
19-
port: 22
19+
port: 22,
2020
};
2121

2222
let fileNamePattern = "";
@@ -34,28 +34,28 @@ async function getImportFilenamePattern(manualOverrideDateString) {
3434
Settings.throwOnInvalid = true;
3535
DateTime.fromISO(manualOverrideDateString);
3636

37-
let parts = manualOverrideDateString.split('-');
37+
let parts = manualOverrideDateString.split("-");
3838
dateToImport = new Date(parts[0], parts[1] - 1, parts[2]);
3939
}
4040

4141
year = dateToImport.getFullYear().toString();
42-
month = (dateToImport.getMonth() + 1).toString().padStart(2, '0');
43-
day = dateToImport.getDate().toString().padStart(2, '0');
44-
date = `${year}-${month}-${day}`
42+
month = (dateToImport.getMonth() + 1).toString().padStart(2, "0");
43+
day = dateToImport.getDate().toString().padStart(2, "0");
44+
date = `${year}-${month}-${day}`;
4545

4646
fileNamePattern = `${sftpSourceFilePrefix}${date}`;
4747
}
4848

4949
async function findFiles(sftpConn) {
50-
console.log(`filepath on server: ${sftpFilePath}`)
50+
console.log(`filepath on server: ${sftpFilePath}`);
5151

5252
const validPath = await sftpConn.exists(sftpFilePath);
5353

5454
if (!validPath) {
5555
return {
5656
success: false,
5757
message: `Path ${sftpFilePath} doesn't exist on SFTP server`,
58-
fileNames: []
58+
fileNames: [],
5959
};
6060
}
6161

@@ -68,7 +68,7 @@ async function findFiles(sftpConn) {
6868
function filterByFileNamePattern(file) {
6969
let name = file.name.toLowerCase();
7070
return name.includes(fileNamePattern.toLowerCase());
71-
}
71+
},
7272
);
7373

7474
if (fileList.length === 0) {
@@ -79,26 +79,30 @@ async function findFiles(sftpConn) {
7979
};
8080
}
8181

82-
const fileNames = fileList.filter(file => file.type != 'd').map(file => file.name);
82+
const fileNames = fileList
83+
.filter((file) => file.type != "d")
84+
.map((file) => file.name);
8385
console.log(fileNames);
8486
return {
8587
success: true,
8688
fileNames,
87-
message: ""
89+
message: "",
8890
};
8991
}
9092

9193
async function checkS3ForFile() {
9294
const s3Client = new AWS.S3({ region: AWS_REGION });
9395
const params = {
9496
Bucket: s3Bucket,
95-
Key: `${s3TargetFolder}/import_year=${year}/import_month=${month}/import_day=${day}/import_date=${date}/${sftpSourceFilePrefix}${date}.${sftpSourceFileExtension}`
97+
Key: `${s3TargetFolder}/import_year=${year}/import_month=${month}/import_day=${day}/import_date=${date}/${sftpSourceFilePrefix}${date}.${sftpSourceFileExtension}`,
9698
};
9799
try {
98100
await s3Client.headObject(params).promise();
99101
return true;
100102
} catch (error) {
101-
console.log(`Today's ${s3TargetFolder} file not yet present in S3 bucket, retrieving file from SFTP`)
103+
console.log(
104+
`Today's ${s3TargetFolder} file not yet present in S3 bucket, retrieving file from SFTP`,
105+
);
102106
return false;
103107
}
104108
}
@@ -109,7 +113,7 @@ function putFile() {
109113
const params = {
110114
Bucket: s3Bucket,
111115
Key: `${s3TargetFolder}/import_year=${year}/import_month=${month}/import_day=${day}/import_date=${date}/${sftpSourceFilePrefix}${date}.${sftpSourceFileExtension}`,
112-
Body: stream
116+
Body: stream,
113117
};
114118

115119
const upload = s3Client.upload(params);
@@ -129,8 +133,7 @@ async function streamFileFromSftpToS3(sftp, fileName) {
129133
}
130134

131135
exports.handler = async (event) => {
132-
133-
let manualOverrideDateString = event['DateToImport'];
136+
let manualOverrideDateString = event["DateToImport"];
134137

135138
console.log(`Manual override date: ${manualOverrideDateString}`);
136139

@@ -139,8 +142,13 @@ exports.handler = async (event) => {
139142
const sftp = new sftpClient();
140143

141144
if (await checkS3ForFile()) {
142-
console.log(`Today's ${s3TargetFolder} file is already present in S3 bucket!`);
143-
return { success: true, message: `File already found in s3, no further action taken` };
145+
console.log(
146+
`Today's ${s3TargetFolder} file is already present in S3 bucket!`,
147+
);
148+
return {
149+
success: true,
150+
message: `File already found in s3, no further action taken`,
151+
};
144152
}
145153

146154
await sftp.connect(config);
@@ -153,26 +161,33 @@ exports.handler = async (event) => {
153161
console.log(findFilesResponse);
154162
return {
155163
success: findFilesResponse.success,
156-
message: findFilesResponse.message
164+
message: findFilesResponse.message,
157165
};
158166
}
159167

160-
await Promise.all(findFilesResponse.fileNames.map(file => streamFileFromSftpToS3(sftp, file)));
168+
await Promise.all(
169+
findFilesResponse.fileNames.map((file) =>
170+
streamFileFromSftpToS3(sftp, file),
171+
),
172+
);
161173

162174
//start trigger
163-
const glue = new AWS.Glue({ apiVersion: '2017-03-31' });
175+
const glue = new AWS.Glue({ apiVersion: "2017-03-31" });
164176
const params = {
165-
Name: trigger_to_run
177+
Name: trigger_to_run,
166178
};
167-
console.log("Starting trigger with params", params)
179+
console.log("Starting trigger with params", params);
168180

169181
await glue.startTrigger(params).promise();
170182

171183
console.log("Success!");
172-
return { success: true, message: `Successfully uploaded ${findFilesResponse.fileNames.length} file(s) to s3` };
184+
return {
185+
success: true,
186+
message: `Successfully uploaded ${findFilesResponse.fileNames.length} file(s) to s3`,
187+
};
173188
} catch (error) {
174189
console.error(error.message);
175190
} finally {
176191
await sftp.end();
177192
}
178-
}
193+
};

0 commit comments

Comments
 (0)