
    TBj0                        d dl mZmZmZmZ d dlZ ee      Zddddddddd	d
ddddddddddddddddddddddddddddddd d!d"d#d$d%d&ddd d!d'd(d)d%d*ddd d!d+d,d-d.dddd+d/d0d1d2d3dddd4d/d5d6d7d8dddd5d/g
Zd9 Z	d: Z
d; Zd<Zh d=Zh d>Zej                  d?      d@        Zej                  dA      dB        Zej                  dCdDgE      dF        ZedGk(  rej'                  dHdIdJK       yy)L    )Flaskjsonifyrequestrender_template_stringN	portainer	Portainerz7Docker Container Management. Start, Stop, Logs, Images.u   🐳z-https://portainer.agentsolutions-mallorca.com)idnamedesciconurl	containercomposeexplorerExplorerzDDateizugriff auf alle VPS-Verzeichnisse und Dateien via FileBrowser.u   📁z,https://explorer.agentsolutions-mallorca.comfilebrowser)r	   r
   r   r   r   r   systemdr   n8nz>Workflow-Automatisierung. Verbindet Apps, APIs und KI-Agenten.u   🔗z'https://n8n.agentsolutions-mallorca.com	paperclip	Paperclipz:Agent-Orchestrator. CEO-Agent mit DeepSeek via OpenRouter.u   📎z-https://paperclip.agentsolutions-mallorca.comzdocker-paperclip-1z/opt/struktur/paperclip/dockerionoszIONOS Cloud Panelz4VPS Verwaltung, DNS, Firewall, Server-Einstellungen.u   🖥zhttps://my.ionos.deT)r	   r
   r   r   r   r   r   externaldeepseek-keyszDeepSeek API Keysz5DeepSeek API-Key Verwaltung und Verbrauchsuebersicht.u   🔑z&https://platform.deepseek.com/api_keysopenrouter-keyszOpenRouter API Keysz;OpenRouter API-Key Verwaltung. Fuer Commander, Carlo, Mari.z#https://openrouter.ai/settings/keyslogszSystem LogszCJournald-Logs aller systemd-Services. Fehleranalyse und Monitoring.u   📋)r	   r
   r   r   r   r   r   
host_checksecuritySecurityzCUFW Firewall und Fail2Ban Intrusion-Prevention Status auf dem Host.u   🛡ufwbackupsBackupsz@Lokale VPS-Backups: Dashboard, Hermes-Configs, System-Snapshots.u   💾c                 n   | j                  d      ry| j                  d      rA	 t        j                  dd| d   gddd      }|j                  j	                         d	k(  rd
S dS | j                  d      rN	 t        j                  dddd| d   gddd      }|j                  j	                         }|dk(  ry
|dk(  ry|xs dS | j                  d      dk(  rW	 t        j                  ddddd      }t        |j                  j	                         xs d      }|dk(  rdS t        |      dz   S | j                  d      dk(  r=	 t        j                  g dddd      }|j                  j	                         d	k(  rdS dS | j                  d      d k(  rW	 t        j                  d!dddd      }t        |j                  j	                         xs d      }|dkD  rt        |      d"z   S d#S y# t
        $ r Y yw xY w# t
        $ r Y yw xY w# t
        $ r Y yw xY w# t
        $ r Y yw xY w# t
        $ r Y yw xY w)$Nr   externr   	systemctl	is-activeT   capture_outputtexttimeoutactiveonlineoffline	unbekanntr   dockerinspectz--formatz{{.State.Status}}runningexitedr   r   z9journalctl --since -1h -p err --quiet 2>/dev/null | wc -lshellr(   r)   r*   0r   okz Fehlerr   )r$   r%   r   aktivinaktivr    z%ls /root/backups/ 2>/dev/null | wc -lz Dateienleer)get
subprocessrunstdoutstrip	Exceptionintstr)svcrsns       &/opt/struktur/dashboard/app-vpshost.py
get_statusrG      sQ   
wwz
wwy	[#i.I.2qJA xx~~/8;8JJ ww{		9j2Es;GWX#$;A  AI~hhy## ww|&	Z%)$TSTVAAHHNN$+,A649s1v	'99 ww|%	@.2qJAhhnn.(:7I	I ww|	)	F%)$TSTVAAHHNN$+,A*+a%3q6J&;V; I  		  		  		  		  		s   =G, #G, 7A G; 8G; >G; AH
 !H
 9H >H AH( )H( ,	G87G8;	HH
	HH	H%$H%(	H43H4c                 6   | j                  d      rH| d   }d|z   dz   d|z   dz   d|z   dz   d}t        j                  |j                  |d      dddd	
      }n2| j                  d      r t        j                  d|| d   gddd      }ny|j                  dk(  S )Nr   zcd z && docker compose up -dz && docker compose stopz && docker compose restart)startstoprestart T<   r3   r   r/      r'   Fr   r:   r;   r<   
