def put_meals(list_id): req = request.get_json() if not req: raise APIError("application/json is required") if not isinstance(req, list): raise APIError("A list of meals is required") list_ = List.query.filter_by(id=list_id).first() meals = Meal.query.filter_by(list_id=list_.id).all() # verify integrity of received list verify_meals(req, meals) for meal in meals: if meal.id not in [i["id"] for i in req if "id" in i]: db.session.delete(meal) db.session.commit() meals = Meal.query.filter_by(list_id=list_.id).all() for index, req_meal in enumerate(req): if "id" in req_meal and req_meal["id"] in [i.id for i in meals]: meals_index = [i.id for i in meals].index(req_meal["id"]) meals[meals_index].order = index meals[meals_index].name = req_meal["name"] else: new_meal = Meal( list_id=list_.id, name=req_meal["name"], order=index ) db.session.add(new_meal) db.session.commit() json_obj = [meal.to_dict() for meal in list_.get_or_create_meals()] return jsonify(json_obj)
def register(): req = request.get_json() if not req: raise APIError("application/json is required") verify_mandatory_user_fields(req) if "password" not in req: raise APIError("password is required") if User.query.filter_by(username=req["username"]).first(): raise APIError("Username already taken") if User.query.filter_by(email=req["email"]).first(): raise APIError("Email already taken") if len(req["password"]) < 8: raise APIError( "Password is too short, please use 8 characters or more") u = User( username=req["username"], email=req["email"], firstname=req["firstname"], lastname=req["lastname"], is_confirmed=False, ) u.set_password(req["password"]) db.session.add(u) db.session.commit() # TODO confirm email # token = generate_confirmation_token(u.email) # confirm_url = url_for('auth.confirm_email', token=token, _external=True) # send_user_confirmation_email(u, confirm_url) login_user(u) return jsonify({"msg": "Registered successfully", **u.to_dict()}), 201
def decorated_function(*args, **kwargs): list_id = kwargs["list_id"] list_ = List.query.filter_by(id=list_id).first() if not list_: raise APIError(f"No list with id {list_id}", 404) if current_user not in list_.get_users_with_access(): raise APIError("You don't have access to this page", 403) return func(*args, **kwargs)
def decorated_function(*args, **kwargs): list_id = kwargs["list_id"] list_ = List.query.filter_by(id=list_id).first() if not list_: raise APIError(f"No list with id {list_id}", 404) if current_user not in list_.get_owners(): raise APIError("Only the list owner can perform this action", 403) return func(*args, **kwargs)
def decorated_function(*args, **kwargs): entry_id = kwargs["entry_id"] entry = Entry.query.filter_by(id=entry_id).first() if not entry: raise APIError(f"No entry with id {entry_id}", 404) list_ = entry.day.list_ if current_user not in list_.get_users_with_access(): raise APIError("You don't have access to this page", 403) return func(*args, **kwargs)
def verify_meals(req, meals): for meal in req: if "id" in meal: if meal["id"] not in [i.id for i in meals]: raise APIError( "ID assignment not allowed, only include pre-existing IDs" ) if "name" not in meal: raise APIError(f"No name received in {meal}")
def verify_mandatory_user_fields(req): if "username" not in req: raise APIError("username is required") if "email" not in req: raise APIError("email is required") if "firstname" not in req: raise APIError("firstname is required") if "lastname" not in req: raise APIError("lastname is required")
def delete_user(user_id): user_ = User.query.filter_by(id=user_id).first() if not user_: raise APIError(f"No user with id {user_id}", 404) if user_ != current_user: raise APIError("You cannot delete another user", 403) db.session.delete(user_) db.session.commit() logout_user() return jsonify({"msg": "User deleted"}), 401
def extract_args(args): offset = int(args.get("offset")) if "offset" in args else 0 if (offset and offset > 5000) or (offset and offset < -5000): raise APIError("Offset needs to be within -5000 and 5000") limit = int(args.get("limit")) if "limit" in args else None if limit and limit > 25: raise APIError("Limit cannot be over 25") start_today = ( bool(args.get("start_today")) if "start_today" in args else False ) return dict(offset=offset, limit=limit, start_today=start_today)
def login(): req = request.get_json() if not req: raise APIError("application/json is required") if "username" not in req: raise APIError("username is required") if "password" not in req: raise APIError("password is required") u = User.query.filter_by(username=req["username"]).first() if u is None or not u.check_password(req["password"]): raise APIError("Invalid username or password!", 401) login_user(u) return jsonify({"msg": "Logged in successfully", **u.to_dict()}), 200
def post_foods(list_id): req = request.get_json() if not req: raise APIError("application/json is required") if "name" not in req: raise APIError("name is required") list_ = List.query.filter_by(id=list_id).first() if Food.query.filter_by(name=req["name"], list_id=list_.id).first(): raise APIError(f'Food {req["name"]} already exists') food = Food(list_id=list_.id, name=req["name"]) db.session.add(food) db.session.commit() json_obj = [food.to_dict() for food in list_.foods] return jsonify(json_obj), 201
def post_categories(list_id): req = request.get_json() if not req: raise APIError("application/json is required") if "name" not in req: raise APIError("name is required") list_ = List.query.filter_by(id=list_id).first() if req["name"] in [i.name for i in list_.categories]: raise APIError(f'FoodCategory {req["name"]} already exists') foodcategory = FoodCategory(name=req["name"], list_id=list_id) db.session.add(foodcategory) db.session.commit() json_obj = [category.to_dict() for category in list_.categories] return jsonify(json_obj), 201
def patch_meals(list_id, meal_id): req = request.get_json() if not req: raise APIError("application/json is required") if "name" not in req: raise APIError("name is required") list_ = List.query.filter_by(id=list_id).first() meal = Meal.query.filter_by(list_id=list_.id, id=meal_id).first() if not meal: raise APIError(f"No meal with id {meal_id} exists", 404) meal.name = req["name"] db.session.commit() json_obj = [meal.to_dict() for meal in list_.get_or_create_meals()] return jsonify(json_obj), 200
def delete_category(food_id, category_id): food = Food.query.filter_by(id=food_id).first() if not food: raise APIError(f"No food with id {food_id} exists", 404) category = FoodCategory.query.filter_by(id=category_id).first() if not category: raise APIError(f"No category with id {category_id} exists", 404) if category.id not in [i.category.id for i in food.categories]: raise APIError( f"Category {category_id} does not belong to Food {food_id}") category_association = FoodCategoryAssociation.query.filter_by( food_id=food.id, category_id=category.id).first() db.session.delete(category_association) db.session.commit() json_obj = [category.category.to_dict() for category in food.categories] return jsonify(json_obj)
def user(): if current_user.is_authenticated: return ( jsonify({"msg": "Session still valid", **current_user.to_dict()}), 200, ) raise APIError("Please log in", 401)
def post_category_association(food_id, category_id): food = Food.query.filter_by(id=food_id).first() if not food: raise APIError(f"No food with id {food_id} exists", 404) category = FoodCategory.query.filter_by(id=category_id).first() if not category: raise APIError(f"No food with id {category_id} exists", 404) if category.id in [i.category.id for i in food.categories]: raise APIError( f"Category {category_id} is already linked to food {food_id}") foodcategoryassociation = FoodCategoryAssociation(food_id=food.id, category_id=category.id) db.session.add(foodcategoryassociation) db.session.commit() json_obj = [category.category.to_dict() for category in food.categories] return jsonify(json_obj)
def delete_category_by_list(list_id, category_id): list_ = List.query.filter_by(id=list_id).first() category = FoodCategory.query.filter_by(id=category_id).first() if not category: raise APIError(f"No category with id {category_id} exists", 404) db.session.delete(category) db.session.commit() json_obj = [category.to_dict() for category in list_.categories] return jsonify(json_obj), 200
def patch_entry(entry_id): # TODO functionize -> get_json -> check that there is content (or raise) req = request.get_json() if not req: raise APIError("application/json is required") entry = Entry.query.filter_by(id=entry_id).first_or_404() entry.value = req["value"] db.session.commit() return jsonify(entry.to_dict()), 200
def delete_share(list_id, share_id): list_ = List.query.filter_by(id=list_id).first() share = ListPermission.query.filter_by(id=share_id, list_id=list_id).first() if not share: raise APIError(f"Share with id {share_id} not found", 404) db.session.delete(share) db.session.commit() return jsonify([i.to_dict() for i in list_.users]), 200
def delete_meal(list_id, meal_id): list_ = List.query.filter_by(id=list_id).first() meal = Meal.query.filter_by(list_id=list_.id, id=meal_id).first() if not meal: raise APIError(f"No meal with id {meal_id} exists", 404) db.session.delete(meal) db.session.commit() json_obj = [meal.to_dict() for meal in list_.get_or_create_meals()] return jsonify(json_obj), 200
def post_list(): req = request.get_json() if not req: raise APIError("application/json is required") if "listname" not in req: raise APIError("listname is required") if req["listname"] == "": raise APIError("Listname cannot be empty") list_ = List(name=req["listname"]) list_.generate_api_key() db.session.add(list_) db.session.commit() perm = ListPermission(list_id=list_.id, user_id=current_user.id, permission_level="owner") db.session.add(perm) db.session.commit() return jsonify(list_.to_dict()), 201
def delete_food(list_id, food_id): list_ = List.query.filter_by(id=list_id).first() food = Food.query.filter_by(list_id=list_.id, id=food_id).first() if not food: raise APIError(f"No meal with id {food_id} exists", 404) db.session.delete(food) db.session.commit() json_obj = [food.to_dict() for food in list_.foods] return jsonify(json_obj), 200
def put_food(list_id, food_id): req = request.get_json() if not req: raise APIError("application/json is required") if "name" not in req: raise APIError("name is required") if "categories" not in req: raise APIError("categories is required") list_ = List.query.filter_by(id=list_id).first() food = Food.query.filter_by(list_id=list_.id, id=food_id).first() if not food: raise APIError(f"No food with id {food_id} exists", 404) food.name = req["name"] categories_to_associate = [ i for i in list_.categories if i.name in req["categories"] ] categories_to_disassociate = [ i for i in list_.categories if i.name not in req["categories"] ] categories_to_add = [ i for i in req["categories"] if i not in [i.name for i in categories_to_associate] ] for category in categories_to_add: fc = FoodCategory(list_id=list_.id, name=category) db.session.add(fc) db.session.commit() fca = FoodCategoryAssociation(category_id=fc.id, food_id=food.id) db.session.add(fca) db.session.commit() for category in categories_to_associate: if category.id not in [i.category.id for i in food.categories]: fca = FoodCategoryAssociation(category_id=category.id, food_id=food.id) db.session.add(fca) for category in categories_to_disassociate: if category in [i.category for i in food.categories]: fca = FoodCategoryAssociation.query.filter_by( category_id=category.id, food_id=food.id).first() db.session.delete(fca) db.session.commit() json_obj = [food.to_dict() for food in list_.foods] return jsonify(json_obj)
def post_list_shares(list_id): list_ = List.query.filter_by(id=list_id).first() req = request.get_json() if not req: raise APIError("application/json is required") if "username" not in req: raise APIError("Username is required") user_ = User.query.filter_by(username=req["username"]).first() if not user_: raise APIError(f"User {req['username']} does not exist", 404) if user_ in list_.get_users_with_access(): raise APIError( f"User {req['username']} already has access to this list") new_perm = ListPermission(user_id=user_.id, list_id=list_.id, permission_level="member") db.session.add(new_perm) db.session.commit() return jsonify([i.to_dict() for i in list_.users]), 201
def post_meals(list_id): req = request.get_json() if not req: raise APIError("application/json is required") if "name" not in req: raise APIError("name is required") list_ = List.query.filter_by(id=list_id).first() if Meal.query.filter_by(name=req["name"], list_id=list_.id).first(): raise APIError(f'Meal {req["name"]} already exists') try: order = 1 + max( [i.order for i in Meal.query.filter_by(list_id=list_.id).all()] ) except ValueError: order = 1 meal = Meal(list_id=list_.id, name=req["name"], order=order) db.session.add(meal) db.session.commit() json_obj = [meal.to_dict() for meal in list_.get_or_create_meals()] return jsonify(json_obj), 201
def put_list_settings(list_id): args = extract_args(request.args) req = request.get_json() if not req: raise APIError("application/json is required") list_ = List.query.filter_by(id=list_id).first() settings = list_.get_settings_for_user(current_user) if "start_day_of_week" not in req: raise APIError("start_day_of_week is required") if "days_to_display" not in req: raise APIError("days_to_display is required") # handle days_to_display days_to_display = int(req["days_to_display"]) if days_to_display < 5 or days_to_display > 21: raise APIError("days_to_display needs to be a number between 5-21") # handle start_day_of_week allowed_days = list(calendar.day_name) allowed_days.append("Today") start_day_of_week = req["start_day_of_week"] if start_day_of_week not in allowed_days: raise APIError( f'start_day_of_week needs to be one of: {" ".join(allowed_days)}') if start_day_of_week == "Today": start_day_of_week = -1 else: start_day_of_week = allowed_days.index(start_day_of_week) # set and commit settings.start_day_of_week = start_day_of_week settings.days_to_display = days_to_display db.session.commit() return jsonify( [list_.to_dict(args["offset"], args["limit"], args["start_today"])])
def patch_list(list_id): args = extract_args(request.args) req = request.get_json() if not req: raise APIError("application/json is required") list_ = List.query.filter_by(id=list_id).first() if "listname" in req: list_.name = req["listname"] db.session.commit() return ( jsonify([ list_.to_dict(args["offset"], args["limit"], args["start_today"]) ]), 200, )
def put_users(user_id): req = request.get_json() if not req: raise APIError("application/json is required") user_ = User.query.filter_by(id=user_id).first() if not user_: raise APIError(f"User with id {user_id} not found", 404) if not user_ == current_user: raise APIError("Insufficient permissions", 403) verify_mandatory_user_fields(req) if "password" in req and req["password"] != "": if len(req["password"]) < 8: raise APIError( "Password is too short, please use 8 characters or more") else: current_user.set_password(req["password"]) if req["username"] != current_user.username: if User.query.filter_by(username=req["username"]).first(): raise APIError("Username already taken") current_user.username = req["username"] if req["email"] != current_user.email: if User.query.filter_by(email=req["email"]).first(): raise APIError("Email already taken") current_user.email = req["email"] # TODO confirm email # token = generate_confirmation_token(u.email) # confirm_url = url_for('auth.confirm_email', token=token, _external=True) # send_user_confirmation_email(u, confirm_url) current_user.firstname = req["firstname"] current_user.lastname = req["lastname"] db.session.commit() return ( jsonify({ "msg": "User updated successfully", **current_user.to_dict() }), 200, )
def decorated_function(*args, **kwargs): if not current_user.is_authenticated: raise APIError("Please log in", 401) return func(*args, **kwargs)
def get_categories_by_food(food_id): food = Food.query.filter_by(id=food_id).first() if not food: raise APIError(f"No food with id {food_id} exists", 404) json_obj = [category.category.to_dict() for category in food.categories] return jsonify(json_obj)