Skip to content
This repository has been archived by the owner on Jan 24, 2024. It is now read-only.

feat: Multiple households #25

Merged
merged 10 commits into from
Apr 5, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 28 additions & 16 deletions app/api/register_controller.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,32 @@
from flask import Blueprint
from app.config import app
import app.controller as api

# Register Endpoints
app.register_blueprint(
api.health, url_prefix='/api/health/8M4F88S8ooi4sMbLBfkkV7ctWwgibW6V')
app.register_blueprint(api.auth, url_prefix='/api/auth')
app.register_blueprint(api.category, url_prefix='/api/category')
app.register_blueprint(api.expense, url_prefix='/api/expense')
app.register_blueprint(api.export, url_prefix='/api/export')
app.register_blueprint(api.importBP, url_prefix='/api/import')
app.register_blueprint(api.item, url_prefix='/api/item')
app.register_blueprint(api.onboarding, url_prefix='/api/onboarding')
app.register_blueprint(api.planner, url_prefix='/api/planner')
app.register_blueprint(api.recipe, url_prefix='/api/recipe')
app.register_blueprint(api.settings, url_prefix='/api/settings')
app.register_blueprint(api.shoppinglist, url_prefix='/api/shoppinglist')
app.register_blueprint(api.tag, url_prefix='/api/tag')
app.register_blueprint(api.user, url_prefix='/api/user')
app.register_blueprint(api.upload, url_prefix='/api/upload')
apiv1 = Blueprint('api', __name__)

api.household.register_blueprint(api.export, url_prefix='/<int:household_id>/export')
api.household.register_blueprint(api.importBP, url_prefix='/<int:household_id>/import')
api.household.register_blueprint(api.categoryHousehold, url_prefix='/<int:household_id>/category')
api.household.register_blueprint(api.plannerHousehold, url_prefix='/<int:household_id>/planner')
api.household.register_blueprint(api.expenseHousehold, url_prefix='/<int:household_id>/expense')
api.household.register_blueprint(api.itemHousehold, url_prefix='/<int:household_id>/item')
api.household.register_blueprint(api.recipeHousehold, url_prefix='/<int:household_id>/recipe')
api.household.register_blueprint(api.shoppinglistHousehold, url_prefix='/<int:household_id>/shoppinglist')
api.household.register_blueprint(api.tagHousehold, url_prefix='/<int:household_id>/tag')

apiv1.register_blueprint(api.health, url_prefix='/health/8M4F88S8ooi4sMbLBfkkV7ctWwgibW6V')
apiv1.register_blueprint(api.auth, url_prefix='/auth')
apiv1.register_blueprint(api.household, url_prefix='/household')
apiv1.register_blueprint(api.category, url_prefix='/category')
apiv1.register_blueprint(api.expense, url_prefix='/expense')
apiv1.register_blueprint(api.item, url_prefix='/item')
apiv1.register_blueprint(api.onboarding, url_prefix='/onboarding')
apiv1.register_blueprint(api.recipe, url_prefix='/recipe')
apiv1.register_blueprint(api.settings, url_prefix='/settings')
apiv1.register_blueprint(api.shoppinglist, url_prefix='/shoppinglist')
apiv1.register_blueprint(api.tag, url_prefix='/tag')
apiv1.register_blueprint(api.user, url_prefix='/user')
apiv1.register_blueprint(api.upload, url_prefix='/upload')

app.register_blueprint(apiv1, url_prefix='/api')
1 change: 1 addition & 0 deletions app/controller/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@
from .expense import *
from .tag import *
from .upload import *
from .household import *
from .category import *
from .health_controller import health
25 changes: 7 additions & 18 deletions app/controller/auth/auth_controller.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from datetime import datetime
from app.helpers import validate_args
from flask import jsonify, Blueprint, request
from flask_jwt_extended import jwt_required, get_jwt_identity, get_jwt
from flask_jwt_extended import current_user, jwt_required, get_jwt
from app.models import User, Token
from app.errors import UnauthorizedRequest
from .schemas import Login, CreateLongLivedToken
Expand All @@ -26,7 +26,7 @@ def check_if_token_revoked(jwt_header, jwt_payload: dict) -> bool:
# identity when creating JWTs and converts it to a JSON serializable format.
@jwt.user_identity_loader
def user_identity_lookup(user: User):
return user.username
return user.id


# Register a callback function that loads a user from your database whenever
Expand All @@ -36,7 +36,7 @@ def user_identity_lookup(user: User):
@jwt.user_lookup_loader
def user_lookup_callback(_jwt_header, jwt_data) -> User:
identity = jwt_data["sub"]
return User.find_by_username(identity)
return User.find_by_id(identity)


@auth.route('', methods=['POST'])
Expand All @@ -62,22 +62,11 @@ def login(args):
'refresh_token': refreshToken
})

