diff --git a/src/main.py b/src/main.py index 595564b..9599dd9 100644 --- a/src/main.py +++ b/src/main.py @@ -18,30 +18,39 @@ import time # To sleep import os # For VARS from the shell. # Variables +app = Flask(__name__) + # Load the configuration file try: + app.logger.debug("Loading config file...") configuration_file = toml.load("configuration/config.toml") except TypeError : - print("Unable to load the config file: invalid type or is a list containing invalid types") + app.logger.error("Unable to load the config file: invalid type or is a list containing invalid types") exit(-1) except toml.TomlDecodeError: - print("An error occured while decoding the file") + app.logger.error("An error occured while decoding the file") exit(-1) except Exception as e: - print("Error while loading file : " + str(e)) + app.logger.error("Error while loading file : " + str(e)) + exit(-1) +app.logger.debug("Config file loaded !") # Define the USB connections here. vendor_id = configuration_file["printer"]["vendor_id"] device_id = configuration_file["printer"]["device_id"] +UPLOAD_FOLDER = str(configuration_file["printer"]["upload_folder"]) + +ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'} # Output the config file if os.getenv('LIPY_DEBUG') == True: pprint.pprint(configuration_file) # We define the app module used by Flask -app = Flask(__name__) app.secret_key = configuration_file["secrets"]["flask_secret_key"] - +app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER +app.config['ALLOWED_EXTENSIONS'] = ALLOWED_EXTENSIONS +app.config['MAX_CONTENT_LENGTH'] = 3 * 1000 * 1000 # Maximum 3Mb for a file upload # Printer connection # Uses the class defined in the printer.py file @@ -61,6 +70,7 @@ limiter = Limiter( @app.route('/') @limiter.limit("1/second", override_defaults=False) def index(): + app.logger.debug("Loading index") return render_template('index.html') # API routes @@ -74,50 +84,86 @@ def index(): @app.route('/api/print') @limiter.limit("1/second", override_defaults=False) def api_index(): + app.logger.debug("Loading API") return render_template("api.html") @app.route('/api/print/sms', methods=['POST']) @limiter.limit("2/minute", override_defaults=False) def api_print_sms(): + app.logger.debug("Printing an sms") try: txt = request.form["txt"] sign = request.form["signature"] except Exception as e: - flash(e) + flash(e,'error') redirect(url_for('index')) try: web.print_sms(txt,sign) except Exception as e: pass - + return redirect(url_for('index')) -@app.route('/api/print/image', methods=['POST']) +@app.route('/api/print/img', methods=['POST']) @limiter.limit("2/minute", override_defaults=False) def api_print_image(): - flash(web.print_image()) - return "print image" + app.logger.debug("Printing an image") + + try: + sign = request.form["signature"] + except Exception as e: + flash(str(e),'error') + redirect(url_for('index')) + + if request.method == 'POST': + # check if the post request has the file part + + if 'img' not in request.files: + flash('No file found. Did you use the good form ?', 'error') + return redirect(url_for("index")) + else: + file = request.files['img'] + + + # If the user does not select a file, the browser submits an + # empty file without a filename. + if file.filename == '': + app.logger.error("Submitted file has no filename !") + flash('No file submitted, please select a file','error') + return redirect(url_for("index")) + + try: + app.logger.debug("Sending the image to the printer.") + web.print_image(file, sign) + except Exception as e: + pass + else: + flash('Cannot access to page with this method.','error') + app.logger.debug('Bad access type to this API.') + + return redirect(url_for("index")) @app.route('/login') @limiter.limit("1/second", override_defaults=False) def login_page(): # web.login(username,password) - return render_template("index.html") + return redirect(url_for("index")) @app.route('/logout') @limiter.limit("1/second", override_defaults=False) def logout_page(): # web.logout(username, password) - return render_template("index.html") + return redirect(url_for("index")) @app.errorhandler(429) def ratelimit_handler(e): flash("Rate limit reached, please slow down :) ( Currently at "+ e.description + ")", 'error') - return render_template('index.html') + return redirect(url_for("index")) @app.route("/ping") @limiter.exempt def ping(): - return "PONG" + flash("🏓 Pong !",'info') + return redirect(url_for("index")) diff --git a/src/printer.py b/src/printer.py index 9f2ea07..d0a840b 100644 --- a/src/printer.py +++ b/src/printer.py @@ -3,6 +3,7 @@ from flask import flash from escpos.printer import Usb, USBNotFoundError from time import sleep, gmtime, strftime import os.path +from PIL import Image class Printer(object): @@ -130,23 +131,48 @@ class Printer(object): self.printer.close except Exception as e: flash("Unable to print because : " + e) - + flash("Message printed : " + clean_msg ,category='info') return True - def print_img(self, path): + def print_img(self, path, sign): + clean_signature = str(sign) - if os.path.isfile(str(path)): - pass - else: + if not os.path.isfile(str(path)): self.app.logger.warning("File does not exist : " + str(path)) + flash('The file path for this image :' + str(path) + " wasn't found. Please try again.", 'error') + return False + else: + self.app.logger.debug("Printing file from " + str(path)) + + + + try: + self.app.logger.debug("Resizing the image") + with Image.open(path) as im: + + basewidth = 575 + img = Image.open(path) + wpercent = (basewidth/float(img.size[0])) + hsize = int((float(img.size[1])*float(wpercent))) + img = img.resize((basewidth,hsize), Image.ANTIALIAS) + if img.height > 1000: + flash("Image is too long, sorry ! Keep it below 500×1000 pixels.",'error') + return False + img.save(path) + except Exception as e: + flash(str(e)) + self.app.logger.error(str(e)) try: self.printer.open(self.usb_args) + self.printer.textln("> " + clean_signature + " @ " + strftime("%Y-%m-%d %H:%M:%S", gmtime())) self.printer.image(path) + self.printer.cut() self.printer.close() + self.app.logger.debug("Printed an image : " + str(path)) + return True except Exception as e: self.printer.close() - return e - else: - self.app.logging.debug("Printed an image : " + str(path)) + flash(str(e),'error') + return False diff --git a/src/templates/index.html b/src/templates/index.html index 8b9f881..ee1f336 100644 --- a/src/templates/index.html +++ b/src/templates/index.html @@ -9,15 +9,15 @@ -
- LittlePrynter icon

