Exemplo n.º 1
0
def fconnect():
    """Handle facebook OAuth login
        GET /auth/fconnect
        If user does not exists create a new user.
    """
    # userinfo has email, username, and access token
    userinfo = json.loads(request.data)
    user_access_token = userinfo.get('access_token')

    # To verify user's access token, we need to get our app token first.
    url = ('https://graph.facebook.com/oauth/access_token?'
           'client_id={}&client_secret={}'
           '&grant_type=client_credentials'.format(
               config.FACEBOOK_CLIENT_ID, config.FACEBOOK_CLIENT_SECRET))
    try:
        h = httplib2.Http()
        result = h.request(url, 'GET')[1]
        app_token = re.search(r'(access_token=)(.+?$)', result).group(2)

        print app_token

        # Using app token, we can verify user's access token
        url = ('https://graph.facebook.com/debug_token'
               '?input_token={}&access_token={}'.format(
                   user_access_token, app_token))

        h = httplib2.Http()
        result = json.loads(h.request(url, 'GET')[1])
        user_data = result.get("data")

        # If the user's token is valid to the app token,
        # Facecook api returns the variable 'is_valid' with True
        if not user_data.get("is_valid"):
            response = make_response(
                json.dumps("User access token is not valid"), 401)
            flash("Facebook connection Error.")
            response.headers['Content-Type'] = 'application/json'
            return response

        email = userinfo.get('email')
        user = User.get_by_email(session, email.strip())

        # Create and store a new user if there is no user exist
        if not user:
            user = User(email=email)
            session.add(user)
            session.commit()

        expire_time, token = generate_token(user)
        flash("Successfully logged in with Facebook")
        response = make_response(redirect(url_for('basic.showMain')), 200)
        response.set_cookie('token', value=token)
        response.set_cookie('expire_time', value=str(expire_time))
        return response
    except:
        response = make_response(json.dumps("User access token is not valid"),
                                 401)
        flash("Facebook connection Error.")
        response.headers['Content-Type'] = 'application/json'
        return response
def deleteItem(item_id):
    """
        GET /item/item id/delete:
            Render an delete item form page
        POST /item/item id/delete:
            Delete the selected item from database
    """
    token = request.cookies.get('token')
    expire_time = request.cookies.get('expire_time')
    # Only authorized user can see an edit item page
    if not token:
        flash("You are not authorized.")
        return redirect(url_for('basic.showMain'))

    if request.method == "GET":
        # Only authorized user can see a delete item page
        user_data = validate_token(token, expire_time)
        if not user_data:
            flash("You are not authorized.")
            return redirect(url_for('basic.showMain'))

        item = Item.get_by_id(session, item_id)
        return render_template('delete_item.html', item=item, user=user_data)

    if request.method == "POST":
        # When user send POST request,
        #     we get a token again from HTTP header, not from cookie
        token = request.headers.get('Authorization')
        # Get item to delete
        item = Item.get_by_id(session, item_id)
        # Only authorized user can delete this item
        user_data = validate_token(token, expire_time)
        if not user_data:
            response = make_response(
                json.dumps({
                    "message": "You are not authorized",
                    "redirect": url_for('basic.showItemDetail',
                                        category_id=item.category_id,
                                        item_id=item_id)
                }), 401
            )
            response.headers['Content-Type'] = 'application/json'
            return response

        # Only authorized user can delete an item
        # Authorized user id must be the same as
        #     the user's id who created the item before.
        user = User.get_by_id(session, user_data.get("id"))
        if not User.is_authorized(session, user.id, item_id):
            response = make_response(
                json.dumps({
                    "message": "You are not authorized",
                    "redirect": url_for('basic.showItemDetail',
                                        category_id=item.category_id,
                                        item_id=item_id)
                }), 401
            )
            response.headers['Content-Type'] = 'application/json'
            return response

        session.delete(item)
        session.commit()

        response = make_response(
            json.dumps({
                "message": "The item was successfully deleted.",
                "redirect": url_for('basic.showMain')
            }), 200
        )
        response.headers['Content-Type'] = 'application/json'
        return response
