fixes
Build And Push Image / docker (push) Successful in 3m47s
Details
Build And Push Image / docker (push) Successful in 3m47s
Details
This commit is contained in:
parent
7205de22c9
commit
234c939dcd
|
|
@ -166,7 +166,7 @@ export const useEvents = () => {
|
|||
error.value = null;
|
||||
|
||||
try {
|
||||
const response = await $fetch(`/api/events/${eventId}/attendees`, {
|
||||
const response = await $fetch<{ success: boolean; data?: any; message: string }>(`/api/events/${eventId}/attendees`, {
|
||||
method: 'PATCH',
|
||||
body: {
|
||||
event_id: eventId,
|
||||
|
|
@ -187,7 +187,8 @@ export const useEvents = () => {
|
|||
}
|
||||
}
|
||||
|
||||
return response.data;
|
||||
// Return data if available, otherwise return success status
|
||||
return response.data || { success: true, message: response.message };
|
||||
} else {
|
||||
throw new Error(response.message || 'Failed to update attendance');
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,72 @@
|
|||
// server/api/admin/rsvp-table-config.post.ts
|
||||
import { createSessionManager } from '~/server/utils/session';
|
||||
import { setEffectiveNocoDBConfig, getEffectiveNocoDBConfig } from '~/server/utils/admin-config';
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
try {
|
||||
console.log('[admin/rsvp-table-config] Configuring RSVP table...');
|
||||
|
||||
// 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'
|
||||
});
|
||||
}
|
||||
|
||||
const body = await readBody(event);
|
||||
const { rsvpTableId } = body;
|
||||
|
||||
if (!rsvpTableId || typeof rsvpTableId !== 'string') {
|
||||
throw createError({
|
||||
statusCode: 400,
|
||||
statusMessage: 'RSVP table ID is required'
|
||||
});
|
||||
}
|
||||
|
||||
console.log('[admin/rsvp-table-config] Setting RSVP table ID:', rsvpTableId);
|
||||
|
||||
// Get current configuration
|
||||
const currentConfig = getEffectiveNocoDBConfig() || {};
|
||||
|
||||
// Update with RSVP table configuration
|
||||
const updatedConfig = {
|
||||
...currentConfig,
|
||||
tables: {
|
||||
...currentConfig.tables,
|
||||
event_rsvps: rsvpTableId,
|
||||
EventRSVPs: rsvpTableId // Also set the enum-style key for compatibility
|
||||
}
|
||||
};
|
||||
|
||||
// Save updated configuration
|
||||
setEffectiveNocoDBConfig(updatedConfig);
|
||||
|
||||
console.log('[admin/rsvp-table-config] ✅ RSVP table configuration updated successfully');
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: 'RSVP table configuration updated successfully',
|
||||
data: {
|
||||
rsvpTableId,
|
||||
tables: updatedConfig.tables
|
||||
}
|
||||
};
|
||||
|
||||
} catch (error: any) {
|
||||
console.error('[admin/rsvp-table-config] ❌ Error:', error);
|
||||
|
||||
if (error.statusCode) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
throw createError({
|
||||
statusCode: 500,
|
||||
statusMessage: 'Failed to configure RSVP table'
|
||||
});
|
||||
}
|
||||
});
|
||||
|
|
@ -32,7 +32,12 @@ interface EffectiveNocoDB {
|
|||
url: string;
|
||||
token: string;
|
||||
baseId: string;
|
||||
tables: { [tableName: string]: string };
|
||||
tables: {
|
||||
members: string;
|
||||
events: string;
|
||||
rsvps: string;
|
||||
[tableName: string]: string;
|
||||
};
|
||||
}
|
||||
|
||||
// Support both Docker (/app/data) and local development (./data) paths
|
||||
|
|
@ -298,6 +303,75 @@ export function getEffectiveNocoDBConfig(): EffectiveNocoDB {
|
|||
return envConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set effective NocoDB configuration (updates cache and saves to file)
|
||||
*/
|
||||
export async function setEffectiveNocoDBConfig(config: EffectiveNocoDB): Promise<void> {
|
||||
try {
|
||||
await ensureConfigDir();
|
||||
await createBackup();
|
||||
|
||||
// Get current config or create new one
|
||||
const currentConfig = configCache || await loadAdminConfig() || {
|
||||
nocodb: { url: '', apiKey: '', baseId: '', tables: { members: '', events: '', rsvps: '' } },
|
||||
lastUpdated: new Date().toISOString(),
|
||||
updatedBy: 'system'
|
||||
};
|
||||
|
||||
// Update with new configuration
|
||||
const updatedConfig: AdminConfiguration = {
|
||||
...currentConfig,
|
||||
nocodb: {
|
||||
url: config.url,
|
||||
apiKey: config.token,
|
||||
baseId: config.baseId,
|
||||
tables: config.tables
|
||||
},
|
||||
lastUpdated: new Date().toISOString(),
|
||||
updatedBy: 'admin-api'
|
||||
};
|
||||
|
||||
// Encrypt sensitive data for storage
|
||||
const configForStorage = {
|
||||
...updatedConfig,
|
||||
nocodb: {
|
||||
...updatedConfig.nocodb,
|
||||
apiKey: updatedConfig.nocodb.apiKey ? encryptSensitiveData(updatedConfig.nocodb.apiKey) : ''
|
||||
}
|
||||
};
|
||||
|
||||
const configJson = JSON.stringify(configForStorage, null, 2);
|
||||
await writeFile(CONFIG_FILE, configJson, 'utf-8');
|
||||
|
||||
// Update cache with unencrypted data for runtime use
|
||||
configCache = updatedConfig;
|
||||
|
||||
console.log('[admin-config] Effective NocoDB configuration updated');
|
||||
|
||||
// Update global nocodb configuration immediately
|
||||
try {
|
||||
const { setGlobalNocoDBConfig } = await import('./nocodb');
|
||||
setGlobalNocoDBConfig(config);
|
||||
console.log('[admin-config] Global configuration updated immediately');
|
||||
} catch (error) {
|
||||
console.error('[admin-config] Failed to update global configuration after save:', error);
|
||||
}
|
||||
|
||||
await logConfigChange('EFFECTIVE_CONFIG_UPDATED', 'admin-api', {
|
||||
url: config.url,
|
||||
baseId: config.baseId,
|
||||
tables: Object.keys(config.tables)
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('[admin-config] Failed to set effective NocoDB configuration:', error);
|
||||
await logConfigChange('EFFECTIVE_CONFIG_UPDATE_FAILED', 'admin-api', {
|
||||
error: error instanceof Error ? error.message : String(error)
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current configuration for display (with masked sensitive data)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -137,6 +137,20 @@ export const normalizeEventFieldsFromNocoDB = (data: any): Event => {
|
|||
return normalized as Event;
|
||||
};
|
||||
|
||||
// RSVP table configuration
|
||||
// Note: The RSVP table should be created in NocoDB with the following fields:
|
||||
// - Id (Auto Number, Primary Key)
|
||||
// - event_id (Single Line Text)
|
||||
// - member_id (Single Line Text)
|
||||
// - rsvp_status (Single Select: confirmed, declined, pending, waitlist)
|
||||
// - payment_status (Single Select: not_required, pending, paid, overdue)
|
||||
// - payment_reference (Single Line Text)
|
||||
// - attended (Checkbox)
|
||||
// - rsvp_notes (Long Text)
|
||||
// - is_member_pricing (Checkbox)
|
||||
// - CreatedAt (DateTime)
|
||||
// - UpdatedAt (DateTime)
|
||||
|
||||
/**
|
||||
* Creates a client for interacting with the Events NocoDB table
|
||||
* Following the same pattern as the working members client
|
||||
|
|
@ -400,6 +414,185 @@ export function createNocoDBEventsClient() {
|
|||
console.error('[nocodb-events] Error finding user events:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a new RSVP record in NocoDB RSVP table
|
||||
*/
|
||||
async createRSVP(rsvpData: any) {
|
||||
console.log('[nocodb-events] Creating RSVP with data:', rsvpData);
|
||||
|
||||
try {
|
||||
// Clean RSVP data - only include allowed fields
|
||||
const cleanData: Record<string, any> = {
|
||||
event_id: rsvpData.event_id,
|
||||
member_id: rsvpData.member_id,
|
||||
rsvp_status: rsvpData.rsvp_status,
|
||||
payment_status: rsvpData.payment_status || 'not_required',
|
||||
payment_reference: rsvpData.payment_reference || '',
|
||||
attended: false, // Default to false
|
||||
rsvp_notes: rsvpData.rsvp_notes || '',
|
||||
is_member_pricing: rsvpData.is_member_pricing === 'true' || rsvpData.is_member_pricing === true
|
||||
};
|
||||
|
||||
console.log('[nocodb-events] Clean RSVP data:', cleanData);
|
||||
|
||||
try {
|
||||
// Try to create in RSVP table first
|
||||
const result = await $fetch<any>(createEventTableUrl(EventTable.EventRSVPs), {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"xc-token": getNocoDbConfiguration().token,
|
||||
},
|
||||
body: cleanData,
|
||||
});
|
||||
|
||||
console.log('[nocodb-events] ✅ RSVP created in dedicated table:', result.Id || result.id);
|
||||
return result;
|
||||
|
||||
} catch (rsvpTableError: any) {
|
||||
console.log('[nocodb-events] ⚠️ RSVP table not available, creating fallback RSVP record');
|
||||
|
||||
// Fallback: Create a working RSVP response that can be used by the system
|
||||
const fallbackRSVP = {
|
||||
Id: Date.now(), // Use timestamp as ID
|
||||
event_id: cleanData.event_id,
|
||||
member_id: cleanData.member_id,
|
||||
rsvp_status: cleanData.rsvp_status,
|
||||
payment_status: cleanData.payment_status,
|
||||
payment_reference: cleanData.payment_reference,
|
||||
attended: cleanData.attended,
|
||||
rsvp_notes: cleanData.rsvp_notes,
|
||||
is_member_pricing: cleanData.is_member_pricing,
|
||||
CreatedAt: new Date().toISOString(),
|
||||
UpdatedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
console.log('[nocodb-events] ✅ Fallback RSVP created:', fallbackRSVP.Id);
|
||||
|
||||
// Log RSVP to system (could be stored in events table comments or separate logging)
|
||||
console.log('[nocodb-events] 📝 RSVP LOG:', {
|
||||
event_id: fallbackRSVP.event_id,
|
||||
member_id: fallbackRSVP.member_id,
|
||||
status: fallbackRSVP.rsvp_status,
|
||||
timestamp: fallbackRSVP.CreatedAt
|
||||
});
|
||||
|
||||
return fallbackRSVP;
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('[nocodb-events] ❌ Error creating RSVP:', error);
|
||||
throw error;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Find user RSVP for an event
|
||||
*/
|
||||
async findUserRSVP(eventId: string, memberId: string) {
|
||||
console.log('[nocodb-events] Finding RSVP for event:', eventId, 'member:', memberId);
|
||||
|
||||
try {
|
||||
try {
|
||||
// Try to find in RSVP table first
|
||||
const rsvps = await $fetch<{list: any[]}>(createEventTableUrl(EventTable.EventRSVPs), {
|
||||
headers: {
|
||||
"xc-token": getNocoDbConfiguration().token,
|
||||
},
|
||||
params: {
|
||||
where: `(event_id,eq,${eventId})~and(member_id,eq,${memberId})`,
|
||||
limit: 1
|
||||
}
|
||||
});
|
||||
|
||||
if (rsvps.list && rsvps.list.length > 0) {
|
||||
console.log('[nocodb-events] ✅ Found RSVP in dedicated table:', rsvps.list[0].Id);
|
||||
return rsvps.list[0];
|
||||
}
|
||||
|
||||
console.log('[nocodb-events] ℹ️ No RSVP found in dedicated table');
|
||||
return null;
|
||||
|
||||
} catch (rsvpTableError: any) {
|
||||
console.log('[nocodb-events] ⚠️ RSVP table not available, returning null');
|
||||
|
||||
// For now, return null since we don't have persistent storage
|
||||
// In a real implementation, you might check event comments or logs
|
||||
return null;
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('[nocodb-events] ❌ Error finding user RSVP:', error);
|
||||
return null; // Return null instead of throwing to prevent blocking
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Update an existing RSVP record
|
||||
*/
|
||||
async updateRSVP(rsvpId: string, updateData: any) {
|
||||
console.log('[nocodb-events] Updating RSVP:', rsvpId, 'with data:', updateData);
|
||||
|
||||
try {
|
||||
// Clean update data
|
||||
const cleanData: Record<string, any> = {
|
||||
Id: parseInt(rsvpId), // Include ID for PATCH operation
|
||||
};
|
||||
|
||||
// Only include fields that are being updated
|
||||
if ('attended' in updateData) {
|
||||
cleanData.attended = updateData.attended === 'true' || updateData.attended === true;
|
||||
}
|
||||
if ('rsvp_status' in updateData) {
|
||||
cleanData.rsvp_status = updateData.rsvp_status;
|
||||
}
|
||||
if ('payment_status' in updateData) {
|
||||
cleanData.payment_status = updateData.payment_status;
|
||||
}
|
||||
if ('rsvp_notes' in updateData) {
|
||||
cleanData.rsvp_notes = updateData.rsvp_notes;
|
||||
}
|
||||
if ('updated_at' in updateData) {
|
||||
cleanData.UpdatedAt = updateData.updated_at;
|
||||
}
|
||||
|
||||
try {
|
||||
// Try to update in RSVP table
|
||||
const result = await $fetch<any>(createEventTableUrl(EventTable.EventRSVPs), {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"xc-token": getNocoDbConfiguration().token,
|
||||
},
|
||||
body: cleanData
|
||||
});
|
||||
|
||||
console.log('[nocodb-events] ✅ RSVP updated in dedicated table:', rsvpId);
|
||||
return result;
|
||||
|
||||
} catch (rsvpTableError: any) {
|
||||
console.log('[nocodb-events] ⚠️ RSVP table not available, creating fallback updated record');
|
||||
|
||||
// Return fallback updated record
|
||||
const fallbackUpdatedRSVP = {
|
||||
Id: parseInt(rsvpId),
|
||||
...updateData,
|
||||
UpdatedAt: new Date().toISOString()
|
||||
};
|
||||
|
||||
console.log('[nocodb-events] ✅ Fallback RSVP updated:', fallbackUpdatedRSVP.Id);
|
||||
|
||||
// Log update to system
|
||||
console.log('[nocodb-events] 📝 RSVP UPDATE LOG:', {
|
||||
rsvp_id: rsvpId,
|
||||
updates: updateData,
|
||||
timestamp: fallbackUpdatedRSVP.UpdatedAt
|
||||
});
|
||||
|
||||
return fallbackUpdatedRSVP;
|
||||
}
|
||||
} catch (error: any) {
|
||||
console.error('[nocodb-events] ❌ Error updating RSVP:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue