""" Webdist Flask backend """ import json import logging import subprocess import sqlite3 from datetime import datetime from flask import Flask, render_template, request # Enable logging logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) logger = logging.getLogger(__name__) def create_app(config): """ creates and returns the Flask app """ _app = Flask(__name__) _app.config.from_file(config, load=json.load) # initialize moment on the app within create_app() return _app app = create_app("/etc/webdist/main.json") logger.info(app.config) def cursor_row_to_dict(cursor, row): """ Converts a sqlite3 cursor row into a dict """ items = {} for idx, key in enumerate(cursor.description): if key[0] in ['buildtime']: items[key[0]] = datetime.fromtimestamp(row[idx]).isoformat() else: items[key[0]] = row[idx] return items def latest(): """ Returns a dict of latest packages """ response = {} for repo in app.config['WEBDIST_CONFIG']['repos']: response[repo] = [] repo_sources_db = "file:" + app.config['WEBDIST_CONFIG']['repos'][repo]['path'] + \ f"{app.config['WEBDIST_CONFIG']['repos'][repo]['dbname']}-sources.db?mode=ro" conn = sqlite3.connect(repo_sources_db, uri=True) cursor = conn.cursor() cursor.execute( 'SELECT * FROM sources ORDER BY buildtime DESC limit 100') for row in cursor: response[repo].append(cursor_row_to_dict(cursor, row)) return response def query(querystring): """ Performs a query of a package """ logger.info("Query of %s", querystring) response = {} for repo in app.config['WEBDIST_CONFIG']['repos']: response[repo] = [] repo_sources_db = "file:" + app.config['WEBDIST_CONFIG']['repos'][repo]['path'] + \ f"{app.config['WEBDIST_CONFIG']['repos'][repo]['dbname']}-sources.db?mode=ro" conn = sqlite3.connect(repo_sources_db, uri=True) cursor = conn.cursor() cursor.execute( f'SELECT * FROM sources where name like "%%{querystring}%%" ' 'or summary like "%%{querystring}%%" ' 'ORDER BY name="{querystring}" DESC, name like "{qs}%%" DESC, ' 'name like "%%{querystring}%%" DESC limit 10') for row in cursor: response[repo].append(cursor_row_to_dict(cursor, row)) return response @app.route("/") def _search(): return render_template("index.html") @app.route("/latest") def _latest(): data = latest() return render_template("latest.html", data=data) @app.route("/button/") def _button(name): script = app.config['WEBDIST_CONFIG']['buttons'][name]['script'] output = subprocess.check_output([script]) return render_template("button.html",output=output.decode()) @app.route("/query/") def _query(querystring): data = query(querystring) return render_template("query.html", data=data) @app.route("/api/v1/config") def api_config(): """ GET config API call """ logger.info("Origin: %s", request.headers['Origin']) return {'result': app.config['WEBDIST_CONFIG'] } @app.route("/api/v1/latest") def api_latest(): """ Get latest packages API call """ data = latest() return {'result': data } @app.route("/api/v1/button/") def api_button(name): """ Call a button associated script """ script = app.config['WEBDIST_CONFIG']['buttons'][name]['script'] output = subprocess.check_output([script]) return {'result': output.decode() } @app.after_request def after_request(response): """ Allow API request origins specified in configuration file """ white_origin = app.config['WEBDIST_CONFIG']['white_origins'] if request.headers['Origin'] in white_origin: response.headers['Access-Control-Allow-Origin'] = request.headers['Origin'] response.headers['Access-Control-Allow-Methods'] = 'PUT,GET,POST,DELETE' response.headers['Access-Control-Allow-Headers'] = 'Content-Type,Authorization' return response