From 317cf4b180523caf0cca3f231fdd12096d2de336 Mon Sep 17 00:00:00 2001 From: kisfenyo Date: Sun, 1 Feb 2026 20:44:13 +0100 Subject: [PATCH] reverted --- glance-system/glance-helper.yaml | 719 ----------------------------- glance-system/glance-kisfenyo.yaml | 12 +- 2 files changed, 1 insertion(+), 730 deletions(-) diff --git a/glance-system/glance-helper.yaml b/glance-system/glance-helper.yaml index 64e1585..7af2b64 100644 --- a/glance-system/glance-helper.yaml +++ b/glance-system/glance-helper.yaml @@ -28,725 +28,6 @@ data: APP = FastAPI() - # ================================ - # Simple Notes Widget - Multi-user - # ================================ - - def get_notes_file(user: str) -> str: - """Get notes file path for a user, with validation.""" - # Sanitize username: only allow alphanumeric, dash, underscore - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) - if not safe_user: - safe_user = "default" - data_dir = os.environ.get("DATA_DIR", "/data") - return os.path.join(data_dir, f"notes_{safe_user}.txt") - - def load_notes(user: str) -> str: - """Load notes from file for a specific user.""" - notes_file = get_notes_file(user) - try: - if os.path.exists(notes_file): - with open(notes_file, "r", encoding="utf-8") as f: - return f.read() - except Exception as e: - print(f"Error loading notes for {user}: {e}") - return "" - - def save_notes(user: str, content: str) -> bool: - """Save notes to file for a specific user.""" - notes_file = get_notes_file(user) - try: - with open(notes_file, "w", encoding="utf-8") as f: - f.write(content) - return True - except Exception as e: - print(f"Error saving notes for {user}: {e}") - return False - - @APP.get("/notes") - def notes_widget(key: str = "", user: str = "default", accent: str = "ffffff", bgcolor: str = ""): - """Serve the notes widget HTML page for a specific user with optional theme.""" - expected_key = os.environ.get("GLANCE_HELPER_KEY", "") - if key != expected_key: - return Response(content="Unauthorized", status_code=401) - - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - # Sanitize accent color (hex only, default to white) - safe_accent = re.sub(r'[^a-fA-F0-9]', '', accent)[:6] or "ffffff" - # Sanitize bgcolor (hex only, default to dark purple matching Orsi's theme) - safe_bgcolor = re.sub(r'[^a-fA-F0-9]', '', bgcolor)[:6] or "2d1f3d" - - current_notes = load_notes(safe_user) - escaped_notes = current_notes.replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """) - - html = f""" - - - - - - - -
- -
-
- - - """ - return Response(content=html, media_type="text/html") - - @APP.post("/notes/save") - async def save_notes_api(key: str = "", user: str = "default", content: dict = None): - """API endpoint to save notes for a specific user.""" - expected_key = os.environ.get("GLANCE_HELPER_KEY", "") - if key != expected_key: - return Response(content="Unauthorized", status_code=401) - - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - - if content and "content" in content: - if save_notes(safe_user, content["content"]): - return {"status": "ok", "user": safe_user} - return Response(content="Failed to save", status_code=500) - - # ================================ - # Unified User Data System (Notes, Todo, Motivation) - # ================================ - # File format: - # [Notes] - # Free-form notes text... - # - # [Todo] - # - [ ] Uncompleted task - # - [x] Completed task - # - # [Motivation] - # Quote 1 - # Quote 2 - - def get_userdata_file(user: str) -> str: - """Get user data file path, with validation.""" - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - data_dir = os.environ.get("DATA_DIR", "/data") - return os.path.join(data_dir, f"userdata_{safe_user}.txt") - - def load_userdata(user: str) -> dict: - """Load and parse user data file into sections.""" - filepath = get_userdata_file(user) - sections = {"Notes": "", "Todo": [], "Motivation": []} - try: - if os.path.exists(filepath): - with open(filepath, "r", encoding="utf-8") as f: - content = f.read() - current_section = None - section_lines = [] - for line in content.split('\n'): - stripped = line.strip() - if stripped.startswith('[') and stripped.endswith(']'): - # Save previous section - if current_section == "Notes": - sections["Notes"] = '\n'.join(section_lines).strip() - elif current_section == "Todo": - for l in section_lines: - l = l.strip() - if l.startswith('- [x] '): - sections["Todo"].append({"text": l[6:], "done": True}) - elif l.startswith('- [ ] '): - sections["Todo"].append({"text": l[6:], "done": False}) - elif current_section == "Motivation": - for l in section_lines: - l = l.strip() - if l: - sections["Motivation"].append(l) - # Start new section - current_section = stripped[1:-1] - section_lines = [] - else: - section_lines.append(line) - # Handle last section - if current_section == "Notes": - sections["Notes"] = '\n'.join(section_lines).strip() - elif current_section == "Todo": - for l in section_lines: - l = l.strip() - if l.startswith('- [x] '): - sections["Todo"].append({"text": l[6:], "done": True}) - elif l.startswith('- [ ] '): - sections["Todo"].append({"text": l[6:], "done": False}) - elif current_section == "Motivation": - for l in section_lines: - l = l.strip() - if l: - sections["Motivation"].append(l) - except Exception as e: - print(f"Error loading userdata for {user}: {e}") - return sections - - def save_userdata(user: str, sections: dict) -> bool: - """Save sections back to user data file.""" - filepath = get_userdata_file(user) - try: - lines = [] - lines.append("[Notes]") - lines.append(sections.get("Notes", "")) - lines.append("") - lines.append("[Todo]") - for item in sections.get("Todo", []): - mark = "x" if item.get("done") else " " - lines.append(f"- [{mark}] {item.get('text', '')}") - lines.append("") - lines.append("[Motivation]") - for quote in sections.get("Motivation", []): - lines.append(quote) - with open(filepath, "w", encoding="utf-8") as f: - f.write('\n'.join(lines)) - return True - except Exception as e: - print(f"Error saving userdata for {user}: {e}") - return False - - # -------------------------------- - # Todo Widget - # -------------------------------- - @APP.get("/userdata/todo") - def todo_widget(key: str = "", user: str = "default", accent: str = "5ac8d8", bgcolor: str = "transparent"): - """Serve the Todo widget HTML page.""" - expected_key = os.environ.get("GLANCE_HELPER_KEY", "") - if key != expected_key: - return Response(content="Unauthorized", status_code=401) - - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - safe_accent = re.sub(r'[^a-fA-F0-9]', '', accent)[:6] or "5ac8d8" - # Handle transparent background - if bgcolor == "transparent" or not bgcolor: - bg_style = "transparent" - else: - safe_bgcolor = re.sub(r'[^a-fA-F0-9]', '', bgcolor)[:6] - bg_style = f"#{safe_bgcolor}" if safe_bgcolor else "transparent" - - sections = load_userdata(safe_user) - todos = sections.get("Todo", []) - - # Build todo items HTML - todo_html = "" - for i, item in enumerate(todos): - checked = "checked" if item.get("done") else "" - text_escaped = item.get("text", "").replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """) - done_class = "done" if item.get("done") else "" - todo_html += f'''
- - {text_escaped} - -
''' - - html = f""" - - - - - - - -
-
- - -
-
{todo_html if todo_html else '
No tasks yet
'}
-
-
- - - """ - return Response(content=html, media_type="text/html") - - @APP.post("/userdata/todo/add") - async def todo_add(key: str = "", user: str = "default", content: dict = None): - expected_key = os.environ.get("GLANCE_HELPER_KEY", "") - if key != expected_key: - return Response(content="Unauthorized", status_code=401) - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - if content and content.get("text"): - sections = load_userdata(safe_user) - sections["Todo"].append({"text": content["text"].strip(), "done": False}) - if save_userdata(safe_user, sections): - return {"status": "ok"} - return Response(content="Failed", status_code=500) - - @APP.post("/userdata/todo/toggle") - async def todo_toggle(key: str = "", user: str = "default", index: int = 0): - expected_key = os.environ.get("GLANCE_HELPER_KEY", "") - if key != expected_key: - return Response(content="Unauthorized", status_code=401) - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - sections = load_userdata(safe_user) - if 0 <= index < len(sections["Todo"]): - sections["Todo"][index]["done"] = not sections["Todo"][index]["done"] - if save_userdata(safe_user, sections): - return {"status": "ok"} - return Response(content="Failed", status_code=500) - - @APP.post("/userdata/todo/delete") - async def todo_delete(key: str = "", user: str = "default", index: int = 0): - expected_key = os.environ.get("GLANCE_HELPER_KEY", "") - if key != expected_key: - return Response(content="Unauthorized", status_code=401) - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - sections = load_userdata(safe_user) - if 0 <= index < len(sections["Todo"]): - sections["Todo"].pop(index) - if save_userdata(safe_user, sections): - return {"status": "ok"} - return Response(content="Failed", status_code=500) - - # -------------------------------- - # Motivation Widget - # -------------------------------- - import random as _random - - @APP.get("/userdata/motivation") - def motivation_widget(key: str = "", user: str = "default", accent: str = "5ac8d8", bgcolor: str = "transparent"): - """Serve the Motivation widget HTML page with random quote.""" - expected_key = os.environ.get("GLANCE_HELPER_KEY", "") - if key != expected_key: - return Response(content="Unauthorized", status_code=401) - - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - safe_accent = re.sub(r'[^a-fA-F0-9]', '', accent)[:6] or "5ac8d8" - if bgcolor == "transparent" or not bgcolor: - bg_style = "transparent" - else: - safe_bgcolor = re.sub(r'[^a-fA-F0-9]', '', bgcolor)[:6] - bg_style = f"#{safe_bgcolor}" if safe_bgcolor else "transparent" - - sections = load_userdata(safe_user) - quotes = sections.get("Motivation", []) - - # Pick random quote - current_quote = _random.choice(quotes) if quotes else "Add your first motivational quote!" - current_quote_escaped = current_quote.replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """) - - # Build manage URL (opens in new tab) - manage_url = f"/userdata/motivation/manage?key={expected_key}&user={safe_user}&accent={safe_accent}" - - html = f""" - - - - - - - -
- ⚙️ -
-
"{current_quote_escaped}"
-
- -
- - """ - return Response(content=html, media_type="text/html") - - @APP.get("/userdata/motivation/manage") - def motivation_manage(key: str = "", user: str = "default", accent: str = "5ac8d8"): - """Full-page management interface for motivation quotes.""" - expected_key = os.environ.get("GLANCE_HELPER_KEY", "") - if key != expected_key: - return Response(content="Unauthorized", status_code=401) - - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - safe_accent = re.sub(r'[^a-fA-F0-9]', '', accent)[:6] or "5ac8d8" - - sections = load_userdata(safe_user) - quotes = sections.get("Motivation", []) - - # Build quotes list HTML - quotes_html = "" - for i, q in enumerate(quotes): - q_escaped = q.replace("&", "&").replace("<", "<").replace(">", ">").replace('"', """) - quotes_html += f'''
- {i+1}. - {q_escaped} - -
''' - - html = f""" - - - - - Manage Motivation Quotes - - - -
-
-

Manage Motivation Quotes

-

User: {safe_user} • {len(quotes)} quote{'s' if len(quotes) != 1 else ''}

-
-
- - -
-
-
- {quotes_html if quotes_html else '
No quotes yet. Add your first motivational quote above!
'} -
-
Close this tab when done. Refresh your dashboard to see changes.
-
- - - """ - return Response(content=html, media_type="text/html") - - @APP.post("/userdata/motivation/add") - async def motivation_add(key: str = "", user: str = "default", content: dict = None): - expected_key = os.environ.get("GLANCE_HELPER_KEY", "") - if key != expected_key: - return Response(content="Unauthorized", status_code=401) - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - if content and content.get("text"): - sections = load_userdata(safe_user) - sections["Motivation"].append(content["text"].strip()) - if save_userdata(safe_user, sections): - return {"status": "ok"} - return Response(content="Failed", status_code=500) - - @APP.post("/userdata/motivation/delete") - async def motivation_delete(key: str = "", user: str = "default", index: int = 0): - expected_key = os.environ.get("GLANCE_HELPER_KEY", "") - if key != expected_key: - return Response(content="Unauthorized", status_code=401) - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - sections = load_userdata(safe_user) - if 0 <= index < len(sections["Motivation"]): - sections["Motivation"].pop(index) - if save_userdata(safe_user, sections): - return {"status": "ok"} - return Response(content="Failed", status_code=500) - - @APP.get("/userdata/motivation/random") - def motivation_random(key: str = "", user: str = "default"): - """Get a random motivation quote as JSON.""" - expected_key = os.environ.get("GLANCE_HELPER_KEY", "") - if key != expected_key: - return Response(content="Unauthorized", status_code=401) - safe_user = re.sub(r'[^a-zA-Z0-9_-]', '', user) or "default" - sections = load_userdata(safe_user) - quotes = sections.get("Motivation", []) - if quotes: - return {"quote": _random.choice(quotes), "total": len(quotes)} - return {"quote": "", "total": 0} - # ================================ # Időkép configuration # ================================ diff --git a/glance-system/glance-kisfenyo.yaml b/glance-system/glance-kisfenyo.yaml index d7b498b..26ef292 100644 --- a/glance-system/glance-kisfenyo.yaml +++ b/glance-system/glance-kisfenyo.yaml @@ -764,11 +764,7 @@ data: - type: calendar first-day-of-week: monday # Tasks (persistent, file-based) - - type: iframe - css-class: iframe-no-tint - source: https://glance-helper.dooplex.hu/userdata/todo?key=oplQqnLnJK2vErRVYJpvVUcSDBOSbCHZSbsYY2bwSifgTMfT&user=kisfenyo&accent=5ac8d8&bgcolor=0f1c24 - height: 200 - title: Tasks + - type: to-do # Outline Notes iframe - type: iframe source: https://outline.dooplex.hu/collection/dooplex-server-iTAZn04AaR/recent @@ -852,12 +848,6 @@ data: {{ end }} - # Motivation Quote - - type: iframe - css-class: iframe-no-tint - source: https://glance-helper.dooplex.hu/userdata/motivation?key=oplQqnLnJK2vErRVYJpvVUcSDBOSbCHZSbsYY2bwSifgTMfT&user=kisfenyo&accent=5ac8d8&bgcolor=0f1c24 - height: 80 - title: Motivation # Calendar Events Widget (Családi only) - type: custom-api