Skip to content

Commit baca842

Browse files
Fix: Shopify Admin API access lost
The user is reporting that they no longer have access to the Shopify Admin API. This commit aims to investigate and resolve the issue causing this loss of access.
1 parent 094f2de commit baca842

File tree

5 files changed

+378
-0
lines changed

5 files changed

+378
-0
lines changed
Lines changed: 226 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,226 @@
1+
import React, { useState } from 'react';
2+
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
3+
import { Button } from '@/components/ui/button';
4+
import { Badge } from '@/components/ui/badge';
5+
import { AlertTriangle, CheckCircle, XCircle, RefreshCw } from 'lucide-react';
6+
import { supabase } from '@/integrations/supabase/client';
7+
import { useAuth } from '@/contexts/AuthContext';
8+
import { toast } from '@/hooks/use-toast';
9+
10+
interface DiagnosticResult {
11+
test: string;
12+
status: 'success' | 'error' | 'warning';
13+
message: string;
14+
details?: string;
15+
}
16+
17+
export const ShopifyDiagnostic: React.FC = () => {
18+
const [results, setResults] = useState<DiagnosticResult[]>([]);
19+
const [isRunning, setIsRunning] = useState(false);
20+
const { user } = useAuth();
21+
22+
const runDiagnostic = async () => {
23+
setIsRunning(true);
24+
const diagnosticResults: DiagnosticResult[] = [];
25+
26+
try {
27+
// Test 1: Vérifier l'authentification utilisateur
28+
if (!user) {
29+
diagnosticResults.push({
30+
test: 'Authentification utilisateur',
31+
status: 'error',
32+
message: 'Utilisateur non connecté'
33+
});
34+
} else {
35+
diagnosticResults.push({
36+
test: 'Authentification utilisateur',
37+
status: 'success',
38+
message: 'Utilisateur connecté',
39+
details: `UID: ${user.uid}`
40+
});
41+
}
42+
43+
// Test 2: Vérifier les intégrations Shopify existantes
44+
try {
45+
const { data: integrations, error: integrationsError } = await supabase
46+
.from('shopify_integrations')
47+
.select('*')
48+
.eq('user_id', user?.uid)
49+
.eq('active', true);
50+
51+
if (integrationsError) throw integrationsError;
52+
53+
if (!integrations || integrations.length === 0) {
54+
diagnosticResults.push({
55+
test: 'Intégrations Shopify',
56+
status: 'warning',
57+
message: 'Aucune intégration active trouvée'
58+
});
59+
} else {
60+
diagnosticResults.push({
61+
test: 'Intégrations Shopify',
62+
status: 'success',
63+
message: `${integrations.length} intégration(s) trouvée(s)`,
64+
details: integrations.map(i => i.shop_domain).join(', ')
65+
});
66+
67+
// Test 3: Vérifier les tokens pour chaque intégration
68+
for (const integration of integrations) {
69+
try {
70+
// Test simple d'accès API via edge function
71+
const { data: shopTest, error: shopTestError } = await supabase.functions.invoke('shopify-test-api', {
72+
body: {
73+
shopDomain: integration.shop_domain,
74+
accessToken: integration.access_token
75+
}
76+
});
77+
78+
if (shopTestError) throw shopTestError;
79+
80+
if (shopTest?.success) {
81+
diagnosticResults.push({
82+
test: `API Access - ${integration.shop_domain}`,
83+
status: 'success',
84+
message: 'Accès API fonctionnel'
85+
});
86+
} else {
87+
diagnosticResults.push({
88+
test: `API Access - ${integration.shop_domain}`,
89+
status: 'error',
90+
message: 'Accès API bloqué',
91+
details: shopTest?.error || 'Token invalide ou expiré'
92+
});
93+
}
94+
} catch (error) {
95+
diagnosticResults.push({
96+
test: `API Access - ${integration.shop_domain}`,
97+
status: 'error',
98+
message: 'Erreur de connexion API',
99+
details: error.message
100+
});
101+
}
102+
}
103+
}
104+
} catch (error) {
105+
diagnosticResults.push({
106+
test: 'Intégrations Shopify',
107+
status: 'error',
108+
message: 'Erreur accès base de données',
109+
details: error.message
110+
});
111+
}
112+
113+
// Test 4: Vérifier les clés API Shopify
114+
try {
115+
const { data: configTest, error: configError } = await supabase.functions.invoke('shopify-config-test');
116+
117+
if (configError) throw configError;
118+
119+
if (configTest?.apiKeyConfigured) {
120+
diagnosticResults.push({
121+
test: 'Configuration API Shopify',
122+
status: 'success',
123+
message: 'Clés API configurées'
124+
});
125+
} else {
126+
diagnosticResults.push({
127+
test: 'Configuration API Shopify',
128+
status: 'error',
129+
message: 'Clés API manquantes ou invalides'
130+
});
131+
}
132+
} catch (error) {
133+
diagnosticResults.push({
134+
test: 'Configuration API Shopify',
135+
status: 'error',
136+
message: 'Impossible de vérifier la configuration',
137+
details: error.message
138+
});
139+
}
140+
141+
} catch (error) {
142+
console.error('Erreur diagnostic:', error);
143+
toast({
144+
title: "Erreur diagnostic",
145+
description: "Impossible de terminer le diagnostic",
146+
variant: "destructive"
147+
});
148+
}
149+
150+
setResults(diagnosticResults);
151+
setIsRunning(false);
152+
};
153+
154+
const getStatusIcon = (status: DiagnosticResult['status']) => {
155+
switch (status) {
156+
case 'success':
157+
return <CheckCircle className="h-4 w-4 text-green-600" />;
158+
case 'error':
159+
return <XCircle className="h-4 w-4 text-red-600" />;
160+
case 'warning':
161+
return <AlertTriangle className="h-4 w-4 text-yellow-600" />;
162+
}
163+
};
164+
165+
const getStatusBadge = (status: DiagnosticResult['status']) => {
166+
switch (status) {
167+
case 'success':
168+
return <Badge variant="default" className="bg-green-100 text-green-800">OK</Badge>;
169+
case 'error':
170+
return <Badge variant="destructive">ERREUR</Badge>;
171+
case 'warning':
172+
return <Badge variant="secondary" className="bg-yellow-100 text-yellow-800">ATTENTION</Badge>;
173+
}
174+
};
175+
176+
return (
177+
<Card>
178+
<CardHeader>
179+
<div className="flex items-center justify-between">
180+
<CardTitle className="flex items-center space-x-2">
181+
<AlertTriangle className="h-5 w-5 text-blue-600" />
182+
<span>Diagnostic Shopify API</span>
183+
</CardTitle>
184+
<Button
185+
onClick={runDiagnostic}
186+
disabled={isRunning}
187+
className="flex items-center space-x-2"
188+
>
189+
<RefreshCw className={`h-4 w-4 ${isRunning ? 'animate-spin' : ''}`} />
190+
<span>Lancer diagnostic</span>
191+
</Button>
192+
</div>
193+
</CardHeader>
194+
195+
<CardContent>
196+
{results.length === 0 ? (
197+
<div className="text-center py-8 text-muted-foreground">
198+
Cliquez sur "Lancer diagnostic" pour vérifier l'état de votre configuration Shopify
199+
</div>
200+
) : (
201+
<div className="space-y-4">
202+
{results.map((result, index) => (
203+
<div key={index} className="flex items-start space-x-3 p-3 border rounded-lg">
204+
<div className="flex-shrink-0 mt-0.5">
205+
{getStatusIcon(result.status)}
206+
</div>
207+
<div className="flex-1 min-w-0">
208+
<div className="flex items-center justify-between">
209+
<h4 className="font-medium text-sm">{result.test}</h4>
210+
{getStatusBadge(result.status)}
211+
</div>
212+
<p className="text-sm text-muted-foreground mt-1">{result.message}</p>
213+
{result.details && (
214+
<p className="text-xs text-muted-foreground mt-1 font-mono bg-gray-50 p-2 rounded">
215+
{result.details}
216+
</p>
217+
)}
218+
</div>
219+
</div>
220+
))}
221+
</div>
222+
)}
223+
</CardContent>
224+
</Card>
225+
);
226+
};