def editItem(category_id, item_id):
    """
        GET /category/category id/item/item id/edit:
            Render an edit item form page
        POST /category/category id/item/item id/edit:
            Update the selected item's attributes
            Fields:
                title (required)
                description
                category (required)
    """
    token = request.cookies.get('token')
    expire_time = request.cookies.get('expire_time')
    # Only authorized user can see an edit item page
    if not token:
        flash("You are not authorized.")
        return redirect(url_for('basic.showMain'))

    if request.method == "GET":

        # Only authorized user can see an edit item page
        user_data = validate_token(token, expire_time)
        if not user_data:
            flash("You are not authorized.")
            return redirect(url_for('basic.showMain'))

        # Only authorized user can see an edit item page
        # Authorized user id must be the same as
        #     the user's id who created the item before.
        if not User.is_authorized(session, user_data.get("id"), item_id):
            flash("You are not authorized.")
            return redirect(url_for('basic.showMain'))

        categories = Category.get_all(session)
        item = Item.get_by_id(session, item_id)
        return render_template('edit_item.html',
                               categories=categories, item=item)

    if request.method == "POST":
        # When user send POST request,
        #     we get a token again from HTTP header, not from cookie
        token = request.headers.get('Authorization')
        # Only authorized user can edit this item
        user_data = validate_token(token, expire_time)
        if not user_data:
            response = make_response(
                json.dumps({
                    "message": "You are not authorized",
                    "redirect": url_for('basic.showItemDetail',
                                        category_id=category_id,
                                        item_id=item_id)
                }), 401
            )
            response.headers['Content-Type'] = 'application/json'
            return response

        item = Item.get_by_id(session, item_id)
        title = request.form.get('title')
        description = request.form.get('description')
        new_category_id = request.form.get('category')

        # In the form in HTML title field is required.
        # No title means the user use another way to send POST request
        if not title:
            response = make_response(
                json.dumps({
                    "message": "Please use the proper way",
                    "redirect": url_for('basic.showItemDetail',
                                        category_id=category_id,
                                        item_id=item_id)
                }), 401
            )
            response.headers['Content-Type'] = 'application/json'
            return response

        # Only authorized user can edit item
        # Authorized user id must be the same as
        #     the user's id who created the item before.
        user = User.get_by_id(session, user_data.get("id"))
        if not User.is_authorized(session, user.id, item_id):
            response = make_response(
                json.dumps({
                    "message": "You are not authorized",
                    "redirect": url_for('basic.showItemDetail',
                                        category_id=item.category_id,
                                        item_id=item_id)
                }), 401
            )
            response.headers['Content-Type'] = 'application/json'
            return response

        item.title = title
        item.description = description
        item.category_id = new_category_id
        session.add(item)
        session.commit()

        response = make_response(
            json.dumps({
                "message": "The item was successfully edited.",
                "redirect": url_for('basic.showItemDetail',
                                    category_id=category_id,
                                    item_id=item.id)
            }), 200
        )
        response.headers['Content-Type'] = 'application/json'
        return response
Exemplo n.º 4
0
def login(cached_email=None):
    """Render login page and handle login form data.
        Requests:
            GET /auth/login
            POST /auth/login
    """
    if request.method == 'GET':
        csrf_token = generate_csrf_token()
        response = make_response(
            render_template('login.html',
                            cached_email=cached_email,
                            client_id=CLIENT_ID,
                            csrf_token=csrf_token))
        # Store the csrf_token in the browser cookie.
        response.set_cookie('csrf_token', value=csrf_token)
        return response

    # Form fields:
    #     email: user email, required
    #     password: user password, required
    if request.method == 'POST':
        # Check csrf token
        cookie_csrf_token = request.cookies.get('csrf_token')
        form_csrf_token = request.form.get('_csrf_token')

        # CSRF attack detected!
        if cookie_csrf_token != form_csrf_token:
            flash("Please use proper login.")
            return render_template('login.html',
                                   cached_email=cached_email,
                                   client_id=CLIENT_ID,
                                   csrf_token="")

        # Get user data from login form.
        email = request.form.get('email')
        password = request.form.get('password')

        # User must fill the email and password field.
        if not (email and password):
            flash("Please fill the form. ")
            return render_template('login.html', cached_email=email)

        # Find user in the database by email.
        user = User.get_by_email(session, email.strip())
        # User does not exists.
        if not user:
            flash("Invalid email address or password. ")
            return render_template('login.html', cached_email=email)

        # User exist, but Password does not.
        # The user have logged in with OAuth
        if not user.password:
            flash("You've signed up with social service. ")
            return render_template('login.html', cached_email=email)

        # Password incorrect.
        if not check_password(password, user.password, user.salt):
            flash("Invalid email address or password. ")
            return render_template('login.html', cached_email=email)

        # Generate JSON web token for user.
        # As long as client has non-expired and valid token,
        #     they do not need to login again.
        expire_time, token = generate_token(user)
        response = make_response(redirect(url_for('basic.showMain')))
        # Store the token in the browser cookie.
        response.set_cookie('token', value=token)
        response.set_cookie('expire_time', value=str(expire_time))
        return response
