-
Notifications
You must be signed in to change notification settings - Fork 0
/
EtsyPollingTransactions.py
236 lines (202 loc) · 7.45 KB
/
EtsyPollingTransactions.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
import os
import json
import boto3
import logging
import requests
import datetime
from boto3.dynamodb.conditions import Key
# set up logging
logger = logging.getLogger()
logger.setLevel(logging.INFO)
# set up AWS resources
session = boto3.Session()
s3 = session.resource('s3')
dynamodb = boto3.resource('dynamodb')
table = dynamodb.Table('etsy-oauth')
BASE_URL = 'https://api.etsy.com/v3/application'
class etsy():
def __init__(self, api_keystring='', access_token='', refresh_token='', shop_id='', user_id=''):
'''
Initialize Etsy object.
'''
self.api_keystring = api_keystring
self.access_token = access_token
self.refresh_token = refresh_token
self.shop_id = shop_id
self.user_id = user_id
self.oauth_url = 'https://api.etsy.com/v3/public/oauth/token'
self.base_url = 'https://api.etsy.com/v3/application'
self.headers = {
'x-api-key': self.api_keystring,
'Authorization' : f'Bearer {self.access_token}'
}
def _http_req(self, method, suffix, body=None):
'''
Execute HTTP API requests for Etsy REST API.
'''
resp = requests.request(
method=method,
url=self.base_url + suffix,
headers=self.headers,
data=json.dumps(body)
)
logger.info(f'STATUS_CODE:{resp.status_code} | URL:{self.base_url + suffix}')
if resp.status_code == 401 and resp.json().get('error') == 'invalid_token':
self._refresh_token()
logger.info('Retrying API call after Token Refresh...')
resp = requests.request(
method=method,
url=self.base_url + suffix,
headers=self.headers,
data=json.dumps(body)
)
if resp.status_code == 200:
return resp.json()
else:
raise ConnectionError(
"Could Not Connect. Status Code: {0}".format(resp.status_code)
)
def _refresh_token(self):
'''
Update Etsy Oauth tokens after epiration.
'''
logger.info('NEW METHOD | Attempting to update Access and Refresh tokens...')
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
data = {
'grant_type': 'refresh_token',
'client_id': self.api_keystring,
'refresh_token': self.refresh_token
}
resp = requests.post(self.oauth_url, headers=headers, data=data)
if resp.status_code == 200:
logger.info('NEW METHOD | Sucessfully updated Access and Refresh tokens...')
self.set_access_token(resp.json().get('access_token'))
self.set_refresh_token(resp.json().get('refresh_token'))
self.set_headers()
def set_access_token(self, access_token):
'''
Update Access Token.
'''
self.access_token = access_token
def set_refresh_token(self, refresh_token):
'''
Update Refresh Token.
'''
self.refresh_token = refresh_token
def set_headers(self):
'''
Update HTTP Headers.
'''
self.headers = {
'x-api-key': self.api_keystring,
'Authorization' : f'Bearer {self.access_token}'
}
def get_access_token(self):
'''
Retrieve Access Token.
'''
return self.access_token
def get_refresh_token(self):
'''
Retrieve Refresh Token.
'''
return self.refresh_token
def get_shop_trans(self):
'''
Retrieve Etsy shop transactions.
'''
logger.info('NEW METHOD | Retrieving shop transactions...')
path = f'/shops/{self.shop_id}/transactions'
resp = self._http_req('GET', path)
return resp
def get_shop_receipt(self, receipt_id):
'''
Retrieve Etsy shop receipt.
'''
logger.info('NEW METHOD | Retrieving transaction receipt...')
path = f'/shops/{self.shop_id}/receipts/{receipt_id}'
resp = self._http_req('GET', path)
return resp
def db_table_query(query_key):
'''
Query table for current key info.
'''
response = table.query(KeyConditionExpression=Key('oauth_key_type').eq(query_key))
token = response['Items'][0].get('oauth_key_value')
return token
# set contants
def update_constants():
'''
Update and set global constants from DynamoDB.
'''
global BUCKET, API_KEYSTRING, SHOP_ID, USER_ID, ETSY_ACCESS_TOKEN, ETSY_REFRESH_TOKEN
BUCKET = db_table_query('ETSY_BUCKET')
API_KEYSTRING = db_table_query('ETSY_API_KEYSTRING')
SHOP_ID = db_table_query('ETSY_SHOP_ID')
USER_ID = db_table_query('ETSY_USER_ID')
ETSY_ACCESS_TOKEN = db_table_query('ETSY_ACCESS_TOKEN')
ETSY_REFRESH_TOKEN = db_table_query('ETSY_REFRESH_TOKEN')
def db_table_query(query_key):
'''
Query table for current key info.
'''
response = table.query(KeyConditionExpression=Key('oauth_key_type').eq(query_key))
token = response['Items'][0].get('oauth_key_value')
return token
def db_update_table(update_key_valu, update_key_type):
'''
Update table with new key info.
'''
logger.info(f'Updating {update_key_type}...')
table.put_item(Item={'oauth_key_value': update_key_valu, 'oauth_key_type': update_key_type})
def process_trans(trans):
'''
Process latest transactions and compare against last queried.
'''
if not trans:
return []
new_trans = []
for tran in trans:
# get last queried time and then update it with now()
timestamp = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
queried_timestamp = db_table_query('ETSY_LAST_QUERIED')
db_update_table(timestamp, 'ETSY_LAST_QUERIED')
# process timestamps
paid_time = datetime.datetime.fromtimestamp(tran.get('paid_timestamp'))
queried_time = datetime.datetime.strptime(queried_timestamp, '%Y-%m-%dT%H:%M:%S')
# new order not caught with previous query
if paid_time > queried_time:
obj = s3.Object(BUCKET, 'etsy/' + f'etsy_trans_{timestamp}.json')
obj.put(Body=json.dumps(tran, indent=4))
new_trans.append(tran)
return new_trans
def handler(event, context):
'''
Routine polling Etsy for new orders while maintaining Oauth API keys in DynamoDB table.
'''
update_constants()
# NEW METHOD | Retrieve Latest Etsy Update
etsy_api = etsy(
api_keystring=API_KEYSTRING,
access_token=ETSY_ACCESS_TOKEN,
refresh_token=ETSY_REFRESH_TOKEN,
shop_id=SHOP_ID,
user_id=USER_ID
)
trans = etsy_api.get_shop_trans()
timestamp = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S')
# update the db after refresh
db_update_table(etsy_api.get_access_token(), 'ETSY_ACCESS_TOKEN')
db_update_table(etsy_api.get_refresh_token(), 'ETSY_REFRESH_TOKEN')
db_update_table(timestamp, 'ETSY_LAST_UPDATED')
# save recent transactions
obj = s3.Object(BUCKET, 'etsy/' + f'etsy_new_trans_{timestamp}.json')
obj.put(Body=json.dumps(trans, indent=4))
# retrieve receipt and save file
rec = etsy_api.get_shop_receipt(trans['results'][0].get('receipt_id'))
obj_r = s3.Object(BUCKET, 'etsy/' + f'etsy_receipt_{timestamp}.json')
obj_r.put(Body=json.dumps(rec, indent=4))
# process transactions
# process_trans(trans.get('results', []))