diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..eabd9a7 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,36 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = false +insert_final_newline = false + +[*.md] +trim_trailing_whitespace = true + +[*.py] +indent_size = 4 + +[*.js] +indent_size = 2 + +[*.html] +indent_size = 2 + +[*.css] +indent_size = 2 + +[*.scss] +indent_size = 2 + +[*.yaml] +indent_size = 2 + +[*.yml] +indent_size = 2 \ No newline at end of file diff --git a/.flake8 b/.flake8 new file mode 100644 index 0000000..1cfd4e0 --- /dev/null +++ b/.flake8 @@ -0,0 +1,3 @@ +[flake8] +ignore = E501 +max-line-length = 120 \ No newline at end of file diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml new file mode 100644 index 0000000..e83fef6 --- /dev/null +++ b/.github/workflows/lint.yaml @@ -0,0 +1,23 @@ +name: Lint + +on: [push, pull_request] + +jobs: + flake8_py3: + runs-on: ubuntu-latest + steps: + - name: Setup Python + uses: actions/setup-python@v4.6.0 + with: + python-version: '3.10' + architecture: x64 + - name: Checkout PyTorch + uses: actions/checkout@master + - name: Install flake8 + run: pip install flake8 + - name: Run flake8 + uses: suo/flake8-github-action@releases/v1 + with: + checkName: 'flake8_py3' # NOTE: this needs to be the same as the job name + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index d2a6c12..93f9daa 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,14 @@ { - "python.pythonPath": "/usr/bin/python" + "python.pythonPath": "/usr/bin/python", + "python.testing.unittestArgs": [ + "-v", + "-s", + "./backend/tests", + "-p", + "*test.py" + ], + "python.testing.pytestEnabled": false, + "python.testing.unittestEnabled": true, + "python.linting.pylintEnabled": false, + "python.linting.flake8Enabled": true } \ No newline at end of file diff --git a/backend/app.py b/backend/app.py index 29f55fd..6ea7dab 100644 --- a/backend/app.py +++ b/backend/app.py @@ -1,5 +1,5 @@ from flask import Flask, render_template, abort, request, redirect, send_from_directory, jsonify -from flask.wrappers import Request, Response +from flask.wrappers import Response import helpers import database import data_adapters @@ -12,6 +12,7 @@ app = Flask(__name__, static_url_path='/static') basic_auth = BasicAuth(app) accept_entries = True + @app.route("/") def home(): if basic_auth.authenticate(): @@ -95,7 +96,7 @@ def settings_post(): else: abort(400) if theme is not None and theme in helpers.get_themes(): - helpers.set_theme(app,theme) + helpers.set_theme(app, theme) else: abort(400) if username != "" and username != app.config['BASIC_AUTH_USERNAME']: @@ -143,7 +144,7 @@ def update_songs(): return Response('{"status": "%s" }' % status, mimetype='text/json') -@app.route("/api/songs/compl") # type: ignore +@app.route("/api/songs/compl") # type: ignore @nocache def get_song_completions(input_string=""): input_string = request.args.get('search', input_string) @@ -176,7 +177,7 @@ def delete_entries(): return updates = database.delete_entries(request.json) if updates >= 0: - return Response('{"status": "OK", "updates": '+str(updates)+'}', mimetype='text/json') + return Response('{"status": "OK", "updates": ' + str(updates) + '}', mimetype='text/json') else: return Response('{"status": "FAIL"}', mimetype='text/json', status=400) @@ -190,6 +191,7 @@ def mark_sung(entry_id): else: return Response('{"status": "FAIL"}', mimetype='text/json') + @app.route("/api/entries/mark_transferred/") @nocache @basic_auth.required @@ -205,7 +207,7 @@ def mark_transferred(entry_id): @basic_auth.required def set_accept_entries(value): if (value == '0' or value == '1'): - helpers.set_accept_entries(app,bool(int(value))) + helpers.set_accept_entries(app, bool(int(value))) return Response('{"status": "OK"}', mimetype='text/json') else: return Response('{"status": "FAIL"}', mimetype='text/json', status=400) @@ -215,7 +217,7 @@ def set_accept_entries(value): @nocache def get_accept_entries(): accept_entries = helpers.get_accept_entries(app) - return Response('{"status": "OK", "value": '+str(int(accept_entries))+'}', mimetype='text/json') + return Response('{"status": "OK", "value": ' + str(int(accept_entries)) + '}', mimetype='text/json') @app.route("/api/played/clear") @@ -257,17 +259,17 @@ def activate_job(): helpers.setup_config(app) - @app.after_request def add_header(response): """ Add headers to both force latest IE rendering engine or Chrome Frame, and also to cache the rendered page for 10 minutes. """ - if not 'Cache-Control' in response.headers: + if 'Cache-Control' not in response.headers: response.headers['Cache-Control'] = 'private, max-age=600, no-cache, must-revalidate' return response + @app.context_processor def inject_version(): return dict(karaoqueue_version=app.config['VERSION']) diff --git a/backend/data_adapters.py b/backend/data_adapters.py index 20cd2b4..0136322 100644 --- a/backend/data_adapters.py +++ b/backend/data_adapters.py @@ -1,5 +1,5 @@ def dict_from_rows(rows): - outlist=[] + outlist = [] for row in rows: outlist.append(dict(row._mapping)) - return outlist \ No newline at end of file + return outlist diff --git a/backend/database.py b/backend/database.py index 59a0d4c..fdf6d86 100644 --- a/backend/database.py +++ b/backend/database.py @@ -1,7 +1,5 @@ # -*- coding: utf_8 -*- -from email.mime import base -from MySQLdb import Connection from sqlalchemy import create_engine, engine, text import pandas from io import StringIO @@ -209,7 +207,7 @@ def delete_entries(ids): "par_id": idlist}) conn.commit() return cur.rowcount - except Exception as error: + except Exception: return -1 @@ -227,7 +225,7 @@ def get_config(key: str) -> str: text("SELECT `Value` FROM config WHERE `Key`= :par_key"), {"par_key": key}) # type: ignore conn.commit() return cur.fetchall()[0][0] - except IndexError as error: + except IndexError: return "" @@ -256,7 +254,7 @@ def check_config_table() -> bool: if conn.dialect.has_table(conn, 'config'): # type: ignore # type: ignore - if (conn.execute(text("SELECT COUNT(*) FROM config")).fetchone()[0] > 0): # type: ignore + if (conn.execute(text("SELECT COUNT(*) FROM config")).fetchone()[0] > 0): # type: ignore return True else: return False diff --git a/backend/helpers.py b/backend/helpers.py index 2b8d4eb..fff6b8d 100644 --- a/backend/helpers.py +++ b/backend/helpers.py @@ -1,6 +1,5 @@ import requests from bs4 import BeautifulSoup -import json import os import uuid from flask import make_response, Flask @@ -8,6 +7,7 @@ from functools import wraps, update_wrapper from datetime import datetime import database + def get_catalog_url(): r = requests.get('https://www.karafun.de/karaoke-song-list.html') soup = BeautifulSoup(r.content, 'html.parser') @@ -69,13 +69,15 @@ def load_dbconfig(app: Flask): else: app.config['DBCONNSTRING'] = "" else: - exit("No database connection string found. Cannot continue. Please set the environment variable DBSTRING or create a file .dbconn in the root directory of the project.") + exit("""No database connection string found. Cannot continue. + Please set the environment variable DBSTRING or + create a file .dbconn in the root directory of the project.""") # Check if config exists in DB, if not, create it. def setup_config(app: Flask): - if check_config_exists() == False: + if check_config_exists() is False: print("No config found, creating new config") initial_username = os.environ.get("INITIAL_USERNAME") initial_password = os.environ.get("INITIAL_PASSWORD") diff --git a/backend/main.py b/backend/main.py index 210a38e..6026b0f 100644 --- a/backend/main.py +++ b/backend/main.py @@ -1,4 +1,4 @@ from app import app if __name__ == "__main__": - app.run() \ No newline at end of file + app.run()