Exemplo n.º 5
0
def signup():
    """Render login page and handle login form data.
        Requests:
            GET /auth/signup
            POST /auth/signup
    """
    if request.method == 'GET':
        csrf_token = generate_csrf_token()
        response = make_response(
            render_template('signup.html', client_id=CLIENT_ID))
        # Store the csrf_token in the browser cookie.
        response.set_cookie('csrf_token', value=csrf_token)
        return response

    # Form fields:
    #     email: user email, required
    #     password: user password, required
    #     confirm: user confirm password, required
    # User email, and hashed password and salt are stored when login succeed.
    if request.method == 'POST':
        # Check csrf token
        cookie_csrf_token = request.cookies.get('csrf_token')
        form_csrf_token = request.form.get('_csrf_token')

        # CSRF attack detected!
        if cookie_csrf_token != form_csrf_token:
            flash("Please use proper signup.")
            return render_template('signup.html',
                                   client_id=CLIENT_ID,
                                   csrf_token="")

        # Get user data from login form.
        email = request.form.get('email')
        password = request.form.get('password')
        confirm = request.form.get('confirm')
        # User must fill the email and password field.
        if not (email and password and confirm):
            flash("Please fill the form. ")
            return render_template('signup.html', cached_email=email)

        # Password field and confirm fields must be the same.
        if not (password == confirm):
            flash("Confirm password has to be the same as password")
            return render_template('signup.html', cached_email=email)

        # Find user in the database by email.
        user = User.get_by_email(session, email.strip())
        # User already exist, remind user that.
        if user:
            if user.password:
                flash("Such user already exist. Please login")
                return render_template('signup.html', cached_email=email)
        # Create a new user object
        else:
            user = User(email=email.strip())
        # Store encrypted password and salt in the database
        user.password, user.salt = encrypt_password(password)
        session.add(user)
        session.commit()

        # Generate JSON web token for user.
        # As long as client has non-expired and valid token,
        #     they do not need to login again.
        expire_time, token = generate_token(user)
        response = make_response(redirect(url_for('basic.showMain')))
        # Store the token in the browser cookie.
        response.set_cookie('token', value=token)
        response.set_cookie('expire_time', value=str(expire_time))
        return response
