diff --git a/app_templates.ini b/app_templates.ini index f23de31..e830836 100644 --- a/app_templates.ini +++ b/app_templates.ini @@ -4,3 +4,80 @@ url = your-website.com icon = static/images/apps/nextcloud.png description = A safe home for all your data – community-driven, free & open source open_in = this_tab + +[Home Assistant] +prefix = https:// +url = your-website.com +icon = static/images/apps/home-assistant.png +description = Open source home automation that puts local control and privacy first +open_in = this_tab + +[Emby] +prefix = https:// +url = your-website.com +icon = static/images/apps/emby.png +description = Emby Server is a personal media server with apps on just about every device +open_in = this_tab + +[Bitwarden] +prefix = https:// +url = your-website.com +icon = static/images/apps/bitwarden.png +description = A free and open-source password management service +open_in = this_tab + +[Deluge] +prefix = https:// +url = your-website.com +icon = static/images/apps/deluge.png +description = Deluge is a lightweight, Free Software, cross-platform BitTorrent client +open_in = this_tab + +[Gitea] +prefix = https:// +url = your-website.com +icon = static/images/apps/gitea.png +description = A painless self-hosted Git service +open_in = this_tab + +[SSH] +prefix = https:// +url = your-website.com +icon = static/images/apps/terminal.png +description = SSH, terminal, shell, shellinabox +open_in = this_tab + +[Portainer] +prefix = https:// +url = your-website.com +icon = static/images/apps/portainer.png +description = Making Docker management easy +open_in = this_tab + +[Nginx Proxy Manager] +prefix = https:// +url = your-website.com +icon = static/images/apps/nginxproxymanager.png +description = Docker container for managing Nginx proxy hosts with a simple, powerful interface +open_in = this_tab + +[Sonarr] +prefix = https:// +url = your-website.com +icon = static/images/apps/sonarr.png +description = Smart PVR for newsgroup and bittorrent users +open_in = this_tab + +[Radarr] +prefix = https:// +url = your-website.com +icon = static/images/apps/radarr.png +description = A fork of Sonarr to work with movies à la Couchpotato +open_in = this_tab + +[Jackett] +prefix = http:// +url = 192.168.39.175:9117 +icon = static/images/apps/jackett.png +description = API Support for your favorite torrent trackers +open_in = this_tab diff --git a/dashmachine/main/models.py b/dashmachine/main/models.py index 6f9df53..8a6f749 100644 --- a/dashmachine/main/models.py +++ b/dashmachine/main/models.py @@ -19,6 +19,30 @@ class Apps(db.Model): sidebar_icon = db.Column(db.String()) description = db.Column(db.String()) open_in = db.Column(db.String()) + data_template = db.Column(db.String()) + + +class TemplateApps(db.Model): + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String()) + prefix = db.Column(db.String()) + url = db.Column(db.String()) + icon = db.Column(db.String()) + sidebar_icon = db.Column(db.String()) + description = db.Column(db.String()) + open_in = db.Column(db.String()) + + +class ApiCalls(db.Model): + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String()) + resource = db.Column(db.String()) + method = db.Column(db.String()) + payload = db.Column(db.String()) + authentication = db.Column(db.String()) + username = db.Column(db.String()) + password = db.Column(db.String()) + value_template = db.Column(db.String()) db.create_all() diff --git a/dashmachine/main/routes.py b/dashmachine/main/routes.py index 7810a2d..19a3c40 100755 --- a/dashmachine/main/routes.py +++ b/dashmachine/main/routes.py @@ -5,6 +5,7 @@ from htmlmin.main import minify from flask import render_template, url_for, redirect, request, Blueprint, jsonify from flask_login import current_user from dashmachine.main.models import Files +from dashmachine.main.utils import get_rest_data from dashmachine.paths import cache_folder from dashmachine import app, db @@ -59,6 +60,12 @@ def app_view(url): return render_template("main/app-view.html", url=f"https://{url}") +@main.route("/load_rest_data", methods=["GET"]) +def load_rest_data(): + data_template = get_rest_data(request.args.get("template")) + return data_template[:50] + + # ------------------------------------------------------------------------------ # TCDROP routes # ------------------------------------------------------------------------------ diff --git a/dashmachine/main/utils.py b/dashmachine/main/utils.py index d62a0e5..b73f48b 100755 --- a/dashmachine/main/utils.py +++ b/dashmachine/main/utils.py @@ -1,9 +1,9 @@ import os from shutil import copyfile +from requests import get from configparser import ConfigParser - from dashmachine.paths import dashmachine_folder, images_folder -from dashmachine.main.models import Apps +from dashmachine.main.models import Apps, ApiCalls, TemplateApps from dashmachine.settings_system.models import Settings from dashmachine.user_system.models import User from dashmachine.user_system.utils import add_edit_user @@ -26,6 +26,7 @@ def read_config(): return {"msg": f"Invalid Config: {e}."} Apps.query.delete() + ApiCalls.query.delete() Settings.query.delete() try: @@ -41,6 +42,53 @@ def read_config(): for section in config.sections(): if section != "Settings": + + # API call creation + if "platform" in config[section]: + api_call = ApiCalls() + api_call.name = section + if "resource" in config[section]: + api_call.resource = config[section]["resource"] + else: + return { + "msg": f"Invalid Config: {section} does not contain resource." + } + + if "method" in config[section]: + api_call.method = config[section]["method"] + else: + api_call.method = "GET" + + if "payload" in config[section]: + api_call.payload = config[section]["payload"] + else: + api_call.payload = None + + if "authentication" in config[section]: + api_call.authentication = config[section]["authentication"] + else: + api_call.authentication = None + + if "username" in config[section]: + api_call.username = config[section]["username"] + else: + api_call.username = None + + if "password" in config[section]: + api_call.password = config[section]["password"] + else: + api_call.password = None + + if "value_template" in config[section]: + api_call.value_template = config[section]["value_template"] + else: + api_call.value_template = section + + db.session.add(api_call) + db.session.commit() + continue + + # App creation app = Apps() app.name = section if "prefix" in config[section]: @@ -73,11 +121,41 @@ def read_config(): else: app.open_in = "this_tab" + if "data_template" in config[section]: + app.data_template = config[section]["data_template"] + else: + app.data_template = None + db.session.add(app) db.session.commit() return {"msg": "success", "settings": row2dict(settings)} +def read_template_apps(): + config = ConfigParser() + try: + config.read("app_templates.ini") + except Exception as e: + return {"msg": f"Invalid Config: {e}."} + + TemplateApps.query.delete() + + for section in config.sections(): + template_app = TemplateApps() + template_app.name = section + template_app.prefix = config[section]["prefix"] + template_app.url = config[section]["url"] + template_app.icon = config[section]["icon"] + if "sidebar_icon" in config[section]: + template_app.sidebar_icon = config[section]["sidebar_icon"] + else: + template_app.sidebar_icon = template_app.icon + template_app.description = config[section]["description"] + template_app.open_in = config[section]["open_in"] + db.session.add(template_app) + db.session.commit() + + # establishes routes decorated w/ @public_route as accessible while not signed # in. See login and register routes for usage def public_route(decorated_function): @@ -86,6 +164,7 @@ def public_route(decorated_function): def dashmachine_init(): + read_template_apps() user_data_folder = os.path.join(dashmachine_folder, "user_data") # create the user_data subdirectories, link them to static @@ -106,4 +185,24 @@ def dashmachine_init(): user = User.query.first() if not user: - add_edit_user(username="admin", password="admin") \ No newline at end of file + add_edit_user(username="admin", password="admin") + + +def get_rest_data(template): + while template and template.find("{{") > -1: + start_braces = template.find("{{") + 2 + end_braces = template.find("}}") + key = template[start_braces:end_braces] + key_w_braces = template[start_braces - 2 : end_braces + 2] + value = do_api_call(key) + template = template.replace(key_w_braces, value) + return template + + +def do_api_call(key): + api_call = ApiCalls.query.filter_by(name=key).first() + if api_call.method.upper() == "GET": + value = get(api_call.resource) + exec(f"{key} = {value.json()}") + value = str(eval(api_call.value_template)) + return value diff --git a/dashmachine/settings_system/routes.py b/dashmachine/settings_system/routes.py index b3f4a6e..c7bd692 100644 --- a/dashmachine/settings_system/routes.py +++ b/dashmachine/settings_system/routes.py @@ -18,7 +18,10 @@ def settings(): config_form.config.data = config_file.read() files_html = load_files_html() return render_template( - "settings_system/settings.html", config_form=config_form, files_html=files_html, user_form=user_form + "settings_system/settings.html", + config_form=config_form, + files_html=files_html, + user_form=user_form, ) diff --git a/dashmachine/settings_system/utils.py b/dashmachine/settings_system/utils.py index 3ab494e..57fea69 100644 --- a/dashmachine/settings_system/utils.py +++ b/dashmachine/settings_system/utils.py @@ -7,7 +7,5 @@ def load_files_html(): backgrounds = listdir(backgrounds_images_folder) icons = listdir(icons_images_folder) return render_template( - "settings_system/files.html", - backgrounds=backgrounds, - icons=icons, + "settings_system/files.html", backgrounds=backgrounds, icons=icons, ) diff --git a/dashmachine/templates/main/home.html b/dashmachine/templates/main/home.html index 4af7890..9cd2397 100755 --- a/dashmachine/templates/main/home.html +++ b/dashmachine/templates/main/home.html @@ -1,4 +1,6 @@ {% extends "main/layout.html" %} +{% from 'global_macros.html' import data %} + {% block page_vendor_css %} {% endblock page_vendor_css %} @@ -41,6 +43,11 @@