示例#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
示例#2
0
def editItem(category_id, item_id):
    item = getItemInfo(item_id)
    category = getCategoryInfo(category_id)
    form = EditItem(request.form)
    if request.files:
        form.picture.data = request.files['picture']
    if request.method == 'POST' and form.validate():
        if form.title.data:
            item.title = ' '.join(
                name.capitalize() for name in form.title.data.split()
            )
        if form.description.data:
            item.description = form.description.data
        if form.picture.data:
            item.picture = saveItemPicture(form.picture.data, item.id)
        session.add(item)
        session.commit()
        flash("Succesfully edited item %s" % item.title)
        return redirect(
            url_for(
                'showItem',
                category_id=category_id,
                item_id=item.id
            )
        )
    return render_template(
        'edititem.html',
        category=category,
        item=item,
        form=form
    )
示例#3
0
def deleteUser(user_id):
    user = getUserInfo(user_id)
    if request.method == 'GET':
        return render_template('deleteuser.html', user=user)
    session.delete(user)
    session.commit()
    flash("Successfully deleted user")
    return redirect(url_for('logout'))
示例#4
0
def deleteCategory(category_id):
    category = getCategoryInfo(category_id)
    # we still need to check for the emptiness of the category so we may
    # protect categories that are not empty from deletion
    if not category.items:
        if request.method == 'GET':
            return render_template('deletecategory.html', category=category)
        else:
            session.delete(category)
            session.commit()
            flash("Successfully deleted category %s" % category.title)
            return redirect(url_for('index'))
    flash("A category may only be deleted if it doesn't have any items")
    return redirect(url_for('showCategory', category_id=category.id))
示例#5
0
def deleteItem(category_id, item_id):
    item = getItemInfo(item_id)
    category = getCategoryInfo(category_id)
    if request.method == 'GET':
        return render_template(
            'deleteitem.html',
            category=category,
            item=item
        )
    else:
        # Before deleting the item from the db, we delete it's picture file
        deleteItemPicture(item.picture)
        session.delete(item)
        session.commit()
        flash("Successfully deleted item %s" % item.title)
        return redirect(url_for('showCategory', category_id=category.id))
示例#6
0
def newCategory():
    # Create the WTForm
    form = CategoryForm(request.form)
    if request.method == 'POST' and form.validate():
        # If it's a post and the form is valid, we format the title and Create
        # the new category
        new_category = Category(
            title=' '.join(
                name.capitalize() for name in form.title.data.split()
            )
        )
        session.add(new_category)
        session.commit()
        flash("New category %s successfully created!" % new_category.title)
        return redirect(url_for('index'))
    else:
        return render_template('newcategory.html', form=form)
示例#7
0
def createUser(login_session):
    ''' Method for creating an user from the login_session

    This method should be called after the successful completion of the oauth
    flow and consequent acquisition of the required user info:
        - username
        - email
        - picture
    '''
    # We are presuming that the username and email will be formatted correctly
    new_user = User(
        name=login_session['username'],
        email=login_session['email'],
        picture=login_session['picture']
    )
    session.add(new_user)
    session.commit()
    user = getUserByEmail(login_session['email'])
    return user.id
示例#8
0
def newItem(category_id):
    category = getCategoryInfo(category_id)
    # create the WTForm
    form = NewItem(request.form)
    # The picture is mandatory, but we need to pass it separately to WTForm as
    # the constructor only receives the form itself..
    if request.files:
        form.picture.data = request.files['picture']
    if request.method == 'POST' and form.validate():
        # After validating the form, we build the item object with the
        # formatted title and with an empty string for the picture.
        # We need to do this because we will use the item id to save the
        # picture.
        new_item = Item(
            title=' '.join(
                name.capitalize() for name in form.title.data.split()
            ),
            description=form.description.data,
            picture='',
            category_id=category.id,
            user_id=login_session['user_id']
        )
        session.add(new_item)
        session.commit()
        # Now that we have the new item id, we save the picture and update the
        # item with the picture path
        path = saveItemPicture(form.picture.data, new_item.id)
        new_item.picture = path
        session.add(new_item)
        session.commit()
        flash("Added %s to %s!" % (new_item.title, category.title))
        return redirect(url_for('showCategory', category_id=category.id))
    else:
        return render_template(
            'newitem.html',
            category=category,
            form=form
        )
def addItem():
    """
        GET /items:
            Render a create item form page
        POST /items:
            Create a new item and store it in database.
            Fields:
                title (required)
                description
                category (required)
            Created date are default saved as timestamp
    """
    token = request.cookies.get('token')
    expire_time = request.cookies.get('expire_time')
    # Only authenticated user can add a new item
    if not token:
        flash("Please login.")
        return redirect(url_for('auth.login'))

    if request.method == "GET":
        user_data = validate_token(token, expire_time)
        categories = Category.get_all(session)
        return render_template('add_item.html',
                               categories=categories, 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')
        # Only authenticated user can add a new item
        user_data = validate_token(token, expire_time)
        if not user_data:
            response = make_response(
                json.dumps({
                    "message": "Please login",
                    "redirect": url_for('auth.login')
                }), 401
            )
            response.headers['Content-Type'] = 'application/json'
            return response

        # Get title, description, and category_id from the form.
        title = request.form.get('title')
        description = request.form.get('description')
        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.addItem')
                }), 401
            )
            response.headers['Content-Type'] = 'application/json'
            return response

        # Create a new item row with the fields user has inputted
        item = Item(title=title, description=description,
                    category_id=category_id, user_id=user_data.get("id"))
        session.add(item)
        session.commit()
        # Redirect to the detail page, so user can check their input.
        response = make_response(
            json.dumps({
                "message": "The item was successfully created.",
                "redirect": url_for('basic.showItemDetail',
                                    category_id=category_id, item_id=item.id)
                }), 200
            )
        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
示例#11
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
示例#12
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
示例#13
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
示例#14
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
示例#15
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
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
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
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 addItem():
    """
        GET /items:
            Render a create item form page
        POST /items:
            Create a new item and store it in database.
            Fields:
                title (required)
                description
                category (required)
            Created date are default saved as timestamp
    """
    token = request.cookies.get("token")
    expire_time = request.cookies.get("expire_time")
    # Only authenticated user can add a new item
    if not token:
        flash("Please login.")
        return redirect(url_for("auth.login"))

    if request.method == "GET":
        user_data = validate_token(token, expire_time)
        categories = Category.get_all(session)
        return render_template("add_item.html", categories=categories, 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")
        # Only authenticated user can add a new item
        user_data = validate_token(token, expire_time)
        if not user_data:
            response = make_response(json.dumps({"message": "Please login", "redirect": url_for("auth.login")}), 401)
            response.headers["Content-Type"] = "application/json"
            return response

        # Get title, description, and category_id from the form.
        title = request.form.get("title")
        description = request.form.get("description")
        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.addItem")}), 401
            )
            response.headers["Content-Type"] = "application/json"
            return response

        # Create a new item row with the fields user has inputted
        item = Item(title=title, description=description, category_id=category_id, user_id=user_data.get("id"))
        session.add(item)
        session.commit()
        # Redirect to the detail page, so user can check their input.
        response = make_response(
            json.dumps(
                {
                    "message": "The item was successfully created.",
                    "redirect": url_for("basic.showItemDetail", category_id=category_id, item_id=item.id),
                }
            ),
            200,
        )
        response.headers["Content-Type"] = "application/json"
        return response