Exemplo n.º 6
0
def gconnect():
    """Handle Google OAuth login.
        GET /auth/gconnect
        If user does not exists create a new user.
    """

    # Check csrf token
    cookie_csrf_token = request.cookies.get('csrf_token')
    if request.args.get('_csrf_token') != cookie_csrf_token:
        flash("Please use proper authentication.")
        response = make_response(json.dumps('Fail to connect'), 401)
        response.headers['Content-Type'] = 'application/json'
        return response

    # code is a return value from front-end google + oauth API
    code = request.data
    try:
        # Create oauth login flow based on client_secret.json
        # Please make sure that you have downloaded and placed
        #     client_secret.json properly. Please read README file.
        oauth_flow = flow_from_clientsecrets('settings/client_secret.json',
                                             scope='')
        oauth_flow.redirect_uri = 'postmessage'
        credentials = oauth_flow.step2_exchange(code)
    except FlowExchangeError:
        flash("Google plus connection Error.")
        response = make_response(json.dumps('Fail to upgrade'), 401)
        response.headers['Content-Type'] = 'application/json'
        return response
    # Get an access_token from Goolge OAuth provider
    access_token = credentials.access_token
    url = ('https://www.googleapis.'
           'com/oauth2/v1/tokeninfo?access_token=%s' % access_token)
    h = httplib2.Http()
    result = json.loads(h.request(url, 'GET')[1])
    if result.get('error') is not None:
        flash("Google plus connection Error.")
        response = make_response(json.dumps(result.get('error')), 500)
        response.headers['Content-Type'] = 'application/json'
        return response

    # Get user id stored in Google
    gplus_id = credentials.id_token['sub']
    if result['user_id'] != gplus_id:
        flash("Google plus connection Error.")
        response = make_response(json.dumps("Token's user ID doesn't match"),
                                 401)
        response.headers['Content-Type'] = 'application/json'
        return response

    # Make sure client id is correct
    if result['issued_to'] != CLIENT_ID:
        response = make_response(json.dumps("Token's client ID doesn't match"),
                                 401)
        flash("Google plus connection Error.")
        response.headers['Content-Type'] = 'application/json'
        return response

    # Retrieve user info. stored in Google
    userinfo_url = 'https://www.googleapis.com/oauth2/v1/userinfo'
    params = {'access_token': credentials.access_token, 'alt': 'json'}
    answer = requests.get(userinfo_url, params=params)

    data = json.loads(answer.text)
    email = data['email']
    user = User.get_by_email(session, email.strip())

    # If user does not exist, create a new user
    if not user:
        user = User(email=email)

    session.add(user)
    session.commit()

    # Generate JSON web token for user.
    # As long as client has non-expired and valid token,
    #     they do not need to login again.
    flash("Successfully logged in with Google +")
    expire_time, token = generate_token(user)
    response = make_response(redirect(url_for('basic.showMain')))
    # Store the JSON web token and Google + access token in the browser cookie.
    response.set_cookie('token', value=token)
    response.set_cookie('expire_time', value=str(expire_time))
    response.set_cookie('gplus_token', value=access_token)
    return response
Exemplo n.º 7
0
def fconnect():
    """Handle facebook OAuth login
        GET /auth/fconnect
        If user does not exists create a new user.
    """
    # userinfo has email, username, and access token
    userinfo = json.loads(request.data)
    user_access_token = userinfo.get('access_token')

    # To verify user's access token, we need to get our app token first.
    url = ('https://graph.facebook.com/oauth/access_token?'
           'client_id={}&client_secret={}'
           '&grant_type=client_credentials'
           .format(config.FACEBOOK_CLIENT_ID,
                   config.FACEBOOK_CLIENT_SECRET))
    try:
        h = httplib2.Http()
        result = h.request(url, 'GET')[1]
        app_token = re.search(r'(access_token=)(.+?$)', result).group(2)

        print app_token

        # Using app token, we can verify user's access token
        url = ('https://graph.facebook.com/debug_token'
               '?input_token={}&access_token={}'
               .format(user_access_token, app_token))

        h = httplib2.Http()
        result = json.loads(h.request(url, 'GET')[1])
        user_data = result.get("data")

        # If the user's token is valid to the app token,
        # Facecook api returns the variable 'is_valid' with True
        if not user_data.get("is_valid"):
            response = make_response(
                json.dumps("User access token is not valid"), 401
            )
            flash("Facebook connection Error.")
            response.headers['Content-Type'] = 'application/json'
            return response

        email = userinfo.get('email')
        user = User.get_by_email(session, email.strip())

        # Create and store a new user if there is no user exist
        if not user:
            user = User(email=email)
            session.add(user)
            session.commit()

        expire_time, token = generate_token(user)
        flash("Successfully logged in with Facebook")
        response = make_response(
            redirect(url_for('basic.showMain')), 200
        )
        response.set_cookie('token', value=token)
        response.set_cookie('expire_time', value=str(expire_time))
        return response
    except:
        response = make_response(
            json.dumps("User access token is not valid"), 401
        )
        flash("Facebook connection Error.")
        response.headers['Content-Type'] = 'application/json'
        return response
