Skip to content

Commit 6c2b444

Browse files
committed
Home links are now dynamic
Links are listed on home page only if the associated service was found in docker compose.
1 parent c779b83 commit 6c2b444

5 files changed

Lines changed: 122 additions & 46 deletions

File tree

src/adminui/context.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ class Context:
3131
sshd_enabled: bool = False
3232
kiosk_enabled: bool = False
3333

34+
# links to other services
35+
has_clock: bool = False
36+
has_filemanager: bool = False
37+
has_zimmanager: bool = False
38+
has_metrics: bool = False
39+
3440
@property
3541
def fqdn(self) -> str:
3642
return f"{self.domain}.{self.tld}"

src/adminui/frontend.py

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
from fastapi import APIRouter, Depends, Request, Response
44
from fastapi.responses import RedirectResponse
55
from fastapi.templating import Jinja2Templates
6+
from pydantic.main import BaseModel
67

78
from adminui.auth.session import Session
89
from adminui.auth.views import login_required
@@ -15,10 +16,51 @@
1516
templates = Jinja2Templates(directory=TEMPLATES_DIR)
1617

1718

19+
class Link(BaseModel):
20+
url: str
21+
title: str
22+
text: str
23+
24+
1825
@router.get("/", name="home")
1926
def home(request: Request, session: Session = Depends(login_required)) -> Response:
27+
links: list[Link] = []
28+
if context.has_clock:
29+
links.append(
30+
Link(
31+
url=f"http://clock.{context.fqdn}/",
32+
title="Clock",
33+
text="Update date and time as seen by the Hotspot.",
34+
)
35+
)
36+
if context.has_zimmanager:
37+
links.append(
38+
Link(
39+
url=f"http://zim-manager.{context.fqdn}/",
40+
title="ZIM Manager",
41+
text="Add or remove content (ZIM files).",
42+
)
43+
)
44+
if context.has_filemanager:
45+
links.append(
46+
Link(
47+
url=f"http://resources.{context.fqdn}/admin/?p=",
48+
title="File Manager",
49+
text="Add, move, delete files visible in File Manager app.",
50+
)
51+
)
52+
if context.has_metrics:
53+
links.append(
54+
Link(
55+
url=f"http://metrics.{context.fqdn}/",
56+
title="Metrics",
57+
text="See your Hotspot's usage statistics.",
58+
)
59+
)
2060
return templates.TemplateResponse(
21-
request=request, name="home.html", context={"session": session, "ctx": context}
61+
request=request,
62+
name="home.html",
63+
context={"session": session, "ctx": context, "links": links},
2264
)
2365

2466

src/adminui/setup.py

Lines changed: 53 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
from offspot_config.utils.yaml import yaml_load
55

6-
from adminui.constants import DOCKER_COMPOSE_PATH, HOSTAPD_CONF_PATH
6+
from adminui.constants import DOCKER_COMPOSE_PATH, HOSTAPD_CONF_PATH, logger
77
from adminui.context import Context
88
from adminui.hostbridge import bridge
99
from adminui.utils import read_offspot_conf
@@ -32,6 +32,11 @@ class ComposeData:
3232

3333
kiwix_prefix: str = "browse"
3434

35+
has_clock: bool = False
36+
has_filemanager: bool = False
37+
has_zimmanager: bool = False
38+
has_metrics: bool = False
39+
3540

3641
@dataclass
3742
class WifiConf:
@@ -57,29 +62,61 @@ def get_from_compose() -> ComposeData:
5762
svc_names = compose["services"]["reverse-proxy"]["environment"]["SERVICES"].split(
5863
","
5964
)
65+
66+
has_clock = has_filemanager = has_zimmanager = has_metrics = False
6067
kiwix_prefix = "kiwix"
6168
for svc_name in svc_names:
62-
if svc_name.endswith(":kiwix"):
69+
svc_id = svc_name.rsplit(":", 1)[-1]
70+
if svc_id == "kiwix":
6371
kiwix_prefix = svc_name.split(":", 1)[0]
6472

