From f860a20fa07c3fdd831cd08dff9eee44b5d508a9 Mon Sep 17 00:00:00 2001 From: "IGNY8 VPS (Salman)" Date: Mon, 1 Dec 2025 09:43:27 +0000 Subject: [PATCH] mig --- .../igny8_core/modules/integration/views.py | 74 ++++++++++++ .../sites/WordPressIntegrationForm.tsx | 108 +++++++----------- frontend/src/services/integration.api.ts | 1 + 3 files changed, 119 insertions(+), 64 deletions(-) diff --git a/backend/igny8_core/modules/integration/views.py b/backend/igny8_core/modules/integration/views.py index af102089..10b6f12e 100644 --- a/backend/igny8_core/modules/integration/views.py +++ b/backend/igny8_core/modules/integration/views.py @@ -751,5 +751,79 @@ class IntegrationViewSet(SiteSectorModelViewSet): status.HTTP_400_BAD_REQUEST, request ) + + @action(detail=False, methods=['post'], url_path='generate-api-key') + def generate_api_key(self, request): + """ + Generate a new API key for a site's WordPress integration. + + POST /api/v1/integration/integrations/generate-api-key/ + + Body: + { + "site_id": 5 + } + """ + site_id = request.data.get('site_id') + if not site_id: + return error_response( + 'Site ID is required', + None, + status.HTTP_400_BAD_REQUEST, + request + ) + + try: + site = Site.objects.get(id=site_id) + except Site.DoesNotExist: + return error_response( + f'Site with ID {site_id} not found', + None, + status.HTTP_404_NOT_FOUND, + request + ) + + # Generate API key with format: igny8_site_{site_id}_{timestamp}_{random} + import time + import random + import string + + timestamp = int(time.time() * 1000) + random_suffix = ''.join(random.choices(string.ascii_lowercase + string.digits, k=10)) + api_key = f"igny8_site_{site_id}_{timestamp}_{random_suffix}" + + # Get or create SiteIntegration + integration, created = SiteIntegration.objects.get_or_create( + site=site, + defaults={ + 'integration_type': 'wordpress', + 'is_active': True, + 'credentials_json': {'api_key': api_key}, + 'config_json': {} + } + ) + + # If integration already exists, update the API key + if not created: + credentials = integration.get_credentials() + credentials['api_key'] = api_key + integration.credentials_json = credentials + integration.save() + + logger.info( + f"Generated new API key for site {site.name} (ID: {site_id}), " + f"integration {'created' if created else 'updated'}" + ) + + # Serialize the integration with the new key + serializer = self.get_serializer(integration) + + return success_response({ + 'integration': serializer.data, + 'api_key': api_key, + 'message': f"API key {'generated' if created else 'regenerated'} successfully", + }, request=request) + + diff --git a/frontend/src/components/sites/WordPressIntegrationForm.tsx b/frontend/src/components/sites/WordPressIntegrationForm.tsx index 1ad2b1dc..66f8cf18 100644 --- a/frontend/src/components/sites/WordPressIntegrationForm.tsx +++ b/frontend/src/components/sites/WordPressIntegrationForm.tsx @@ -42,43 +42,35 @@ export default function WordPressIntegrationForm({ const [apiKey, setApiKey] = useState(''); const [apiKeyVisible, setApiKeyVisible] = useState(false); - // Load API key from site settings on mount + // Load API key from integration on mount or when integration changes useEffect(() => { - loadApiKeyFromSite(); - }, [siteId]); - - const loadApiKeyFromSite = async () => { - try { - const siteData = await fetchAPI(`/v1/auth/sites/${siteId}/`); - if (siteData?.wp_api_key) { - setApiKey(siteData.wp_api_key); - } else { - // Clear API key if it doesn't exist in the backend - setApiKey(''); - } - } catch (error) { - // API key might not exist yet, that's okay + if (integration?.api_key) { + setApiKey(integration.api_key); + } else { setApiKey(''); } - }; + }, [integration]); const handleGenerateApiKey = async () => { try { setGeneratingKey(true); - // Generate API key - format: igny8_site_{siteId}_{timestamp}_{random} - const timestamp = Date.now(); - const random = Math.random().toString(36).substring(2, 15); - const token = `igny8_site_${siteId}_${timestamp}_${random}`; - setApiKey(token); + + // Call the new generate-api-key endpoint + const response = await fetchAPI('/v1/integration/integrations/generate-api-key/', { + method: 'POST', + body: JSON.stringify({ site_id: siteId }), + }); + + const newKey = response.api_key; + setApiKey(newKey); setApiKeyVisible(true); - // Save API key to site settings immediately - await saveApiKeyToSite(token); + // Trigger integration update + if (onIntegrationUpdate && response.integration) { + onIntegrationUpdate(response.integration); + } - // Reload the API key from backend to ensure consistency - await loadApiKeyFromSite(); - - toast.success('API key generated and saved successfully'); + toast.success('API key generated successfully'); } catch (error: any) { toast.error(`Failed to generate API key: ${error.message}`); } finally { @@ -92,20 +84,23 @@ export default function WordPressIntegrationForm({ } try { setGeneratingKey(true); - // Generate new API key - const timestamp = Date.now(); - const random = Math.random().toString(36).substring(2, 15); - const token = `igny8_site_${siteId}_${timestamp}_${random}`; - setApiKey(token); + + // Call the generate-api-key endpoint to create a new key + const response = await fetchAPI('/v1/integration/integrations/generate-api-key/', { + method: 'POST', + body: JSON.stringify({ site_id: siteId }), + }); + + const newKey = response.api_key; + setApiKey(newKey); setApiKeyVisible(true); - // Save new API key to site settings - await saveApiKeyToSite(token); + // Trigger integration update + if (onIntegrationUpdate && response.integration) { + onIntegrationUpdate(response.integration); + } - // Reload the API key from backend to ensure consistency - await loadApiKeyFromSite(); - - toast.success('API key regenerated and saved successfully'); + toast.success('API key regenerated successfully'); } catch (error: any) { toast.error(`Failed to regenerate API key: ${error.message}`); } finally { @@ -119,24 +114,21 @@ export default function WordPressIntegrationForm({ } try { setGeneratingKey(true); - // Clear API key from site settings by setting it to empty string - await fetchAPI(`/v1/auth/sites/${siteId}/`, { - method: 'PATCH', - body: JSON.stringify({ wp_api_key: '' }), - }); + + if (!integration) { + toast.error('No integration found'); + return; + } + + // Delete the integration to revoke the API key + await integrationApi.deleteIntegration(integration.id); setApiKey(''); setApiKeyVisible(false); - // Trigger integration update to reload the integration state - if (onIntegrationUpdate && integration) { - await loadApiKeyFromSite(); - // Reload integration to reflect changes - const integrations = await integrationApi.getSiteIntegrations(siteId); - const wp = integrations.find(i => i.platform === 'wordpress'); - if (wp) { - onIntegrationUpdate(wp); - } + // Trigger integration update + if (onIntegrationUpdate) { + onIntegrationUpdate(null as any); } toast.success('API key revoked successfully'); @@ -147,18 +139,6 @@ export default function WordPressIntegrationForm({ } }; - const saveApiKeyToSite = async (key: string) => { - try { - await fetchAPI(`/v1/auth/sites/${siteId}/`, { - method: 'PATCH', - body: JSON.stringify({ wp_api_key: key }), - }); - } catch (error: any) { - console.error('Failed to save API key to site:', error); - throw error; - } - }; - const handleCopyApiKey = () => { if (apiKey) { navigator.clipboard.writeText(apiKey); diff --git a/frontend/src/services/integration.api.ts b/frontend/src/services/integration.api.ts index 4ee3987d..a9275a84 100644 --- a/frontend/src/services/integration.api.ts +++ b/frontend/src/services/integration.api.ts @@ -11,6 +11,7 @@ export interface SiteIntegration { platform_type: 'cms' | 'ecommerce' | 'custom_api'; config_json: Record; credentials_json?: Record; + api_key?: string; // WordPress API key from credentials is_active: boolean; sync_enabled: boolean; last_sync_at?: string;