Recovered state: integrated TrendSurferAgent, restored frontend/backend files, and cleaned up recovery scripts

This commit is contained in:
ajaysi
2026-02-08 13:56:57 +05:30
parent 1db10ccd0f
commit e404a86502
333 changed files with 42223 additions and 10875 deletions

View File

@@ -14,11 +14,12 @@ import json
from urllib.parse import quote
from ..analytics_cache_service import analytics_cache
from services.database import get_user_db_path
class BingOAuthService:
"""Manages Bing Webmaster Tools OAuth2 authentication flow."""
def __init__(self, db_path: str = "alwrity.db"):
self.db_path = db_path
def __init__(self):
# Bing Webmaster OAuth2 credentials
self.client_id = os.getenv('BING_CLIENT_ID', '')
self.client_secret = os.getenv('BING_CLIENT_SECRET', '')
@@ -26,16 +27,20 @@ class BingOAuthService:
self.base_url = "https://www.bing.com"
self.api_base_url = "https://www.bing.com/webmaster/api.svc/json"
# Validate configuration
if not self.client_id or not self.client_secret or self.client_id == 'your_bing_client_id_here':
logger.error("Bing Webmaster OAuth client credentials not configured. Please set BING_CLIENT_ID and BING_CLIENT_SECRET environment variables with valid Bing Webmaster application credentials.")
logger.error("To get credentials: 1. Go to https://www.bing.com/webmasters/ 2. Sign in to Bing Webmaster Tools 3. Go to Settings > API Access 4. Create OAuth client")
self._init_db()
logger.warning("Bing Webmaster OAuth client credentials not configured. Please set BING_CLIENT_ID and BING_CLIENT_SECRET environment variables with valid Bing Webmaster application credentials.")
logger.warning("To get credentials: 1. Go to https://www.bing.com/webmasters/ 2. Sign in to Bing Webmaster Tools 3. Go to Settings > API Access 4. Create OAuth client")
def _init_db(self):
def _get_db_path(self, user_id: str) -> str:
return get_user_db_path(user_id)
def _init_db(self, user_id: str):
"""Initialize database tables for OAuth tokens."""
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
# Ensure directory exists
os.makedirs(os.path.dirname(db_path), exist_ok=True)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS bing_oauth_tokens (
@@ -62,21 +67,26 @@ class BingOAuthService:
)
''')
conn.commit()
logger.info("Bing Webmaster OAuth database initialized.")
def generate_authorization_url(self, user_id: str, scope: str = "webmaster.manage") -> Dict[str, Any]:
"""Generate Bing Webmaster OAuth2 authorization URL."""
try:
# Check if credentials are properly configured
if not self.client_id or not self.client_secret or self.client_id == 'your_bing_client_id_here':
logger.error("Bing Webmaster OAuth client credentials not configured")
logger.warning("Bing Webmaster OAuth client credentials not configured")
return None
# Generate secure state parameter
state = secrets.token_urlsafe(32)
# Generate secure state parameter with user_id embedded
# Format: user_id:random_token
random_token = secrets.token_urlsafe(32)
state = f"{user_id}:{random_token}"
# Ensure DB tables exist for this user
self._init_db(user_id)
db_path = self._get_db_path(user_id)
# Store state in database for validation
with sqlite3.connect(self.db_path) as conn:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
INSERT INTO bing_oauth_states (state, user_id, expires_at)
@@ -111,8 +121,23 @@ class BingOAuthService:
try:
logger.info(f"Bing Webmaster OAuth callback started - code: {code[:20]}..., state: {state[:20]}...")
# Extract user_id from state
if ':' not in state:
logger.error(f"Invalid state format (missing user_id): {state[:20]}...")
return None
user_id = state.split(':')[0]
if not user_id:
logger.error("Empty user_id in state")
return None
db_path = self._get_db_path(user_id)
if not os.path.exists(db_path):
logger.error(f"User database not found for user {user_id}")
return None
# Validate state parameter
with sqlite3.connect(self.db_path) as conn:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
# First, look up the state regardless of expiry to provide clearer logs
cursor.execute('''
@@ -126,7 +151,13 @@ class BingOAuthService:
logger.error(f"Bing OAuth: State not found or already used. state='{state[:12]}...'")
return None
user_id, created_at, expires_at = row
db_user_id, created_at, expires_at = row
# Verify user_id matches
if db_user_id != user_id:
logger.error(f"Bing OAuth: State user_id mismatch. Expected {user_id}, got {db_user_id}")
return None
# Check expiry explicitly
cursor.execute("SELECT datetime('now') < ?", (expires_at,))
not_expired = cursor.fetchone()[0] == 1
@@ -180,7 +211,7 @@ class BingOAuthService:
# Calculate expiration
expires_at = datetime.now() + timedelta(seconds=expires_in)
with sqlite3.connect(self.db_path) as conn:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
INSERT INTO bing_oauth_tokens
@@ -191,6 +222,7 @@ class BingOAuthService:
logger.info(f"Bing OAuth: Token inserted into database for user {user_id}")
# Proactively fetch and cache user sites using the fresh token
try:
headers = {'Authorization': f'Bearer {access_token}'}
response = requests.get(
@@ -245,7 +277,11 @@ class BingOAuthService:
Returns number of rows deleted.
"""
try:
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
if not os.path.exists(db_path):
return 0
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
# Delete tokens that are expired or explicitly inactive
cursor.execute('''
@@ -268,7 +304,11 @@ class BingOAuthService:
def get_user_tokens(self, user_id: str) -> List[Dict[str, Any]]:
"""Get all active Bing tokens for a user."""
try:
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
if not os.path.exists(db_path):
return []
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
SELECT id, access_token, refresh_token, token_type, expires_at, scope, created_at
@@ -288,17 +328,19 @@ class BingOAuthService:
"scope": row[5],
"created_at": row[6]
})
return tokens
except Exception as e:
logger.error(f"Error getting Bing tokens for user {user_id}: {e}")
logger.error(f"Error retrieving Bing tokens for user {user_id}: {e}")
return []
def get_user_token_status(self, user_id: str) -> Dict[str, Any]:
"""Get detailed token status for a user including expired tokens."""
"""Get status of Bing OAuth tokens for a user."""
try:
with sqlite3.connect(self.db_path) as conn:
# Ensure DB tables exist for this user before querying
self._init_db(user_id)
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
# Get all tokens (active and expired)
@@ -437,7 +479,8 @@ class BingOAuthService:
expires_in = token_info.get('expires_in', 3600)
expires_at = datetime.now() + timedelta(seconds=expires_in)
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
UPDATE bing_oauth_tokens
@@ -467,7 +510,8 @@ class BingOAuthService:
def revoke_token(self, user_id: str, token_id: int) -> bool:
"""Revoke a Bing OAuth token."""
try:
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
UPDATE bing_oauth_tokens
@@ -566,13 +610,13 @@ class BingOAuthService:
if refreshed_token:
logger.info(f"Bing get_user_sites: Token {i+1} refreshed successfully")
# Update the token in the database
self.update_token_in_db(token["id"], refreshed_token)
self.update_token_in_db(user_id, token["id"], refreshed_token)
# Use the new token
token["access_token"] = refreshed_token["access_token"]
else:
logger.warning(f"Bing get_user_sites: Failed to refresh token {i+1} - refresh token may be expired")
# Mark token as inactive since refresh failed
self.mark_token_inactive(token["id"])
self.mark_token_inactive(user_id, token["id"])
continue
else:
logger.warning(f"Bing get_user_sites: No refresh token available for token {i+1}")
@@ -639,10 +683,11 @@ class BingOAuthService:
logger.error(f"Error getting Bing user sites: {e}")
return []
def update_token_in_db(self, token_id: str, refreshed_token: Dict[str, Any]) -> bool:
def update_token_in_db(self, user_id: str, token_id: str, refreshed_token: Dict[str, Any]) -> bool:
"""Update the access token in the database after refresh."""
try:
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
# Compute expires_at from expires_in if expires_at missing
expires_at_value = refreshed_token.get("expires_at")
@@ -667,10 +712,11 @@ class BingOAuthService:
logger.error(f"Error updating Bing token in database: {e}")
return False
def mark_token_inactive(self, token_id: str) -> bool:
def mark_token_inactive(self, user_id: str, token_id: str) -> bool:
"""Mark a token as inactive in the database."""
try:
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
UPDATE bing_oauth_tokens
@@ -922,4 +968,4 @@ class BingOAuthService:
except Exception as e:
logger.error(f"Error getting comprehensive Bing analytics: {e}")
return {"error": str(e)}
return {"error": str(e)}

View File

@@ -10,16 +10,26 @@ from datetime import datetime, timedelta
from loguru import logger
from services.database import get_user_db_path
class WixOAuthService:
"""Manages Wix OAuth2 authentication flow and token storage."""
def __init__(self, db_path: str = "alwrity.db"):
def __init__(self, db_path: Optional[str] = None):
self.db_path = db_path
self._init_db()
def _init_db(self):
def _get_db_path(self, user_id: str) -> str:
if self.db_path:
return self.db_path
return get_user_db_path(user_id)
def _init_db(self, user_id: str):
"""Initialize database tables for OAuth tokens."""
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
# Ensure directory exists
os.makedirs(os.path.dirname(db_path), exist_ok=True)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS wix_oauth_tokens (
@@ -39,7 +49,6 @@ class WixOAuthService:
)
''')
conn.commit()
logger.info("Wix OAuth database initialized.")
def store_tokens(
self,
@@ -69,11 +78,15 @@ class WixOAuthService:
True if tokens were stored successfully
"""
try:
# Ensure DB is initialized for this user
self._init_db(user_id)
db_path = self._get_db_path(user_id)
expires_at = None
if expires_in:
expires_at = datetime.now() + timedelta(seconds=expires_in)
with sqlite3.connect(self.db_path) as conn:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
INSERT INTO wix_oauth_tokens
@@ -92,7 +105,14 @@ class WixOAuthService:
def get_user_tokens(self, user_id: str) -> List[Dict[str, Any]]:
"""Get all active Wix tokens for a user."""
try:
with sqlite3.connect(self.db_path) as conn:
# Ensure database tables exist to prevent 'no such table' errors
self._init_db(user_id)
db_path = self._get_db_path(user_id)
if not os.path.exists(db_path):
return []
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
SELECT id, access_token, refresh_token, token_type, expires_at, expires_in, scope, site_id, member_id, created_at
@@ -125,7 +145,22 @@ class WixOAuthService:
def get_user_token_status(self, user_id: str) -> Dict[str, Any]:
"""Get detailed token status for a user including expired tokens."""
try:
with sqlite3.connect(self.db_path) as conn:
# Ensure database tables exist to prevent 'no such table' errors
self._init_db(user_id)
db_path = self._get_db_path(user_id)
if not os.path.exists(db_path):
return {
"has_tokens": False,
"has_active_tokens": False,
"has_expired_tokens": False,
"active_tokens": [],
"expired_tokens": [],
"total_tokens": 0,
"last_token_date": None
}
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
# Get all tokens (active and expired)
@@ -213,11 +248,15 @@ class WixOAuthService:
) -> bool:
"""Update tokens for a user (e.g., after refresh)."""
try:
# Ensure DB initialized for this user
self._init_db(user_id)
db_path = self._get_db_path(user_id)
expires_at = None
if expires_in:
expires_at = datetime.now() + timedelta(seconds=expires_in)
with sqlite3.connect(self.db_path) as conn:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
if refresh_token:
cursor.execute('''
@@ -245,7 +284,8 @@ class WixOAuthService:
def revoke_token(self, user_id: str, token_id: int) -> bool:
"""Revoke a Wix OAuth token."""
try:
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
UPDATE wix_oauth_tokens

View File

@@ -13,10 +13,13 @@ from loguru import logger
import json
import base64
from services.database import get_user_db_path
class WordPressOAuthService:
"""Manages WordPress.com OAuth2 authentication flow."""
def __init__(self, db_path: str = "alwrity.db"):
def __init__(self, db_path: str = None):
# db_path is deprecated in favor of dynamic user_id based paths
self.db_path = db_path
# WordPress.com OAuth2 credentials
self.client_id = os.getenv('WORDPRESS_CLIENT_ID', '')
@@ -29,11 +32,15 @@ class WordPressOAuthService:
logger.error("WordPress OAuth client credentials not configured. Please set WORDPRESS_CLIENT_ID and WORDPRESS_CLIENT_SECRET environment variables with valid WordPress.com application credentials.")
logger.error("To get credentials: 1. Go to https://developer.wordpress.com/apps/ 2. Create a new application 3. Set redirect URI to: https://your-domain.com/wp/callback")
self._init_db()
def _get_db_path(self, user_id: str) -> str:
return get_user_db_path(user_id)
def _init_db(self):
def _init_db(self, user_id: str):
"""Initialize database tables for OAuth tokens."""
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
os.makedirs(os.path.dirname(db_path), exist_ok=True)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS wordpress_oauth_tokens (
@@ -61,7 +68,6 @@ class WordPressOAuthService:
)
''')
conn.commit()
logger.info("WordPress OAuth database initialized.")
def generate_authorization_url(self, user_id: str, scope: str = "global") -> Dict[str, Any]:
"""Generate WordPress OAuth2 authorization URL."""
@@ -71,11 +77,15 @@ class WordPressOAuthService:
logger.error("WordPress OAuth client credentials not configured")
return None
# Generate secure state parameter
state = secrets.token_urlsafe(32)
# Generate secure state parameter with user_id for routing
random_token = secrets.token_urlsafe(32)
state = f"{user_id}:{random_token}"
# Store state in database for validation
with sqlite3.connect(self.db_path) as conn:
self._init_db(user_id)
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
INSERT INTO wordpress_oauth_states (state, user_id)
@@ -111,8 +121,20 @@ class WordPressOAuthService:
try:
logger.info(f"WordPress OAuth callback started - code: {code[:20]}..., state: {state[:20]}...")
# Extract user_id from state
if ':' not in state:
logger.error(f"Invalid WordPress state format: {state}")
return None
user_id = state.split(':')[0]
db_path = self._get_db_path(user_id)
if not os.path.exists(db_path):
logger.error(f"User database not found for user {user_id}")
return None
# Validate state parameter
with sqlite3.connect(self.db_path) as conn:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
SELECT user_id FROM wordpress_oauth_states
@@ -124,9 +146,6 @@ class WordPressOAuthService:
logger.error(f"Invalid or expired state parameter: {state}")
return None
user_id = result[0]
logger.info(f"WordPress OAuth: State validated for user {user_id}")
# Clean up used state
cursor.execute('DELETE FROM wordpress_oauth_states WHERE state = ?', (state,))
conn.commit()
@@ -163,7 +182,7 @@ class WordPressOAuthService:
# Calculate expiration (WordPress tokens typically expire in 2 weeks)
expires_at = datetime.now() + timedelta(days=14)
with sqlite3.connect(self.db_path) as conn:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
INSERT INTO wordpress_oauth_tokens
@@ -190,7 +209,14 @@ class WordPressOAuthService:
def get_user_tokens(self, user_id: str) -> List[Dict[str, Any]]:
"""Get all active WordPress tokens for a user."""
try:
with sqlite3.connect(self.db_path) as conn:
# Ensure database tables exist to prevent 'no such table' errors
self._init_db(user_id)
db_path = self._get_db_path(user_id)
if not os.path.exists(db_path):
return []
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
SELECT id, access_token, token_type, expires_at, scope, blog_id, blog_url, created_at
@@ -221,7 +247,22 @@ class WordPressOAuthService:
def get_user_token_status(self, user_id: str) -> Dict[str, Any]:
"""Get detailed token status for a user including expired tokens."""
try:
with sqlite3.connect(self.db_path) as conn:
# Ensure database tables exist to prevent 'no such table' errors
self._init_db(user_id)
db_path = self._get_db_path(user_id)
if not os.path.exists(db_path):
return {
"has_tokens": False,
"has_active_tokens": False,
"has_expired_tokens": False,
"active_tokens": [],
"expired_tokens": [],
"total_tokens": 0,
"last_token_date": None
}
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
# Get all tokens (active and expired)
@@ -318,7 +359,8 @@ class WordPressOAuthService:
def revoke_token(self, user_id: str, token_id: int) -> bool:
"""Revoke a WordPress OAuth token."""
try:
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
UPDATE wordpress_oauth_tokens

