fixes of broken fucntions

This commit is contained in:
Desktop
2025-11-16 04:56:48 +05:00
parent 5eb2464d2d
commit 5908115686
8 changed files with 141 additions and 46 deletions

View File

@@ -194,6 +194,26 @@ class AccountModelViewSet(viewsets.ModelViewSet):
status_code=status.HTTP_404_NOT_FOUND, status_code=status.HTTP_404_NOT_FOUND,
request=request request=request
) )
def list(self, request, *args, **kwargs):
"""
Override list to return unified format
"""
queryset = self.filter_queryset(self.get_queryset())
# Check if pagination is enabled
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
# Use paginator's get_paginated_response which already returns unified format
return self.get_paginated_response(serializer.data)
# No pagination - return all results in unified format
serializer = self.get_serializer(queryset, many=True)
return success_response(
data=serializer.data,
request=request
)
class SiteSectorModelViewSet(AccountModelViewSet): class SiteSectorModelViewSet(AccountModelViewSet):

View File

@@ -12,6 +12,7 @@ from igny8_core.api.base import SiteSectorModelViewSet
from igny8_core.api.pagination import CustomPageNumberPagination from igny8_core.api.pagination import CustomPageNumberPagination
from igny8_core.api.response import success_response, error_response from igny8_core.api.response import success_response, error_response
from igny8_core.api.throttles import DebugScopedRateThrottle from igny8_core.api.throttles import DebugScopedRateThrottle
from igny8_core.api.permissions import IsAuthenticatedAndActive, IsViewerOrAbove, IsEditorOrAbove
from .models import Keywords, Clusters, ContentIdeas from .models import Keywords, Clusters, ContentIdeas
from .serializers import KeywordSerializer, ContentIdeasSerializer from .serializers import KeywordSerializer, ContentIdeasSerializer
from .cluster_serializers import ClusterSerializer from .cluster_serializers import ClusterSerializer
@@ -25,7 +26,7 @@ class KeywordViewSet(SiteSectorModelViewSet):
""" """
queryset = Keywords.objects.all() queryset = Keywords.objects.all()
serializer_class = KeywordSerializer serializer_class = KeywordSerializer
permission_classes = [] # Allow any for now permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove]
pagination_class = CustomPageNumberPagination # Explicitly use custom pagination pagination_class = CustomPageNumberPagination # Explicitly use custom pagination
throttle_scope = 'planner' throttle_scope = 'planner'
throttle_classes = [DebugScopedRateThrottle] throttle_classes = [DebugScopedRateThrottle]
@@ -668,6 +669,7 @@ class ClusterViewSet(SiteSectorModelViewSet):
""" """
queryset = Clusters.objects.all() queryset = Clusters.objects.all()
serializer_class = ClusterSerializer serializer_class = ClusterSerializer
permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove]
pagination_class = CustomPageNumberPagination # Explicitly use custom pagination pagination_class = CustomPageNumberPagination # Explicitly use custom pagination
throttle_scope = 'planner' throttle_scope = 'planner'
throttle_classes = [DebugScopedRateThrottle] throttle_classes = [DebugScopedRateThrottle]
@@ -957,6 +959,7 @@ class ContentIdeasViewSet(SiteSectorModelViewSet):
""" """
queryset = ContentIdeas.objects.all() queryset = ContentIdeas.objects.all()
serializer_class = ContentIdeasSerializer serializer_class = ContentIdeasSerializer
permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove]
pagination_class = CustomPageNumberPagination pagination_class = CustomPageNumberPagination
throttle_scope = 'planner' throttle_scope = 'planner'
throttle_classes = [DebugScopedRateThrottle] # Explicitly use custom pagination throttle_classes = [DebugScopedRateThrottle] # Explicitly use custom pagination

View File

@@ -10,6 +10,7 @@ from django.db import transaction
from igny8_core.api.base import AccountModelViewSet from igny8_core.api.base import AccountModelViewSet
from igny8_core.api.response import success_response, error_response from igny8_core.api.response import success_response, error_response
from igny8_core.api.throttles import DebugScopedRateThrottle from igny8_core.api.throttles import DebugScopedRateThrottle
from igny8_core.api.permissions import IsAuthenticatedAndActive, IsAdminOrOwner
from django.conf import settings from django.conf import settings
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@@ -21,7 +22,7 @@ class IntegrationSettingsViewSet(viewsets.ViewSet):
Following reference plugin pattern: WordPress uses update_option() for igny8_api_settings Following reference plugin pattern: WordPress uses update_option() for igny8_api_settings
We store in IntegrationSettings model with account isolation We store in IntegrationSettings model with account isolation
""" """
permission_classes = [] # Allow any for now permission_classes = [IsAuthenticatedAndActive, IsAdminOrOwner]
throttle_scope = 'system_admin' throttle_scope = 'system_admin'
throttle_classes = [DebugScopedRateThrottle] throttle_classes = [DebugScopedRateThrottle]

