Dieser Commit ist enthalten in:
Claude Project Manager
2025-07-03 21:11:05 +02:00
Commit 08ed938105
239 geänderte Dateien mit 21554 neuen und 0 gelöschten Zeilen

0
database/__init__.py Normale Datei
Datei anzeigen

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

Binäre Datei nicht angezeigt.

Datei anzeigen

BIN
database/accounts.db Normale Datei

Binäre Datei nicht angezeigt.

480
database/db_manager.py Normale Datei
Datei anzeigen

@ -0,0 +1,480 @@
"""
Datenbankmanager für den Social Media Account Generator.
"""
import os
import json
import sqlite3
import logging
from datetime import datetime
from typing import Dict, List, Any, Optional, Tuple, Union
logger = logging.getLogger("db_manager")
class DatabaseManager:
"""Klasse zur Verwaltung der Datenbank für Account-Informationen."""
def __init__(self, db_path: str = "database/accounts.db"):
"""
Initialisiert den DatabaseManager.
Args:
db_path: Pfad zur Datenbank-Datei
"""
self.db_path = db_path
# Stelle sicher, dass das Datenbankverzeichnis existiert
os.makedirs(os.path.dirname(self.db_path), exist_ok=True)
# Datenbank initialisieren
self.init_db()
def init_db(self) -> None:
"""Initialisiert die Datenbank und erstellt die benötigten Tabellen, wenn sie nicht existieren."""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# Accounts-Tabelle erstellen
cursor.execute('''
CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
platform TEXT NOT NULL,
username TEXT NOT NULL,
password TEXT NOT NULL,
email TEXT,
phone TEXT,
full_name TEXT,
created_at TEXT NOT NULL,
last_login TEXT,
notes TEXT,
cookies TEXT,
status TEXT
)
''')
# Settings-Tabelle erstellen
cursor.execute('''
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL
)
''')
conn.commit()
conn.close()
logger.info("Datenbank initialisiert")
except sqlite3.Error as e:
logger.error(f"Fehler bei der Datenbankinitialisierung: {e}")
def add_account(self, account_data: Dict[str, Any]) -> int:
"""
Fügt einen Account zur Datenbank hinzu.
Args:
account_data: Dictionary mit Account-Daten
Returns:
ID des hinzugefügten Accounts oder -1 im Fehlerfall
"""
try:
# Prüfe, ob erforderliche Felder vorhanden sind
required_fields = ["platform", "username", "password"]
for field in required_fields:
if field not in account_data:
logger.error(f"Fehlendes Pflichtfeld: {field}")
return -1
# Sicherstellen, dass created_at vorhanden ist
if "created_at" not in account_data:
account_data["created_at"] = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# SQL-Anweisung vorbereiten
fields = ", ".join(account_data.keys())
placeholders = ", ".join(["?" for _ in account_data])
query = f"INSERT INTO accounts ({fields}) VALUES ({placeholders})"
# Anweisung ausführen
cursor.execute(query, list(account_data.values()))
# ID des hinzugefügten Datensatzes abrufen
account_id = cursor.lastrowid
conn.commit()
conn.close()
logger.info(f"Account hinzugefügt: {account_data['username']} (ID: {account_id})")
return account_id
except sqlite3.Error as e:
logger.error(f"Fehler beim Hinzufügen des Accounts: {e}")
return -1
def get_account(self, account_id: int) -> Optional[Dict[str, Any]]:
"""
Gibt einen Account anhand seiner ID zurück.
Args:
account_id: ID des Accounts
Returns:
Dictionary mit Account-Daten oder None, wenn der Account nicht gefunden wurde
"""
try:
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row # Für dict-like Zugriff auf Zeilen
cursor = conn.cursor()
cursor.execute("SELECT * FROM accounts WHERE id = ?", (account_id,))
row = cursor.fetchone()
conn.close()
if row:
# Konvertiere Row in Dictionary
account = dict(row)
logger.debug(f"Account gefunden: {account['username']} (ID: {account_id})")
return account
else:
logger.warning(f"Account nicht gefunden: ID {account_id}")
return None
except sqlite3.Error as e:
logger.error(f"Fehler beim Abrufen des Accounts: {e}")
return None
def get_all_accounts(self) -> List[Dict[str, Any]]:
"""
Gibt alle Accounts zurück.
Returns:
Liste von Dictionaries mit Account-Daten
"""
try:
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute("SELECT * FROM accounts ORDER BY id DESC")
rows = cursor.fetchall()
conn.close()
# Konvertiere Rows in Dictionaries
accounts = [dict(row) for row in rows]
logger.info(f"{len(accounts)} Accounts abgerufen")
return accounts
except sqlite3.Error as e:
logger.error(f"Fehler beim Abrufen aller Accounts: {e}")
return []
def get_accounts_by_platform(self, platform: str) -> List[Dict[str, Any]]:
"""
Gibt alle Accounts einer bestimmten Plattform zurück.
Args:
platform: Plattformname (z.B. "instagram")
Returns:
Liste von Dictionaries mit Account-Daten
"""
try:
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
cursor.execute("SELECT * FROM accounts WHERE platform = ? ORDER BY id DESC", (platform.lower(),))
rows = cursor.fetchall()
conn.close()
# Konvertiere Rows in Dictionaries
accounts = [dict(row) for row in rows]
logger.info(f"{len(accounts)} Accounts für Plattform '{platform}' abgerufen")
return accounts
except sqlite3.Error as e:
logger.error(f"Fehler beim Abrufen der Accounts für Plattform '{platform}': {e}")
return []
def update_account(self, account_id: int, update_data: Dict[str, Any]) -> bool:
"""
Aktualisiert einen Account in der Datenbank.
Args:
account_id: ID des zu aktualisierenden Accounts
update_data: Dictionary mit zu aktualisierenden Feldern
Returns:
True bei Erfolg, False im Fehlerfall
"""
if not update_data:
logger.warning("Keine Aktualisierungsdaten bereitgestellt")
return False
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# SQL-Anweisung vorbereiten
set_clause = ", ".join([f"{field} = ?" for field in update_data.keys()])
values = list(update_data.values())
values.append(account_id)
query = f"UPDATE accounts SET {set_clause} WHERE id = ?"
# Anweisung ausführen
cursor.execute(query, values)
conn.commit()
conn.close()
logger.info(f"Account aktualisiert: ID {account_id}")
return True
except sqlite3.Error as e:
logger.error(f"Fehler beim Aktualisieren des Accounts: {e}")
return False
def delete_account(self, account_id: int) -> bool:
"""
Löscht einen Account aus der Datenbank.
Args:
account_id: ID des zu löschenden Accounts
Returns:
True bei Erfolg, False im Fehlerfall
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("DELETE FROM accounts WHERE id = ?", (account_id,))
conn.commit()
conn.close()
logger.info(f"Account gelöscht: ID {account_id}")
return True
except sqlite3.Error as e:
logger.error(f"Fehler beim Löschen des Accounts: {e}")
return False
def search_accounts(self, query: str, platform: Optional[str] = None) -> List[Dict[str, Any]]:
"""
Sucht nach Accounts in der Datenbank.
Args:
query: Suchbegriff
platform: Optional, Plattform für die Einschränkung der Suche
Returns:
Liste von Dictionaries mit gefundenen Account-Daten
"""
try:
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row
cursor = conn.cursor()
# Suchbegriff für LIKE-Operator vorbereiten
search_term = f"%{query}%"
if platform:
query_sql = """
SELECT * FROM accounts
WHERE (username LIKE ? OR email LIKE ? OR phone LIKE ? OR full_name LIKE ?)
AND platform = ?
ORDER BY id DESC
"""
cursor.execute(query_sql, (search_term, search_term, search_term, search_term, platform.lower()))
else:
query_sql = """
SELECT * FROM accounts
WHERE username LIKE ? OR email LIKE ? OR phone LIKE ? OR full_name LIKE ?
ORDER BY id DESC
"""
cursor.execute(query_sql, (search_term, search_term, search_term, search_term))
rows = cursor.fetchall()
conn.close()
# Konvertiere Rows in Dictionaries
accounts = [dict(row) for row in rows]
logger.info(f"{len(accounts)} Accounts gefunden für Suchbegriff '{query}'")
return accounts
except sqlite3.Error as e:
logger.error(f"Fehler bei der Suche nach Accounts: {e}")
return []
def get_account_count(self, platform: Optional[str] = None) -> int:
"""
Gibt die Anzahl der Accounts zurück.
Args:
platform: Optional, Plattform für die Einschränkung der Zählung
Returns:
Anzahl der Accounts
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
if platform:
cursor.execute("SELECT COUNT(*) FROM accounts WHERE platform = ?", (platform.lower(),))
else:
cursor.execute("SELECT COUNT(*) FROM accounts")
count = cursor.fetchone()[0]
conn.close()
return count
except sqlite3.Error as e:
logger.error(f"Fehler beim Zählen der Accounts: {e}")
return 0
def get_setting(self, key: str, default: Any = None) -> Any:
"""
Gibt einen Einstellungswert zurück.
Args:
key: Schlüssel der Einstellung
default: Standardwert, falls die Einstellung nicht gefunden wurde
Returns:
Wert der Einstellung oder der Standardwert
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("SELECT value FROM settings WHERE key = ?", (key,))
row = cursor.fetchone()
conn.close()
if row:
# Versuche, den Wert als JSON zu parsen
try:
return json.loads(row[0])
except json.JSONDecodeError:
# Wenn kein gültiges JSON, gib den Rohwert zurück
return row[0]
else:
return default
except sqlite3.Error as e:
logger.error(f"Fehler beim Abrufen der Einstellung '{key}': {e}")
return default
def set_setting(self, key: str, value: Any) -> bool:
"""
Setzt einen Einstellungswert.
Args:
key: Schlüssel der Einstellung
value: Wert der Einstellung (wird als JSON gespeichert, wenn es kein String ist)
Returns:
True bei Erfolg, False im Fehlerfall
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
# Wert als JSON speichern, wenn es kein String ist
if not isinstance(value, str):
value = json.dumps(value)
# Prüfen, ob die Einstellung bereits existiert
cursor.execute("SELECT COUNT(*) FROM settings WHERE key = ?", (key,))
exists = cursor.fetchone()[0] > 0
if exists:
cursor.execute("UPDATE settings SET value = ? WHERE key = ?", (value, key))
else:
cursor.execute("INSERT INTO settings (key, value) VALUES (?, ?)", (key, value))
conn.commit()
conn.close()
logger.info(f"Einstellung gespeichert: {key}")
return True
except sqlite3.Error as e:
logger.error(f"Fehler beim Speichern der Einstellung '{key}': {e}")
return False
def delete_setting(self, key: str) -> bool:
"""
Löscht eine Einstellung.
Args:
key: Schlüssel der zu löschenden Einstellung
Returns:
True bei Erfolg, False im Fehlerfall
"""
try:
conn = sqlite3.connect(self.db_path)
cursor = conn.cursor()
cursor.execute("DELETE FROM settings WHERE key = ?", (key,))
conn.commit()
conn.close()
logger.info(f"Einstellung gelöscht: {key}")
return True
except sqlite3.Error as e:
logger.error(f"Fehler beim Löschen der Einstellung '{key}': {e}")
return False
def backup_database(self, backup_path: Optional[str] = None) -> bool:
"""
Erstellt ein Backup der Datenbank.
Args:
backup_path: Optional, Pfad für das Backup
Returns:
True bei Erfolg, False im Fehlerfall
"""
if not backup_path:
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
backup_path = f"database/backup/accounts_{timestamp}.db"
# Stelle sicher, dass das Backup-Verzeichnis existiert
os.makedirs(os.path.dirname(backup_path), exist_ok=True)
try:
# SQLite-Backup-API verwenden
conn = sqlite3.connect(self.db_path)
backup_conn = sqlite3.connect(backup_path)
conn.backup(backup_conn)
conn.close()
backup_conn.close()
logger.info(f"Datenbank-Backup erstellt: {backup_path}")
return True
except sqlite3.Error as e:
logger.error(f"Fehler beim Erstellen des Datenbank-Backups: {e}")
return False