View File

@@ -15,13 +15,57 @@ from .wordpress_content import WordPressContentManager
import sqlite3
from services.database import get_user_db_path
class WordPressPublisher:
"""High-level WordPress publishing service."""
"""Handles publishing content to WordPress."""
def __init__(self, db_path: str = "alwrity.db"):
"""Initialize WordPress publisher."""
self.wp_service = WordPressService(db_path)
def __init__(self, db_path: str = None):
# db_path is deprecated
self.db_path = db_path
def _get_db_path(self, user_id: str) -> str:
return get_user_db_path(user_id)
def _init_db(self, user_id: str):
"""Initialize database tables for published posts."""
db_path = self._get_db_path(user_id)
os.makedirs(os.path.dirname(db_path), exist_ok=True)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS wordpress_posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id TEXT NOT NULL,
wp_post_id INTEGER NOT NULL,
wp_url TEXT NOT NULL,
title TEXT NOT NULL,
status TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
def save_post_info(self, user_id: str, wp_post_id: int, wp_url: str, title: str, status: str) -> bool:
"""Save information about a published post."""
try:
self._init_db(user_id)
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
INSERT INTO wordpress_posts (user_id, wp_post_id, wp_url, title, status)
VALUES (?, ?, ?, ?, ?)
''', (user_id, wp_post_id, wp_url, title, status))
conn.commit()
return True
except Exception as e:
logger.error(f"Error saving WordPress post info: {e}")
return False
def publish_blog_post(self, user_id: str, site_id: int,
title: str, content: str,

View File

@@ -17,19 +17,27 @@ from PIL import Image
from loguru import logger
from services.database import get_user_db_path
class WordPressService:
"""Main WordPress service class for managing WordPress integrations."""
"""Service for WordPress integration."""
def __init__(self, db_path: str = "alwrity.db"):
"""Initialize WordPress service with database path."""
def __init__(self, db_path: str = None):
# db_path is deprecated in favor of dynamic user_id based paths
self.db_path = db_path
self.api_version = "v2"
self._ensure_tables()
# self._ensure_tables() # Deferred to per-user calls
def _ensure_tables(self) -> None:
def _get_db_path(self, user_id: str) -> str:
return get_user_db_path(user_id)
def _ensure_tables(self, user_id: str) -> None:
"""Ensure required database tables exist."""
try:
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
os.makedirs(os.path.dirname(db_path), exist_ok=True)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
# WordPress sites table
@@ -64,10 +72,10 @@ class WordPressService:
''')
conn.commit()
logger.info("WordPress database tables ensured")
# logger.info("WordPress database tables ensured")
except Exception as e:
logger.error(f"Error ensuring WordPress tables: {e}")
logger.error(f"Error ensuring WordPress tables for user {user_id}: {e}")
raise
def add_site(self, user_id: str, site_url: str, site_name: str, username: str, app_password: str) -> bool:
@@ -82,7 +90,10 @@ class WordPressService:
logger.error(f"Failed to connect to WordPress site: {site_url}")
return False
with sqlite3.connect(self.db_path) as conn:
self._ensure_tables(user_id)
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
INSERT OR REPLACE INTO wordpress_sites
@@ -101,8 +112,18 @@ class WordPressService:
def get_user_sites(self, user_id: str) -> List[Dict[str, Any]]:
"""Get all WordPress sites for a user."""
try:
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
if not os.path.exists(db_path):
return []
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
# Check if table exists
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='wordpress_sites'")
if not cursor.fetchone():
return []
cursor.execute('''
SELECT id, site_url, site_name, username, is_active, created_at, updated_at
FROM wordpress_sites
@@ -129,16 +150,17 @@ class WordPressService:
logger.error(f"Error getting WordPress sites for user {user_id}: {e}")
return []
def get_site_credentials(self, site_id: int) -> Optional[Dict[str, str]]:
def get_site_credentials(self, user_id: str, site_id: int) -> Optional[Dict[str, str]]:
"""Get credentials for a specific WordPress site."""
try:
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
SELECT site_url, username, app_password
FROM wordpress_sites
WHERE id = ? AND is_active = 1
''', (site_id,))
WHERE id = ? AND user_id = ? AND is_active = 1
''', (site_id, user_id))
result = cursor.fetchone()
if result:
@@ -174,7 +196,8 @@ class WordPressService:
def disconnect_site(self, user_id: str, site_id: int) -> bool:
"""Disconnect a WordPress site."""
try:
with sqlite3.connect(self.db_path) as conn:
db_path = self._get_db_path(user_id)
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
UPDATE wordpress_sites
@@ -190,10 +213,10 @@ class WordPressService:
logger.error(f"Error disconnecting WordPress site {site_id}: {e}")
return False
def get_site_info(self, site_id: int) -> Optional[Dict[str, Any]]:
def get_site_info(self, user_id: str, site_id: int) -> Optional[Dict[str, Any]]:
"""Get detailed information about a WordPress site."""
try:
credentials = self.get_site_credentials(site_id)
credentials = self.get_site_credentials(user_id, site_id)
if not credentials:
return None
@@ -224,26 +247,40 @@ class WordPressService:
def get_posts_for_all_sites(self, user_id: str) -> List[Dict[str, Any]]:
"""Get all tracked WordPress posts for all sites of a user."""
with sqlite3.connect(self.db_path) as conn:
cursor = conn.cursor()
cursor.execute('''
SELECT wp.id, wp.wordpress_post_id, wp.title, wp.status, wp.published_at, wp.last_updated_at,
ws.site_name, ws.site_url
FROM wordpress_posts wp
JOIN wordpress_sites ws ON wp.site_id = ws.id
WHERE wp.user_id = ? AND ws.is_active = TRUE
ORDER BY wp.published_at DESC
''', (user_id,))
posts = []
for post_data in cursor.fetchall():
posts.append({
"id": post_data[0],
"wp_post_id": post_data[1],
"title": post_data[2],
"status": post_data[3],
"published_at": post_data[4],
"created_at": post_data[5],
"site_name": post_data[6],
"site_url": post_data[7]
})
return posts
db_path = self._get_db_path(user_id)
if not os.path.exists(db_path):
return []
try:
with sqlite3.connect(db_path) as conn:
cursor = conn.cursor()
# Check if table exists
cursor.execute("SELECT name FROM sqlite_master WHERE type='table' AND name='wordpress_posts'")
if not cursor.fetchone():
return []
cursor.execute('''
SELECT wp.id, wp.wp_post_id, wp.title, wp.status, wp.published_at, wp.created_at,
ws.site_name, ws.site_url
FROM wordpress_posts wp
JOIN wordpress_sites ws ON wp.site_id = ws.id
WHERE wp.user_id = ? AND ws.is_active = 1
ORDER BY wp.published_at DESC
''', (user_id,))
posts = []
for post_data in cursor.fetchall():
posts.append({
"id": post_data[0],
"wp_post_id": post_data[1],
"title": post_data[2],
"status": post_data[3],
"published_at": post_data[4],
"created_at": post_data[5],
"site_name": post_data[6],
"site_url": post_data[7]
})
return posts
except Exception as e:
logger.error(f"Error getting posts for user {user_id}: {e}")
return []