src/pages/ShopifyTestPage.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import React from 'react';
22
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
33
import { ShopifyTestComponent } from '@/components/ShopifyTestComponent';
4+
import { ShopifyDiagnostic } from '@/components/ShopifyDiagnostic';
45
import { ArrowLeft } from 'lucide-react';
56
import { Button } from '@/components/ui/button';
67
import { useNavigate } from 'react-router-dom';
@@ -44,6 +45,8 @@ export const ShopifyTestPage: React.FC = () => {
4445
</CardContent>
4546
</Card>
4647

48+
<ShopifyDiagnostic />
49+
4750
<ShopifyTestComponent campaignId="test-campaign-123" />
4851
</div>
4952
</div>

supabase/config.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,13 @@ verify_jwt = false
77
verify_jwt = false
88

99
[functions.shopify-webhooks]
10+
verify_jwt = false
11+
12+
[functions.shopify-test-api]
13+
verify_jwt = false
14+
15+
[functions.shopify-config-test]
16+
verify_jwt = false
17+
18+
[functions.shopify-private-app]
1019
verify_jwt = false
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { serve } from "https://deno.land/std@0.168.0/http/server.ts";
2+
3+
const corsHeaders = {
4+
'Access-Control-Allow-Origin': '*',
5+
'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type',
6+
};
7+
8+
serve(async (req) => {
9+
if (req.method === 'OPTIONS') {
10+
return new Response(null, { headers: corsHeaders });
11+
}
12+
13+
try {
14+
const shopifyApiKey = Deno.env.get('SHOPIFY_API_KEY');
15+
const shopifyApiSecret = Deno.env.get('SHOPIFY_API_SECRET');
16+
17+
console.log('Test configuration Shopify:');
18+
console.log('- API Key configurée:', !!shopifyApiKey);
19+
console.log('- API Secret configurée:', !!shopifyApiSecret);
20+
21+
if (shopifyApiKey) {
22+
console.log('- API Key (tronquée):', shopifyApiKey.substring(0, 8) + '...');
23+
}
24+
25+
return new Response(
26+
JSON.stringify({
27+
apiKeyConfigured: !!shopifyApiKey,
28+
apiSecretConfigured: !!shopifyApiSecret,
29+
allConfigured: !!(shopifyApiKey && shopifyApiSecret),
30+
apiKeyPreview: shopifyApiKey ? shopifyApiKey.substring(0, 8) + '...' : null
31+
}),
32+
{
33+
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
34+
}
35+
);
36+
37+
} catch (error) {
38+
console.error('Erreur test configuration:', error);
39+
return new Response(
40+
JSON.stringify({
41+
error: error.message,
42+
apiKeyConfigured: false,
43+
apiSecretConfigured: false,
44+
allConfigured: false
45+
}),
46+
{
47+
status: 500,
48+
headers: { ...corsHeaders, 'Content-Type': 'application/json' }
49+
}
50+
);
51+
}
52+
});

0 commit comments

Comments
 (0)