# Not in use as we are using the refresh token pattern
# @auth.route('/fresh-login', methods=['POST'])
# @validate_args(Login)
# def fresh_login(args):
# username = args['username'].lower()
# user = User.find_by_username(username.lower())
# if not user or not user.check_password(args['password']):
# raise UnauthorizedRequest(message='Unauthorized')
# ret = {'access_token': create_access_token(identity=username, fresh=True)}
# return jsonify(ret), 200


@auth.route('/refresh', methods=['GET'])
@jwt_required(refresh=True)
def refresh():
user = User.find_by_username(get_jwt_identity())
user = current_user
if not user:
raise UnauthorizedRequest(
message='Unauthorized: IP {} refresh attemp with wrong username or password'.format(request.remote_addr))
Expand Down Expand Up @@ -117,7 +106,7 @@ def logout():
@jwt_required()
@validate_args(CreateLongLivedToken)
def createLongLivedToken(args):
user = User.find_by_username(get_jwt_identity())
user = current_user
if not user:
raise UnauthorizedRequest(
message='Unauthorized: IP {}'.format(request.remote_addr))
Expand All @@ -129,10 +118,10 @@ def createLongLivedToken(args):
})


@auth.route('llt/<id>', methods=['DELETE'])
@auth.route('llt/<int:id>', methods=['DELETE'])
@jwt_required()
def deleteLongLivedToken(id):
user = User.find_by_username(get_jwt_identity())
user = current_user
if not user:
raise UnauthorizedRequest(
message='Unauthorized: IP {}'.format(request.remote_addr))
Expand Down
2 changes: 1 addition & 1 deletion app/controller/category/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .category_controller import category
from .category_controller import category, categoryHousehold
38 changes: 25 additions & 13 deletions app/controller/category/category_controller.py
Original file line number Diff line number Diff line change
@@ -1,45 +1,51 @@
from app.helpers import validate_args
from app.helpers import validate_args, authorize_household
from flask import jsonify, Blueprint
from app.errors import NotFoundRequest
from flask_jwt_extended import jwt_required
from app.models import Category
from .schemas import AddCategory, DeleteCategory, UpdateCategory

category = Blueprint('category', __name__)
categoryHousehold = Blueprint('category', __name__)


@category.route('', methods=['GET'])
@categoryHousehold.route('', methods=['GET'])
@jwt_required()
def getAllCategories():
return jsonify([e.obj_to_dict() for e in Category.all_by_ordering()])
@authorize_household()
def getAllCategories(household_id):
return jsonify([e.obj_to_dict() for e in Category.all_by_ordering(household_id)])


@category.route('/<id>', methods=['GET'])
@category.route('/<int:id>', methods=['GET'])
@jwt_required()
def getCategory(id):
category = Category.find_by_id(id)
if not category:
raise NotFoundRequest()
category.checkAuthorized()
return jsonify(category.obj_to_dict())


@category.route('', methods=['POST'])
@categoryHousehold.route('', methods=['POST'])
@jwt_required()
@authorize_household()
@validate_args(AddCategory)
def addCategory(args):
def addCategory(args, household_id):
category = Category()
category.name = args['name']
category.household_id = household_id
category.save()
return jsonify(category.obj_to_dict())


@category.route('/<id>', methods=['POST'])
@category.route('/<int:id>', methods=['POST', 'PATCH'])
@jwt_required()
@validate_args(UpdateCategory)
def updateCategory(args, id):
category = Category.find_by_id(id)
if not category:
raise NotFoundRequest()
category.checkAuthorized()

if 'name' in args:
category.name = args['name']
Expand All @@ -49,19 +55,25 @@ def updateCategory(args, id):
return jsonify(category.obj_to_dict())


@category.route('/<id>', methods=['DELETE'])
@category.route('/<int:id>', methods=['DELETE'])
@jwt_required()
def deleteCategoryById(id):
Category.delete_by_id(id)
category = Category.find_by_id(id)
if not category:
raise NotFoundRequest()
category.checkAuthorized()

category.delete()
return jsonify({'msg': 'DONE'})


@category.route('', methods=['DELETE'])
@categoryHousehold.route('', methods=['DELETE'])
@jwt_required()
@authorize_household()
@validate_args(DeleteCategory)
def deleteExpenseCategoryById(args):
def deleteCategoryByName(args, household_id):
if "name" in args:
category = Category.find_by_name(args['name'])
category = Category.find_by_name(args['name'], household_id)
if category:
category.delete()
return jsonify({'msg': 'DONE'})
Expand Down
2 changes: 1 addition & 1 deletion app/controller/expense/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from .expense_controller import expense
from .expense_controller import expense, expenseHousehold
Loading