View File

@@ -14,7 +14,7 @@ from django.utils import timezone
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from igny8_core.api.base import AccountModelViewSet from igny8_core.api.base import AccountModelViewSet
from igny8_core.api.response import success_response, error_response from igny8_core.api.response import success_response, error_response
from igny8_core.api.permissions import IsEditorOrAbove from igny8_core.api.permissions import IsEditorOrAbove, IsAuthenticatedAndActive, IsViewerOrAbove
from igny8_core.api.throttles import DebugScopedRateThrottle from igny8_core.api.throttles import DebugScopedRateThrottle
from igny8_core.api.pagination import CustomPageNumberPagination from igny8_core.api.pagination import CustomPageNumberPagination
from .models import AIPrompt, AuthorProfile, Strategy from .models import AIPrompt, AuthorProfile, Strategy
@@ -199,6 +199,7 @@ class AuthorProfileViewSet(AccountModelViewSet):
""" """
queryset = AuthorProfile.objects.all() queryset = AuthorProfile.objects.all()
serializer_class = AuthorProfileSerializer serializer_class = AuthorProfileSerializer
permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove]
throttle_scope = 'system' throttle_scope = 'system'
throttle_classes = [DebugScopedRateThrottle] throttle_classes = [DebugScopedRateThrottle]
@@ -216,6 +217,7 @@ class StrategyViewSet(AccountModelViewSet):
""" """
queryset = Strategy.objects.all() queryset = Strategy.objects.all()
serializer_class = StrategySerializer serializer_class = StrategySerializer
permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove]
throttle_scope = 'system' throttle_scope = 'system'
throttle_classes = [DebugScopedRateThrottle] throttle_classes = [DebugScopedRateThrottle]

View File

@@ -8,6 +8,7 @@ from igny8_core.api.base import SiteSectorModelViewSet
from igny8_core.api.pagination import CustomPageNumberPagination from igny8_core.api.pagination import CustomPageNumberPagination
from igny8_core.api.response import success_response, error_response from igny8_core.api.response import success_response, error_response
from igny8_core.api.throttles import DebugScopedRateThrottle from igny8_core.api.throttles import DebugScopedRateThrottle
from igny8_core.api.permissions import IsAuthenticatedAndActive, IsViewerOrAbove, IsEditorOrAbove
from .models import Tasks, Images, Content from .models import Tasks, Images, Content
from .serializers import TasksSerializer, ImagesSerializer, ContentSerializer from .serializers import TasksSerializer, ImagesSerializer, ContentSerializer
@@ -19,6 +20,7 @@ class TasksViewSet(SiteSectorModelViewSet):
""" """
queryset = Tasks.objects.select_related('content_record') queryset = Tasks.objects.select_related('content_record')
serializer_class = TasksSerializer serializer_class = TasksSerializer
permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove]
pagination_class = CustomPageNumberPagination # Explicitly use custom pagination pagination_class = CustomPageNumberPagination # Explicitly use custom pagination
throttle_scope = 'writer' throttle_scope = 'writer'
throttle_classes = [DebugScopedRateThrottle] throttle_classes = [DebugScopedRateThrottle]
@@ -379,6 +381,7 @@ class ImagesViewSet(SiteSectorModelViewSet):
""" """
queryset = Images.objects.all() queryset = Images.objects.all()
serializer_class = ImagesSerializer serializer_class = ImagesSerializer
permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove]
pagination_class = CustomPageNumberPagination pagination_class = CustomPageNumberPagination
throttle_scope = 'writer' throttle_scope = 'writer'
throttle_classes = [DebugScopedRateThrottle] throttle_classes = [DebugScopedRateThrottle]
@@ -777,6 +780,7 @@ class ContentViewSet(SiteSectorModelViewSet):
""" """
queryset = Content.objects.all() queryset = Content.objects.all()
serializer_class = ContentSerializer serializer_class = ContentSerializer
permission_classes = [IsAuthenticatedAndActive, IsViewerOrAbove]
pagination_class = CustomPageNumberPagination pagination_class = CustomPageNumberPagination
throttle_scope = 'writer' throttle_scope = 'writer'
throttle_classes = [DebugScopedRateThrottle] throttle_classes = [DebugScopedRateThrottle]

