Backeup configs & cleanup of files and db

This commit is contained in:
IGNY8 VPS (Salman)
2026-01-13 03:31:20 +00:00
parent b5787081e2
commit f46fbe4343
70 changed files with 26362 additions and 6502 deletions

View File

@@ -374,100 +374,10 @@ class ContentSyncService:
Returns:
dict: Sync result with synced_count
"""
try:
from igny8_core.business.site_building.models import SiteBlueprint
from igny8_core.business.site_building.services.taxonomy_service import TaxonomyService
# Get or create site blueprint for this site
blueprint = SiteBlueprint.objects.filter(
account=integration.account,
site=integration.site
).first()
if not blueprint:
logger.warning(f"No blueprint found for site {integration.site.id}, skipping taxonomy sync")
return {'success': True, 'synced_count': 0}
taxonomy_service = TaxonomyService()
synced_count = 0
# Sync WordPress categories
categories = client.get_categories(per_page=100)
category_records = [
{
'name': cat['name'],
'slug': cat['slug'],
'description': cat.get('description', ''),
'taxonomy_type': 'blog_category',
'external_reference': str(cat['id']),
'metadata': {'parent': cat.get('parent', 0)}
}
for cat in categories
]
if category_records:
taxonomy_service.import_from_external(
blueprint,
category_records,
default_type='blog_category'
)
synced_count += len(category_records)
# Sync WordPress tags
tags = client.get_tags(per_page=100)
tag_records = [
{
'name': tag['name'],
'slug': tag['slug'],
'description': tag.get('description', ''),
'taxonomy_type': 'blog_tag',
'external_reference': str(tag['id'])
}
for tag in tags
]
if tag_records:
taxonomy_service.import_from_external(
blueprint,
tag_records,
default_type='blog_tag'
)
synced_count += len(tag_records)
# Sync WooCommerce product categories if available (401 is expected if WooCommerce not installed or credentials missing)
try:
product_categories = client.get_product_categories(per_page=100)
product_category_records = [
{
'name': cat['name'],
'slug': cat['slug'],
'description': cat.get('description', ''),
'taxonomy_type': 'product_category',
'external_reference': f"wc_cat_{cat['id']}",
'metadata': {'parent': cat.get('parent', 0)}
}
for cat in product_categories
]
if product_category_records:
taxonomy_service.import_from_external(
blueprint,
product_category_records,
default_type='product_category'
)
synced_count += len(product_category_records)
except Exception as e:
# Silently skip WooCommerce if not available (401 means no consumer key/secret configured or plugin not installed)
logger.debug(f"WooCommerce product categories not available: {e}")
return {
'success': True,
'synced_count': synced_count
}
except Exception as e:
logger.error(f"Error syncing taxonomies from WordPress: {e}", exc_info=True)
return {
'success': False,
'error': str(e),
'synced_count': 0
}
# REMOVED: Legacy SiteBlueprint taxonomy sync removed.
# Taxonomy management now uses ContentTaxonomy model.
logger.info(f"Skipping legacy taxonomy sync for site {integration.site.id}")
return {'success': True, 'synced_count': 0}
def _sync_taxonomies_to_wordpress(
self,

View File

@@ -308,11 +308,14 @@ class SyncHealthService:
"""
Detect mismatches between IGNY8 and WordPress.
DEPRECATED: Legacy SiteBlueprint taxonomy mismatch detection removed.
Taxonomy management now uses ContentTaxonomy model.
Args:
integration: SiteIntegration instance
Returns:
dict: Mismatch details
dict: Mismatch details (empty for now)
"""
mismatches = {
'taxonomies': {
@@ -330,116 +333,8 @@ class SyncHealthService:
}
}
try:
from igny8_core.utils.wordpress import WordPressClient
from igny8_core.business.site_building.models import SiteBlueprint, SiteBlueprintTaxonomy
from igny8_core.business.content.models import Content
credentials = integration.get_credentials()
client = WordPressClient(
site_url=integration.config_json.get('site_url', ''),
username=credentials.get('username'),
app_password=credentials.get('app_password')
)
# Get site blueprint
blueprint = SiteBlueprint.objects.filter(
account=integration.account,
site=integration.site
).first()
if not blueprint:
return mismatches
# Check taxonomy mismatches
# Get IGNY8 taxonomies
igny8_taxonomies = SiteBlueprintTaxonomy.objects.filter(
site_blueprint=blueprint
)
# Get WordPress categories
wp_categories = client.get_categories(per_page=100)
wp_category_ids = {str(cat['id']): cat for cat in wp_categories}
# Get WordPress tags
wp_tags = client.get_tags(per_page=100)
wp_tag_ids = {str(tag['id']): tag for tag in wp_tags}
for taxonomy in igny8_taxonomies:
if taxonomy.external_reference:
# Check if still exists in WordPress
if taxonomy.taxonomy_type in ['blog_category', 'product_category']:
if taxonomy.external_reference not in wp_category_ids:
mismatches['taxonomies']['missing_in_wordpress'].append({
'id': taxonomy.id,
'name': taxonomy.name,
'type': taxonomy.taxonomy_type,
'external_reference': taxonomy.external_reference
})
elif taxonomy.taxonomy_type in ['blog_tag', 'product_tag']:
if taxonomy.external_reference not in wp_tag_ids:
mismatches['taxonomies']['missing_in_wordpress'].append({
'id': taxonomy.id,
'name': taxonomy.name,
'type': taxonomy.taxonomy_type,
'external_reference': taxonomy.external_reference
})
else:
# Taxonomy exists in IGNY8 but not synced to WordPress
mismatches['taxonomies']['missing_in_wordpress'].append({
'id': taxonomy.id,
'name': taxonomy.name,
'type': taxonomy.taxonomy_type
})
# Check for WordPress taxonomies not in IGNY8
for cat in wp_categories:
if not SiteBlueprintTaxonomy.objects.filter(
site_blueprint=blueprint,
external_reference=str(cat['id'])
).exists():
mismatches['taxonomies']['missing_in_igny8'].append({
'name': cat['name'],
'slug': cat['slug'],
'type': 'blog_category',
'external_reference': str(cat['id'])
})
for tag in wp_tags:
if not SiteBlueprintTaxonomy.objects.filter(
site_blueprint=blueprint,
external_reference=str(tag['id'])
).exists():
mismatches['taxonomies']['missing_in_igny8'].append({
'name': tag['name'],
'slug': tag['slug'],
'type': 'blog_tag',
'external_reference': str(tag['id'])
})
# Check content mismatches (basic check)
igny8_content = Content.objects.filter(
account=integration.account,
site=integration.site,
source='igny8',
status='publish'
)
for content in igny8_content[:50]: # Limit check
if content.metadata and content.metadata.get('wordpress_id'):
# Content should exist in WordPress (would need to check)
# For now, just note if metadata exists
pass
else:
# Content not synced to WordPress
mismatches['posts']['missing_in_wordpress'].append({
'id': content.id,
'title': content.title,
'type': content.content_type
})
except Exception as e:
logger.warning(f"Error detecting WordPress mismatches: {e}")
# Legacy taxonomy detection removed - would need to be reimplemented with ContentTaxonomy
logger.info(f"Mismatch detection for integration {integration.id} - legacy code removed")
return mismatches

View File

@@ -1,5 +0,0 @@
"""
Integration Tests
Phase 6: Site Integration & Multi-Destination Publishing
"""

View File

@@ -1,155 +0,0 @@
"""
Tests for ContentSyncService
Phase 6: Site Integration & Multi-Destination Publishing
"""
from django.test import TestCase
from unittest.mock import patch, Mock
from igny8_core.auth.models import Account, Site, Sector, User, Plan, Industry, IndustrySector
from igny8_core.business.integration.models import SiteIntegration
from igny8_core.business.integration.services.content_sync_service import ContentSyncService
from igny8_core.business.content.models import Content
class ContentSyncServiceTestCase(TestCase):
"""Test cases for ContentSyncService"""
def setUp(self):
"""Set up test data"""
# Create plan first
self.plan = Plan.objects.create(
name="Test Plan",
slug="test-plan",
price=0,
credits_per_month=1000
)
# Create user first (Account needs owner)
self.user = User.objects.create_user(
username='testuser',
email='test@test.com',
password='testpass123',
role='owner'
)
# Create account with owner
self.account = Account.objects.create(
name="Test Account",
slug="test-account",
plan=self.plan,
owner=self.user
)
# Update user to have account
self.user.account = self.account
self.user.save()
# Create industry and sector
self.industry = Industry.objects.create(
name="Test Industry",
slug="test-industry"
)
self.industry_sector = IndustrySector.objects.create(
industry=self.industry,
name="Test Sector",
slug="test-sector"
)
self.site = Site.objects.create(
account=self.account,
name="Test Site",
slug="test-site",
industry=self.industry
)
self.sector = Sector.objects.create(
account=self.account,
site=self.site,
industry_sector=self.industry_sector,
name="Test Sector",
slug="test-sector"
)
self.integration = SiteIntegration.objects.create(
account=self.account,
site=self.site,
platform='wordpress',
platform_type='cms',
sync_enabled=True
)
self.service = ContentSyncService()
def test_sync_content_from_wordpress_creates_content(self):
"""Test: WordPress sync works (when plugin connected)"""
mock_posts = [
{
'id': 1,
'title': 'Test Post',
'content': '<p>Test content</p>',
'status': 'publish',
}
]
with patch.object(self.service, '_fetch_wordpress_posts') as mock_fetch:
mock_fetch.return_value = mock_posts
result = self.service.sync_from_wordpress(self.integration)
self.assertTrue(result.get('success'))
self.assertEqual(result.get('synced_count'), 1)
# Verify content was created
content = Content.objects.filter(site=self.site).first()
self.assertIsNotNone(content)
self.assertEqual(content.title, 'Test Post')
self.assertEqual(content.source, 'wordpress')
def test_sync_content_from_shopify_creates_content(self):
"""Test: Content sync works"""
mock_products = [
{
'id': 1,
'title': 'Test Product',
'body_html': '<p>Product description</p>',
}
]
with patch.object(self.service, '_fetch_shopify_products') as mock_fetch:
mock_fetch.return_value = mock_products
result = self.service.sync_from_shopify(self.integration)
self.assertTrue(result.get('success'))
self.assertEqual(result.get('synced_count'), 1)
def test_sync_handles_duplicate_content(self):
"""Test: Content sync works"""
# Create existing content
Content.objects.create(
account=self.account,
site=self.site,
sector=self.sector,
title="Test Post",
html_content="<p>Existing</p>",
source='wordpress'
)
mock_posts = [
{
'id': 1,
'title': 'Test Post',
'content': '<p>Updated content</p>',
}
]
with patch.object(self.service, '_fetch_wordpress_posts') as mock_fetch:
mock_fetch.return_value = mock_posts
result = self.service.sync_from_wordpress(self.integration)
# Should update existing, not create duplicate
content_count = Content.objects.filter(
site=self.site,
title='Test Post'
).count()
self.assertEqual(content_count, 1)

View File

@@ -1,141 +0,0 @@
"""
Tests for IntegrationService
Phase 6: Site Integration & Multi-Destination Publishing
"""
from django.test import TestCase
from igny8_core.auth.models import Account, Site, Sector, User, Plan, Industry, IndustrySector
from igny8_core.business.integration.models import SiteIntegration
from igny8_core.business.integration.services.integration_service import IntegrationService
class IntegrationServiceTestCase(TestCase):
"""Test cases for IntegrationService"""
def setUp(self):
"""Set up test data"""
# Create plan first
self.plan = Plan.objects.create(
name="Test Plan",
slug="test-plan",
price=0,
credits_per_month=1000
)
# Create user first (Account needs owner)
self.user = User.objects.create_user(
username='testuser',
email='test@test.com',
password='testpass123',
role='owner'
)
# Create account with owner
self.account = Account.objects.create(
name="Test Account",
slug="test-account",
plan=self.plan,
owner=self.user
)
# Update user to have account
self.user.account = self.account
self.user.save()
# Create industry and sector
self.industry = Industry.objects.create(
name="Test Industry",
slug="test-industry"
)
self.industry_sector = IndustrySector.objects.create(
industry=self.industry,
name="Test Sector",
slug="test-sector"
)
self.site = Site.objects.create(
account=self.account,
name="Test Site",
slug="test-site",
industry=self.industry
)
self.sector = Sector.objects.create(
account=self.account,
site=self.site,
industry_sector=self.industry_sector,
name="Test Sector",
slug="test-sector"
)
self.service = IntegrationService()
def test_create_integration_stores_config(self):
"""Test: Site integrations work correctly"""
integration = self.service.create_integration(
site=self.site,
platform='wordpress',
config={'url': 'https://example.com'},
credentials={'api_key': 'test-key'},
platform_type='cms'
)
self.assertIsNotNone(integration)
self.assertEqual(integration.platform, 'wordpress')
self.assertEqual(integration.platform_type, 'cms')
self.assertEqual(integration.config_json.get('url'), 'https://example.com')
self.assertTrue(integration.is_active)
def test_get_integrations_for_site_returns_all(self):
"""Test: Site integrations work correctly"""
self.service.create_integration(
site=self.site,
platform='wordpress',
config={},
credentials={}
)
self.service.create_integration(
site=self.site,
platform='shopify',
config={},
credentials={}
)
integrations = self.service.get_integrations_for_site(self.site)
self.assertEqual(integrations.count(), 2)
platforms = [i.platform for i in integrations]
self.assertIn('wordpress', platforms)
self.assertIn('shopify', platforms)
def test_test_connection_validates_credentials(self):
"""Test: Site integrations work correctly"""
# Test with unsupported platform to verify NotImplementedError is raised
integration = self.service.create_integration(
site=self.site,
platform='unsupported_platform',
config={'url': 'https://example.com'},
credentials={'api_key': 'test-key'}
)
with self.assertRaises(NotImplementedError):
# Connection testing should raise NotImplementedError for unsupported platforms
self.service.test_connection(integration)
def test_update_integration_updates_fields(self):
"""Test: Site integrations work correctly"""
integration = self.service.create_integration(
site=self.site,
platform='wordpress',
config={'url': 'https://old.com'},
credentials={}
)
updated = self.service.update_integration(
integration,
config={'url': 'https://new.com'},
is_active=False
)
self.assertEqual(updated.config_json.get('url'), 'https://new.com')
self.assertFalse(updated.is_active)

View File

@@ -1,127 +0,0 @@
"""
Tests for SyncService
Phase 6: Site Integration & Multi-Destination Publishing
"""
from django.test import TestCase
from django.utils import timezone
from unittest.mock import patch, Mock
from igny8_core.auth.models import Account, Site, Sector, User, Plan, Industry, IndustrySector
from igny8_core.business.integration.models import SiteIntegration
from igny8_core.business.integration.services.sync_service import SyncService
class SyncServiceTestCase(TestCase):
"""Test cases for SyncService"""
def setUp(self):
"""Set up test data"""
# Create plan first
self.plan = Plan.objects.create(
name="Test Plan",
slug="test-plan",
price=0,
credits_per_month=1000
)
# Create user first (Account needs owner)
self.user = User.objects.create_user(
username='testuser',
email='test@test.com',
password='testpass123',
role='owner'
)
# Create account with owner
self.account = Account.objects.create(
name="Test Account",
slug="test-account",
plan=self.plan,
owner=self.user
)
# Update user to have account
self.user.account = self.account
self.user.save()
# Create industry and sector
self.industry = Industry.objects.create(
name="Test Industry",
slug="test-industry"
)
self.industry_sector = IndustrySector.objects.create(
industry=self.industry,
name="Test Sector",
slug="test-sector"
)
self.site = Site.objects.create(
account=self.account,
name="Test Site",
slug="test-site",
industry=self.industry
)
self.sector = Sector.objects.create(
account=self.account,
site=self.site,
industry_sector=self.industry_sector,
name="Test Sector",
slug="test-sector"
)
self.integration = SiteIntegration.objects.create(
account=self.account,
site=self.site,
platform='wordpress',
platform_type='cms',
sync_enabled=True,
sync_status='pending'
)
self.service = SyncService()
def test_sync_updates_status(self):
"""Test: Two-way sync functions properly"""
with patch.object(self.service, '_sync_to_external') as mock_sync_to, \
patch.object(self.service, '_sync_from_external') as mock_sync_from:
mock_sync_to.return_value = {'success': True, 'synced': 5}
mock_sync_from.return_value = {'success': True, 'synced': 3}
result = self.service.sync(self.integration, direction='both')
self.assertTrue(result.get('success'))
self.integration.refresh_from_db()
self.assertEqual(self.integration.sync_status, 'success')
self.assertIsNotNone(self.integration.last_sync_at)
def test_sync_to_external_only(self):
"""Test: Two-way sync functions properly"""
with patch.object(self.service, '_sync_to_external') as mock_sync_to:
mock_sync_to.return_value = {'success': True, 'synced': 5}
result = self.service.sync(self.integration, direction='to_external')
self.assertTrue(result.get('success'))
mock_sync_to.assert_called_once()
def test_sync_from_external_only(self):
"""Test: WordPress sync works (when plugin connected)"""
with patch.object(self.service, '_sync_from_external') as mock_sync_from:
mock_sync_from.return_value = {'success': True, 'synced': 3}
result = self.service.sync(self.integration, direction='from_external')
self.assertTrue(result.get('success'))
mock_sync_from.assert_called_once()
def test_sync_handles_errors(self):
"""Test: Two-way sync functions properly"""
with patch.object(self.service, '_sync_to_external') as mock_sync_to:
mock_sync_to.side_effect = Exception("Sync failed")
result = self.service.sync(self.integration, direction='to_external')
self.assertFalse(result.get('success'))
self.integration.refresh_from_db()
self.assertEqual(self.integration.sync_status, 'failed')
self.assertIsNotNone(self.integration.sync_error)