Little Prynter

+
+ LittlePrynter icon

Little Prynter



{% with messages = get_flashed_messages(category_filter=('error')) %} {% if messages %} {% for message in messages %} - + {% endfor %} {% endif %} {% endwith %} @@ -25,7 +25,7 @@ {% with messages = get_flashed_messages(category_filter=('info')) %} {% if messages %} {% for message in messages %} - + {% endfor %} {% endif %} {% endwith %} @@ -40,20 +40,30 @@
-
-
+
+
- - -
+
-
+ +
+

Print an image

+
+
+
+
+ +
+
+ + +

diff --git a/src/web.py b/src/web.py index a5d05c1..9157795 100644 --- a/src/web.py +++ b/src/web.py @@ -1,4 +1,5 @@ from flask import Flask, request +from werkzeug.utils import secure_filename from printer import Printer import time import os @@ -19,11 +20,49 @@ class Web(object): return self.printer.print_sms(texte, sign) - def print_image(self, image): - pass + def print_image(self, image, sign: str) -> bool: + self.app.logger.debug("Uploading file") + try: + self.app.logger.debug("Uploading file from " + str(sign)) + if self.upload_file(image): + self.app.logger.debug("File has been uploaded, printing...") + self.printer.print_img(os.path.join(self.app.config['UPLOAD_FOLDER'], secure_filename(image.filename)), sign) + return True + else: + return False + except Exception as e: + self.app.logger.error(e) + raise Exception + + else: + flash("Could not upload file.",'error') + return False def login(username: str,password: str) -> bool: pass def logout(username: str, password: str) -> bool: pass + + def allowed_file(self, filename) -> bool: + self.app.logger.debug("Is the filename allowed ?") + return '.' in filename and filename.rsplit('.', 1)[1].lower() in self.app.config['ALLOWED_EXTENSIONS'] + + def upload_file(self, image)-> bool: + self.app.logger.debug("Validating file") + if image and self.allowed_file(image.filename): + filename = secure_filename(image.filename) + self.app.logger.debug("File valid") + try: + image.save(os.path.join(self.app.config['UPLOAD_FOLDER'], filename)) + self.app.logger.debug("File saved") + except Exception as e: + self.app.logger.error("Could not save file") + flash(e,'error') + return False + + self.app.logger.debug("File saved to " + str(os.path.join(self.app.config['UPLOAD_FOLDER'], filename))) + return True + else: + self.app.logger.error("Could not save file " + str(filename)) + return False