View File

@@ -134,12 +134,13 @@ export function usePersistentToggle(
try { try {
const endpoint = getEndpoint.replace('{id}', resourceId); const endpoint = getEndpoint.replace('{id}', resourceId);
// fetchAPI extracts data from unified format {success: true, data: {...}}
// So result IS the data object, not wrapped
const result = await fetchAPI(endpoint); const result = await fetchAPI(endpoint);
if (result.success && result.data) { if (result && typeof result === 'object') {
const apiData = result.data; setData(result);
setData(apiData); const newEnabled = extractEnabled(result);
const newEnabled = extractEnabled(apiData);
setEnabled(newEnabled); setEnabled(newEnabled);
} else { } else {
// No data yet - use initial state // No data yet - use initial state

View File

@@ -333,6 +333,9 @@ export default function Integration() {
} }
try { try {
// fetchAPI extracts data from unified format {success: true, data: {...}}
// But test endpoint may return {success: true, ...} directly (not wrapped)
// So data could be either the extracted data object or the full response
const data = await fetchAPI(`/v1/system/settings/integrations/${selectedIntegration}/test/`, { const data = await fetchAPI(`/v1/system/settings/integrations/${selectedIntegration}/test/`, {
method: 'POST', method: 'POST',
body: JSON.stringify({ body: JSON.stringify({
@@ -341,24 +344,51 @@ export default function Integration() {
}), }),
}); });
if (data.success) { // Handle both unified format (extracted) and direct format
toast.success(data.message || 'API connection test successful!'); // If data has success field, it's the direct response (not extracted)
if (data.response) { // If data doesn't have success but has other fields, it's extracted data (successful)
toast.info(`Response: ${data.response}`); if (data && typeof data === 'object') {
} if (data.success === true || data.success === false) {
if (data.tokens_used) { // Direct response format (not extracted by fetchAPI)
toast.info(`Tokens used: ${data.tokens_used}`); if (data.success) {
} toast.success(data.message || 'API connection test successful!');
if (data.response) {
// Update validation status to success toast.info(`Response: ${data.response}`);
if (selectedIntegration) { }
setValidationStatuses(prev => ({ if (data.tokens_used) {
...prev, toast.info(`Tokens used: ${data.tokens_used}`);
[selectedIntegration]: 'success', }
}));
// Update validation status to success
if (selectedIntegration) {
setValidationStatuses(prev => ({
...prev,
[selectedIntegration]: 'success',
}));
}
} else {
throw new Error(data.error || data.message || 'Connection test failed');
}
} else {
// Extracted data format (successful response)
toast.success('API connection test successful!');
if (data.response) {
toast.info(`Response: ${data.response}`);
}
if (data.tokens_used) {
toast.info(`Tokens used: ${data.tokens_used}`);
}
// Update validation status to success
if (selectedIntegration) {
setValidationStatuses(prev => ({
...prev,
[selectedIntegration]: 'success',
}));
}
} }
} else { } else {
throw new Error(data.error || 'Connection test failed'); throw new Error('Invalid response format');
} }
} catch (error: any) { } catch (error: any) {
console.error('Error testing connection:', error); console.error('Error testing connection:', error);

View File

@@ -640,34 +640,24 @@ export async function autoClusterKeywords(keywordIds: number[], sectorId?: numbe
const requestBody = { ids: keywordIds, sector_id: sectorId }; const requestBody = { ids: keywordIds, sector_id: sectorId };
try { try {
// fetchAPI will automatically extract data from unified format // fetchAPI extracts data from unified format {success: true, data: {...}}
// For action endpoints, response is {success: true, data: {...}} // So response is already the data object: {task_id: "...", ...}
// fetchAPI extracts and returns the data field, so response should already be the data object
const response = await fetchAPI(endpoint, { const response = await fetchAPI(endpoint, {
method: 'POST', method: 'POST',
body: JSON.stringify(requestBody), body: JSON.stringify(requestBody),
}); });
// After fetchAPI processing, response should be the data object (not wrapped in success/data) // Wrap extracted data with success: true for frontend compatibility
// But check if it's still wrapped (shouldn't happen, but for safety)
if (response && typeof response === 'object') { if (response && typeof response === 'object') {
if ('success' in response && response.success === false) { return { success: true, ...response } as any;
// Error response - return as-is
return response as any;
}
// If response has data field, extract it
if ('data' in response && response.data) {
return { success: true, ...response.data } as any;
}
// Response is already the data object (after fetchAPI extraction)
// Ensure it has success: true
if (!('success' in response)) {
return { success: true, ...response } as any;
}
} }
return response as any; return { success: true, ...response } as any;
} catch (error: any) { } catch (error: any) {
// Error responses are thrown by fetchAPI, but wrap them for consistency
if (error.response && typeof error.response === 'object') {
return { success: false, error: error.message, ...error.response } as any;
}
throw error; throw error;
} }
} }
@@ -677,13 +667,24 @@ export async function autoGenerateIdeas(clusterIds: number[]): Promise<{ success
const requestBody = { ids: clusterIds }; const requestBody = { ids: clusterIds };
try { try {
// fetchAPI extracts data from unified format {success: true, data: {...}}
// So response is already the data object: {task_id: "...", ...}
const response = await fetchAPI(endpoint, { const response = await fetchAPI(endpoint, {
method: 'POST', method: 'POST',
body: JSON.stringify(requestBody), body: JSON.stringify(requestBody),
}); });
return response; // Wrap extracted data with success: true for frontend compatibility
if (response && typeof response === 'object') {
return { success: true, ...response } as any;
}
return { success: true, ...response } as any;
} catch (error: any) { } catch (error: any) {
// Error responses are thrown by fetchAPI, but wrap them for consistency
if (error.response && typeof error.response === 'object') {
return { success: false, error: error.message, ...error.response } as any;
}
throw error; throw error;
} }
} }
@@ -693,13 +694,24 @@ export async function generateSingleIdea(ideaId: string | number, clusterId: num
const requestBody = { cluster_id: clusterId }; const requestBody = { cluster_id: clusterId };
try { try {
// fetchAPI extracts data from unified format {success: true, data: {...}}
// So response is already the data object: {task_id: "...", ...}
const response = await fetchAPI(endpoint, { const response = await fetchAPI(endpoint, {
method: 'POST', method: 'POST',
body: JSON.stringify(requestBody), body: JSON.stringify(requestBody),
}); });
return response; // Wrap extracted data with success: true for frontend compatibility
if (response && typeof response === 'object') {
return { success: true, ...response } as any;
}
return { success: true, ...response } as any;
} catch (error: any) { } catch (error: any) {
// Error responses are thrown by fetchAPI, but wrap them for consistency
if (error.response && typeof error.response === 'object') {
return { success: false, error: error.message, ...error.response } as any;
}
throw error; throw error;
} }
} }
@@ -1000,13 +1012,24 @@ export async function autoGenerateContent(ids: number[]): Promise<{ success: boo
const requestBody = { ids }; const requestBody = { ids };
try { try {
// fetchAPI extracts data from unified format {success: true, data: {...}}
// So response is already the data object: {task_id: "...", ...}
const response = await fetchAPI(endpoint, { const response = await fetchAPI(endpoint, {
method: 'POST', method: 'POST',
body: JSON.stringify(requestBody), body: JSON.stringify(requestBody),
}); });
return response; // Wrap extracted data with success: true for frontend compatibility
if (response && typeof response === 'object') {
return { success: true, ...response } as any;
}
return { success: true, ...response } as any;
} catch (error: any) { } catch (error: any) {
// Error responses are thrown by fetchAPI, but wrap them for consistency
if (error.response && typeof error.response === 'object') {
return { success: false, error: error.message, ...error.response } as any;
}
throw error; throw error;
} }
} }
@@ -1016,13 +1039,24 @@ export async function autoGenerateImages(taskIds: number[]): Promise<{ success:
const requestBody = { task_ids: taskIds }; const requestBody = { task_ids: taskIds };
try { try {
// fetchAPI extracts data from unified format {success: true, data: {...}}
// So response is already the data object: {task_id: "...", ...}
const response = await fetchAPI(endpoint, { const response = await fetchAPI(endpoint, {
method: 'POST', method: 'POST',
body: JSON.stringify(requestBody), body: JSON.stringify(requestBody),
}); });
return response; // Wrap extracted data with success: true for frontend compatibility
if (response && typeof response === 'object') {
return { success: true, ...response } as any;
}
return { success: true, ...response } as any;
} catch (error: any) { } catch (error: any) {
// Error responses are thrown by fetchAPI, but wrap them for consistency
if (error.response && typeof error.response === 'object') {
return { success: false, error: error.message, ...error.response } as any;
}
throw error; throw error;
} }
} }