finance-watcher / api / endpoints / user.py
user.py
Raw
from pathlib import Path
import sys

sys.path.append(str(Path(__file__).parent.parent.parent))

from flask import request
from flask_restx import Namespace, Resource, fields
from database.finance_database import FinanceDatabase

from helpers.helper_functions import (
    create_encrypted_string, json_success_response, json_error_response
)

namespace = Namespace(
    'user', 
    description='API endpoints related to User resource'
)


user_payload = namespace.model("Payload", {
    "name": fields.String(required=True, description="Name of the user"),
    "email": fields.String(required=True, description="Email of the user"),
    "password": fields.String(
        required=True, description="Password of the user"
    )
})

user_id_payload = namespace.model("Payload", {
    "password": fields.String(required=True, description='New password')
})

user_password_payload = namespace.model("Payload", {
    "email": fields.String(required=True, description="Email of the user"),
    "password": fields.String(
        required=True, description="Password of the user"
    )
})


@namespace.route('')
@namespace.expect(user_payload)
class UserAPI(Resource):
    """
    API for the User resource.
    """
    def post(self):
        """
        Insert a User into the database.
        Returns the user id and name if successful.

        Expected payload:
        {
            name: str,
            email: str,
            password: str
        }

        Expected return:
        {
            user_id: int,
            name: str
        }
        """
        payload = request.json
        name = payload['name']
        email = payload['email']
        password = payload['password']

        password_enc = create_encrypted_string(password)

        finance_db = FinanceDatabase()
        user = finance_db.insert_dashboard_user(
            name=name,
            email=email,
            password=password_enc
        )

        if user is None:
            return json_error_response(
                f"ERROR: Failed to insert user '{email}' into the database."
            )

        return json_success_response({
            'user_id':user.id,
            'name': user.name
        })
    

@namespace.route('/<int:id>')
class UserByIdAPI(Resource):
    """
    API for the User resource by id.

    Expected return:
    {
        user_id: int,
        name: str
    }
    """
    def get(self, id: int):
        """
        Gets the User based on the id given.
        """
        finance_db = FinanceDatabase()
        user = finance_db.get_dashboard_user(id)
        if user is None:
            return json_error_response(
                'ERROR: Failed to get user.'
            )
        return json_success_response({
            'user_id': user.id,
            'name': user.name
        })
    
    @namespace.expect(user_id_payload)
    def put(self, id: int):
        payload = request.json
        password = payload['password']

        password_enc = create_encrypted_string(password)

        finance_db = FinanceDatabase()
        try:
            is_success = finance_db.update_user_password(
                user_id=id, password=password_enc
            )

            return json_success_response() if is_success else json_error_response(
                'ERROR: Failed to update password.'
            )

        except Exception:
            return json_error_response(
                'ERROR: Failed to update password.'
            )


@namespace.route('/password')
class UserPasswordAPI(Resource):

    @namespace.expect(user_password_payload)
    def post(self):
        """
        Checks if the user and password credentials are correct.

        If correct, return 200.
        If incorrect password, return 401.
        If email is not in the database, return 404.
        """
        payload = request.json

        finance_db = FinanceDatabase()

        email = payload['email']
        password = payload['password']

        user = finance_db.get_user_by_email(email)
        if user is None:
            return json_error_response(
                'ERROR: User not found.', 404
            )
        
        password_enc = create_encrypted_string(password)

        if finance_db.check_user(user.id, password_enc):
            return json_success_response()
        return json_error_response(
            'ERROR: Invalid login credentials.', 401
        )