zebra-day 1.0.2__py3-none-any.whl → 2.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- zebra_day/__init__.py +7 -2
- zebra_day/_version.py +1 -0
- zebra_day/cli/__init__.py +80 -30
- zebra_day/cli/cognito.py +15 -9
- zebra_day/cli/gui.py +101 -13
- zebra_day/cli/printer.py +34 -27
- zebra_day/cli/template.py +19 -15
- zebra_day/cmd_mgr.py +3 -6
- zebra_day/docs/gx420d-gx430d-ug-en.pdf +0 -0
- zebra_day/docs/hardware_config_guide.md +149 -0
- zebra_day/docs/programatic_guide.md +181 -0
- zebra_day/docs/qln420_zebra_manual.pdf +0 -0
- zebra_day/docs/uid_screed_light.md +38 -0
- zebra_day/docs/zd620-zd420-ug-en.pdf +0 -0
- zebra_day/docs/zebra_day_ui_guide.md +194 -0
- zebra_day/etc/printer_config.json +5 -11
- zebra_day/etc/printer_config.template.json +5 -11
- zebra_day/etc/tmp_printers120.json +10 -0
- zebra_day/etc/tmp_printers139.json +10 -0
- zebra_day/etc/tmp_printers145.json +10 -0
- zebra_day/etc/tmp_printers147.json +10 -0
- zebra_day/etc/tmp_printers207.json +10 -0
- zebra_day/etc/tmp_printers34.json +10 -0
- zebra_day/etc/tmp_printers389.json +10 -0
- zebra_day/etc/tmp_printers398.json +10 -0
- zebra_day/etc/tmp_printers437.json +10 -0
- zebra_day/etc/tmp_printers439.json +10 -0
- zebra_day/etc/tmp_printers440.json +10 -0
- zebra_day/etc/tmp_printers469.json +10 -0
- zebra_day/etc/tmp_printers485.json +10 -0
- zebra_day/etc/tmp_printers508.json +10 -0
- zebra_day/etc/tmp_printers531.json +10 -0
- zebra_day/etc/tmp_printers540.json +10 -0
- zebra_day/etc/tmp_printers542.json +10 -0
- zebra_day/etc/tmp_printers543.json +10 -0
- zebra_day/etc/tmp_printers552.json +10 -0
- zebra_day/etc/tmp_printers715.json +10 -0
- zebra_day/etc/tmp_printers835.json +10 -0
- zebra_day/etc/tmp_printers842.json +10 -0
- zebra_day/etc/tmp_printers931.json +10 -0
- zebra_day/etc/tmp_printers969.json +10 -0
- zebra_day/etc/tmp_printers972.json +10 -0
- zebra_day/exceptions.py +1 -1
- zebra_day/files/blank_preview.png +0 -0
- zebra_day/files/corners_20cmX30cm_preview.png +0 -0
- zebra_day/files/corners_smallTube_preview.png +0 -0
- zebra_day/files/generic_2inX1in_preview.png +0 -0
- zebra_day/files/test_png_12020.png +0 -0
- zebra_day/files/test_png_12352.png +0 -0
- zebra_day/files/test_png_15472.png +0 -0
- zebra_day/files/test_png_24493.png +0 -0
- zebra_day/files/test_png_2897.png +0 -0
- zebra_day/files/test_png_30069.png +0 -0
- zebra_day/files/test_png_31690.png +0 -0
- zebra_day/files/test_png_33804.png +0 -0
- zebra_day/files/test_png_34737.png +0 -0
- zebra_day/files/test_png_4161.png +0 -0
- zebra_day/files/test_png_44748.png +0 -0
- zebra_day/files/test_png_4635.png +0 -0
- zebra_day/files/test_png_47791.png +0 -0
- zebra_day/files/test_png_47799.png +0 -0
- zebra_day/files/test_png_55588.png +0 -0
- zebra_day/files/test_png_56349.png +0 -0
- zebra_day/files/test_png_58809.png +0 -0
- zebra_day/files/test_png_5936.png +0 -0
- zebra_day/files/test_png_64110.png +0 -0
- zebra_day/files/test_png_64891.png +0 -0
- zebra_day/files/test_png_67242.png +0 -0
- zebra_day/files/test_png_69002.png +0 -0
- zebra_day/files/test_png_70065.png +0 -0
- zebra_day/files/test_png_72366.png +0 -0
- zebra_day/files/test_png_77793.png +0 -0
- zebra_day/files/test_png_89893.png +0 -0
- zebra_day/files/test_png_9572.png +0 -0
- zebra_day/files/tube_20mmX30mmA_preview.png +0 -0
- zebra_day/imgs/.hold +0 -0
- zebra_day/imgs/bar_ltpurp.png +0 -0
- zebra_day/imgs/bar_purp.png +0 -0
- zebra_day/imgs/bar_purp3.png +0 -0
- zebra_day/imgs/bar_red.png +0 -0
- zebra_day/imgs/legacy/UBC_gantt_chart.png +0 -0
- zebra_day/imgs/legacy/gx420d_network_config.png +0 -0
- zebra_day/imgs/legacy/gx420d_printer_config.png +0 -0
- zebra_day/imgs/legacy/ngrok.png +0 -0
- zebra_day/imgs/legacy/printer_details.png +0 -0
- zebra_day/imgs/legacy/quick_start_test_label.png +0 -0
- zebra_day/imgs/legacy/quick_start_test_label2.png +0 -0
- zebra_day/imgs/legacy/zd620_network_config.png +0 -0
- zebra_day/imgs/legacy/zd620_printer_config.png +0 -0
- zebra_day/imgs/legacy/zday_quick_gui.png +0 -0
- zebra_day/imgs/legacy/zebra_day_alt_css_dog.png +0 -0
- zebra_day/imgs/legacy/zebra_day_alt_css_flower.png +0 -0
- zebra_day/imgs/legacy/zebra_day_alt_css_main.png +0 -0
- zebra_day/imgs/legacy/zebra_day_available_zpl_templates.png +0 -0
- zebra_day/imgs/legacy/zebra_day_bkup_pconfig.png +0 -0
- zebra_day/imgs/legacy/zebra_day_home.png +0 -0
- zebra_day/imgs/legacy/zebra_day_manual_print.png +0 -0
- zebra_day/imgs/legacy/zebra_day_printer_fleet_json.png +0 -0
- zebra_day/imgs/legacy/zebra_day_quick_ex.png +0 -0
- zebra_day/imgs/legacy/zebra_day_zpl_template_IRLa.png +0 -0
- zebra_day/imgs/legacy/zebra_day_zpl_template_IRLb.png +0 -0
- zebra_day/imgs/ui_api_docs.png +0 -0
- zebra_day/imgs/ui_config.png +0 -0
- zebra_day/imgs/ui_dashboard.png +0 -0
- zebra_day/imgs/ui_print_request.png +0 -0
- zebra_day/imgs/ui_printers.png +0 -0
- zebra_day/imgs/ui_templates.png +0 -0
- zebra_day/logging_config.py +4 -9
- zebra_day/mkcert.py +157 -0
- zebra_day/paths.py +1 -2
- zebra_day/print_mgr.py +261 -185
- zebra_day/templates/modern/config.html +7 -0
- zebra_day/templates/modern/config_backups.html +59 -0
- zebra_day/templates/modern/config_editor.html +95 -0
- zebra_day/templates/modern/config_new.html +93 -0
- zebra_day/templates/modern/print_request.html +70 -8
- zebra_day/templates/modern/printer_detail.html +161 -34
- zebra_day/templates/modern/printers.html +17 -6
- zebra_day/templates/modern/template_editor.html +7 -4
- zebra_day/web/__init__.py +1 -1
- zebra_day/web/app.py +99 -17
- zebra_day/web/auth.py +17 -15
- zebra_day/web/middleware.py +8 -5
- zebra_day/web/routers/__init__.py +0 -1
- zebra_day/web/routers/api.py +330 -31
- zebra_day/web/routers/ui.py +174 -591
- zebra_day/zpl_renderer.py +45 -34
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/METADATA +144 -74
- zebra_day-2.1.4.dist-info/RECORD +240 -0
- zebra_day/bin/fetch_zebra_config.py +0 -15
- zebra_day/bin/generate_coord_grid_zpl.py +0 -50
- zebra_day/bin/print_zpl_from_file.py +0 -21
- zebra_day/bin/probe_new_label_dimensions.py +0 -75
- zebra_day/bin/scan_for_networed_zebra_printers.py +0 -23
- zebra_day/bin/scan_for_networed_zebra_printers_arp_scan.sh +0 -1
- zebra_day/bin/scan_for_networed_zebra_printers_curl.sh +0 -30
- zebra_day/bin/zserve.py +0 -1062
- zebra_day/templates/base.html +0 -36
- zebra_day/templates/bpr.html +0 -72
- zebra_day/templates/build_new_config.html +0 -36
- zebra_day/templates/build_print_request.html +0 -32
- zebra_day/templates/chg_ui_style.html +0 -19
- zebra_day/templates/edit_template.html +0 -128
- zebra_day/templates/edit_zpl.html +0 -37
- zebra_day/templates/index.html +0 -82
- zebra_day/templates/legacy/base.html +0 -37
- zebra_day/templates/legacy/bpr.html +0 -72
- zebra_day/templates/legacy/build_new_config.html +0 -36
- zebra_day/templates/legacy/build_print_request.html +0 -32
- zebra_day/templates/legacy/chg_ui_style.html +0 -19
- zebra_day/templates/legacy/edit_template.html +0 -128
- zebra_day/templates/legacy/edit_zpl.html +0 -37
- zebra_day/templates/legacy/index.html +0 -82
- zebra_day/templates/legacy/list_prior_configs.html +0 -24
- zebra_day/templates/legacy/print_result.html +0 -30
- zebra_day/templates/legacy/printer_details.html +0 -25
- zebra_day/templates/legacy/printer_status.html +0 -70
- zebra_day/templates/legacy/save_result.html +0 -17
- zebra_day/templates/legacy/send_print_request.html +0 -34
- zebra_day/templates/legacy/simple_print.html +0 -94
- zebra_day/templates/legacy/view_pstation_json.html +0 -29
- zebra_day/templates/list_prior_configs.html +0 -24
- zebra_day/templates/print_result.html +0 -30
- zebra_day/templates/printer_details.html +0 -25
- zebra_day/templates/printer_status.html +0 -70
- zebra_day/templates/save_result.html +0 -17
- zebra_day/templates/send_print_request.html +0 -34
- zebra_day/templates/simple_print.html +0 -94
- zebra_day/templates/view_pstation_json.html +0 -29
- zebra_day-1.0.2.dist-info/RECORD +0 -179
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/WHEEL +0 -0
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/entry_points.txt +0 -0
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/licenses/LICENSE +0 -0
- {zebra_day-1.0.2.dist-info → zebra_day-2.1.4.dist-info}/top_level.txt +0 -0
zebra_day/__init__.py
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
"""
|
|
2
2
|
zebra_day - A Python library to manage Zebra printer fleets and ZPL print requests.
|
|
3
3
|
"""
|
|
4
|
+
|
|
4
5
|
from __future__ import annotations
|
|
5
6
|
|
|
7
|
+
try:
|
|
8
|
+
from zebra_day._version import __version__
|
|
9
|
+
except ImportError:
|
|
10
|
+
__version__ = "0.0.0.dev0"
|
|
11
|
+
|
|
6
12
|
from zebra_day.exceptions import (
|
|
7
13
|
ConfigError,
|
|
8
14
|
ConfigFileNotFoundError,
|
|
@@ -18,10 +24,9 @@ from zebra_day.exceptions import (
|
|
|
18
24
|
from zebra_day.logging_config import configure_logging, get_logger
|
|
19
25
|
|
|
20
26
|
__all__ = [
|
|
21
|
-
|
|
27
|
+
"__version__",
|
|
22
28
|
"configure_logging",
|
|
23
29
|
"get_logger",
|
|
24
|
-
# Exceptions
|
|
25
30
|
"ZebraDayError",
|
|
26
31
|
"PrinterConnectionError",
|
|
27
32
|
"PrinterNotFoundError",
|
zebra_day/_version.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.1.4"
|
zebra_day/cli/__init__.py
CHANGED
|
@@ -1,19 +1,21 @@
|
|
|
1
1
|
"""zebra_day CLI - Zebra Printer Fleet Management CLI using Typer."""
|
|
2
2
|
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
3
5
|
import os
|
|
6
|
+
import socket
|
|
4
7
|
import sys
|
|
5
|
-
from
|
|
6
|
-
from typing import Optional
|
|
8
|
+
from typing import Any
|
|
7
9
|
|
|
8
10
|
import typer
|
|
9
11
|
from rich.console import Console
|
|
10
12
|
from rich.table import Table
|
|
11
13
|
|
|
12
14
|
from zebra_day import paths as xdg
|
|
15
|
+
from zebra_day.cli.cognito import cognito_app
|
|
13
16
|
from zebra_day.cli.gui import gui_app
|
|
14
17
|
from zebra_day.cli.printer import printer_app
|
|
15
18
|
from zebra_day.cli.template import template_app
|
|
16
|
-
from zebra_day.cli.cognito import cognito_app
|
|
17
19
|
|
|
18
20
|
console = Console()
|
|
19
21
|
|
|
@@ -35,6 +37,7 @@ def _get_version() -> str:
|
|
|
35
37
|
"""Get zebra_day version."""
|
|
36
38
|
try:
|
|
37
39
|
from importlib.metadata import version
|
|
40
|
+
|
|
38
41
|
return version("zebra_day")
|
|
39
42
|
except Exception:
|
|
40
43
|
return "dev"
|
|
@@ -92,7 +95,7 @@ def status(
|
|
|
92
95
|
"""Show printer fleet status, network connectivity, and service health."""
|
|
93
96
|
import json as json_mod
|
|
94
97
|
|
|
95
|
-
status_data = {
|
|
98
|
+
status_data: dict[str, dict[str, Any]] = {
|
|
96
99
|
"gui_server": {"running": False, "pid": None, "url": None},
|
|
97
100
|
"printers": {"configured": 0, "labs": []},
|
|
98
101
|
"config": {"exists": False, "path": None},
|
|
@@ -117,14 +120,12 @@ def status(
|
|
|
117
120
|
status_data["config"]["exists"] = True
|
|
118
121
|
try:
|
|
119
122
|
import zebra_day.print_mgr as zdpm
|
|
123
|
+
|
|
120
124
|
zp = zdpm.zpl()
|
|
121
125
|
if hasattr(zp, "printers") and "labs" in zp.printers:
|
|
122
126
|
labs = list(zp.printers["labs"].keys())
|
|
123
127
|
status_data["printers"]["labs"] = labs
|
|
124
|
-
total_printers = sum(
|
|
125
|
-
len([k for k in zp.printers["labs"][lab].keys()])
|
|
126
|
-
for lab in labs
|
|
127
|
-
)
|
|
128
|
+
total_printers = sum(len(list(zp.printers["labs"][lab].keys())) for lab in labs)
|
|
128
129
|
status_data["printers"]["configured"] = total_printers
|
|
129
130
|
except Exception:
|
|
130
131
|
pass
|
|
@@ -136,25 +137,29 @@ def status(
|
|
|
136
137
|
# Human-readable output
|
|
137
138
|
console.print("\n[bold]Service Status[/bold]")
|
|
138
139
|
if status_data["gui_server"]["running"]:
|
|
139
|
-
console.print(
|
|
140
|
+
console.print(
|
|
141
|
+
f" [green]●[/green] GUI Server: [green]Running[/green] (PID {status_data['gui_server']['pid']})"
|
|
142
|
+
)
|
|
140
143
|
console.print(f" URL: [cyan]{status_data['gui_server']['url']}[/cyan]")
|
|
141
144
|
else:
|
|
142
145
|
console.print(" [dim]○[/dim] GUI Server: [dim]Not running[/dim]")
|
|
143
146
|
|
|
144
147
|
console.print("\n[bold]Printer Fleet[/bold]")
|
|
145
148
|
if status_data["config"]["exists"]:
|
|
146
|
-
console.print(
|
|
149
|
+
console.print(" [green]●[/green] Config: [green]Loaded[/green]")
|
|
147
150
|
console.print(f" Printers: {status_data['printers']['configured']}")
|
|
148
151
|
console.print(f" Labs: {', '.join(status_data['printers']['labs']) or 'none'}")
|
|
149
152
|
else:
|
|
150
153
|
console.print(" [yellow]○[/yellow] Config: [yellow]Not found[/yellow]")
|
|
151
|
-
console.print(
|
|
154
|
+
console.print(" Run [cyan]zday bootstrap[/cyan] to initialize")
|
|
152
155
|
console.print()
|
|
153
156
|
|
|
154
157
|
|
|
155
158
|
@app.command("bootstrap")
|
|
156
159
|
def bootstrap(
|
|
157
|
-
ip_stub:
|
|
160
|
+
ip_stub: str | None = typer.Option(
|
|
161
|
+
None, "--ip-stub", "-i", help="IP stub for printer scan (e.g., 192.168.1)"
|
|
162
|
+
),
|
|
158
163
|
skip_scan: bool = typer.Option(False, "--skip-scan", "-s", help="Skip printer network scan"),
|
|
159
164
|
json_output: bool = typer.Option(False, "--json", "-j", help="Output as JSON"),
|
|
160
165
|
):
|
|
@@ -166,20 +171,16 @@ def bootstrap(
|
|
|
166
171
|
3. Scan the network for Zebra printers (unless --skip-scan)
|
|
167
172
|
"""
|
|
168
173
|
import json as json_mod
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
"data_dir": str(xdg.get_data_dir()),
|
|
175
|
-
"printers_found": 0,
|
|
176
|
-
"labs": [],
|
|
177
|
-
}
|
|
174
|
+
|
|
175
|
+
config_dir = str(xdg.get_config_dir())
|
|
176
|
+
data_dir = str(xdg.get_data_dir())
|
|
177
|
+
printers_found = 0
|
|
178
|
+
labs: list[str] = []
|
|
178
179
|
|
|
179
180
|
if not json_output:
|
|
180
181
|
console.print("\n[bold cyan]zebra_day Bootstrap[/bold cyan]\n")
|
|
181
|
-
console.print("[green]✓[/green] Config directory: " +
|
|
182
|
-
console.print("[green]✓[/green] Data directory: " +
|
|
182
|
+
console.print("[green]✓[/green] Config directory: " + config_dir)
|
|
183
|
+
console.print("[green]✓[/green] Data directory: " + data_dir)
|
|
183
184
|
|
|
184
185
|
if skip_scan:
|
|
185
186
|
if not json_output:
|
|
@@ -202,24 +203,74 @@ def bootstrap(
|
|
|
202
203
|
|
|
203
204
|
try:
|
|
204
205
|
import zebra_day.print_mgr as zdpm
|
|
206
|
+
|
|
205
207
|
zp = zdpm.zpl()
|
|
206
208
|
zp.probe_zebra_printers_add_to_printers_json(ip_stub=ip_stub)
|
|
207
209
|
|
|
208
210
|
if hasattr(zp, "printers") and "labs" in zp.printers:
|
|
209
211
|
for lab in zp.printers["labs"]:
|
|
210
|
-
printers_in_lab = len(
|
|
211
|
-
|
|
212
|
-
|
|
212
|
+
printers_in_lab = len(list(zp.printers["labs"][lab].keys()))
|
|
213
|
+
printers_found += printers_in_lab
|
|
214
|
+
labs.append(lab)
|
|
213
215
|
|
|
214
216
|
if not json_output:
|
|
215
|
-
console.print(f"[green]✓[/green] Scan complete: {
|
|
216
|
-
if
|
|
217
|
-
console.print(f" Labs: {', '.join(
|
|
217
|
+
console.print(f"[green]✓[/green] Scan complete: {printers_found} printer(s) found")
|
|
218
|
+
if labs:
|
|
219
|
+
console.print(f" Labs: {', '.join(labs)}")
|
|
218
220
|
except Exception as e:
|
|
219
221
|
if not json_output:
|
|
220
222
|
console.print(f"[yellow]⚠[/yellow] Scan error: {e}")
|
|
221
223
|
|
|
224
|
+
# Generate HTTPS certificates if mkcert is available
|
|
225
|
+
certs_generated = False
|
|
226
|
+
cert_path_str = None
|
|
227
|
+
|
|
228
|
+
if not json_output:
|
|
229
|
+
console.print("\n[cyan]→[/cyan] Checking HTTPS certificates...")
|
|
230
|
+
|
|
231
|
+
try:
|
|
232
|
+
from zebra_day import mkcert
|
|
233
|
+
|
|
234
|
+
if not mkcert.is_mkcert_installed():
|
|
235
|
+
if not json_output:
|
|
236
|
+
console.print("[yellow]⚠[/yellow] mkcert not installed")
|
|
237
|
+
console.print(
|
|
238
|
+
" Install with: [dim]brew install mkcert[/dim] (macOS) or "
|
|
239
|
+
"[dim]sudo apt install mkcert[/dim] (Ubuntu)"
|
|
240
|
+
)
|
|
241
|
+
elif not mkcert.is_ca_installed():
|
|
242
|
+
if not json_output:
|
|
243
|
+
console.print("[yellow]⚠[/yellow] mkcert CA not installed")
|
|
244
|
+
console.print(" Run: [dim]mkcert -install[/dim] (one-time, requires password)")
|
|
245
|
+
elif mkcert.certificates_exist():
|
|
246
|
+
if not json_output:
|
|
247
|
+
console.print(f"[green]✓[/green] Certificates exist: {mkcert.CERT_FILE}")
|
|
248
|
+
certs_generated = True
|
|
249
|
+
cert_path_str = str(mkcert.CERT_FILE)
|
|
250
|
+
else:
|
|
251
|
+
if not json_output:
|
|
252
|
+
console.print(" Generating certificates...")
|
|
253
|
+
if mkcert.generate_certificates():
|
|
254
|
+
if not json_output:
|
|
255
|
+
console.print(f"[green]✓[/green] Certificates generated: {mkcert.CERT_FILE}")
|
|
256
|
+
certs_generated = True
|
|
257
|
+
cert_path_str = str(mkcert.CERT_FILE)
|
|
258
|
+
else:
|
|
259
|
+
if not json_output:
|
|
260
|
+
console.print("[yellow]⚠[/yellow] Failed to generate certificates")
|
|
261
|
+
except Exception as e:
|
|
262
|
+
if not json_output:
|
|
263
|
+
console.print(f"[yellow]⚠[/yellow] Certificate check error: {e}")
|
|
264
|
+
|
|
222
265
|
if json_output:
|
|
266
|
+
result = {
|
|
267
|
+
"config_dir": config_dir,
|
|
268
|
+
"data_dir": data_dir,
|
|
269
|
+
"printers_found": printers_found,
|
|
270
|
+
"labs": labs,
|
|
271
|
+
"https_certs_generated": certs_generated,
|
|
272
|
+
"cert_path": cert_path_str,
|
|
273
|
+
}
|
|
223
274
|
console.print(json_mod.dumps(result, indent=2))
|
|
224
275
|
else:
|
|
225
276
|
console.print("\n[bold green]✓ Bootstrap complete![/bold green]")
|
|
@@ -237,4 +288,3 @@ def main():
|
|
|
237
288
|
|
|
238
289
|
if __name__ == "__main__":
|
|
239
290
|
raise SystemExit(main())
|
|
240
|
-
|
zebra_day/cli/cognito.py
CHANGED
|
@@ -5,7 +5,6 @@ basic status and info commands.
|
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
7
|
import os
|
|
8
|
-
from typing import Optional
|
|
9
8
|
|
|
10
9
|
import typer
|
|
11
10
|
from rich.console import Console
|
|
@@ -18,6 +17,7 @@ def _is_cognito_available() -> bool:
|
|
|
18
17
|
"""Check if daylily-cognito is installed."""
|
|
19
18
|
try:
|
|
20
19
|
from daylily_cognito.cli import cognito_app as _ # noqa: F401
|
|
20
|
+
|
|
21
21
|
return True
|
|
22
22
|
except ImportError:
|
|
23
23
|
return False
|
|
@@ -28,7 +28,8 @@ def _get_cognito_app() -> typer.Typer:
|
|
|
28
28
|
if _is_cognito_available():
|
|
29
29
|
# Import and return the full cognito CLI from daylily-cognito
|
|
30
30
|
from daylily_cognito.cli import cognito_app
|
|
31
|
-
|
|
31
|
+
|
|
32
|
+
return cognito_app # type: ignore[no-any-return]
|
|
32
33
|
else:
|
|
33
34
|
# Return a minimal fallback app
|
|
34
35
|
return _create_fallback_app()
|
|
@@ -36,7 +37,9 @@ def _get_cognito_app() -> typer.Typer:
|
|
|
36
37
|
|
|
37
38
|
def _create_fallback_app() -> typer.Typer:
|
|
38
39
|
"""Create a fallback cognito app with basic commands."""
|
|
39
|
-
app = typer.Typer(
|
|
40
|
+
app = typer.Typer(
|
|
41
|
+
help="Cognito authentication management (limited - daylily-cognito not installed)"
|
|
42
|
+
)
|
|
40
43
|
|
|
41
44
|
@app.command("status")
|
|
42
45
|
def status():
|
|
@@ -76,7 +79,9 @@ def _create_fallback_app() -> typer.Typer:
|
|
|
76
79
|
console.print(" Start server with: [cyan]zday gui start --auth cognito[/cyan]")
|
|
77
80
|
else:
|
|
78
81
|
console.print("\n[yellow]⚠[/yellow] Cognito is not fully configured")
|
|
79
|
-
console.print(
|
|
82
|
+
console.print(
|
|
83
|
+
" Set environment variables or install daylily-cognito for full management"
|
|
84
|
+
)
|
|
80
85
|
|
|
81
86
|
@app.command("info")
|
|
82
87
|
def info():
|
|
@@ -85,7 +90,7 @@ def _create_fallback_app() -> typer.Typer:
|
|
|
85
90
|
console.print("To enable Cognito authentication for zebra_day:\n")
|
|
86
91
|
|
|
87
92
|
console.print("[bold]1. Install auth dependencies:[/bold]")
|
|
88
|
-
console.print(
|
|
93
|
+
console.print(' [cyan]pip install -e ".[auth]"[/cyan]\n')
|
|
89
94
|
|
|
90
95
|
console.print("[bold]2. Set environment variables:[/bold]")
|
|
91
96
|
console.print(" [cyan]export COGNITO_USER_POOL_ID=your-pool-id[/cyan]")
|
|
@@ -96,21 +101,23 @@ def _create_fallback_app() -> typer.Typer:
|
|
|
96
101
|
console.print(" [cyan]zday gui start --auth cognito[/cyan]\n")
|
|
97
102
|
|
|
98
103
|
if not _is_cognito_available():
|
|
99
|
-
console.print(
|
|
104
|
+
console.print(
|
|
105
|
+
"[dim]For full Cognito management (create, teardown), install daylily-cognito:[/dim]"
|
|
106
|
+
)
|
|
100
107
|
console.print("[dim] pip install daylily-cognito[/dim]")
|
|
101
108
|
|
|
102
109
|
@app.command("create")
|
|
103
110
|
def create():
|
|
104
111
|
"""Create/configure a Cognito user pool (requires daylily-cognito)."""
|
|
105
112
|
console.print("[yellow]⚠[/yellow] This command requires daylily-cognito")
|
|
106
|
-
console.print(
|
|
113
|
+
console.print(' Install with: [cyan]pip install -e ".[auth]"[/cyan]')
|
|
107
114
|
raise typer.Exit(1)
|
|
108
115
|
|
|
109
116
|
@app.command("teardown")
|
|
110
117
|
def teardown():
|
|
111
118
|
"""Remove Cognito configuration (requires daylily-cognito)."""
|
|
112
119
|
console.print("[yellow]⚠[/yellow] This command requires daylily-cognito")
|
|
113
|
-
console.print(
|
|
120
|
+
console.print(' Install with: [cyan]pip install -e ".[auth]"[/cyan]')
|
|
114
121
|
raise typer.Exit(1)
|
|
115
122
|
|
|
116
123
|
return app
|
|
@@ -118,4 +125,3 @@ def _create_fallback_app() -> typer.Typer:
|
|
|
118
125
|
|
|
119
126
|
# Export the cognito app - either the full version from daylily-cognito or the fallback
|
|
120
127
|
cognito_app = _get_cognito_app()
|
|
121
|
-
|
zebra_day/cli/gui.py
CHANGED
|
@@ -7,7 +7,6 @@ import sys
|
|
|
7
7
|
import time
|
|
8
8
|
from datetime import datetime
|
|
9
9
|
from pathlib import Path
|
|
10
|
-
from typing import Optional, Literal
|
|
11
10
|
|
|
12
11
|
import typer
|
|
13
12
|
from rich.console import Console
|
|
@@ -20,7 +19,11 @@ console = Console()
|
|
|
20
19
|
# PID and log file locations
|
|
21
20
|
STATE_DIR = xdg.get_state_dir()
|
|
22
21
|
LOG_DIR = xdg.get_logs_dir()
|
|
22
|
+
CONFIG_DIR = xdg.get_config_dir()
|
|
23
23
|
PID_FILE = STATE_DIR / "gui.pid"
|
|
24
|
+
DEFAULT_CERT_DIR = CONFIG_DIR / "certs"
|
|
25
|
+
DEFAULT_CERT_FILE = DEFAULT_CERT_DIR / "server.crt"
|
|
26
|
+
DEFAULT_KEY_FILE = DEFAULT_CERT_DIR / "server.key"
|
|
24
27
|
|
|
25
28
|
|
|
26
29
|
def _ensure_dirs():
|
|
@@ -35,13 +38,13 @@ def _get_log_file() -> Path:
|
|
|
35
38
|
return LOG_DIR / f"gui_{ts}.log"
|
|
36
39
|
|
|
37
40
|
|
|
38
|
-
def _get_latest_log() ->
|
|
41
|
+
def _get_latest_log() -> Path | None:
|
|
39
42
|
"""Get the most recent log file."""
|
|
40
43
|
logs = sorted(LOG_DIR.glob("gui_*.log"), reverse=True)
|
|
41
44
|
return logs[0] if logs else None
|
|
42
45
|
|
|
43
46
|
|
|
44
|
-
def _get_pid() ->
|
|
47
|
+
def _get_pid() -> int | None:
|
|
45
48
|
"""Get the running server PID if exists."""
|
|
46
49
|
if PID_FILE.exists():
|
|
47
50
|
try:
|
|
@@ -57,20 +60,71 @@ def _check_auth_dependencies() -> bool:
|
|
|
57
60
|
"""Check if auth dependencies are available."""
|
|
58
61
|
try:
|
|
59
62
|
import jose # noqa: F401
|
|
63
|
+
|
|
60
64
|
return True
|
|
61
65
|
except ImportError:
|
|
62
66
|
return False
|
|
63
67
|
|
|
64
68
|
|
|
69
|
+
def _resolve_ssl_paths(cert: str | None, key: str | None) -> tuple[str | None, str | None, bool]:
|
|
70
|
+
"""
|
|
71
|
+
Resolve SSL certificate and key paths.
|
|
72
|
+
|
|
73
|
+
Priority:
|
|
74
|
+
1. Explicit --cert/--key arguments
|
|
75
|
+
2. SSL_CERT_PATH/SSL_KEY_PATH environment variables
|
|
76
|
+
3. Default paths in ~/.config/zebra_day/certs/
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Tuple of (cert_path, key_path, use_https)
|
|
80
|
+
"""
|
|
81
|
+
cert_path = cert
|
|
82
|
+
key_path = key
|
|
83
|
+
|
|
84
|
+
# Check environment variables
|
|
85
|
+
if not cert_path:
|
|
86
|
+
cert_path = os.environ.get("SSL_CERT_PATH")
|
|
87
|
+
if not key_path:
|
|
88
|
+
key_path = os.environ.get("SSL_KEY_PATH")
|
|
89
|
+
|
|
90
|
+
# Check default paths
|
|
91
|
+
if not cert_path and DEFAULT_CERT_FILE.exists():
|
|
92
|
+
cert_path = str(DEFAULT_CERT_FILE)
|
|
93
|
+
if not key_path and DEFAULT_KEY_FILE.exists():
|
|
94
|
+
key_path = str(DEFAULT_KEY_FILE)
|
|
95
|
+
|
|
96
|
+
# Validate both exist
|
|
97
|
+
if cert_path and key_path:
|
|
98
|
+
if Path(cert_path).exists() and Path(key_path).exists():
|
|
99
|
+
return cert_path, key_path, True
|
|
100
|
+
|
|
101
|
+
return None, None, False
|
|
102
|
+
|
|
103
|
+
|
|
65
104
|
@gui_app.command("start")
|
|
66
105
|
def start(
|
|
67
106
|
port: int = typer.Option(8118, "--port", "-p", help="Port to run the server on"),
|
|
68
107
|
host: str = typer.Option("0.0.0.0", "--host", "-h", help="Host to bind to"),
|
|
69
108
|
auth: str = typer.Option("none", "--auth", "-a", help="Authentication mode: none or cognito"),
|
|
70
109
|
reload: bool = typer.Option(False, "--reload", "-r", help="Enable auto-reload (foreground)"),
|
|
71
|
-
background: bool = typer.Option(
|
|
110
|
+
background: bool = typer.Option(
|
|
111
|
+
True, "--background/--foreground", "-b/-f", help="Run in background"
|
|
112
|
+
),
|
|
113
|
+
cert: str | None = typer.Option(None, "--cert", help="Path to SSL certificate file"),
|
|
114
|
+
key: str | None = typer.Option(None, "--key", help="Path to SSL private key file"),
|
|
115
|
+
no_https: bool = typer.Option(
|
|
116
|
+
False, "--no-https", help="Disable HTTPS even if certificates are available"
|
|
117
|
+
),
|
|
72
118
|
):
|
|
73
|
-
"""Start the zebra_day web UI server.
|
|
119
|
+
"""Start the zebra_day web UI server.
|
|
120
|
+
|
|
121
|
+
By default, HTTPS is enabled if certificates are found in:
|
|
122
|
+
- Explicit --cert/--key arguments
|
|
123
|
+
- SSL_CERT_PATH/SSL_KEY_PATH environment variables
|
|
124
|
+
- ~/.config/zebra_day/certs/server.crt and server.key
|
|
125
|
+
|
|
126
|
+
Use --no-https to force HTTP mode.
|
|
127
|
+
"""
|
|
74
128
|
_ensure_dirs()
|
|
75
129
|
|
|
76
130
|
# Validate auth option
|
|
@@ -89,7 +143,7 @@ def start(
|
|
|
89
143
|
if auth == "cognito":
|
|
90
144
|
if not _check_auth_dependencies():
|
|
91
145
|
console.print("[red]✗[/red] Authentication requested but python-jose is not installed")
|
|
92
|
-
console.print(
|
|
146
|
+
console.print(' Install with: [cyan]pip install -e ".[auth]"[/cyan]')
|
|
93
147
|
raise typer.Exit(1)
|
|
94
148
|
|
|
95
149
|
# Check required env vars
|
|
@@ -105,17 +159,47 @@ def start(
|
|
|
105
159
|
raise typer.Exit(1)
|
|
106
160
|
console.print("[green]✓[/green] Cognito authentication enabled")
|
|
107
161
|
|
|
108
|
-
#
|
|
162
|
+
# Resolve SSL paths
|
|
163
|
+
cert_path, key_path, use_https = _resolve_ssl_paths(cert, key)
|
|
164
|
+
|
|
165
|
+
if no_https:
|
|
166
|
+
use_https = False
|
|
167
|
+
cert_path = None
|
|
168
|
+
key_path = None
|
|
169
|
+
|
|
170
|
+
protocol = "https" if use_https else "http"
|
|
171
|
+
|
|
172
|
+
if use_https:
|
|
173
|
+
console.print("[green]✓[/green] HTTPS enabled")
|
|
174
|
+
console.print(f" Certificate: [dim]{cert_path}[/dim]")
|
|
175
|
+
console.print(f" Private key: [dim]{key_path}[/dim]")
|
|
176
|
+
else:
|
|
177
|
+
console.print("[yellow]⚠[/yellow] Running in HTTP mode (insecure)")
|
|
178
|
+
console.print(" For HTTPS, generate certificates with mkcert:")
|
|
179
|
+
console.print(f" [dim]mkdir -p {DEFAULT_CERT_DIR}[/dim]")
|
|
180
|
+
console.print(
|
|
181
|
+
f" [dim]mkcert -cert-file {DEFAULT_CERT_FILE} -key-file {DEFAULT_KEY_FILE} localhost 127.0.0.1 ::1[/dim]"
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
# Build command with SSL parameters
|
|
185
|
+
ssl_args = ""
|
|
186
|
+
if use_https and cert_path and key_path:
|
|
187
|
+
ssl_args = f", ssl_certfile='{cert_path}', ssl_keyfile='{key_path}'"
|
|
188
|
+
|
|
109
189
|
cmd = [
|
|
110
190
|
sys.executable,
|
|
111
191
|
"-c",
|
|
112
|
-
f"from zebra_day.web.app import run_server; run_server(host='{host}', port={port}, reload={reload}, auth='{auth}')",
|
|
192
|
+
f"from zebra_day.web.app import run_server; run_server(host='{host}', port={port}, reload={reload}, auth='{auth}'{ssl_args})",
|
|
113
193
|
]
|
|
114
194
|
|
|
115
195
|
# Set up environment
|
|
116
196
|
env = os.environ.copy()
|
|
117
197
|
env["PYTHONUNBUFFERED"] = "1"
|
|
118
198
|
env["ZEBRA_DAY_AUTH_MODE"] = auth
|
|
199
|
+
if cert_path:
|
|
200
|
+
env["SSL_CERT_PATH"] = cert_path
|
|
201
|
+
if key_path:
|
|
202
|
+
env["SSL_KEY_PATH"] = key_path
|
|
119
203
|
|
|
120
204
|
if reload:
|
|
121
205
|
background = False
|
|
@@ -149,10 +233,12 @@ def start(
|
|
|
149
233
|
|
|
150
234
|
PID_FILE.write_text(str(proc.pid))
|
|
151
235
|
console.print(f"[green]✓[/green] Server started (PID {proc.pid})")
|
|
152
|
-
console.print(f" URL: [cyan]
|
|
236
|
+
console.print(f" URL: [cyan]{protocol}://{host}:{port}[/cyan]")
|
|
153
237
|
console.print(f" Logs: [dim]{log_file}[/dim]")
|
|
154
238
|
else:
|
|
155
|
-
console.print(
|
|
239
|
+
console.print(
|
|
240
|
+
f"[green]✓[/green] Starting server on [cyan]{protocol}://{host}:{port}[/cyan]"
|
|
241
|
+
)
|
|
156
242
|
console.print(" Press Ctrl+C to stop\n")
|
|
157
243
|
try:
|
|
158
244
|
result = subprocess.run(cmd, cwd=Path.cwd(), env=env)
|
|
@@ -188,7 +274,7 @@ def stop():
|
|
|
188
274
|
console.print("[yellow]⚠[/yellow] Server was not running")
|
|
189
275
|
except PermissionError:
|
|
190
276
|
console.print(f"[red]✗[/red] Permission denied stopping PID {pid}")
|
|
191
|
-
raise typer.Exit(1)
|
|
277
|
+
raise typer.Exit(1) from None
|
|
192
278
|
|
|
193
279
|
|
|
194
280
|
@gui_app.command("status")
|
|
@@ -197,8 +283,11 @@ def status():
|
|
|
197
283
|
pid = _get_pid()
|
|
198
284
|
if pid:
|
|
199
285
|
log_file = _get_latest_log()
|
|
286
|
+
# Check if HTTPS is likely enabled based on cert availability
|
|
287
|
+
_, _, use_https = _resolve_ssl_paths(None, None)
|
|
288
|
+
protocol = "https" if use_https else "http"
|
|
200
289
|
console.print(f"[green]●[/green] Server is [green]running[/green] (PID {pid})")
|
|
201
|
-
console.print(f" URL: [cyan]
|
|
290
|
+
console.print(f" URL: [cyan]{protocol}://0.0.0.0:8118[/cyan]")
|
|
202
291
|
if log_file:
|
|
203
292
|
console.print(f" Logs: [dim]{log_file}[/dim]")
|
|
204
293
|
else:
|
|
@@ -252,4 +341,3 @@ def restart(
|
|
|
252
341
|
stop()
|
|
253
342
|
time.sleep(1)
|
|
254
343
|
start(port=port, host=host, auth=auth, reload=False, background=True)
|
|
255
|
-
|