returncode)rB   actdcmdsrC   s        rF   docker_actionrT   C   s    
wwy	N%??	$== 19'CCE NN488C,DTXbde		NNHc3{+;<*.T2G <<1    c                     | j                  d      }|sy|dvryt        j                  d||gddd      }|j                  dk(  S )	Nr   F>   rJ   rI   rK   r$   TrN   r'   r   rO   )rB   rQ   unitrC   s       rF   systemd_actionrX   R   sK    779D
..uS$/4Y[\A<<1rU   a  <!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VPS Verwaltung</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body { background: #0f1117; color: #e2e8f0; font-family: -apple-system, BlinkMacSystemFont, Segoe UI, sans-serif; min-height: 100vh; }
  header { padding: 2rem 3rem; border-bottom: 1px solid #1e2330; display:flex; align-items:center; justify-content:space-between; }
  header h1 { font-size: 1.5rem; font-weight: 600; color: #fff; }
  header span { font-size: 0.85rem; color: #64748b; }
  .grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 1.5rem; padding: 3rem; }
  .card { background: #161b27; border: 1px solid #1e2330; border-radius: 12px; padding: 1.5rem; }
  .card-header { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 1rem; }
  .card-icon { font-size: 2rem; }
  .badge { font-size: 0.7rem; padding: 0.25rem 0.7rem; border-radius: 99px; font-weight: 600; }
  .badge.online, .badge.ok, .badge.aktiv { background: #1a3a2a; color: #4ade80; border: 1px solid #166534; }
  .badge.offline, .badge.inaktiv { background: #3a1a1a; color: #f87171; border: 1px solid #7f1d1d; }
  .badge.loading { background: #2a2a1a; color: #fbbf24; border: 1px solid #78350f; }
  .badge.extern { background: #1e2a3a; color: #93c5fd; border: 1px solid #1e3a5f; }
  .badge.info { background: #2a2a3a; color: #a78bfa; border: 1px solid #4c1d95; }
  .card-title { font-size: 1.1rem; font-weight: 600; color: #fff; margin-bottom: 0.4rem; }
  .card-desc { font-size: 0.85rem; color: #64748b; line-height: 1.5; margin-bottom: 1.2rem; }
  .card-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
  .btn { font-size: 0.75rem; padding: 0.4rem 0.9rem; border-radius: 6px; border: none; cursor: pointer; font-weight: 500; }
  .btn-open { background: #1e3a5f; color: #60a5fa; }
  .btn-restart { background: #1e3a2a; color: #4ade80; }
  .btn-stop { background: #3a1e1e; color: #f87171; }
  .btn-start { background: #1a3a2a; color: #4ade80; }
  footer { text-align: center; padding: 2rem; color: #334155; font-size: 0.8rem; }
  .section-group { padding: 0 3rem; margin-bottom: 0.5rem; }
  .section-group-title { font-size: 0.9rem; font-weight: 600; color: #94a3b8; text-transform: uppercase; letter-spacing: 2px; margin-bottom: 1rem; margin-top: 2.5rem; border-left: 3px solid #3b82f6; padding-left: 0.75rem; }
  .section-group-title.tools { border-left-color: #a855f7; }

</style>
</head>
<body>
<header>
  <div><h1>VPS Verwaltung</h1><span>Verwaltung &amp; Tools &middot; 31.70.68.228</span></div>
  <a href="https://agentsolutions-mallorca.com" style="font-size:0.85rem;color:#3b82f6;text-decoration:none;border:1px solid #1e3a5f;padding:0.4rem 1rem;border-radius:8px;">&larr; Zurueck</a>
</header>
<div class="section-group"><div class="section-group-title">VPS Verwaltung</div></div>
<div class="grid" id="grid-verwaltung">
  {% for s in services_verwaltung %}
  <div class="card" id="card-{{s.id}}">
    <div class="card-header">
      <div class="card-icon">{{s.icon}}</div>
      <span class="badge loading" id="badge-{{s.id}}">{% if s.get('external') %}extern{% else %}...{% endif %}</span>
    </div>
    <div class="card-title">{{s.name}}</div>
    <div class="card-desc">{{s.desc}}</div>
    <div class="card-actions">
      {% if s.url %}<a class="btn btn-open" href="{{s.url}}" {%if s.url.startswith('http')%}target="_blank"{%endif%}>{{s.btn_label if s.btn_label else 'Oeffnen'}}</a>{% endif %}
      {% if not s.get('external') and not s.get('host_check') %}
      <button class="btn btn-restart" onclick="action('{{s.id}}','restart')">Restart</button>
      <button class="btn btn-stop" onclick="action('{{s.id}}','stop')">Stop</button>
      <button class="btn btn-start" onclick="action('{{s.id}}','start')">Start</button>
      {% endif %}
    </div>
  </div>
  {% endfor %}
</div>
<div class="section-group"><div class="section-group-title tools">KI &amp; Automation</div></div>
<div class="grid" id="grid-tools">
  {% for s in services_tools %}
  <div class="card" id="card-{{s.id}}">
    <div class="card-header">
      <div class="card-icon">{{s.icon}}</div>
      <span class="badge loading" id="badge-{{s.id}}">{% if s.get('external') %}extern{% else %}...{% endif %}</span>
    </div>
    <div class="card-title">{{s.name}}</div>
    <div class="card-desc">{{s.desc}}</div>
    <div class="card-actions">
      {% if s.url %}<a class="btn btn-open" href="{{s.url}}" {%if s.url.startswith('http')%}target="_blank"{%endif%}>{{s.btn_label if s.btn_label else 'Oeffnen'}}</a>{% endif %}
      {% if not s.get('external') and not s.get('host_check') %}
      <button class="btn btn-restart" onclick="action('{{s.id}}','restart')">Restart</button>
      <button class="btn btn-stop" onclick="action('{{s.id}}','stop')">Stop</button>
      <button class="btn btn-start" onclick="action('{{s.id}}','start')">Start</button>
      {% endif %}
    </div>
  </div>
  {% endfor %}
</div>
<footer>Agent Solutions &middot; VPS Verwaltung &middot; 31.70.68.228</footer>
<script>
function updateStatus() {
  fetch('/api/status').then(r=>r.json()).then(data => {
    data.forEach(s => {
      const b = document.getElementById('badge-'+s.id);
      if (!b) return;
      b.textContent = s.status;
      const st = s.status;
      const cls = ['online','ok','aktiv'].includes(st) ? 'online'
                : ['offline','inaktiv'].includes(st) ? 'offline'
                : st === 'extern' ? 'extern'
                : st.includes('Fehler') ? 'offline'
                : (st.includes('Dateien') || st.includes('leer')) ? 'info'
                : 'loading';
      b.className = 'badge ' + cls;
    });
  });
}
function action(id, act) {
  const b = document.getElementById('badge-'+id);
  b.textContent = '...'; b.className = 'badge loading';
  fetch('/api/action', {method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({id,action:act})}).then(()=>setTimeout(updateStatus,3000));
}
updateStatus(); setInterval(updateStatus, 15000);
</script>
</body>
</html>>   r   r   r    r   r   r   r   >   r   r   r   /c                      t         D  cg c]  } | d   t        v s|  }} t         D  cg c]  } | d   t        v s|  }} t        t        ||      S c c} w c c} w )Nr	   )services_verwaltungservices_tools)SERVICESVERWALTUNG_IDS	TOOLS_IDSr   HTML)rD   svsts      rF   indexrc      sU    	;4N!:!	;B	;	64I!5!	6B	6!$BrRR 
<	6s   AAAAz/api/statusc                  R    t         D  cg c]  } | d   t        |       d c} S c c} w )Nr	   )r	   status)r]   rG   )rD   s    rF   re   re      s#    >FG1T7jm4GGGs   $z/api/actionPOST)methodsc                      t         j                  t        fdt        D        d       } | sddidfS | j	                  d      rt        | d         }d|iS t        | d         }d|iS )Nc              3   :   K   | ]  }|d    d    k(  s|  yw)r	   N ).0rD   datas     rF   	<genexpr>zaction.<locals>.<genexpr>   s      =aqw$t*'<=s   r6   Fi  r   action)r   jsonnextr]   r:   rX   rT   )rB   r6   rl   s     @rF   rn   rn      st    <<D
=8=t
DCe}c!!
wwyCh0 ": 3X/":rU   __main__z	127.0.0.1i  F)hostportdebug)flaskr   r   r   r   r;   __name__appr]   rG   rT   rX   r`   r^   r_   routerc   re   rn   r<   rj   rU   rF   <module>ry      s   A A Ho 5n  yE  N}  LW  dh  iz3y  DP  YG  VZ  gt  AE  F%)is  Ir  AF  SW  X5q  |H  Q@  Oc  pP  Q/9o  zF  Od  sw  DH  VZ  [$7Ax  CO  X@  OS  `d  rv  w&;  FC  MY  bG  VZ  gk  y}  ~=2w  BN  W[  jn  {  OU  Vz3x  CO  X\  ko  |@  PU  Vi1s  ~J  SW  fj  w{  KT  U,^od j-	3S S =H H =6(+	 ,	 zGG4uG5 rU   