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
Esempio n. 4
0
    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"