cleaning up api

This commit is contained in:
2025-03-12 15:49:47 +08:00
parent 285a0c780a
commit 9d7d1abb49
10 changed files with 1974 additions and 839 deletions

View File

@@ -1,7 +1,8 @@
import { Context } from 'hono';
import supabase from '../utils/supabase';
export const getInfluencers = async (c: Context) => {
// Get all influencers with filtering and pagination
const getInfluencers = async (c: Context) => {
try {
const {
platform,
@@ -20,12 +21,13 @@ export const getInfluencers = async (c: Context) => {
name,
platform,
profile_url,
external_id,
followers_count,
video_count,
platform_count,
created_at,
updated_at
`);
`, { count: 'exact' });
// Apply filters
if (platform) {
@@ -49,6 +51,7 @@ export const getInfluencers = async (c: Context) => {
const { data: influencers, error, count } = await query;
if (error) {
console.error('Error fetching influencers:', error);
return c.json({ error: error.message }, 500);
}
@@ -59,11 +62,13 @@ export const getInfluencers = async (c: Context) => {
offset: Number(offset)
});
} catch (error) {
console.error('Error in getInfluencers:', error);
return c.json({ error: 'Internal server error' }, 500);
}
};
export const getInfluencerById = async (c: Context) => {
// Get a specific influencer by ID
const getInfluencerById = async (c: Context) => {
try {
const { influencer_id } = c.req.param();
@@ -74,32 +79,30 @@ export const getInfluencerById = async (c: Context) => {
name,
platform,
profile_url,
external_id,
followers_count,
video_count,
platform_count,
created_at,
updated_at,
posts (
post_id,
title,
description,
published_at
)
updated_at
`)
.eq('influencer_id', influencer_id)
.single();
if (error) {
console.error('Error fetching influencer:', error);
return c.json({ error: 'Influencer not found' }, 404);
}
return c.json(influencer);
} catch (error) {
console.error('Error in getInfluencerById:', error);
return c.json({ error: 'Internal server error' }, 500);
}
};
export const getInfluencerStats = async (c: Context) => {
// Get aggregated stats for influencers
const getInfluencerStats = async (c: Context) => {
try {
const { platform } = c.req.query();
@@ -114,6 +117,7 @@ export const getInfluencerStats = async (c: Context) => {
const { data: stats, error } = await query;
if (error) {
console.error('Error fetching influencer stats:', error);
return c.json({ error: error.message }, 500);
}
@@ -126,11 +130,212 @@ export const getInfluencerStats = async (c: Context) => {
),
average_videos: Math.round(
stats.reduce((sum: number, item: any) => sum + (item.video_count || 0), 0) / (stats.length || 1)
)
),
platform_distribution: stats.reduce((acc: Record<string, number>, item: any) => {
const platform = item.platform || 'unknown';
acc[platform] = (acc[platform] || 0) + 1;
return acc;
}, {})
};
return c.json(aggregatedStats);
} catch (error) {
console.error('Error in getInfluencerStats:', error);
return c.json({ error: 'Internal server error' }, 500);
}
};
// Create a new influencer
const createInfluencer = async (c: Context) => {
try {
const { name, platform, profile_url, external_id, followers_count, video_count } = await c.req.json();
if (!name) {
return c.json({ error: 'Name is required' }, 400);
}
const { data: influencer, error } = await supabase
.from('influencers')
.insert({
name,
platform,
profile_url,
external_id,
followers_count: followers_count || 0,
video_count: video_count || 0
})
.select()
.single();
if (error) {
if (error.code === '23505') { // Unique constraint violation
return c.json({ error: 'An influencer with this external ID already exists' }, 409);
}
console.error('Error creating influencer:', error);
return c.json({ error: 'Failed to create influencer' }, 500);
}
return c.json(influencer, 201);
} catch (error) {
console.error('Error in createInfluencer:', error);
return c.json({ error: 'Internal server error' }, 500);
}
};
// Update an existing influencer
const updateInfluencer = async (c: Context) => {
try {
const { influencer_id } = c.req.param();
const { name, platform, profile_url, external_id, followers_count, video_count } = await c.req.json();
// Check if influencer exists
const { data: existingInfluencer, error: fetchError } = await supabase
.from('influencers')
.select('influencer_id')
.eq('influencer_id', influencer_id)
.single();
if (fetchError || !existingInfluencer) {
return c.json({ error: 'Influencer not found' }, 404);
}
const updateData: any = {};
if (name !== undefined) updateData.name = name;
if (platform !== undefined) updateData.platform = platform;
if (profile_url !== undefined) updateData.profile_url = profile_url;
if (external_id !== undefined) updateData.external_id = external_id;
if (followers_count !== undefined) updateData.followers_count = followers_count;
if (video_count !== undefined) updateData.video_count = video_count;
updateData.updated_at = new Date().toISOString();
const { data: updatedInfluencer, error: updateError } = await supabase
.from('influencers')
.update(updateData)
.eq('influencer_id', influencer_id)
.select()
.single();
if (updateError) {
if (updateError.code === '23505') { // Unique constraint violation
return c.json({ error: 'An influencer with this external ID already exists' }, 409);
}
console.error('Error updating influencer:', updateError);
return c.json({ error: 'Failed to update influencer' }, 500);
}
return c.json(updatedInfluencer);
} catch (error) {
console.error('Error in updateInfluencer:', error);
return c.json({ error: 'Internal server error' }, 500);
}
};
// Delete an influencer
const deleteInfluencer = async (c: Context) => {
try {
const { influencer_id } = c.req.param();
// Check if influencer exists
const { data: existingInfluencer, error: fetchError } = await supabase
.from('influencers')
.select('influencer_id')
.eq('influencer_id', influencer_id)
.single();
if (fetchError || !existingInfluencer) {
return c.json({ error: 'Influencer not found' }, 404);
}
// Check if influencer has any posts
const { data: posts, error: postsError } = await supabase
.from('posts')
.select('post_id')
.eq('influencer_id', influencer_id)
.limit(1);
if (!postsError && posts && posts.length > 0) {
return c.json({
error: 'Cannot delete influencer with existing posts. Delete their posts first or use the force parameter.'
}, 400);
}
// Delete the influencer
const { error: deleteError } = await supabase
.from('influencers')
.delete()
.eq('influencer_id', influencer_id);
if (deleteError) {
console.error('Error deleting influencer:', deleteError);
return c.json({ error: 'Failed to delete influencer' }, 500);
}
return c.body(null, 204);
} catch (error) {
console.error('Error in deleteInfluencer:', error);
return c.json({ error: 'Internal server error' }, 500);
}
};
// Get all posts for a specific influencer
const getInfluencerPosts = async (c: Context) => {
try {
const { influencer_id } = c.req.param();
const { limit = '20', offset = '0' } = c.req.query();
// Check if influencer exists
const { data: influencer, error: influencerError } = await supabase
.from('influencers')
.select('influencer_id, name')
.eq('influencer_id', influencer_id)
.single();
if (influencerError || !influencer) {
return c.json({ error: 'Influencer not found' }, 404);
}
// Get posts for the influencer
const { data: posts, error: postsError, count } = await supabase
.from('posts')
.select(`
post_id,
platform,
post_url,
title,
description,
published_at,
created_at,
updated_at
`, { count: 'exact' })
.eq('influencer_id', influencer_id)
.order('published_at', { ascending: false })
.range(parseInt(offset), parseInt(offset) + parseInt(limit) - 1);
if (postsError) {
console.error('Error fetching influencer posts:', postsError);
return c.json({ error: 'Failed to fetch influencer posts' }, 500);
}
return c.json({
influencer_id,
influencer_name: influencer.name,
posts,
count,
limit: parseInt(limit),
offset: parseInt(offset)
});
} catch (error) {
console.error('Error in getInfluencerPosts:', error);
return c.json({ error: 'Internal server error' }, 500);
}
};
export default {
getInfluencers,
getInfluencerById,
getInfluencerStats,
createInfluencer,
updateInfluencer,
deleteInfluencer,
getInfluencerPosts
};