Exemplo n.º 8
0
def login(cached_email=None):
    """Render login page and handle login form data.
        Requests:
            GET /auth/login
            POST /auth/login
    """
    if request.method == 'GET':
        csrf_token = generate_csrf_token()
        response = make_response(
            render_template('login.html', cached_email=cached_email,
                            client_id=CLIENT_ID, csrf_token=csrf_token)
        )
        # Store the csrf_token in the browser cookie.
        response.set_cookie('csrf_token', value=csrf_token)
        return response

    # Form fields:
    #     email: user email, required
    #     password: user password, required
    if request.method == 'POST':
        # Check csrf token
        cookie_csrf_token = request.cookies.get('csrf_token')
        form_csrf_token = request.form.get('_csrf_token')

        # CSRF attack detected!
        if cookie_csrf_token != form_csrf_token:
            flash("Please use proper login.")
            return render_template('login.html', cached_email=cached_email,
                                   client_id=CLIENT_ID, csrf_token="")

        # Get user data from login form.
        email = request.form.get('email')
        password = request.form.get('password')

        # User must fill the email and password field.
        if not (email and password):
            flash("Please fill the form. ")
            return render_template('login.html', cached_email=email)

        # Find user in the database by email.
        user = User.get_by_email(session, email.strip())
        # User does not exists.
        if not user:
            flash("Invalid email address or password. ")
            return render_template('login.html', cached_email=email)

        # User exist, but Password does not.
        # The user have logged in with OAuth
        if not user.password:
            flash("You've signed up with social service. ")
            return render_template('login.html', cached_email=email)

        # Password incorrect.
        if not check_password(password, user.password, user.salt):
            flash("Invalid email address or password. ")
            return render_template('login.html', cached_email=email)

        # Generate JSON web token for user.
        # As long as client has non-expired and valid token,
        #     they do not need to login again.
        expire_time, token = generate_token(user)
        response = make_response(redirect(url_for('basic.showMain')))
        # Store the token in the browser cookie.
        response.set_cookie('token', value=token)
        response.set_cookie('expire_time', value=str(expire_time))
        return response
Exemplo n.º 9
0
def gconnect():
    """Handle Google OAuth login.
        GET /auth/gconnect
        If user does not exists create a new user.
    """

    # Check csrf token
    cookie_csrf_token = request.cookies.get('csrf_token')
    if request.args.get('_csrf_token') != cookie_csrf_token:
        flash("Please use proper authentication.")
        response = make_response(json.dumps('Fail to connect'), 401)
        response.headers['Content-Type'] = 'application/json'
        return response

    # code is a return value from front-end google + oauth API
    code = request.data
    try:
        # Create oauth login flow based on client_secret.json
        # Please make sure that you have downloaded and placed
        #     client_secret.json properly. Please read README file.
        oauth_flow = flow_from_clientsecrets('settings/client_secret.json',
                                             scope='')
        oauth_flow.redirect_uri = 'postmessage'
        credentials = oauth_flow.step2_exchange(code)
    except FlowExchangeError:
        flash("Google plus connection Error.")
        response = make_response(json.dumps('Fail to upgrade'), 401)
        response.headers['Content-Type'] = 'application/json'
        return response
    # Get an access_token from Goolge OAuth provider
    access_token = credentials.access_token
    url = ('https://www.googleapis.'
           'com/oauth2/v1/tokeninfo?access_token=%s'
           % access_token)
    h = httplib2.Http()
    result = json.loads(h.request(url, 'GET')[1])
    if result.get('error') is not None:
        flash("Google plus connection Error.")
        response = make_response(
            json.dumps(result.get('error')), 500
        )
        response.headers['Content-Type'] = 'application/json'
        return response

    # Get user id stored in Google
    gplus_id = credentials.id_token['sub']
    if result['user_id'] != gplus_id:
        flash("Google plus connection Error.")
        response = make_response(
            json.dumps("Token's user ID doesn't match"), 401
        )
        response.headers['Content-Type'] = 'application/json'
        return response

    # Make sure client id is correct
    if result['issued_to'] != CLIENT_ID:
        response = make_response(
            json.dumps("Token's client ID doesn't match"), 401
        )
        flash("Google plus connection Error.")
        response.headers['Content-Type'] = 'application/json'
        return response

    # Retrieve user info. stored in Google
    userinfo_url = 'https://www.googleapis.com/oauth2/v1/userinfo'
    params = {'access_token': credentials.access_token, 'alt': 'json'}
    answer = requests.get(userinfo_url, params=params)

    data = json.loads(answer.text)
    email = data['email']
    user = User.get_by_email(session, email.strip())

    # If user does not exist, create a new user
    if not user:
        user = User(email=email)

    session.add(user)
    session.commit()

    # Generate JSON web token for user.
    # As long as client has non-expired and valid token,
    #     they do not need to login again.
    flash("Successfully logged in with Google +")
    expire_time, token = generate_token(user)
    response = make_response(redirect(url_for('basic.showMain')))
    # Store the JSON web token and Google + access token in the browser cookie.
    response.set_cookie('token', value=token)
    response.set_cookie('expire_time', value=str(expire_time))
    response.set_cookie('gplus_token', value=access_token)
    return response