65-
return ComposeData(tld=tld, domain=domain, kiwix_prefix=kiwix_prefix)
73+
if svc_id == "hwclock":
74+
has_clock = True
75+
if svc_id == "zim-manager":
76+
has_zimmanager = True
77+
if svc_id == "resources":
78+
has_filemanager = True
79+
if svc_id == "metrics":
80+
has_metrics = True
81+
82+
return ComposeData(
83+
tld=tld,
84+
domain=domain,
85+
kiwix_prefix=kiwix_prefix,
86+
has_clock=has_clock,
87+
has_zimmanager=has_zimmanager,
88+
has_filemanager=has_filemanager,
89+
has_metrics=has_metrics,
90+
)
6691

6792

6893
def get_capabilities_from_config() -> Capabilities:
69-
yaml_config = read_offspot_conf()
70-
cap = yaml_config.get("capabilities", {})
71-
# only SSID change ATM
72-
return Capabilities(change_ssid=cap.get("change_ssid"))
94+
capabilities = Capabilities()
95+
try:
96+
yaml_config = read_offspot_conf()
97+
except Exception as exc:
98+
logger.error(f"Failed to read capabilities from config: {exc}")
99+
logger.exception(exc)
100+
else:
101+
cap = yaml_config.get("capabilities", {})
102+
# only SSID change ATM
103+
capabilities.change_ssid = cap.get("change_ssid")
104+
return capabilities
73105

74106

75107
def get_wifi_conf_from_offspot_yaml() -> WifiConf:
76108
"""read offspot.yaml for updated-not-applied changes to WiFi conf"""
77109
conf = WifiConf()
78-
yaml_config = read_offspot_conf()
79-
ap = yaml_config.get("ap", {})
80-
conf.profile = ap.get("profile", conf.profile)
81-
conf.ssid = ap.get("ssid", conf.ssid)
82-
conf.passphrase = ap.get("passphrase", conf.passphrase)
110+
try:
111+
yaml_config = read_offspot_conf()
112+
except Exception as exc:
113+
logger.error(f"Failed to read offspot config: {exc}")
114+
logger.exception(exc)
115+
else:
116+
ap = yaml_config.get("ap", {})
117+
conf.profile = ap.get("profile", conf.profile)
118+
conf.ssid = ap.get("ssid", conf.ssid)
119+
conf.passphrase = ap.get("passphrase", conf.passphrase)
83120
return conf
84121

85122

@@ -135,6 +172,10 @@ def prepare_context():
135172
tld=compose_data.tld,
136173
domain=compose_data.domain,
137174
kiwix_prefix=compose_data.kiwix_prefix,
175+
has_clock=compose_data.has_clock,
176+
has_zimmanager=compose_data.has_zimmanager,
177+
has_filemanager=compose_data.has_filemanager,
178+
has_metrics=compose_data.has_metrics,
138179
can_change_ssid=capabilities.change_ssid,
139180
wifi_profile=wifi_conf.profile,
140181
wifi_ssid=wifi_conf.ssid,

src/adminui/templates/home.html

Lines changed: 18 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -50,60 +50,47 @@
5050
<p>Beware that while it's not possible to harm the device from here, given you have control over the Hotspot's content, be careful when <strong>deleting</strong>.</p>
5151
</div>
5252

53-
<div class="config-options row mb-5">
53+
<div class="config-options row mb-5">
5454
<div class="col-12 col-md-4 col-xl-3">
5555
<h2>Configuration options</h2>
5656
</div>
5757
<div class="col-12 offset-xl-1 col-md-8 d-flex flex-row cards">
5858
<a href="{{ url_for('wifi_config') }}" class="card">
59-
<h5 class="card-title">WiFi</h5>
59+
<h5 class="card-title">WiFi Settings</h5>
6060
<p class="card-text">Change the Hotspot's WiFi network settings.</p>
6161
</a>
6262

6363
<a href="{{ url_for('optional_config') }}" class="card">
6464
<h5 class="card-title">Optional Features</h5>
6565
<p class="card-text">Enable/disable additional features.</p>
6666
</a>
67-
</div>
68-
67+
</div>
6968
</div>
7069

