This commit is contained in:
96
server/api/admin/fix-event-attendee-counts.post.ts
Normal file
96
server/api/admin/fix-event-attendee-counts.post.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
// server/api/admin/fix-event-attendee-counts.post.ts
|
||||
import { createSessionManager } from '~/server/utils/session';
|
||||
import { createNocoDBEventsClient } from '~/server/utils/nocodb-events';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
console.log('[admin/fix-event-attendee-counts] Starting attendee count fix...');
|
||||
|
||||
// Verify admin session
|
||||
const sessionManager = createSessionManager();
|
||||
const cookieHeader = getHeader(event, 'cookie');
|
||||
const session = sessionManager.getSession(cookieHeader);
|
||||
|
||||
if (!session?.user || session.user.tier !== 'admin') {
|
||||
throw createError({
|
||||
statusCode: 403,
|
||||
statusMessage: 'Admin access required'
|
||||
});
|
||||
}
|
||||
|
||||
console.log('[admin/fix-event-attendee-counts] Authorized admin user:', session.user.email);
|
||||
|
||||
const eventsClient = createNocoDBEventsClient();
|
||||
|
||||
// Get all events
|
||||
const eventsResponse = await eventsClient.findAll({ limit: 1000 });
|
||||
const events = eventsResponse.list || [];
|
||||
|
||||
console.log('[admin/fix-event-attendee-counts] Found', events.length, 'events to process');
|
||||
|
||||
const results = [];
|
||||
|
||||
// Process each event
|
||||
for (const eventObj of events) {
|
||||
try {
|
||||
const eventId = eventObj.event_id || eventObj.id || (eventObj as any).Id;
|
||||
const eventTitle = eventObj.title || 'Unknown Event';
|
||||
|
||||
console.log('[admin/fix-event-attendee-counts] Processing event:', eventTitle, 'ID:', eventId);
|
||||
|
||||
// Force update the attendee count
|
||||
const newCount = await eventsClient.forceUpdateEventAttendeeCount(eventId.toString());
|
||||
|
||||
results.push({
|
||||
event_id: eventId,
|
||||
title: eventTitle,
|
||||
old_count: eventObj.current_attendees || 0,
|
||||
new_count: newCount,
|
||||
status: 'success'
|
||||
});
|
||||
|
||||
console.log('[admin/fix-event-attendee-counts] ✅ Fixed event:', eventTitle, 'Count:', newCount);
|
||||
|
||||
} catch (eventError: any) {
|
||||
console.error('[admin/fix-event-attendee-counts] ❌ Error processing event:', eventObj.title, eventError);
|
||||
|
||||
results.push({
|
||||
event_id: eventObj.event_id || eventObj.id,
|
||||
title: eventObj.title || 'Unknown Event',
|
||||
old_count: eventObj.current_attendees || 0,
|
||||
new_count: 0,
|
||||
status: 'error',
|
||||
error: eventError.message
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const successCount = results.filter(r => r.status === 'success').length;
|
||||
const errorCount = results.filter(r => r.status === 'error').length;
|
||||
|
||||
console.log('[admin/fix-event-attendee-counts] ✅ Fix completed. Success:', successCount, 'Errors:', errorCount);
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `Fixed attendee counts for ${successCount} events (${errorCount} errors)`,
|
||||
data: {
|
||||
total_events: events.length,
|
||||
success_count: successCount,
|
||||
error_count: errorCount,
|
||||
results: results
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('[admin/fix-event-attendee-counts] ❌ Error:', error);
|
||||
|
||||
if (error.statusCode) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Failed to fix event attendee counts'
|
||||
});
|
||||
}
|
||||
});
|
||||
@@ -135,12 +135,12 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
const newRSVP = await eventsClient.createRSVP(rsvpData);
|
||||
|
||||
// Update event attendee count
|
||||
// Update event attendee count using the new force update method
|
||||
try {
|
||||
await updateEventAttendeeCount(eventId);
|
||||
console.log('[RSVP] ✅ Updated event attendee count for event:', eventId);
|
||||
const newAttendeeCount = await eventsClient.forceUpdateEventAttendeeCount(eventId);
|
||||
console.log('[RSVP] ✅ Force updated event attendee count for event:', eventId, 'to:', newAttendeeCount);
|
||||
} catch (countError) {
|
||||
console.log('[RSVP] ⚠️ Failed to update attendee count:', countError);
|
||||
console.log('[RSVP] ⚠️ Failed to force update attendee count:', countError);
|
||||
// Don't fail the RSVP creation if count update fails
|
||||
}
|
||||
|
||||
|
||||
@@ -180,31 +180,9 @@ export const normalizeEventFieldsFromNocoDB = (data: any): Event => {
|
||||
* Following the same pattern as the working members client
|
||||
*/
|
||||
export function createNocoDBEventsClient() {
|
||||
// Validate API token before using it (from incoming version)
|
||||
// Use the centralized configuration from nocodb.ts which now prioritizes environment variables
|
||||
const config = getNocoDbConfiguration();
|
||||
const token = config.token;
|
||||
|
||||
if (token) {
|
||||
const cleanToken = token.trim();
|
||||
|
||||
// Check for non-ASCII characters that would cause ByteString errors
|
||||
if (!/^[\x00-\xFF]*$/.test(cleanToken)) {
|
||||
console.error('[nocodb-events] ❌ CRITICAL ERROR: API token contains invalid Unicode characters!');
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Events system: NocoDB API token contains invalid characters. Please reconfigure the database connection.'
|
||||
});
|
||||
}
|
||||
|
||||
// Additional validation for common token issues
|
||||
if (cleanToken.includes('•') || cleanToken.includes('…') || cleanToken.includes('"') || cleanToken.includes('"')) {
|
||||
console.error('[nocodb-events] ❌ CRITICAL ERROR: API token contains formatting characters!');
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Events system: NocoDB API token contains formatting characters. Please reconfigure with the raw token from NocoDB.'
|
||||
});
|
||||
}
|
||||
}
|
||||
console.log('[nocodb-events] ✅ Using NocoDB configuration (prioritizes environment variables)');
|
||||
|
||||
const eventsClient = {
|
||||
/**
|
||||
@@ -737,6 +715,29 @@ export function createNocoDBEventsClient() {
|
||||
console.error('[nocodb-events] ❌ Error calculating attendee count for event:', eventId, error);
|
||||
return 0; // Return 0 if calculation fails
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Force update attendee count for an event and save to database
|
||||
*/
|
||||
async forceUpdateEventAttendeeCount(eventId: string): Promise<number> {
|
||||
console.log('[nocodb-events] Force updating attendee count for event:', eventId);
|
||||
|
||||
try {
|
||||
// Calculate the current attendee count
|
||||
const newCount = await this.calculateEventAttendeeCount(eventId);
|
||||
|
||||
// Update the event's current_attendees field directly
|
||||
await this.update(eventId, {
|
||||
current_attendees: newCount.toString()
|
||||
});
|
||||
|
||||
console.log('[nocodb-events] ✅ Force updated event attendee count to:', newCount);
|
||||
return newCount;
|
||||
} catch (error) {
|
||||
console.error('[nocodb-events] ❌ Error force updating attendee count:', error);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -212,17 +212,29 @@ export const setGlobalNocoDBConfig = (config: any) => {
|
||||
export const getNocoDbConfiguration = () => {
|
||||
let configToUse: any = null;
|
||||
|
||||
// Try to use the global configuration first
|
||||
if (globalNocoDBConfig) {
|
||||
console.log('[nocodb] Using global configuration - URL:', globalNocoDBConfig.url);
|
||||
// 1. PRIORITY: Check for environment variables first (container-friendly)
|
||||
const envConfig = {
|
||||
url: process.env.NUXT_NOCODB_URL || process.env.NOCODB_URL,
|
||||
token: process.env.NUXT_NOCODB_TOKEN || process.env.NOCODB_TOKEN || process.env.NOCODB_API_TOKEN,
|
||||
baseId: process.env.NUXT_NOCODB_BASE_ID || process.env.NOCODB_BASE_ID
|
||||
};
|
||||
|
||||
if (envConfig.url && envConfig.token) {
|
||||
console.log('[nocodb] ✅ Using environment variables - URL:', envConfig.url);
|
||||
configToUse = envConfig;
|
||||
}
|
||||
// 2. FALLBACK: Try to use the global admin panel configuration
|
||||
else if (globalNocoDBConfig) {
|
||||
console.log('[nocodb] Using admin panel configuration - URL:', globalNocoDBConfig.url);
|
||||
configToUse = {
|
||||
url: globalNocoDBConfig.url,
|
||||
token: globalNocoDBConfig.token,
|
||||
baseId: globalNocoDBConfig.baseId
|
||||
};
|
||||
} else {
|
||||
// Fallback to runtime config
|
||||
console.log('[nocodb] Global config not available, using runtime config');
|
||||
}
|
||||
// 3. LAST RESORT: Runtime config
|
||||
else {
|
||||
console.log('[nocodb] ⚠️ Using fallback runtime config');
|
||||
const config = useRuntimeConfig().nocodb;
|
||||
configToUse = {
|
||||
...config,
|
||||
@@ -231,33 +243,42 @@ export const getNocoDbConfiguration = () => {
|
||||
console.log('[nocodb] Fallback configuration URL:', configToUse.url);
|
||||
}
|
||||
|
||||
// Validate API token before using it
|
||||
if (configToUse.token) {
|
||||
const token = configToUse.token.trim();
|
||||
|
||||
// Check for non-ASCII characters that would cause ByteString errors
|
||||
if (!/^[\x00-\xFF]*$/.test(token)) {
|
||||
console.error('[nocodb] ❌ CRITICAL ERROR: API token contains invalid Unicode characters!');
|
||||
console.error('[nocodb] This will cause ByteString conversion errors in HTTP headers.');
|
||||
console.error('[nocodb] Please update the API token in the admin configuration.');
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'NocoDB API token contains invalid characters. Please reconfigure the database connection in the admin panel with a valid API token.'
|
||||
});
|
||||
}
|
||||
|
||||
// Additional validation for common token issues
|
||||
if (token.includes('•') || token.includes('…') || token.includes('"') || token.includes('"')) {
|
||||
console.error('[nocodb] ❌ CRITICAL ERROR: API token contains formatting characters!');
|
||||
console.error('[nocodb] Found characters like bullets (•), quotes, etc. that break HTTP headers.');
|
||||
console.error('[nocodb] Please copy the raw API token from NocoDB without any formatting.');
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'NocoDB API token contains formatting characters (bullets, quotes, etc.). Please reconfigure with the raw token from NocoDB.'
|
||||
});
|
||||
}
|
||||
// Validate configuration completeness
|
||||
if (!configToUse.url || !configToUse.token) {
|
||||
console.error('[nocodb] ❌ CRITICAL ERROR: Incomplete NocoDB configuration!');
|
||||
console.error('[nocodb] URL:', configToUse.url ? 'SET' : 'MISSING');
|
||||
console.error('[nocodb] Token:', configToUse.token ? 'SET' : 'MISSING');
|
||||
console.error('[nocodb] Set environment variables: NUXT_NOCODB_URL, NUXT_NOCODB_TOKEN');
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'NocoDB configuration incomplete. Set NUXT_NOCODB_URL and NUXT_NOCODB_TOKEN environment variables.'
|
||||
});
|
||||
}
|
||||
|
||||
// Validate API token before using it
|
||||
const token = configToUse.token.trim();
|
||||
|
||||
// Check for non-ASCII characters that would cause ByteString errors
|
||||
if (!/^[\x00-\xFF]*$/.test(token)) {
|
||||
console.error('[nocodb] ❌ CRITICAL ERROR: API token contains invalid Unicode characters!');
|
||||
console.error('[nocodb] This will cause ByteString conversion errors in HTTP headers.');
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'NocoDB API token contains invalid characters. Please set a valid NUXT_NOCODB_TOKEN environment variable.'
|
||||
});
|
||||
}
|
||||
|
||||
// Additional validation for common token issues
|
||||
if (token.includes('•') || token.includes('…') || token.includes('"') || token.includes('"')) {
|
||||
console.error('[nocodb] ❌ CRITICAL ERROR: API token contains formatting characters!');
|
||||
console.error('[nocodb] Found characters like bullets (•), quotes, etc. that break HTTP headers.');
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'NocoDB API token contains formatting characters. Please set a clean NUXT_NOCODB_TOKEN environment variable.'
|
||||
});
|
||||
}
|
||||
|
||||
console.log('[nocodb] ✅ Configuration validated successfully');
|
||||
return configToUse;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user