Add Linker and Optimizer modules with API integration and frontend components
- Added Linker and Optimizer apps to `INSTALLED_APPS` in `settings.py`. - Configured API endpoints for Linker and Optimizer in `urls.py`. - Implemented `OptimizeContentFunction` for content optimization in the AI module. - Created prompts for content optimization and site structure generation. - Updated `OptimizerService` to utilize the new AI function for content optimization. - Developed frontend components including dashboards and content lists for Linker and Optimizer. - Integrated new routes and sidebar navigation for Linker and Optimizer in the frontend. - Enhanced content management with source and sync status filters in the Writer module. - Comprehensive test coverage added for new features and components.
This commit is contained in:
2
backend/igny8_core/modules/linker/tests/__init__.py
Normal file
2
backend/igny8_core/modules/linker/tests/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
# Linker module tests
|
||||
|
||||
137
backend/igny8_core/modules/linker/tests/test_views.py
Normal file
137
backend/igny8_core/modules/linker/tests/test_views.py
Normal file
@@ -0,0 +1,137 @@
|
||||
"""
|
||||
Tests for Linker API endpoints
|
||||
"""
|
||||
from unittest.mock import patch
|
||||
from django.test import TestCase
|
||||
from rest_framework.test import APIClient
|
||||
from rest_framework import status
|
||||
from igny8_core.business.content.models import Content
|
||||
from igny8_core.business.billing.exceptions import InsufficientCreditsError
|
||||
from igny8_core.api.tests.test_integration_base import IntegrationTestBase
|
||||
|
||||
|
||||
class LinkerAPITests(IntegrationTestBase):
|
||||
"""Tests for Linker API endpoints"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.client = APIClient()
|
||||
self.client.force_authenticate(user=self.user)
|
||||
|
||||
# Create test content
|
||||
self.content = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Test Content",
|
||||
html_content="<p>Test content.</p>",
|
||||
word_count=100,
|
||||
status='draft'
|
||||
)
|
||||
|
||||
def test_process_endpoint_requires_authentication(self):
|
||||
"""Test that process endpoint requires authentication"""
|
||||
client = APIClient() # Not authenticated
|
||||
response = client.post('/api/v1/linker/process/', {
|
||||
'content_id': self.content.id
|
||||
})
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
|
||||
@patch('igny8_core.modules.linker.views.LinkerService.process')
|
||||
def test_process_endpoint_success(self, mock_process):
|
||||
"""Test successful processing"""
|
||||
mock_content = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Linked Content",
|
||||
html_content="<p>Linked.</p>",
|
||||
internal_links=[{'content_id': 1, 'anchor_text': 'test'}],
|
||||
linker_version=1,
|
||||
word_count=100
|
||||
)
|
||||
mock_process.return_value = mock_content
|
||||
|
||||
response = self.client.post('/api/v1/linker/process/', {
|
||||
'content_id': self.content.id
|
||||
}, format='json')
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertTrue(response.data['success'])
|
||||
self.assertEqual(response.data['data']['content_id'], self.content.id)
|
||||
self.assertEqual(response.data['data']['links_added'], 1)
|
||||
|
||||
def test_process_endpoint_invalid_content_id(self):
|
||||
"""Test process endpoint with invalid content ID"""
|
||||
response = self.client.post('/api/v1/linker/process/', {
|
||||
'content_id': 99999
|
||||
}, format='json')
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
@patch('igny8_core.modules.linker.views.LinkerService.process')
|
||||
def test_process_endpoint_insufficient_credits(self, mock_process):
|
||||
"""Test process endpoint with insufficient credits"""
|
||||
mock_process.side_effect = InsufficientCreditsError("Insufficient credits")
|
||||
|
||||
response = self.client.post('/api/v1/linker/process/', {
|
||||
'content_id': self.content.id
|
||||
}, format='json')
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_402_PAYMENT_REQUIRED)
|
||||
|
||||
@patch('igny8_core.modules.linker.views.LinkerService.batch_process')
|
||||
def test_batch_process_endpoint_success(self, mock_batch):
|
||||
"""Test successful batch processing"""
|
||||
content2 = Content.objects.create(
|
||||
account=self.account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Content 2",
|
||||
word_count=100
|
||||
)
|
||||
|
||||
mock_batch.return_value = [self.content, content2]
|
||||
|
||||
response = self.client.post('/api/v1/linker/batch_process/', {
|
||||
'content_ids': [self.content.id, content2.id]
|
||||
}, format='json')
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertTrue(response.data['success'])
|
||||
self.assertEqual(len(response.data['data']), 2)
|
||||
|
||||
def test_batch_process_endpoint_validation(self):
|
||||
"""Test batch process endpoint validation"""
|
||||
response = self.client.post('/api/v1/linker/batch_process/', {
|
||||
'content_ids': [] # Empty list
|
||||
}, format='json')
|
||||
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
def test_process_endpoint_respects_account_isolation(self):
|
||||
"""Test that process endpoint respects account isolation"""
|
||||
from igny8_core.auth.models import Account
|
||||
other_account = Account.objects.create(
|
||||
name="Other Account",
|
||||
slug="other",
|
||||
plan=self.plan,
|
||||
owner=self.user
|
||||
)
|
||||
|
||||
other_content = Content.objects.create(
|
||||
account=other_account,
|
||||
site=self.site,
|
||||
sector=self.sector,
|
||||
title="Other Content",
|
||||
word_count=100
|
||||
)
|
||||
|
||||
response = self.client.post('/api/v1/linker/process/', {
|
||||
'content_id': other_content.id
|
||||
}, format='json')
|
||||
|
||||
# Should return 400 because content belongs to different account
|
||||
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
|
||||
|
||||
Reference in New Issue
Block a user