BIN
database/instagram_accounts.db Normale Datei

Binäre Datei nicht angezeigt.

112
database/schema.sql Normale Datei
Datei anzeigen

@ -0,0 +1,112 @@
-- SQLite-Datenbankschema für Instagram Account Generator
-- Accounts-Tabelle
CREATE TABLE IF NOT EXISTS accounts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT NOT NULL,
password TEXT NOT NULL,
email TEXT,
phone TEXT,
full_name TEXT,
created_at TEXT,
notes TEXT,
status TEXT DEFAULT 'active',
proxy_used TEXT,
metadata TEXT
);
-- Proxy-Nutzungen-Tabelle
CREATE TABLE IF NOT EXISTS proxy_usage (
id INTEGER PRIMARY KEY AUTOINCREMENT,
proxy_type TEXT NOT NULL,
proxy_string TEXT NOT NULL,
used_at TEXT NOT NULL,
success INTEGER DEFAULT 0,
account_id INTEGER,
FOREIGN KEY (account_id) REFERENCES accounts (id)
);
-- Fehler-Protokoll-Tabelle
CREATE TABLE IF NOT EXISTS error_logs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
error_type TEXT NOT NULL,
error_message TEXT NOT NULL,
stack_trace TEXT,
timestamp TEXT NOT NULL,
account_id INTEGER,
proxy_used TEXT,
FOREIGN KEY (account_id) REFERENCES accounts (id)
);
-- Einstellungen-Tabelle
CREATE TABLE IF NOT EXISTS settings (
key TEXT PRIMARY KEY,
value TEXT NOT NULL,
updated_at TEXT NOT NULL
);
-- SMS-Verifizierungen-Tabelle
CREATE TABLE IF NOT EXISTS sms_verifications (
id INTEGER PRIMARY KEY AUTOINCREMENT,
phone_number TEXT NOT NULL,
verification_code TEXT,
service_name TEXT NOT NULL DEFAULT 'instagram',
timestamp TEXT NOT NULL,
status TEXT DEFAULT 'pending',
account_id INTEGER,
FOREIGN KEY (account_id) REFERENCES accounts (id)
);
-- E-Mail-Verifizierungen-Tabelle
CREATE TABLE IF NOT EXISTS email_verifications (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email_address TEXT NOT NULL,
verification_code TEXT,
service_name TEXT NOT NULL DEFAULT 'instagram',
timestamp TEXT NOT NULL,
status TEXT DEFAULT 'pending',
account_id INTEGER,
FOREIGN KEY (account_id) REFERENCES accounts (id)
);
-- Lizenzen-Tabelle
CREATE TABLE IF NOT EXISTS licenses (
id INTEGER PRIMARY KEY AUTOINCREMENT,
license_key TEXT NOT NULL UNIQUE,
activated_at TEXT,
expires_at TEXT,
status TEXT DEFAULT 'inactive',
hardware_id TEXT,
metadata TEXT
);
-- Nutzungsdaten-Tabelle (für Statistiken)
CREATE TABLE IF NOT EXISTS usage_stats (
id INTEGER PRIMARY KEY AUTOINCREMENT,
action_type TEXT NOT NULL,
timestamp TEXT NOT NULL,
success INTEGER DEFAULT 0,
details TEXT
);
-- Indizes für bessere Performance
CREATE INDEX IF NOT EXISTS idx_accounts_username ON accounts(username);
CREATE INDEX IF NOT EXISTS idx_accounts_email ON accounts(email);
CREATE INDEX IF NOT EXISTS idx_accounts_status ON accounts(status);
CREATE INDEX IF NOT EXISTS idx_accounts_created_at ON accounts(created_at);
CREATE INDEX IF NOT EXISTS idx_proxy_usage_proxy_type ON proxy_usage(proxy_type);
CREATE INDEX IF NOT EXISTS idx_proxy_usage_used_at ON proxy_usage(used_at);
CREATE INDEX IF NOT EXISTS idx_error_logs_error_type ON error_logs(error_type);
CREATE INDEX IF NOT EXISTS idx_error_logs_timestamp ON error_logs(timestamp);
CREATE INDEX IF NOT EXISTS idx_sms_verifications_phone ON sms_verifications(phone_number);
CREATE INDEX IF NOT EXISTS idx_email_verifications_email ON email_verifications(email_address);
CREATE INDEX IF NOT EXISTS idx_licenses_key ON licenses(license_key);
CREATE INDEX IF NOT EXISTS idx_usage_stats_action_type ON usage_stats(action_type);
CREATE INDEX IF NOT EXISTS idx_usage_stats_timestamp ON usage_stats(timestamp);
-- Beispieldaten für Testzwecke
INSERT OR IGNORE INTO settings (key, value, updated_at)
VALUES ('app_version', '1.0.0', datetime('now'));
INSERT OR IGNORE INTO settings (key, value, updated_at)
VALUES ('last_update_check', datetime('now'), datetime('now'));