Exemplo n.º 10
0
def signup():
    """Render login page and handle login form data.
        Requests:
            GET /auth/signup
            POST /auth/signup
    """
    if request.method == 'GET':
        csrf_token = generate_csrf_token()
        response = make_response(
            render_template('signup.html', client_id=CLIENT_ID)
        )
        # Store the csrf_token in the browser cookie.
        response.set_cookie('csrf_token', value=csrf_token)
        return response

    # Form fields:
    #     email: user email, required
    #     password: user password, required
    #     confirm: user confirm password, required
    # User email, and hashed password and salt are stored when login succeed.
    if request.method == 'POST':
        # Check csrf token
        cookie_csrf_token = request.cookies.get('csrf_token')
        form_csrf_token = request.form.get('_csrf_token')

        # CSRF attack detected!
        if cookie_csrf_token != form_csrf_token:
            flash("Please use proper signup.")
            return render_template('signup.html',
                                   client_id=CLIENT_ID, csrf_token="")

        # Get user data from login form.
        email = request.form.get('email')
        password = request.form.get('password')
        confirm = request.form.get('confirm')
        # User must fill the email and password field.
        if not (email and password and confirm):
            flash("Please fill the form. ")
            return render_template('signup.html', cached_email=email)

        # Password field and confirm fields must be the same.
        if not (password == confirm):
            flash("Confirm password has to be the same as password")
            return render_template('signup.html', cached_email=email)

        # Find user in the database by email.
        user = User.get_by_email(session, email.strip())
        # User already exist, remind user that.
        if user:
            if user.password:
                flash("Such user already exist. Please login")
                return render_template('signup.html', cached_email=email)
        # Create a new user object
        else:
            user = User(email=email.strip())
        # Store encrypted password and salt in the database
        user.password, user.salt = encrypt_password(password)
        session.add(user)
        session.commit()

        # Generate JSON web token for user.
        # As long as client has non-expired and valid token,
        #     they do not need to login again.
        expire_time, token = generate_token(user)
        response = make_response(redirect(url_for('basic.showMain')))
        # Store the token in the browser cookie.
        response.set_cookie('token', value=token)
        response.set_cookie('expire_time', value=str(expire_time))
        return response
Exemplo n.º 11
0
# Get engine and session for dummy data importing
engine = create_engine(config.DATABASE_URI)
Base.metadata.create_all(engine)

DBSession = sessionmaker(bind=engine)
session = DBSession()

# Create dummy users(10 users)
# Example:
#     Username: [email protected] ~ [email protected]
#     Password: user1password ~ user10@password
for i in range(10):
    password = "******".format(i + 1)
    enc, salt = encrypt_password(password)
    user = User(name="user{}".format(i + 1),
                email="user{}@email.com".format(i + 1),
                password=enc,
                salt=salt)
    session.add(user)
    session.commit()

# Create dummy categories and items(10 categories, 100 items)
# Example:
#     Category: category1 ~ category10
#     Item: item1_c1 ~ item10_c10
for c in range(10):
    category = Category(name="category{}".format(c + 1))
    session.add(category)
    session.commit()

    # 10 items in each category
    for i in range(10):
