base
This commit is contained in:
		
							
								
								
									
										0
									
								
								settingspanel/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								settingspanel/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										3
									
								
								settingspanel/admin.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								settingspanel/admin.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| from django.contrib import admin | ||||
|  | ||||
| # Register your models here. | ||||
							
								
								
									
										6
									
								
								settingspanel/apps.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								settingspanel/apps.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| from django.apps import AppConfig | ||||
|  | ||||
|  | ||||
| class SettingspanelConfig(AppConfig): | ||||
|     default_auto_field = 'django.db.models.BigAutoField' | ||||
|     name = 'settingspanel' | ||||
							
								
								
									
										33
									
								
								settingspanel/forms.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								settingspanel/forms.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| from django import forms | ||||
|  | ||||
| WIDE = {"class": "input-wide"} | ||||
|  | ||||
| class ArrSettingsForm(forms.Form): | ||||
|     sonarr_url     = forms.URLField(label="Sonarr URL", required=False, | ||||
|                                     widget=forms.URLInput(attrs=WIDE)) | ||||
|     sonarr_api_key = forms.CharField(label="Sonarr API Key", required=False, | ||||
|                                     widget=forms.PasswordInput(render_value=True, attrs=WIDE)) | ||||
|     radarr_url     = forms.URLField(label="Radarr URL", required=False, | ||||
|                                     widget=forms.URLInput(attrs=WIDE)) | ||||
|     radarr_api_key = forms.CharField(label="Radarr API Key", required=False, | ||||
|                                     widget=forms.PasswordInput(render_value=True, attrs=WIDE)) | ||||
|  | ||||
| class MailSettingsForm(forms.Form): | ||||
|     mail_host = forms.CharField(label="Mail Host", required=False) | ||||
|     mail_port = forms.IntegerField(label="Mail Port", required=False, min_value=1, max_value=65535) | ||||
|     mail_secure = forms.ChoiceField( | ||||
|         label="Sicherheit", required=False, | ||||
|         choices=[("", "Kein TLS/SSL"), ("starttls", "STARTTLS"), ("ssl", "SSL/TLS")] | ||||
|     ) | ||||
|     mail_user = forms.CharField(label="Mail Benutzer", required=False) | ||||
|     mail_password = forms.CharField( | ||||
|         label="Mail Passwort", required=False, | ||||
|         widget=forms.PasswordInput(render_value=True) | ||||
|     ) | ||||
|     mail_from = forms.EmailField(label="Absender (From)", required=False) | ||||
|  | ||||
| class AccountForm(forms.Form): | ||||
|     username = forms.CharField(label="Benutzername", required=False) | ||||
|     email = forms.EmailField(label="E-Mail", required=False) | ||||
|     new_password = forms.CharField(label="Neues Passwort", required=False, widget=forms.PasswordInput) | ||||
|     repeat_password = forms.CharField(label="Passwort wiederholen", required=False, widget=forms.PasswordInput) | ||||
							
								
								
									
										34
									
								
								settingspanel/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								settingspanel/migrations/0001_initial.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| # Generated by Django 5.2.5 on 2025-08-08 23:24 | ||||
|  | ||||
| from django.db import migrations, models | ||||
|  | ||||
|  | ||||
| class Migration(migrations.Migration): | ||||
|  | ||||
|     initial = True | ||||
|  | ||||
|     dependencies = [ | ||||
|     ] | ||||
|  | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name='AppSettings', | ||||
|             fields=[ | ||||
|                 ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), | ||||
|                 ('singleton_id', models.PositiveSmallIntegerField(default=1, editable=False, unique=True)), | ||||
|                 ('sonarr_url', models.URLField(blank=True, null=True)), | ||||
|                 ('sonarr_api_key', models.CharField(blank=True, max_length=255, null=True)), | ||||
|                 ('radarr_url', models.URLField(blank=True, null=True)), | ||||
|                 ('radarr_api_key', models.CharField(blank=True, max_length=255, null=True)), | ||||
|                 ('mail_host', models.CharField(blank=True, max_length=255, null=True)), | ||||
|                 ('mail_port', models.PositiveIntegerField(blank=True, null=True)), | ||||
|                 ('mail_secure', models.CharField(blank=True, choices=[('', 'Kein TLS/SSL'), ('starttls', 'STARTTLS'), ('ssl', 'SSL/TLS')], max_length=10, null=True)), | ||||
|                 ('mail_user', models.CharField(blank=True, max_length=255, null=True)), | ||||
|                 ('mail_password', models.CharField(blank=True, max_length=255, null=True)), | ||||
|                 ('mail_from', models.EmailField(blank=True, max_length=254, null=True)), | ||||
|                 ('acc_username', models.CharField(blank=True, max_length=150, null=True)), | ||||
|                 ('acc_email', models.EmailField(blank=True, max_length=254, null=True)), | ||||
|                 ('updated_at', models.DateTimeField(auto_now=True)), | ||||
|             ], | ||||
|         ), | ||||
|     ] | ||||
							
								
								
									
										0
									
								
								settingspanel/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								settingspanel/migrations/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										36
									
								
								settingspanel/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										36
									
								
								settingspanel/models.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| from django.db import models | ||||
