-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
331 lines (254 loc) · 11.4 KB
/
app.py
File metadata and controls
331 lines (254 loc) · 11.4 KB
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
from flask import Flask, jsonify, request, Response
import create_db
from mysql.connector import connection, Error
import os
from dotenv import load_dotenv
from collections.abc import Iterable
app = Flask(__name__)
load_dotenv()
def get_conn():
conn = connection.MySQLConnection(
host = os.getenv('DB_HOST'),
user = os.getenv('DB_USER'),
password = os.getenv('DB_PASSWORD'),
database = os.getenv('DB_NAME')
)
return conn
@app.route('/posts', methods=['GET', 'POST'])
def get_posts():
res = {}
res_code = 200
try:
conn = get_conn()
cursor = conn.cursor()
if request.method == "GET":
cursor.execute('SELECT * FROM posts')
posts_description = cursor.description
results = cursor.fetchall()
res= []
for post in results:
r = dict(zip([event[0] for event in posts_description], post))
# Getting the category name from the category id
cursor.execute('SELECT category FROM categories WHERE category_id = %s', [r.get('category')])
c = cursor.fetchone()
r['category'] = str(c[0])
# To add tags details
cursor.execute('SELECT tag FROM tags WHERE tag_id IN (SELECT tag_id FROM post_tags WHERE post_id = %s)',(r.get('id'),))
tags_db = cursor.fetchall()
tags = []
for tag in tags_db:
tags.append(tag[0])
r['tags'] = tags
res.append(r)
elif request.method == 'POST':
'''
Validation Paramters
1. Check the number of keys whether they are are meeting the required count
2. Check whether they are the ones we need
3. Validate Category
i) Check wheter the category is present in the DB
ii) If so get the category_id
4. Validate tags
i) Validate wheter the tags is Iteratable
ii) If so, get the id of each, if any one not found, raise error
5. Insert into posts table
6. Insert into posts_tags table
7. Commit the changes
'''
# Start the transaction
conn.start_transaction(isolation_level='REPEATABLE READ')
data = request.json
mandatory_keys = set(['title', 'content', 'category', 'tags'])
# Checking for the count of the keys
if len(data.keys()) != 4:
raise Error("The required fields are not present. Please add title, content, category, tags ONLY!")
# Checking all the keys one by one
for key in data.keys():
if key not in mandatory_keys:
raise Error("The required fields are not present. Please add title, content, category, tags ONLY!")
# Validating Category and Tags
# Validating Category
cursor.execute('SELECT category_id FROM categories WHERE LOWER(category) = LOWER(%s)',[data.get('category')])
category_id = cursor.fetchone()
if not category_id:
raise Error("Please select the existing Category only")
category_id = category_id[0]
# Validating Tags
tags = data.get('tags')
if not isinstance(tags, Iterable):
raise Error("The Tags should be iterable")
tag_ids = []
for tag in tags:
cursor.execute('SELECT tag_id FROM tags WHERE LOWER(tag) = LOWER(%s)', [tag])
tag_id = cursor.fetchone()
if not tag_id:
raise Error("The Tag is not present in the DB, Please select existing tags")
tag_ids.append(tag_id[0])
# Inserting the data
cursor.execute('INSERT INTO posts (title, content, category, createdAt, updatedAt) VALUES (%s, %s, %s, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)',[data.get('title'), data.get('content'), category_id])
# cursor.execute('select id from posts where id = last_insert_id()')
post_id = cursor.lastrowid
for tag_id in tag_ids:
cursor.execute('INSERT INTO post_tags (post_id, tag_id) VALUES (%s, %s)', [post_id, tag_id])
cursor.execute('SELECT * FROM posts where id = %s', [post_id])
post = cursor.fetchone()
if not post:
raise Error("Post Not Found")
res = dict(zip([event[0] for event in cursor.description], post))
# Getting the category name from the category id
cursor.execute('SELECT category FROM categories WHERE category_id = %s', [res.get('category')])
c = cursor.fetchone()
res['category'] = str(c[0])
# To add tags details
cursor.execute('SELECT tag FROM tags WHERE tag_id IN (SELECT tag_id FROM post_tags WHERE post_id = %s)',(res.get('id'),))
tags_db = cursor.fetchall()
tags = []
for tag in tags_db:
tags.append(tag[0])
res['tags'] = tags
res_code = 201
conn.commit()
except Error as e:
res = {
'msg' : str(e)
}
res_code = 400
conn.rollback()
finally:
cursor.close()
conn.close()
return jsonify(res), res_code
@app.route('/posts/<int:id>', methods=['GET', 'PUT', 'DELETE'])
def post(id):
if request.method == 'GET':
try:
conn = get_conn()
cursor = conn.cursor()
cursor.execute('SELECT * FROM posts WHERE id = %s', [id])
post = cursor.fetchone()
if not post:
raise Error("Post Not Found")
res = dict(zip([event[0] for event in cursor.description], post))
res_code = 200
# Getting the category name from the category id
cursor.execute('SELECT category FROM categories WHERE category_id = %s', [res.get('category')])
c = cursor.fetchone()
res['category'] = str(c[0])
# To add tags details
cursor.execute('SELECT tag FROM tags WHERE tag_id IN (SELECT tag_id FROM post_tags WHERE post_id = %s)',(res.get('id'),))
tags_db = cursor.fetchall()
tags = []
for tag in tags_db:
tags.append(tag[0])
res['tags'] = tags
except Error as e:
res = {
'msg' : str(e)
}
res_code = 404
finally:
cursor.close()
conn.close()
elif request.method == 'PUT':
res_code = 200
res = {}
try:
conn = get_conn()
cursor = conn.cursor(dictionary=True)
conn.start_transaction(isolation_level='READ COMMITTED')
'''
Method to put a value:
PUT: a method where we will replace the whole row.
1. Check if the id for post is there
2. If it exist the validate all the validations done on POST
3. Update that id and return the POST
'''
cursor.execute('SELECT * FROM posts WHERE id = %s', [id])
res = cursor.fetchone()
if not res:
res_code = 404
raise Error(f"The post with id {id} not Found")
data = request.json
mandatory_keys = set(['title', 'content', 'category', 'tags'])
# Checking for the count of the keys
if len(data.keys()) != 4:
raise Error("The required fields are not present. Please add title, content, category, tags ONLY!")
# Checking all the keys one by one
for key in data.keys():
if key not in mandatory_keys:
raise Error("The required fields are not present. Please add title, content, category, tags ONLY!")
# Validating Category and Tags
# Validating Category
cursor.execute('SELECT category_id FROM categories WHERE LOWER(category) = LOWER(%s)',[data.get('category')])
category_id = cursor.fetchone()
print(category_id)
if not category_id:
raise Error("Please select the existing Category only")
category_id = category_id['category_id']
# Validating Tags
tags = data.get('tags')
if not isinstance(tags, Iterable):
raise Error("The Tags should be iterable")
tag_ids = []
for tag in tags:
cursor.execute('SELECT tag_id FROM tags WHERE LOWER(tag) = LOWER(%s)', [tag])
tag_id = cursor.fetchone()
if not tag_id:
raise Error("The Tag is not present in the DB, Please select existing tags")
tag_ids.append(tag_id['tag_id'])
cursor.execute('DELETE FROM post_tags WHERE post_id = %s', [id])
cursor.execute('UPDATE posts SET title = %s, content = %s, category = %s, updatedAt = CURRENT_TIMESTAMP WHERE id = %s',[data.get('title'), data.get('content'), category_id, id])
for tag_id in tag_ids:
cursor.execute('INSERT INTO post_tags (post_id, tag_id) VALUES (%s, %s)', [id, tag_id])
# After Modification, fetching the row
cursor.execute('SELECT * FROM posts where id = %s', [id])
res = cursor.fetchone()
# if not post:
# raise Error("Post Not Found")
# res = dict(zip([event[0] for event in cursor.description], post))
# Getting the category name from the category id
cursor.execute('SELECT category FROM categories WHERE category_id = %s', [res.get('category')])
c = cursor.fetchone()
res['category'] = str(c['category'])
# To add tags details
cursor.execute('SELECT tag FROM tags WHERE tag_id IN (SELECT tag_id FROM post_tags WHERE post_id = %s)',(res.get('id'),))
tags_db = cursor.fetchall()
tags = []
for tag in tags_db:
tags.append(tag['tag'])
res['tags'] = tags
res_code = 200
conn.commit()
except Error as e:
res = {
'msg': str(e)
}
conn.rollback()
finally:
cursor.close()
conn.close()
elif request.method == 'DELETE':
try:
conn = get_conn()
cursor = conn.cursor(dictionary=True)
conn.start_transaction(isolation_level='READ COMMITTED')
res_code = 204
cursor.execute('SELECT * FROM posts WHERE id = %s', [id])
post = cursor.fetchone()
if not post:
res_code = 404
raise Error("Post Not Found")
cursor.execute('DELETE FROM posts WHERE id = %s', [id])
conn.commit()
return Response(status=res_code)
except Error as e:
res = {
'msg' : str(e)
}
conn.rollback()
finally:
cursor.close()
conn.close()
return jsonify(res), res_code
if __name__ == "__main__":
app.run(debug=True)