fonctionnalité majeure : setup ultra simplifié (installation/configuration des infos supabase directement du web)
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
import { supabase } from './supabase';
|
||||
import { supabaseAdmin } from './supabase-admin';
|
||||
|
||||
export interface AdminUser {
|
||||
id: string;
|
||||
email: string;
|
||||
role: 'admin' | 'super_admin';
|
||||
export interface UserPermissions {
|
||||
user_id: string;
|
||||
is_admin: boolean;
|
||||
is_super_admin: boolean;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
}
|
||||
@@ -21,17 +21,28 @@ export const authService = {
|
||||
async isAdmin(): Promise<boolean> {
|
||||
try {
|
||||
const user = await this.getCurrentUser();
|
||||
if (!user) return false;
|
||||
if (!user) {
|
||||
console.log('🔍 isAdmin: Aucun utilisateur connecté');
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('🔍 isAdmin: Vérification pour utilisateur:', user.id, user.email);
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('admin_users')
|
||||
.select('id')
|
||||
.eq('id', user.id)
|
||||
.from('user_permissions')
|
||||
.select('is_admin')
|
||||
.eq('user_id', user.id)
|
||||
.single();
|
||||
|
||||
if (error) return false;
|
||||
return !!data;
|
||||
} catch {
|
||||
if (error) {
|
||||
console.error('❌ isAdmin: Erreur lors de la vérification:', error);
|
||||
return false;
|
||||
}
|
||||
|
||||
console.log('✅ isAdmin: Utilisateur trouvé dans user_permissions:', !!data);
|
||||
return data?.is_admin || false;
|
||||
} catch (error) {
|
||||
console.error('❌ isAdmin: Exception:', error);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
@@ -43,29 +54,28 @@ export const authService = {
|
||||
if (!user) return false;
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('admin_users')
|
||||
.select('id')
|
||||
.eq('id', user.id)
|
||||
.eq('role', 'super_admin')
|
||||
.from('user_permissions')
|
||||
.select('is_super_admin')
|
||||
.eq('user_id', user.id)
|
||||
.single();
|
||||
|
||||
if (error) return false;
|
||||
return !!data;
|
||||
return data?.is_super_admin || false;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
// Obtenir les informations de l'admin actuel
|
||||
async getCurrentAdmin(): Promise<AdminUser | null> {
|
||||
// Obtenir les permissions de l'utilisateur actuel
|
||||
async getCurrentPermissions(): Promise<UserPermissions | null> {
|
||||
try {
|
||||
const user = await this.getCurrentUser();
|
||||
if (!user) return null;
|
||||
|
||||
const { data, error } = await supabase
|
||||
.from('admin_users')
|
||||
.from('user_permissions')
|
||||
.select('*')
|
||||
.eq('id', user.id)
|
||||
.eq('user_id', user.id)
|
||||
.single();
|
||||
|
||||
if (error) return null;
|
||||
@@ -91,27 +101,44 @@ export const authService = {
|
||||
if (error) throw error;
|
||||
},
|
||||
|
||||
// Lister tous les admins (pour les super admins)
|
||||
async getAllAdmins(): Promise<AdminUser[]> {
|
||||
const { data, error } = await supabase
|
||||
.from('admin_users')
|
||||
.select('*')
|
||||
.order('created_at', { ascending: false });
|
||||
|
||||
// Inscription (pour les tests)
|
||||
async signUp(email: string, password: string) {
|
||||
const { data, error } = await supabase.auth.signUp({
|
||||
email,
|
||||
password,
|
||||
});
|
||||
if (error) throw error;
|
||||
return data || [];
|
||||
return data;
|
||||
},
|
||||
|
||||
// Changer le rôle d'un admin (pour les super admins)
|
||||
async updateAdminRole(adminId: string, role: 'admin' | 'super_admin') {
|
||||
const { data, error } = await supabaseAdmin
|
||||
.from('admin_users')
|
||||
.update({ role })
|
||||
.eq('id', adminId)
|
||||
// Créer un utilisateur admin (côté serveur uniquement)
|
||||
async createAdminUser(email: string, password: string): Promise<{ user: any; permissions: UserPermissions }> {
|
||||
// Créer l'utilisateur dans auth.users
|
||||
const { data: userData, error: userError } = await supabaseAdmin.auth.admin.createUser({
|
||||
email,
|
||||
password,
|
||||
email_confirm: true
|
||||
});
|
||||
|
||||
if (userError) throw userError;
|
||||
if (!userData.user) throw new Error('Utilisateur non créé');
|
||||
|
||||
// Créer les permissions admin
|
||||
const { data: permissionsData, error: permissionsError } = await supabaseAdmin
|
||||
.from('user_permissions')
|
||||
.insert({
|
||||
user_id: userData.user.id,
|
||||
is_admin: true,
|
||||
is_super_admin: true
|
||||
})
|
||||
.select()
|
||||
.single();
|
||||
|
||||
if (error) throw error;
|
||||
return data;
|
||||
if (permissionsError) throw permissionsError;
|
||||
|
||||
return {
|
||||
user: userData.user,
|
||||
permissions: permissionsData
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -192,6 +192,23 @@ export const campaignService = {
|
||||
.eq('slug', slug)
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
if (error.code === 'PGRST116') {
|
||||
return null; // Aucune campagne trouvée
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
return data;
|
||||
},
|
||||
|
||||
// Méthode pour récupérer une campagne par ID
|
||||
async getById(id: string): Promise<Campaign | null> {
|
||||
const { data, error } = await supabase
|
||||
.from('campaigns')
|
||||
.select('*')
|
||||
.eq('id', id)
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
if (error.code === 'PGRST116') {
|
||||
return null; // Aucune campagne trouvée
|
||||
@@ -373,11 +390,15 @@ export const participantService = {
|
||||
// Services pour les votes
|
||||
export const voteService = {
|
||||
async getByParticipant(campaignId: string, participantId: string): Promise<Vote[]> {
|
||||
// Récupérer les votes via les participants de la campagne
|
||||
const { data, error } = await supabase
|
||||
.from('votes')
|
||||
.select('*')
|
||||
.eq('campaign_id', campaignId)
|
||||
.eq('participant_id', participantId);
|
||||
.select(`
|
||||
*,
|
||||
participants!inner(campaign_id)
|
||||
`)
|
||||
.eq('participant_id', participantId)
|
||||
.eq('participants.campaign_id', campaignId);
|
||||
|
||||
if (error) handleSupabaseError(error, 'récupération des votes par participant');
|
||||
return data || [];
|
||||
@@ -439,10 +460,14 @@ export const voteService = {
|
||||
},
|
||||
|
||||
async getByCampaign(campaignId: string): Promise<Vote[]> {
|
||||
// Récupérer les votes via les participants de la campagne
|
||||
const { data, error } = await supabase
|
||||
.from('votes')
|
||||
.select('*')
|
||||
.eq('campaign_id', campaignId);
|
||||
.select(`
|
||||
*,
|
||||
participants!inner(campaign_id)
|
||||
`)
|
||||
.eq('participants.campaign_id', campaignId);
|
||||
|
||||
if (error) handleSupabaseError(error, 'récupération des votes par campagne');
|
||||
return data || [];
|
||||
@@ -456,10 +481,14 @@ export const voteService = {
|
||||
|
||||
if (participantsError) throw participantsError;
|
||||
|
||||
// Récupérer les votes via les participants de la campagne
|
||||
const { data: votes, error: votesError } = await supabase
|
||||
.from('votes')
|
||||
.select('*')
|
||||
.eq('campaign_id', campaignId);
|
||||
.select(`
|
||||
*,
|
||||
participants!inner(campaign_id)
|
||||
`)
|
||||
.eq('participants.campaign_id', campaignId);
|
||||
|
||||
if (votesError) throw votesError;
|
||||
|
||||
@@ -475,20 +504,34 @@ export const voteService = {
|
||||
});
|
||||
},
|
||||
|
||||
// Méthode pour remplacer tous les votes d'un participant de manière atomique
|
||||
// Méthode pour remplacer tous les votes d'un participant
|
||||
async replaceVotes(
|
||||
campaignId: string,
|
||||
participantId: string,
|
||||
votes: Array<{ proposition_id: string; amount: number }>
|
||||
): Promise<void> {
|
||||
// Utiliser une transaction pour garantir l'atomicité
|
||||
const { error } = await supabase.rpc('replace_participant_votes', {
|
||||
p_campaign_id: campaignId,
|
||||
p_participant_id: participantId,
|
||||
p_votes: votes
|
||||
});
|
||||
// 1. Supprimer tous les votes existants du participant
|
||||
const { error: deleteError } = await supabase
|
||||
.from('votes')
|
||||
.delete()
|
||||
.eq('participant_id', participantId);
|
||||
|
||||
if (error) handleSupabaseError(error, 'remplacement des votes du participant');
|
||||
if (deleteError) handleSupabaseError(deleteError, 'suppression des votes existants');
|
||||
|
||||
// 2. Insérer les nouveaux votes
|
||||
if (votes.length > 0) {
|
||||
const votesToInsert = votes.map(vote => ({
|
||||
participant_id: participantId,
|
||||
proposition_id: vote.proposition_id,
|
||||
amount: vote.amount
|
||||
}));
|
||||
|
||||
const { error: insertError } = await supabase
|
||||
.from('votes')
|
||||
.insert(votesToInsert);
|
||||
|
||||
if (insertError) handleSupabaseError(insertError, 'insertion des nouveaux votes');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user