181 lines
6.7 KiB
Python
181 lines
6.7 KiB
Python
#
|
|
# Copyright © 2021,2022 IsardVDI S.L.
|
|
#
|
|
# This file is part of DD
|
|
#
|
|
# DD is free software: you can redistribute it and/or modify
|
|
# it under the terms of the GNU Affero General Public License as published by
|
|
# the Free Software Foundation, either version 3 of the License, or (at your
|
|
# option) any later version.
|
|
#
|
|
# DD is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
# FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License
|
|
# along with DD. If not, see <https://www.gnu.org/licenses/>.
|
|
#
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
import json
|
|
import logging
|
|
import pprint
|
|
import time
|
|
import traceback
|
|
from datetime import datetime, timedelta
|
|
from typing import TYPE_CHECKING, Dict
|
|
|
|
import yaml
|
|
from jinja2 import Environment, FileSystemLoader
|
|
|
|
if TYPE_CHECKING:
|
|
from api.flaskapp import ApiFlaskApp
|
|
|
|
|
|
def write_css() -> None:
|
|
env = Environment(loader=FileSystemLoader("api/static/_templates"))
|
|
css_template = env.get_template("dd.css")
|
|
with open("menu/custom.yaml", "r") as menu_custom_file:
|
|
menu_custom_yaml = menu_custom_file.read()
|
|
menu_custom = yaml.full_load(menu_custom_yaml)
|
|
css = css_template.render(data=menu_custom)
|
|
with open("api/static/css/dd.css", "w") as css_file:
|
|
css_file.write(css)
|
|
|
|
|
|
class Menu:
|
|
app: "ApiFlaskApp"
|
|
|
|
def __init__(self, app: "ApiFlaskApp") -> None:
|
|
self.app = app
|
|
# self.user_menudict=self.gen_user_menu()
|
|
# pprint.pprint(self.user_menudict)
|
|
# self.write_user_menu()
|
|
|
|
self.menudict = self.gen_header()
|
|
pprint.pprint(self.menudict)
|
|
self.write_headers()
|
|
write_css()
|
|
|
|
def patch_url(self, subdomain_part: str, domain: str, url: str) -> str:
|
|
"""
|
|
Patch a URL only if it is a relative URL, so it conforms to:
|
|
https://[{subdomain}.]{domain}{url}
|
|
"""
|
|
# Only modify if it is a relative URL
|
|
if not url or url.startswith("/") or url.startswith("#"):
|
|
# Ensure subdomain doesn't have leading dots
|
|
subdomain_part = subdomain_part.lstrip(".")
|
|
# Ensure the subdomain ends with a trailing dot
|
|
if subdomain_part and not subdomain_part.endswith("."):
|
|
subdomain_part = f"{subdomain_part}."
|
|
# Actually construct the full URL
|
|
url = "".join(
|
|
[
|
|
"https://",
|
|
subdomain_part,
|
|
domain,
|
|
url,
|
|
]
|
|
)
|
|
return url
|
|
|
|
""" HEADER & APP MENU """
|
|
|
|
def gen_header(self) -> Dict:
|
|
domain = self.app.config["DOMAIN"]
|
|
with open(r"menu/system.yaml") as yml:
|
|
system = yaml.load(yml, Loader=yaml.FullLoader)
|
|
|
|
user_menu = []
|
|
for item in system["user_menu"]:
|
|
# We pop 'subdomain' so it is not in user_menu
|
|
item["href"] = self.patch_url(
|
|
item.pop("subdomain", ""), domain, item["href"]
|
|
)
|
|
user_menu.append(item)
|
|
|
|
apps_internal = []
|
|
for app in system.get("apps_internal", []):
|
|
app_href = app["href"] if app.get("href", "") else "/"
|
|
# We pop 'subdomain' so it is not in apps_internal
|
|
app["href"] = self.patch_url(app.pop("subdomain", ""), domain, app_href)
|
|
apps_internal.append(app)
|
|
|
|
with open(r"menu/custom.yaml") as yml:
|
|
custom = yaml.load(yml, Loader=yaml.FullLoader)
|
|
custom["background_login"] = self.patch_url(
|
|
"api", domain, custom.get("background_login", "/img/background.png")
|
|
)
|
|
custom["background_login"] = self.patch_url(
|
|
"api", domain, custom.get("logo", "/img/logo.png")
|
|
)
|
|
custom["product_logo"] = self.patch_url(
|
|
"api", domain, custom.get("product_logo", "/img/product-logo.svg")
|
|
)
|
|
|
|
menudict: Dict = custom
|
|
menudict["user"] = {
|
|
"account": self.patch_url(
|
|
"sso", domain, system.get("user", {}).get("account", "")
|
|
),
|
|
"avatar": self.patch_url(
|
|
"sso", domain, system.get("user", {}).get("avatar", "")
|
|
),
|
|
}
|
|
menudict.update(
|
|
{
|
|
"apps_internal": apps_internal,
|
|
"user_menu": user_menu,
|
|
"user_avatar": menudict["user"]["avatar"],
|
|
}
|
|
)
|
|
return menudict
|
|
|
|
def write_headers(self) -> None:
|
|
env = Environment(loader=FileSystemLoader("api/static/_templates"))
|
|
|
|
template = env.get_template("user_menu.html")
|
|
output_from_parsed_template = template.render(data=self.menudict)
|
|
print(output_from_parsed_template)
|
|
with open("api/static/templates/user_menu_header.html", "w") as fh:
|
|
fh.write(output_from_parsed_template)
|
|
|
|
# with open("api/static/templates/user_menu_header.json", "w") as fh:
|
|
# fh.write(json.dumps(self.menudict))
|
|
|
|
template = env.get_template("apps_menu.html")
|
|
output_from_parsed_template = template.render(data=self.menudict)
|
|
print(output_from_parsed_template)
|
|
with open("api/static/templates/header.html", "w") as fh:
|
|
fh.write(output_from_parsed_template)
|
|
|
|
## Nextcloud. Nginx will serve /header/html/nextcloud -> header_nextcloud.html
|
|
with open("api/static/templates/header_nextcloud.html", "w") as fh:
|
|
fh.write(output_from_parsed_template)
|
|
with open("api/static/templates/header_nextcloud.html", "a") as fh:
|
|
with open("api/static/_templates/nextcloud.html", "r") as nextcloud:
|
|
fh.write(nextcloud.read())
|
|
with open("api/static/templates/header.json", "w") as fh:
|
|
fh.write(json.dumps(self.menudict))
|
|
|
|
## Admin app. Nginx will serve /header/html/admin -> header_admin.html
|
|
template = env.get_template("admin.html")
|
|
output_from_parsed_template = template.render(data=self.menudict)
|
|
print(output_from_parsed_template)
|
|
with open("api/static/templates/header_admin.html", "w") as fh:
|
|
fh.write(output_from_parsed_template)
|
|
|
|
## SSO app. Nginx will serve /header/html/sso -> header_sso.html
|
|
template = env.get_template("sso.html")
|
|
output_from_parsed_template = template.render(data=self.menudict)
|
|
print(output_from_parsed_template)
|
|
with open("api/static/templates/header_sso.html", "w") as fh:
|
|
fh.write(output_from_parsed_template)
|
|
|
|
def get_header(self) -> Dict:
|
|
return self.menudict
|
|
# with open('menu.yaml', 'w') as yml:
|
|
# print(yaml.dump(header, yml, allow_unicode=True))
|