from flask import Blueprint, render_template, redirect, url_for, request, make_response, abort from flask_login import login_required, current_user from models import db from models import Item, ListOfItems from sqlalchemy import desc, text from datetime import datetime import os from log import Log from auth import create_cookie items_bp = Blueprint("items", __name__) ICONPATH = "static/categories/" #without starting / and with ending / def require_list_access(listid): listofitem = db.get_or_404(ListOfItems, int(listid)) if not current_user.can_access_list(listofitem.id): abort(403) return listofitem def require_item_access(itemid): item = db.get_or_404(Item, int(itemid)) if not current_user.can_access_item(item.id): abort(403) return item def client_update_time(): client_updated_at = request.args.get("client_updated_at") if not client_updated_at: return None try: return datetime.fromtimestamp(int(client_updated_at) / 1000) except ValueError: return None def item_update_is_current(item): updated_at = client_update_time() if updated_at is None: return True return item.updated_at is None or updated_at >= item.updated_at def stamp_item_update(item): updated_at = client_update_time() if updated_at is not None: item.updated_at = updated_at # home screen for items @items_bp.route("/items/") @login_required def items(listid): require_list_access(listid) resp = make_response(render_template("items_show.html", user=current_user, items=Item.query.filter_by(listofitems_id=listid, is_suggestion=False).order_by(text("is_checked, category, label")).all(), button_top_url1 = url_for("items.items_append", listid=listid), button_top_txt1 = "add", button_top_url2 = url_for("items.items_clean", listid=listid), button_top_txt2 = "clean")) resp.set_cookie('username', create_cookie(current_user.id)) return resp # webservice for updating checked state of one item @items_bp.route("/item_update//") @login_required def item_update(itemid, itemchecked): i = require_item_access(itemid) if not item_update_is_current(i): return '', 204 i.is_checked = True if itemchecked == 'true' else False stamp_item_update(i) db.session.commit() return '', 204 def interpret_and_add_item(listid, newlabel): # could be # appeltjes # appel goudr #. appel zilver 4 #. appel zilver 4kratten unit = '' quantity = '' if ' ' in newlabel: # could be: # paard 5 # paard 5 poten # 3 paarden # 3kilo schaap # 3 kilo schaap # take the last word words = newlabel.split(' ') # -1- if there is a digit in the last word if any(char.isdigit() for char in words[-1]): # ... paard 5 # ... paard 5poten for char in words[-1]: if char.isdigit(): quantity += char else: unit += char newlabel = ' '.join(words[0:-1]) elif len(words)>2 and any(char.isdigit() for char in words[-2]): # ... paard 5 poten # ... paard 4keer poten for char in words[-2]: if char.isdigit(): quantity += char else: unit += char unit = words[-1] if unit=='' else unit+' '+words[-1] newlabel = ' '.join(words[0:-2]) elif any(char.isdigit() for char in words[0]): # 5 paarden # 5koppig paarden for char in words[0]: if char.isdigit(): quantity += char else: unit += char newlabel = ' '.join(words[1:]) if unit=='': if len(words)>2 and len(words[1])<=4: unit = words[1] newlabel = ' '.join(words[2:]) if unit == '': unit = 'x' if quantity == '': quantity = 1 newlabel=newlabel.title() # check if the item exists already item = Item.query.filter_by(listofitems_id=listid, label=newlabel, unit=unit).first() if item: if item.is_checked: item.quantity += int(quantity) if item.is_suggestion: item.quantity = quantity item.is_suggestion = False item.is_checked = False else: # create a new one item=Item(listofitems_id=listid, label=newlabel) if unit: item.unit = unit if quantity: item.quantity = int(quantity) db.session.add(item) db.session.commit() return item # user adds items to list @items_bp.route("/items_append/", methods=["GET", "POST"]) @login_required def items_append(listid): require_list_access(listid) if request.method == "POST": # a new item has been added newlabel = request.form["newItem"] interpret_and_add_item(listid, newlabel) # read icons icon_names = [] icon_list = os.listdir(ICONPATH) for i in icon_list: if not i.startswith('.'): icon_names.append(os.path.splitext(i)[0]) resp = make_response(render_template("items_append.html", user=current_user, listid=listid, items=Item.query.filter_by(listofitems_id=listid).order_by(Item.label).all(), icons = icon_names, iconpath = '/'+ICONPATH, logo_url=url_for("items.items", listid=listid))) resp.set_cookie('username', create_cookie(current_user.id)) return resp # user adds items to list @items_bp.route("/items_multiappend/", methods=["GET", "POST"]) @login_required def items_multiappend(listid): require_list_access(listid) if request.method == "POST": # a new item has been added newitems = request.form["newItems"] for line in newitems.splitlines(): line = line.strip() if len(line)>2: interpret_and_add_item(listid, line.strip()) return redirect(url_for("items.items_append", listid=listid)) # webservice for deleting one item @items_bp.route("/item_delete/") @login_required def item_delete(itemid): i = require_item_access(itemid) if not item_update_is_current(i): return redirect(url_for("items.items_append", listid=i.listofitems_id)) listid = i.listofitems_id db.session.delete(i) db.session.commit() Log.info(f'User {current_user.id} deleted item {itemid}') # return render_template("items_append.html", user=current_user, # items=Item.query.filter_by(listofitems_id=listid).order_by(Item.label).all(), # iconpath = '/'+ICONPATH, # logo_url=url_for("items.items", listid=listid)) return redirect(url_for("items.items_append", listid=listid)) # webservice for cleaning all checked items to suggestion @items_bp.route("/items_clean/") @login_required def items_clean(listid): require_list_access(listid) for i in Item.query.filter_by(listofitems_id=listid, is_checked=True, is_suggestion=False).all(): i.is_suggestion = True db.session.commit() return redirect(url_for("items.items", listid=listid)) # webservice for adding one item @items_bp.route("/item_addone/") @login_required def item_addone(itemid): i = require_item_access(itemid) if not item_update_is_current(i): resp = make_response(render_template("items_append.html", user=current_user, items=Item.query.filter_by(listofitems_id=i.listofitems_id).order_by(Item.label).all(), logo_url=url_for("items.items", listid=i.listofitems_id))) resp.set_cookie('username', create_cookie(current_user.id)) return resp listid = i.listofitems_id # if it is checked or not on the list yet, set quantity to one if i.is_suggestion or i.is_checked: i.quantity = 1 # and make sure its on the list i.is_suggestion = False i.is_checked = False else: # else add one to the quantity, to a minimum of 2 i.quantity += 1 if i.quantity else 2 # if no unit given, make it 'x' if not i.unit: i.unit = 'x' stamp_item_update(i) db.session.commit() resp = make_response(render_template("items_append.html", user=current_user, items=Item.query.filter_by(listofitems_id=listid).order_by(Item.label).all(), logo_url=url_for("items.items", listid=listid))) resp.set_cookie('username', create_cookie(current_user.id)) return resp # webservice for adding one item with a quantity/unit @items_bp.route("/item_addquantity//") @login_required def item_addquantity(itemid, quantity): i = require_item_access(itemid) if not item_update_is_current(i): resp = make_response(render_template("items_append.html", user=current_user, items=Item.query.filter_by(listofitems_id=i.listofitems_id).order_by(Item.label).all(), logo_url=url_for("items.items", listid=i.listofitems_id))) resp.set_cookie('username', create_cookie(current_user.id)) return resp listid = i.listofitems_id # always add the item to the active todo if i.is_suggestion or i.is_checked: # and make sure its on the list i.is_suggestion = False i.is_checked = False else: i.quantity += int(quantity) stamp_item_update(i) db.session.commit() resp = make_response(render_template("items_append.html", user=current_user, items=Item.query.filter_by(listofitems_id=listid).order_by(Item.label).all(), logo_url=url_for("items.items", listid=listid))) resp.set_cookie('username', create_cookie(current_user.id)) return resp # webservice for updating category of one item @items_bp.route("/item_update_category//") @login_required def item_upitem_update_categorydate(itemid, category): i = require_item_access(itemid) if not item_update_is_current(i): return '', 204 i.category = category stamp_item_update(i) db.session.commit() return '', 204