70+
{% if links %}
7171
<div class="other-options row">
72-
7372
<div class="col-12 col-md-4 col-xl-3">
74-
<h2>Configuration options</h2>
73+
<h2>Additional tools</h2>
7574
</div>
7675

7776
<div class="col-12 offset-xl-1 col-md-8 d-flex flex-row cards mb-3">
7877
<p class="notice">These links will take you elsewhere on the Hotspot and you may have to login again.</p>
7978
</div>
8079

81-
<div class="col-12 offset-md-4 offset-xl-4 col-md-8 d-flex flex-row cards mb-3">
82-
<a href="http://clock.{{ ctx.fqdn }}/" class="card" target="_blank">
83-
<h5 class="card-title">Clock</h5>
84-
<p class="card-text">Update date and time as seen by the Hotspot.</p>
85-
</a>
86-
87-
<a href="http://zim-manager.{{ ctx.fqdn }}/" class="card" target="_blank">
88-
<h5 class="card-title">Manage ZIM files</h5>
89-
<p class="card-text">Add or remove content (ZIM files).</p>
90-
</a>
91-
</div>
92-
93-
<div class="col-12 offset-md-4 offset-xl-4 col-md-8 d-flex flex-row cards">
94-
<a href="http://resources.{{ ctx.fqdn }}/admin/?p=" class="card" target="_blank">
95-
<h5 class="card-title">Manage File Manager</h5>
96-
<p class="card-text">Add, move, delete files visible in File Manager app.</p>
97-
</a>
98-
99-
<a href="http://metrics.{{ ctx.fqdn }}/" class="card" target="_blank">
100-
<h5 class="card-title">Access Metrics</h5>
101-
<p class="card-text">See your Hotspot's usage statistics.</p>
102-
</a>
103-
</div>
104-
80+
{% for link in links %}
81+
{% if loop.index0 is even() %}
82+
<div class="col-12 offset-md-4 offset-xl-4 col-md-8 d-flex flex-row cards mb-3">
83+
{% endif %}
84+
<a href="{{ link.url }}" class="card" target="_blank">
85+
<h5 class="card-title">{{ link.title }}</h5>
86+
<p class="card-text">{{ link.text }}</p>
87+
</a>
88+
{% if loop.index0 is odd() or (loop.last and loop.length is odd()) %}
89+
</div>
90+
{% endif %}
91+
{% endfor %}
10592
</div>
106-
</div>
93+
{% endif %}
10794
</div>
10895

10996
{% endblock %}

src/adminui/templates/wifi/config.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,11 @@
4343
<div class="field-row mb-2">
4444
<!-- ^[^!#;+\]/"\t][^+\]/"\t]{0,31}$ -->
4545
<input class="form-control {% if errors.ssid %} is-invalid{% endif %}" pattern='^[^!#;+\]\/"\t][^+\]\/"\t]{0,31}$' required minlength="1" maxlength="31" type="text" name="ssid" placeholder="My Network name" value="{{ form.ssid }}" />
46-
<div class="invalid-feedback {% if errors.ssid %}display-until-validated{% endif %}">{% if errors.ssid %}{{ errors.ssid }}{% else %}Max 32 chars. Can't start with a symbol. <code>+</code>, <code>]</code>, <code>/</code>, <code>"</code>, <code>\t</code> prohibited.{% endif %}</div>
46+
<div class="invalid-feedback {% if errors.ssid %}display-until-validated{% endif %}">{% if errors.ssid %}{{ errors.ssid }}{% else %}Max 32 characters. Can't start with a symbol. <code>+</code>, <code>]</code>, <code>/</code>, <code>"</code>, <code>\t</code> prohibited.{% endif %}</div>
4747
</div>
4848

4949
<div class="feature-doc">
50-
<p>That's the name of your network. It must be at most 32 chars long.</p>
50+
<p>That's the name of your network. It must be at most 32 characters long.</p>
5151
</div>
5252
</div>
5353
</div>

0 commit comments

Comments
 (0)