def deleteItem(item_id):
    """
        GET /item/item id/delete:
            Render an delete item form page
        POST /item/item id/delete:
            Delete the selected item from database
    """
    token = request.cookies.get("token")
    expire_time = request.cookies.get("expire_time")
    # Only authorized user can see an edit item page
    if not token:
        flash("You are not authorized.")
        return redirect(url_for("basic.showMain"))

    if request.method == "GET":
        # Only authorized user can see a delete item page
        user_data = validate_token(token, expire_time)
        if not user_data:
            flash("You are not authorized.")
            return redirect(url_for("basic.showMain"))

        item = Item.get_by_id(session, item_id)
        return render_template("delete_item.html", item=item, user=user_data)

    if request.method == "POST":
        # When user send POST request,
        #     we get a token again from HTTP header, not from cookie
        token = request.headers.get("Authorization")
        # Get item to delete
        item = Item.get_by_id(session, item_id)
        # Only authorized user can delete this item
        user_data = validate_token(token, expire_time)
        if not user_data:
            response = make_response(
                json.dumps(
                    {
                        "message": "You are not authorized",
                        "redirect": url_for("basic.showItemDetail", category_id=item.category_id, item_id=item_id),
                    }
                ),
                401,
            )
            response.headers["Content-Type"] = "application/json"
            return response

        # Only authorized user can delete an item
        # Authorized user id must be the same as
        #     the user's id who created the item before.
        user = User.get_by_id(session, user_data.get("id"))
        if not User.is_authorized(session, user.id, item_id):
            response = make_response(
                json.dumps(
                    {
                        "message": "You are not authorized",
                        "redirect": url_for("basic.showItemDetail", category_id=item.category_id, item_id=item_id),
                    }
                ),
                401,
            )
            response.headers["Content-Type"] = "application/json"
            return response

        session.delete(item)
        session.commit()

        response = make_response(
            json.dumps({"message": "The item was successfully deleted.", "redirect": url_for("basic.showMain")}), 200
        )
        response.headers["Content-Type"] = "application/json"
        return response
def editItem(category_id, item_id):
    """
        GET /category/category id/item/item id/edit:
            Render an edit item form page
        POST /category/category id/item/item id/edit:
            Update the selected item's attributes
            Fields:
                title (required)
                description
                category (required)
    """
    token = request.cookies.get("token")
    expire_time = request.cookies.get("expire_time")
    # Only authorized user can see an edit item page
    if not token:
        flash("You are not authorized.")
        return redirect(url_for("basic.showMain"))

    if request.method == "GET":

        # Only authorized user can see an edit item page
        user_data = validate_token(token, expire_time)
        if not user_data:
            flash("You are not authorized.")
            return redirect(url_for("basic.showMain"))

        # Only authorized user can see an edit item page
        # Authorized user id must be the same as
        #     the user's id who created the item before.
        if not User.is_authorized(session, user_data.get("id"), item_id):
            flash("You are not authorized.")
            return redirect(url_for("basic.showMain"))

        categories = Category.get_all(session)
        item = Item.get_by_id(session, item_id)
        return render_template("edit_item.html", categories=categories, item=item)

    if request.method == "POST":
        # When user send POST request,
        #     we get a token again from HTTP header, not from cookie
        token = request.headers.get("Authorization")
        # Only authorized user can edit this item
        user_data = validate_token(token, expire_time)
        if not user_data:
            response = make_response(
                json.dumps(
                    {
                        "message": "You are not authorized",
                        "redirect": url_for("basic.showItemDetail", category_id=category_id, item_id=item_id),
                    }
                ),
                401,
            )
            response.headers["Content-Type"] = "application/json"
            return response

        item = Item.get_by_id(session, item_id)
        title = request.form.get("title")
        description = request.form.get("description")
        new_category_id = request.form.get("category")

        # In the form in HTML title field is required.
        # No title means the user use another way to send POST request
        if not title:
            response = make_response(
                json.dumps(
                    {
                        "message": "Please use the proper way",
                        "redirect": url_for("basic.showItemDetail", category_id=category_id, item_id=item_id),
                    }
                ),
                401,
            )
            response.headers["Content-Type"] = "application/json"
            return response

        # Only authorized user can edit item
        # Authorized user id must be the same as
        #     the user's id who created the item before.
        user = User.get_by_id(session, user_data.get("id"))
        if not User.is_authorized(session, user.id, item_id):
            response = make_response(
                json.dumps(
                    {
                        "message": "You are not authorized",
                        "redirect": url_for("basic.showItemDetail", category_id=item.category_id, item_id=item_id),
                    }
                ),
                401,
            )
            response.headers["Content-Type"] = "application/json"
            return response

        item.title = title
        item.description = description
        item.category_id = new_category_id
        session.add(item)
        session.commit()

        response = make_response(
            json.dumps(
                {
                    "message": "The item was successfully edited.",
                    "redirect": url_for("basic.showItemDetail", category_id=category_id, item_id=item.id),
                }
            ),
            200,
        )
        response.headers["Content-Type"] = "application/json"
        return response