def post(self): # first check the auth token auth_header = request.headers.get('Authorization') if not auth_header: return "No authorization token", 403 T = Token() identity = T.check(auth_header) if not identity: return "Wrong token", 403 # unpack the address data = request.json if not data: return "Malformed request", 400 success, result = unpack( data, "unit_number", "street_number", "street_name", "suburb", "postcode", "state", required=True ) if not success: return "Missing parameter in address", 400 unitnumber, streetnumber, streetname, suburb, postcode, state = result # check all validity success, msg = check_address( unitnumber, streetnumber, streetname, suburb, postcode, state ) if not success: return msg, 400 sql = """INSERT INTO customer_address(user_id, unit_number, street_number, street_name, suburb, state, postcode) VALUES(?, ?, ?, ?, ?, ?, ?) """ values = (identity['user_id'], unitnumber, streetnumber, streetname, suburb, state, postcode) try: with sqlite3.connect(os.environ.get("DB_FILE")) as conn: conn.row_factory = lambda C, R: {c[0]: R[i] for i, c in enumerate(C.description)} cur = conn.cursor() cur.execute(sql, values) new_address_id = cur.lastrowid return {"address_id": new_address_id}, 200 except Exception as e: print(e) return "Internal server error", 500
def put(self): auth=request.headers.get("Authorization") if not auth: return "No authorization token",403 T=Token() identity=T.check(auth) if not identity: return"Wrong token",403 ids = identity['user_id'] data=request.json if not data: return "Malformed request", 400 is_unpack_ok, modified_data = unpack( data, "first_name","last_name","email","mobile","password", required=False ) if not is_unpack_ok: return "Malformed request", 400 f_name, l_name, email, mobile, password = modified_data # also prepare the sql for the relevant modified data # one data => one sql => one tuple in the sql_param_list sql_list = [] sql_param_list = [] if f_name: ok, msg = check_name(f_name) if not ok: return msg, 400 sql_list.append("UPDATE user SET first_name = ? WHERE user_id = ?") sql_param_list.append((f_name, ids)) if l_name: ok, msg = check_name(l_name) if not ok: return msg, 400 sql_list.append("UPDATE user SET last_name = ? WHERE user_id = ?") sql_param_list.append((l_name, ids)) if email: ok, msg = check_email(email) if not ok: return msg, 400 sql_list.append("UPDATE user SET email = ? WHERE user_id = ?") sql_param_list.append((email, ids)) if mobile: ok, msg = check_mobile(mobile); if not ok: return msg, 400 sql_list.append("UPDATE user SET mobile = ? WHERE user_id = ?") sql_param_list.append((mobile, ids)) if password: ok, msg = check_password(password) if not ok: return msg, 400 sql_list.append("UPDATE user SET password = ? WHERE user_id = ?") sql_param_list.append((password, ids)) # if nothing update, this is a malformed request if len(sql_list) == 0: return "Malformed request", 400 try: with sqlite3.connect(os.environ.get("DB_FILE")) as conn: conn.row_factory = lambda C, R: {c[0]: R[i] for i, c in enumerate(C.description)} cur = conn.cursor() for i in range(len(sql_list)): cur.execute(sql_list[i], sql_param_list[i]) return "OK", 200 except Exception as e: print(e) return "Internal server error", 500
def put(self): # first check the auth token auth_header = request.headers.get('Authorization') if not auth_header: return "No authorization token", 403 T = Token() identity = T.check(auth_header) if not identity: return "Wrong token", 403 # require the address_id if not request.args.get("address_id"): return "Missing address_id", 400 address_id = None try: address_id = int(request.args.get("address_id")) except ValueError: return "Address_id should be integer", 400 if address_id and address_id <= 0: return "Address_id should be positive", 400 # check if the token user has the address or not sql_1 = """ SELECT * FROM customer_address WHERE user_id = ? and address_id = ? """ sql_1_param = (identity['user_id'], address_id) try: with sqlite3.connect(os.environ.get("DB_FILE")) as conn: conn.row_factory = lambda C, R: {c[0]: R[i] for i, c in enumerate(C.description)} cur = conn.cursor() result = cur.execute(sql_1, sql_1_param) if not result: return "Invalid address_id", 401 except Exception as e: print(e) return "Internal server error", 500 # nwo unpack the address data = request.json if not data: return "Malformed request", 400 success, result = unpack( data, "unit_number", "street_number", "street_name", "suburb", "postcode", "state", required=True ) if not success: return "Missing parameter in address", 400 unitnumber, streetnumber, streetname, suburb, postcode, state = result # check all validity success, msg = check_address( unitnumber, streetnumber, streetname, suburb, postcode, state ) if not success: return msg, 400 # sql sql_2 = """ UPDATE customer_address SET unit_number = ?, street_number = ?, street_name = ?, suburb = ?, postcode = ?, state = ? WHERE user_id = ? AND address_id = ? """ sql_2_param = ( unitnumber, streetnumber, streetname, suburb, postcode, state, identity['user_id'], address_id ) try: with sqlite3.connect(os.environ.get("DB_FILE")) as conn: conn.row_factory = lambda C, R: {c[0]: R[i] for i, c in enumerate(C.description)} cur = conn.cursor() cur.execute(sql_2, sql_2_param) return "OK", 200 except Exception as e: print(e) return "Internal server error", 500
def post(self): """Only admin can upload""" identity, msg, code = check_admin_identity() if not identity: return msg, code data = request.json if not data: return "No data", 400 # scan all attributes, make sure all keys are ok for key in data: if key not in simple_attributes and key not in detail_attributes and key != "photos": return "Invalid attribute {}".format(key), 400 # simple_attributes must be fullfilled # the thumbnail can be empty for now success, unpack_result = unpack( data, "name", "price", "stock_number", "status", ) if not success: return "Simple attributes must be fullfilled (you can leave thumbnail for now)", 400 # the admin must upload at least one photo if "photos" not in data: return "No photos provided", 400 if not (type(data['photos']) is list): return "The photos value must be a list", 400 if len(data['photos']) == 0: return "Need to provide at least one photo", 400 print(data) # sql part try: with sqlite3.connect(os.environ.get("DB_FILE")) as conn: conn.row_factory = lambda C, R: { c[0]: R[i] for i, c in enumerate(C.description) } cur = conn.cursor() # insert simple profile and get id # view starts from 0 sql_1 = """ INSERT INTO item(name, price, stock_number, status, view) VALUES (?, ?, ?, ?, 0) """ param_1 = tuple(unpack_result) cur.execute(sql_1, param_1) new_item_id = cur.lastrowid # now insert a row into the table "laptop" sql_2 = "INSERT INTO laptop(item_id) VALUES (?)" param_2 = (new_item_id, ) cur.execute(sql_2, param_2) # now insert for all detail attributes for key in data: if key in detail_attributes: sql_3 = "UPDATE laptop SET {} = ? WHERE item_id = ?".format( key) param_3 = (data[key], new_item_id) cur.execute(sql_3, param_3) # insert all photos for src in data['photos']: sql_4 = "INSERT INTO photo(item_id, photo) VALUES (?, ?)" param_4 = (new_item_id, src) cur.execute(sql_4, param_4) # after insertion, return the id result = { "item_id": new_item_id, } return result, 200 except Exception as e: print(e) return "Internal server error", 500
def post(self): if not request.json: return "Malformed request", 400 data = request.json # check data success, result = unpack(data, "first_name", "last_name", "email", "mobile", "password", "address", required=True) if not success: return "Missing parameter", 400 firstname, lastname, email, mobile, password, address = result # also decompose the address success, result = unpack(address, "unit_number", "street_number", "street_name", "suburb", "postcode", "state", required=True) if not success: return "Missing parameter in address", 400 unitnumber, streetnumber, streetname, suburb, postcode, state = result # now do some check success, msg = check_name(firstname, lastname) if not success: return msg, 400 success, msg = check_email(email) if not success: return msg, 400 success, msg = check_password(password) if not success: return msg, 400 success, msg = check_mobile(mobile) if not success: return msg, 400 success, msg = check_address(unitnumber, streetnumber, streetname, suburb, postcode, state) if not success: return msg, 400 # create the user and the address try: with sqlite3.connect(os.environ.get("DB_FILE")) as conn: cur = conn.cursor() sql_1 = """ INSERT INTO user(role, password, first_name, last_name, email, mobile) VALUES (1, ?, ?, ?, ?, ?) """ sql_1_param = (password, firstname, lastname, email, mobile) cur.execute(sql_1, sql_1_param) # get the new account id user_id = cur.lastrowid sql_2 = """ INSERT INTO customer_address(user_id, unit_number, street_number, street_name, suburb, state, postcode) VALUES(?, ?, ?, ?, ?, ?, ?) """ sql_2_param = (user_id, unitnumber, streetnumber, streetname, suburb, state, postcode) cur.execute(sql_2, sql_2_param) # generate the token T = Token() token = T.generate(user_id=user_id, role=1) return_value = {'token': token, 'role': 1} return return_value, 200 except sqlite3.IntegrityError as e: print(e) return "Email taken already", 409 except sqlite3.Error as e: print(e) return "Internal server error", 500
def submit_order(cart, identity): # example cart data format: # { # "address_id": 0, # "notes": "string", # "card_last_four": "string", # "total_price": "string", # "items": [ # { # "item_id": 0, # "quantity": 0, # "price": 0 # } # ] # } # unpack the first level flag, result = unpack(cart, "address_id", "notes", "card_last_four", "total_price", "items", required=True) if not flag: return 400, "Missing parameter" address_id, notes, card_last_four, total_price, items = result # address_id try: address_id = int(address_id) if address_id < 0: raise ValueError except ValueError: return 400, "Parameter address_id must be a positive integer" try: with sqlite3.connect(os.environ.get("DB_FILE")) as conn: conn.row_factory = lambda C, R: { c[0]: R[i] for i, c in enumerate(C.description) } cur = conn.cursor() sql_1 = """ SELECT * FROM customer_address WHERE user_id = ? AND address_id = ? """ sql_1_param = (identity["user_id"], address_id) cur.execute(sql_1, sql_1_param) sql_1_result = cur.fetchone() if not sql_1_result: return 400, "Invalid address_id" except Exception as e: print(e) return 500, "Internal Server Error" # variable 'notes' no need to check # check card_last_four if re.match("^\d{4}$", card_last_four) is None: return 402, "Invalid card last four digits" # check total_price # convert to float first, check the amount later try: total_price = float(total_price) if total_price < 0: raise ValueError except ValueError: return 400, "total price must be positive float" # check the items # "items": [ # { # "item_id": 0, # "quantity": 0, # "price": 0 # } # ] if not isinstance(items, list): return 400, "key 'items' must be a list" # store backend_total_price order_total_price = 0 # check the interior try: with sqlite3.connect(os.environ.get("DB_FILE")) as conn: conn.row_factory = lambda C, R: { c[0]: R[i] for i, c in enumerate(C.description) } cur = conn.cursor() for item in items: flag, result = unpack(item, "item_id", "quantity", "price", required=True) if not flag: raise KeyError item_id, quantity, price = int(result[0]), int( result[1]), float(result[2]) if item_id <= 0 or quantity <= 0 or price < 0: raise ValueError # now check the item_id exist, and price is the same # and quantity is available sql_2 = """ SELECT price, stock_number, status, name FROM item WHERE item_id = ? """ sql_2_param = (item_id, ) cur.execute(sql_2, sql_2_param) sql_2_result = cur.fetchone() # check the item does not exist if not sql_2_result: response = { 'item_id': item_id, } return 409, response # this item is removed from shelf if sql_2_result['status'] == 0: response = { 'item_id': item_id, 'name': sql_2_result['name'], } return 410, response # not enough stock if sql_2_result["stock_number"] < quantity: response = { 'item_id': item_id, 'available_stock': sql_2_result["stock_number"], 'name': sql_2_result['name'], } return 411, response # incorrect unit price if sql_2_result['price'] != price: response = { "item_id": item_id, "price": sql_2_result["price"], "name": sql_2_result['name'], } return 414, response # update the total order price order_total_price += quantity * price except KeyError as e: print(e) return 400, "Missing parameters in key 'items'" except ValueError as e: print(e) return 400, "Item id & quantity must be positive integer, and price must be float" except Exception as e: print(e) return 500, "Internal server error" # check the total price total_price = round(total_price, 2) if total_price != round(order_total_price, 2): response = {'total_price': round(order_total_price, 2)} return 413, response # submit the order try: with sqlite3.connect(os.environ.get("DB_FILE")) as conn: cur = conn.cursor() sql_3 = """ INSERT INTO orders(user_id, unix_time, total_price, address_id, notes, card_last_four) VALUES(?, ?, ?, ?, ?, ?) """ sql_3_param = (identity["user_id"], int(time.time()), total_price, address_id, notes, card_last_four) cur.execute(sql_3, sql_3_param) new_order_id = cur.lastrowid # insert all items # also update the item stock number sql_4 = """ INSERT INTO order_item(ord_id, item_id, quantity, price, snapshot) VALUES(?, ?, ?, ?, ?) """ sql_5 = """ UPDATE item SET stock_number = stock_number - ? WHERE item_id = ? """ for item in items: # get this item snapshot profile_list = [] profile_list.append(item) snapshot = get_all_profiles(profile_list)[0] sql_4_param = ( new_order_id, item['item_id'], item['quantity'], item['price'], json.dumps(snapshot), ) sql_5_param = ( item['quantity'], item['item_id'], ) cur.execute(sql_4, sql_4_param) cur.execute(sql_5, sql_5_param) # success response = {'ord_id': new_order_id, 'total_price': total_price} return 200, response except Exception as e: print(e) print(type(e)) return 500, "Internal server error"