recipes_api.getRecipes view updated for new

standards!
This commit is contained in:
Jadowyne Ulve 2025-04-26 18:30:11 -05:00
parent c7c8383baf
commit df5b575e10
11 changed files with 127 additions and 11 deletions

View File

@ -1839,3 +1839,6 @@
2025-04-21 14:45:18.122865 --- ERROR --- DatabaseError(message='new row for relation "logins" violates check constraint "logins_email_check"DETAIL: Failing row contains (32, ScannerDeviceB, 9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08, test, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, {}, f, {}, device).',
payload=('ScannerDeviceB', '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', 'test', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', '{}', False, '{}', 'device'),
sql='INSERT INTO logins(username, password, email, favorites, unseen_pantry_items, unseen_groups, unseen_shopping_lists, unseen_recipes, seen_pantry_items, seen_groups, seen_shopping_lists, seen_recipes, sites, site_roles, system_admin, flags, row_type) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) RETURNING *;')
2025-04-26 18:29:30.532818 --- ERROR --- DatabaseError(message=''module' object is not callable. Did you mean: 'config.config(...)'?',
payload=(10, 0),
sql='SELECT *, (SELECT COALESCE(array_agg(row_to_json(g)), '{}') FROM main_recipe_items g WHERE rp_id = main_recipes.id) AS rp_items FROM main_recipes LIMIT %s OFFSET %s;')

View File

@ -23,3 +23,44 @@ def getModalSKUs(site, payload, convert=True):
if rows and count:
return rows, count
return [], 0
def getRecipes(site:str, payload:tuple, convert=True):
recordset = []
count = 0
with open("scripts/recipes/sql/getRecipes.sql", "r+") as file:
sql = file.read().replace("%%site_name%%", site)
with open(f"scripts/recipes/sql/getRecipesCount.sql", "r+") as file:
sqlcount = file.read().replace("%%site_name%%", site)
try:
database_config = config.config()
with psycopg2.connect(**database_config) as conn:
with conn.cursor() as cur:
cur.execute(sql, payload)
rows = cur.fetchall()
if rows and convert:
recordset = [postsqldb.tupleDictionaryFactory(cur.description, row) for row in rows]
if rows and not convert:
recordset = rows
cur.execute(sqlcount)
count = cur.fetchone()[0]
except (Exception, psycopg2.DatabaseError) as error:
raise postsqldb.DatabaseError(error, payload, sql)
return recordset, count
def postRecipeUpdate(site, payload, convert=True):
database_config = config.config()
updated = ()
with psycopg2.connect(**database_config) as conn:
with conn.cursor() as cur:
set_clause, values = postsqldb.updateStringFactory(payload['update'])
with open("scripts/recipes/sql/postRecipeUpdate.sql") as file:
sql = file.read().replace("%%site_name%%", site).replace("%%set_clause%%", set_clause)
values.append(payload['id'])
cur.execute(sql, values)
rows = cur.fetchone()
if rows and convert:
updated = postsqldb.tupleDictionaryFactory(cur.description, rows)
elif rows and not convert:
updated = rows
return updated

View File

@ -5,13 +5,22 @@ from main import unfoldCostLayers
from user_api import login_required
import os
import postsqldb, webpush
from flasgger import swag_from
from scripts.recipes import database_recipes
from flask_restx import Api, fields
recipes_api = Blueprint('recipes_api', __name__)
model_api = Api(recipes_api)
@recipes_api.route("/recipes")
@login_required
def recipes():
"""This is the main endpoint to reach the webpage for a list of all recipes
---
responses:
200:
description: returns recipes/index.html with sites, current_site.
"""
sites = [site[1] for site in main.get_sites(session['user']['sites'])]
return render_template("recipes/index.html",
current_site=session['selected_site'],
@ -19,7 +28,24 @@ def recipes():
@recipes_api.route("/recipe/<mode>/<id>")
@login_required
def recipe(mode, id):
def recipe(id, mode='view'):
"""This is the main endpoint to reach the webpage for a recipe's view or edit mode.
---
parameters:
- name: mode
in: path
type: string
required: true
default: view
- name: id
in: path
type: integer
required: true
default: all
responses:
200:
description: Respondes with either the Edit or View webpage for the recipe.
"""
database_config = config()
with psycopg2.connect(**database_config) as conn:
units = postsqldb.UnitsTable.getAll(conn)
@ -32,16 +58,22 @@ def recipe(mode, id):
@recipes_api.route('/recipes/getRecipes', methods=["GET"])
def getRecipes():
""" Get a subquery of recipes from the database by passing a page, limit
---
responses:
200:
description: limit of rows passed returned to requester
"""
recipes = []
count=0
if request.method == "GET":
page = int(request.args.get('page', 1))
limit = int(request.args.get('limit', 1))
offset = (page-1)*limit
database_config = config()
site_name = session['selected_site']
with psycopg2.connect(**database_config) as conn:
recipes, count = postsqldb.RecipesTable.getRecipes(conn, site_name, (limit, offset), convert=True)
return jsonify({'recipes': recipes, 'end': math.ceil(count/limit), 'error': False, 'message': 'bleh'})
recipes, count = database_recipes.getRecipes(site_name, (limit, offset))
return jsonify({'recipes': recipes, 'end': math.ceil(count/limit), 'error': False, 'message': 'fetch was successful!'})
return jsonify({'recipes': recipes, 'end': math.ceil(count/limit), 'error': True, 'message': f'method is not allowed: {request.method}'})
@recipes_api.route('/recipe/getRecipe', methods=["GET"])
def getRecipe():
@ -75,6 +107,12 @@ def addRecipe():
@recipes_api.route('/recipe/getItems', methods=["GET"])
def getItems():
""" Pass along a page, limit, and search strings to get a pagination of items from the system
---
responses:
200:
description: Items were returned successfully!
"""
recordset = []
count = {'count': 0}
if request.method == "GET":
@ -83,22 +121,35 @@ def getItems():
search_string = request.args.get('search_string', 10)
site_name = session['selected_site']
offset = (page - 1) * limit
recordset, count = database_recipes.getModalSKUs(site_name, (limit, offset))
recordset, count = database_recipes.getModalSKUs(site_name, (search_string, limit, offset))
print(recordset)
return jsonify({"items":recordset, "end":math.ceil(count/limit), "error":False, "message":"items fetched succesfully!"})
return jsonify({"items":recordset, "end":math.ceil(count/limit), "error":True, "message":"There was an error with this GET statement"})
update_model = model_api.model('model', {
'id': fields.Integer(min=1),
'update': fields.Raw(required=True, description="all the data to be updated!")
})
@recipes_api.route('/recipe/postUpdate', methods=["POST"])
@model_api.expect(update_model)
def postUpdate():
""" This is an endpoint for updating an RecipeTuple in the sites recipes table
---
responses:
200:
description: The time was updated successfully!
Returns:
dict: returns a dictionary containing the updated recipe object, error status, and a message to post for notifications
"""
recipe = {}
if request.method == "POST":
recipe_id = int(request.get_json()['recipe_id'])
update = request.get_json()['update']
database_config = config()
site_name = session['selected_site']
with psycopg2.connect(**database_config) as conn:
recipe = postsqldb.RecipesTable.updateRecipe(conn, site_name, {'id': recipe_id, 'update': update}, convert=True)
recipe = database_recipes.postRecipeUpdate(site_name, {'id': recipe_id, 'update': update})
return jsonify({'recipe': recipe, 'error': False, 'message': 'Update of Recipe successful!'})
return jsonify({'recipe': recipe, 'error': True, 'message': 'Update of Recipe unsuccessful!'})

View File

@ -0,0 +1,3 @@
SELECT *,
(SELECT COALESCE(array_agg(row_to_json(g)), '{}') FROM %%site_name%%_recipe_items g WHERE rp_id = %%site_name%%_recipes.id) AS rp_items
FROM %%site_name%%_recipes LIMIT %s OFFSET %s;

View File

@ -0,0 +1 @@
SELECT COUNT(*) FROM %%site_name%%_recipes;

View File

@ -1,2 +1,3 @@
SELECT item.id, item.barcode, item.item_name FROM %%site_name%%_items item
WHERE item.search_string LIKE '%%' || %s || '%%'
LIMIT %s OFFSET %s;

View File

@ -0,0 +1 @@
UPDATE %%site_name%%_recipes SET %%set_clause%% WHERE id=%s RETURNING *;

View File

@ -9,8 +9,11 @@ import database
import postsqldb
from webpush import trigger_push_notifications_for_subscriptions
from scripts.recipes import recipes_api
from flasgger import Swagger
app = Flask(__name__, instance_relative_config=True)
swagger = Swagger(app)
UPLOAD_FOLDER = 'static/pictures'
FILES_FOLDER = 'static/files'
app.config.from_pyfile('application.cfg.py')
@ -66,6 +69,18 @@ def inject_user():
@app.route("/transactions/<id>")
@login_required
def transactions(id):
"""This is the main endpoint to reach the webpage for an items transaction history
---
parameters:
- name: id
in: path
type: integer
required: true
default: all
responses:
200:
description: Returns the transactions.html webpage for the item with passed ID
"""
sites = [site[1] for site in main.get_sites(session['user']['sites'])]
return render_template("items/transactions.html", id=id, current_site=session['selected_site'], sites=sites)