|  | ||||
| class AppSettings(models.Model): | ||||
|     # Singleton-Pattern über feste ID | ||||
|     singleton_id = models.PositiveSmallIntegerField(default=1, unique=True, editable=False) | ||||
|  | ||||
|     # Arr | ||||
|     sonarr_url = models.URLField(blank=True, null=True) | ||||
|     sonarr_api_key = models.CharField(max_length=255, blank=True, null=True) | ||||
|     radarr_url = models.URLField(blank=True, null=True) | ||||
|     radarr_api_key = models.CharField(max_length=255, blank=True, null=True) | ||||
|  | ||||
|     # Mail | ||||
|     mail_host = models.CharField(max_length=255, blank=True, null=True) | ||||
|     mail_port = models.PositiveIntegerField(blank=True, null=True) | ||||
|     mail_secure = models.CharField( | ||||
|         max_length=10, blank=True, null=True, | ||||
|         choices=(("", "Kein TLS/SSL"), ("starttls", "STARTTLS"), ("ssl", "SSL/TLS")) | ||||
|     ) | ||||
|     mail_user = models.CharField(max_length=255, blank=True, null=True) | ||||
|     mail_password = models.CharField(max_length=255, blank=True, null=True) | ||||
|     mail_from = models.EmailField(blank=True, null=True) | ||||
|  | ||||
|     # „Account“ | ||||
|     acc_username = models.CharField(max_length=150, blank=True, null=True) | ||||
|     acc_email = models.EmailField(blank=True, null=True) | ||||
|  | ||||
|     updated_at = models.DateTimeField(auto_now=True) | ||||
|  | ||||
|     def __str__(self): | ||||
|         return "AppSettings" | ||||
|  | ||||
|     @classmethod | ||||
|     def current(cls): | ||||
|         obj, _ = cls.objects.get_or_create(singleton_id=1) | ||||
|         return obj | ||||
							
								
								
									
										350
									
								
								settingspanel/templates/settingspanel/settings.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										350
									
								
								settingspanel/templates/settingspanel/settings.html
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,350 @@ | ||||
| {% load static %} | ||||
| <!doctype html> | ||||
| <html lang="de"> | ||||
|  | ||||
| <head> | ||||
|     <meta charset="utf-8"> | ||||
|     <meta name="viewport" content="width=device-width, initial-scale=1"> | ||||
|     <title>Einstellungen – Subscribarr</title> | ||||
|     <style> | ||||
|         :root { | ||||
|             --bg: #0b0b10; | ||||
|             --panel: #12121a; | ||||
|             --panel-b: #1f2030; | ||||
|             --accent: #3b82f6; | ||||
|             --muted: #9aa0b4; | ||||
|             --text: #e6e6e6; | ||||
|         } | ||||
|  | ||||
|         * { | ||||
|             box-sizing: border-box | ||||
|         } | ||||
|  | ||||
|         body { | ||||
|             background: var(--bg); | ||||
|             color: var(--text); | ||||
|             font-family: system-ui, Segoe UI, Roboto, Arial, sans-serif; | ||||
|             margin: 0 | ||||
|         } | ||||
|  | ||||
|         .wrap { | ||||
|             max-width: 1000px; | ||||
|             margin: 0 auto; | ||||
|             padding: 16px | ||||
|         } | ||||
|  | ||||
|         a { | ||||
|             color: #cfd3ea; | ||||
|             text-decoration: none | ||||
|         } | ||||
|  | ||||
|         .topbar { | ||||
|             display: flex; | ||||
|             align-items: center; | ||||
|             justify-content: space-between; | ||||
|             margin-bottom: 16px | ||||
|         } | ||||
|  | ||||
|         .btn { | ||||
|             padding: 10px 14px; | ||||
|             border-radius: 10px; | ||||
|             border: 1px solid #2a2a34; | ||||
|             background: #111119; | ||||
|             color: #fff; | ||||
|             cursor: pointer | ||||
|         } | ||||
|  | ||||
|         .btn-primary { | ||||
|             background: var(--accent); | ||||
|             border-color: transparent | ||||
|         } | ||||
|  | ||||
|         .grid { | ||||
|             display: grid; | ||||
|             gap: 16px | ||||
|         } | ||||
|  | ||||
|         @media(min-width:900px) { | ||||
|             .grid { | ||||
|                 grid-template-columns: 1fr 1fr | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         .card { | ||||
|             background: var(--panel); | ||||
|             border: 1px solid var(--panel-b); | ||||
|             border-radius: 12px; | ||||
|             padding: 14px | ||||
|         } | ||||
|  | ||||
|         .card h2 { | ||||
|             margin: 0 0 10px; | ||||
|             font-size: 1.05rem | ||||
|         } | ||||
|  | ||||
|         .row { | ||||
|             display: grid; | ||||
|             grid-template-columns: 160px minmax(0, 1fr); | ||||
|             /* <= statt 160px 1fr */ | ||||
|             gap: 10px; | ||||
|             align-items: center; | ||||
|             margin-bottom: 10px; | ||||
|         } | ||||
|  | ||||
|         .row label { | ||||
|             color: #c9cbe3 | ||||
|         } | ||||
|  | ||||
|         .row input, | ||||
|         .row select { | ||||
|             width: 100%; | ||||
|             padding: 10px 12px; | ||||
|             border-radius: 10px; | ||||
|             border: 1px solid #2a2a34; | ||||
|             background: #111119; | ||||
|             color: var(--text) | ||||
|         } | ||||
|  | ||||
|         .help { | ||||
|             color: var(--muted); | ||||
|             font-size: .9rem | ||||
|         } | ||||
|  | ||||
|         .msgs { | ||||
|             margin-bottom: 10px | ||||
|         } | ||||
|  | ||||
|         .msg { | ||||
|             background: #0f1425; | ||||
|             border: 1px solid #283058; | ||||
|             border-radius: 10px; | ||||
|             padding: 10px; | ||||
|             margin-bottom: 8px | ||||
|         } | ||||
|  | ||||
|         .input-wide { | ||||
|             width: 100% !important; | ||||
|             max-width: 100%; | ||||
|             min-width: 0; | ||||
|             display: block; | ||||
|         } | ||||
|  | ||||
|         .row input, | ||||
|         .row select, | ||||
|         .row textarea { | ||||
|             width: 100%; | ||||
|             max-width: 100%; | ||||
|             min-width: 0; | ||||
|             display: block; | ||||
|         } | ||||
|  | ||||
|         /* falls du passwort/URL Felder extra stylen willst, gleicher Fix */ | ||||
|         .inline>input, | ||||
|         .inline>.django-url, | ||||
|         /* falls Widget eine Klasse rendert */ | ||||
|         .inline>.django-password { | ||||
|             min-width: 0; | ||||
|             width: 100%; | ||||
|         } | ||||
|  | ||||
|         .inline-actions { | ||||
|             display: inline-flex; | ||||
|             align-items: center; | ||||
|             gap: 8px; | ||||
|             min-width: 220px; | ||||
|             justify-content: flex-end; | ||||
|         } | ||||
|  | ||||
|         .btn { | ||||
|             padding: 10px 14px; | ||||
|             border-radius: 10px; | ||||
|             border: 1px solid #2a2a34; | ||||
|             background: #111119; | ||||
|             color: #fff; | ||||
|             cursor: pointer; | ||||
|         } | ||||
|  | ||||
|         .btn:disabled { | ||||
|             opacity: .6; | ||||
|             cursor: default; | ||||
|         } | ||||
|  | ||||
|         .badge { | ||||
|             padding: 6px 10px; | ||||
|             border-radius: 999px; | ||||
|             font-size: .85rem; | ||||
|             border: 1px solid #2a2a34; | ||||
|             background: #111119; | ||||
|             color: #cfd3ea; | ||||
|             white-space: nowrap; | ||||
|             /* eine Zeile */ | ||||
|             max-width: 140px; | ||||
|             /* begrenzt die Breite */ | ||||
|             overflow: hidden; | ||||
|             text-overflow: ellipsis; | ||||
|             /* falls doch Text drin ist */ | ||||
|         } | ||||
|  | ||||
|         .badge.ok { | ||||
|             border-color: #1f6f3a; | ||||
|             background: #10331f; | ||||
|             color: #a7e3bd; | ||||
|         } | ||||
|  | ||||
|         .badge.err { | ||||
|             border-color: #6f1f2a; | ||||
|             background: #341016; | ||||
|             color: #f1a3b0; | ||||
|         } | ||||
|  | ||||
|         .badge.muted { | ||||
|             opacity: .8; | ||||
|         } | ||||
|     </style> | ||||
| </head> | ||||
|  | ||||
| <body> | ||||
|     <div class="wrap"> | ||||
|         <div class="topbar"> | ||||
|             <div><a href="/" class="btn">← Zurück</a></div> | ||||
|             <div><strong>Einstellungen</strong></div> | ||||
|             <div></div> | ||||
|         </div> | ||||
|  | ||||
|         {% if messages %} | ||||
|         <div class="msgs">{% for m in messages %}<div class="msg">{{ m }}</div>{% endfor %}</div> | ||||
|         {% endif %} | ||||
|  | ||||
|         <form method="post"> | ||||
|             {% csrf_token %} | ||||
|             <div class="grid"> | ||||
|                 <div class="card"> | ||||
|                     <h2>Sonarr & Radarr</h2> | ||||
|  | ||||
|                     <div class="row"> | ||||
|                         <label>Sonarr URL</label> | ||||
|                         <div class="inline"> | ||||
|                             <div class="field">{{ arr_form.sonarr_url }}</div> | ||||
|                             <div class="inline-actions"> | ||||
|                                 <button class="btn" type="button" onclick="testConnection('sonarr', this)">Test | ||||
|                                     Sonarr</button> | ||||
|                                 <span id="sonarrStatus" class="badge muted">—</span> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|  | ||||
|                     <div class="row"> | ||||
|                         <label>Sonarr API Key</label> | ||||
|                         {{ arr_form.sonarr_api_key }} | ||||
|                     </div> | ||||
|  | ||||
|  | ||||
|                     <div class="row"> | ||||
|                         <label>Radarr URL</label> | ||||
|                         <div class="inline"> | ||||
|                             <div class="field">{{ arr_form.radarr_url }}</div> | ||||
|                             <div class="inline-actions"> | ||||
|                                 <button class="btn" type="button" onclick="testConnection('radarr', this)">Test | ||||
|                                     Radarr</button> | ||||
|                                 <span id="radarrStatus" class="badge muted">—</span> | ||||
|                             </div> | ||||
|                         </div> | ||||
|                     </div> | ||||
|  | ||||
|                     <div class="row"> | ||||
|                         <label>Radarr API Key</label> | ||||
|                         {{ arr_form.radarr_api_key }} | ||||
|                     </div> | ||||
|  | ||||
|                     <div class="help">Klicke „Test …“, um die Verbindung gegen <code>/api/v3/system/status</code> zu | ||||
|                         prüfen.</div> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="card"> | ||||
|                     <h2>Mailserver</h2> | ||||
|                     <div class="row"><label>Host</label>{{ mail_form.mail_host }}</div> | ||||
|                     <div class="row"><label>Port</label>{{ mail_form.mail_port }}</div> | ||||
|                     <div class="row"><label>Sicherheit</label>{{ mail_form.mail_secure }}</div> | ||||
|                     <div class="row"><label>Benutzer</label>{{ mail_form.mail_user }}</div> | ||||
|                     <div class="row"><label>Passwort</label>{{ mail_form.mail_password }}</div> | ||||
|                     <div class="row"><label>Absender</label>{{ mail_form.mail_from }}</div> | ||||
|                 </div> | ||||
|  | ||||
|                 <div class="card"> | ||||
|                     <h2>Konto</h2> | ||||
|                     <div class="row"><label>Benutzername</label>{{ account_form.username }}</div> | ||||
|                     <div class="row"><label>E-Mail</label>{{ account_form.email }}</div> | ||||
|                     <div class="row"><label>Neues Passwort</label>{{ account_form.new_password }}</div> | ||||
|                     <div class="row"><label>Passwort wiederholen</label>{{ account_form.repeat_password }}</div> | ||||
|                     <div class="help">Nur Oberfläche – Umsetzung Passwortänderung später.</div> | ||||
|                 </div> | ||||
|             </div> | ||||
|  | ||||
|             <div style="margin-top:16px"> | ||||
|                 <button class="btn btn-primary" type="submit">Speichern</button> | ||||
|             </div> | ||||
|         </form> | ||||
|     </div> | ||||
|  | ||||
|     <script> | ||||
|  | ||||
|         function testConnection(kind) { | ||||
|             const url = document.querySelector(`input[name="${kind}_url"]`).value; | ||||
|             const key = document.querySelector(`input[name="${kind}_api_key"]`).value; | ||||
|  | ||||
|             fetch(`/settings/test-connection/?kind=${kind}&url=${encodeURIComponent(url)}&key=${encodeURIComponent(key)}`) | ||||
|                 .then(r => r.json()) | ||||
|                 .then(data => { | ||||
|                     if (data.ok) { | ||||
|                         alert(kind + " Verbindung erfolgreich!"); | ||||
|                     } else { | ||||
|                         alert(kind + " Fehler: " + data.error); | ||||
|                     } | ||||
|                 }) | ||||
|                 .catch(err => alert(kind + " Fehler: " + err)); | ||||
|         } | ||||
|  | ||||
|         function setBadge(kind, state, text, tooltip) { | ||||
|             const el = document.getElementById(kind + "Status"); | ||||
|             if (!el) return; | ||||
|             el.classList.remove("ok", "err", "muted"); | ||||
|             el.title = tooltip || "";               // voller Fehlertext im Tooltip | ||||
|             if (state === "ok") { | ||||
|                 el.classList.add("ok"); | ||||
|                 el.textContent = "Verbunden"; | ||||
|             } else if (state === "err") { | ||||
|                 el.classList.add("err"); | ||||
|                 el.textContent = "Fehler"; | ||||
|             } else { | ||||
|                 el.classList.add("muted"); | ||||
|                 el.textContent = "—"; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         function testConnection(kind, btnEl) { | ||||
|             const urlEl = document.querySelector(`input[name="${kind}_url"]`); | ||||
|             const keyEl = document.querySelector(`input[name="${kind}_api_key"]`); | ||||
|             const url = urlEl ? urlEl.value.trim() : ""; | ||||
|             const key = keyEl ? keyEl.value.trim() : ""; | ||||
|  | ||||
|             setBadge(kind, "muted", "Teste…"); | ||||
|             if (btnEl) { btnEl.disabled = true; } | ||||
|  | ||||
|             fetch(`/settings/test-connection/?kind=${encodeURIComponent(kind)}&url=${encodeURIComponent(url)}&key=${encodeURIComponent(key)}`) | ||||
|                 .then(r => r.json()) | ||||
|                 .then(data => { | ||||
|                     if (data.ok) { | ||||
|                         setBadge(kind, "ok", "Verbunden", ""); | ||||
|                     } else { | ||||
|                         setBadge(kind, "err", "Fehler", data.error || "Unbekannter Fehler"); | ||||
|                     } | ||||
|                 }) | ||||
|                 .catch(err => setBadge(kind, "err", "Fehler", String(err))) | ||||
|                 .finally(() => { if (btnEl) btnEl.disabled = false; }); | ||||
|         } | ||||
|  | ||||
|     </script> | ||||
|  | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
							
								
								
									
										3
									
								
								settingspanel/tests.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								settingspanel/tests.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| from django.test import TestCase | ||||
|  | ||||
| # Create your tests here. | ||||
							
								
								
									
										8
									
								
								settingspanel/urls.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								settingspanel/urls.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| from django.urls import path | ||||
| from .views import SettingsView, test_connection | ||||
|  | ||||
| app_name = "settingspanel" | ||||
| urlpatterns = [ | ||||
|     path("", SettingsView.as_view(), name="index"), | ||||
|     path("test-connection/", test_connection, name="test_connection"), | ||||
| ] | ||||
							
								
								
									
										83
									
								
								settingspanel/views.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								settingspanel/views.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,83 @@ | ||||
| from django.views import View | ||||
| from django.shortcuts import render, redirect | ||||
| from django.contrib import messages | ||||
| from .forms import ArrSettingsForm, MailSettingsForm, AccountForm | ||||
| from .models import AppSettings | ||||
| from django.http import JsonResponse | ||||
| import requests | ||||
|  | ||||
| def test_connection(request): | ||||
|     kind = request.GET.get("kind")  # "sonarr" | "radarr" | ||||
|     url = (request.GET.get("url") or "").strip() | ||||
|     key = (request.GET.get("key") or "").strip() | ||||
|     if kind not in ("sonarr", "radarr"): | ||||
|         return JsonResponse({"ok": False, "error": "Ungültiger Typ"}, status=400) | ||||
|     if not url or not key: | ||||
|         return JsonResponse({"ok": False, "error": "URL und API-Key erforderlich"}, status=400) | ||||
|  | ||||
|     try: | ||||
|         r = requests.get( | ||||
|             f"{url.rstrip('/')}/api/v3/system/status", | ||||
|             headers={"X-Api-Key": key}, | ||||
|             timeout=5 | ||||
|         ) | ||||
|         if r.status_code == 200: | ||||
|             return JsonResponse({"ok": True}) | ||||
|         return JsonResponse({"ok": False, "error": f"HTTP {r.status_code}"}) | ||||
|     except requests.RequestException as e: | ||||
|         return JsonResponse({"ok": False, "error": str(e)}) | ||||
|  | ||||
| class SettingsView(View): | ||||
|     template_name = "settingspanel/settings.html" | ||||
|  | ||||
|     def get(self, request): | ||||
|         cfg = AppSettings.current() | ||||
|         return render(request, self.template_name, { | ||||
|             "arr_form": ArrSettingsForm(initial={ | ||||
|                 "sonarr_url": cfg.sonarr_url or "", | ||||
|                 "sonarr_api_key": cfg.sonarr_api_key or "", | ||||
|                 "radarr_url": cfg.radarr_url or "", | ||||
|                 "radarr_api_key": cfg.radarr_api_key or "", | ||||
|             }), | ||||
|             "mail_form": MailSettingsForm(initial={ | ||||
|                 "mail_host": cfg.mail_host or "", | ||||
|                 "mail_port": cfg.mail_port or "", | ||||
|                 "mail_secure": cfg.mail_secure or "", | ||||
|                 "mail_user": cfg.mail_user or "", | ||||
|                 "mail_password": cfg.mail_password or "", | ||||
|                 "mail_from": cfg.mail_from or "", | ||||
|             }), | ||||
|             "account_form": AccountForm(initial={ | ||||
|                 "username": cfg.acc_username or "", | ||||
|                 "email": cfg.acc_email or "", | ||||
|             }), | ||||
|         }) | ||||
|  | ||||
|     def post(self, request): | ||||
|         arr_form  = ArrSettingsForm(request.POST) | ||||
|         mail_form = MailSettingsForm(request.POST) | ||||
|         acc_form  = AccountForm(request.POST) | ||||
|         if not (arr_form.is_valid() and mail_form.is_valid() and acc_form.is_valid()): | ||||
|             return render(request, self.template_name, { | ||||
|                 "arr_form": arr_form, "mail_form": mail_form, "account_form": acc_form | ||||
|             }) | ||||
|  | ||||
|         cfg = AppSettings.current() | ||||
|         cfg.sonarr_url     = arr_form.cleaned_data["sonarr_url"] or None | ||||
|         cfg.sonarr_api_key = arr_form.cleaned_data["sonarr_api_key"] or None | ||||
|         cfg.radarr_url     = arr_form.cleaned_data["radarr_url"] or None | ||||
|         cfg.radarr_api_key = arr_form.cleaned_data["radarr_api_key"] or None | ||||
|  | ||||
|         cfg.mail_host     = mail_form.cleaned_data["mail_host"] or None | ||||
|         cfg.mail_port     = mail_form.cleaned_data["mail_port"] or None | ||||
|         cfg.mail_secure   = mail_form.cleaned_data["mail_secure"] or "" | ||||
|         cfg.mail_user     = mail_form.cleaned_data["mail_user"] or None | ||||
|         cfg.mail_password = mail_form.cleaned_data["mail_password"] or None | ||||
|         cfg.mail_from     = mail_form.cleaned_data["mail_from"] or None | ||||
|  | ||||
|         cfg.acc_username = acc_form.cleaned_data["username"] or None | ||||
|         cfg.acc_email    = acc_form.cleaned_data["email"] or None | ||||
|  | ||||
|         cfg.save() | ||||
|         messages.success(request, "Einstellungen gespeichert (DB).") | ||||
|         return redirect("settingspanel:index") | ||||
		Reference in New Issue
	
	Block a user