Initial commit - Project start (July 17, 2025)
Mirror to GitHub / mirror (push) Successful in 26s
Test and Lint / backend-test (push) Successful in 1m11s
continuous-integration/drone/push Build is passing
Test and Lint / frontend-test (push) Successful in 2m28s
Version and Release / version-bump (push) Successful in 32s
Version and Release / trigger-drone (push) Has been skipped
Mirror to GitHub / mirror (push) Successful in 26s
Test and Lint / backend-test (push) Successful in 1m11s
continuous-integration/drone/push Build is passing
Test and Lint / frontend-test (push) Successful in 2m28s
Version and Release / version-bump (push) Successful in 32s
Version and Release / trigger-drone (push) Has been skipped
Original: feat: enhance security logging and ensure rate limit blocks are properly tracked - Add comprehensive logging for rate limit blocks with full request details - IP address (with proper proxy detection), user agent, headers, timestamps - Rate limit info (current count, limit, remaining, reset time) - Separate tracking for auth vs general endpoints - Enhance authentication failure logging - JWT validation failures with detailed error info - Admin auth attempts without token - Failed token validation with user context - All events include IP, path, method, user agent - Improve Winston logger configuration for production - Add automatic log rotation (10MB errors, 50MB combined) - Create separate security.log for auth/rate limit events - Ensure logs directory exists automatically - Add structured JSON format for log aggregation - Support container logging with LOG_TO_CONSOLE env var - Create comprehensive documentation - Security logging guide with examples - Monitoring recommendations - Configuration reference - Add test script to verify logging functionality All rate limit settings remain configurable via admin panel: - Window duration, max requests, auth limits - Skip authenticated requests option - Public endpoints only option 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
// Event/Gallery types
|
||||
export interface Event {
|
||||
id: number;
|
||||
slug: string;
|
||||
event_type: string;
|
||||
event_name: string;
|
||||
event_date: string;
|
||||
host_name?: string;
|
||||
host_email: string;
|
||||
admin_email: string;
|
||||
welcome_message?: string;
|
||||
color_theme?: string;
|
||||
share_link: string;
|
||||
created_at: string;
|
||||
expires_at: string;
|
||||
is_active: boolean;
|
||||
is_archived: boolean;
|
||||
archive_path?: string;
|
||||
archived_at?: string;
|
||||
photo_count?: number;
|
||||
total_size?: number;
|
||||
recent_photos?: Array<{
|
||||
filename: string;
|
||||
type: string;
|
||||
size_bytes: number;
|
||||
uploaded_at: string;
|
||||
}>;
|
||||
allow_user_uploads?: boolean;
|
||||
upload_category_id?: number | null;
|
||||
hero_photo_id?: number | null;
|
||||
total_views?: number;
|
||||
total_downloads?: number;
|
||||
unique_visitors?: number;
|
||||
}
|
||||
|
||||
export interface GalleryInfo {
|
||||
event_name: string;
|
||||
event_type: string;
|
||||
event_date: string;
|
||||
expires_at: string;
|
||||
is_active: boolean;
|
||||
is_expired: boolean;
|
||||
requires_password?: boolean;
|
||||
color_theme?: string;
|
||||
}
|
||||
|
||||
export interface Photo {
|
||||
id: number;
|
||||
filename: string;
|
||||
url: string;
|
||||
thumbnail_url?: string;
|
||||
type: 'collage' | 'individual';
|
||||
category_id?: number;
|
||||
category_name?: string;
|
||||
category_slug?: string;
|
||||
size: number;
|
||||
uploaded_at: string;
|
||||
}
|
||||
|
||||
export interface PhotoCategory {
|
||||
id: number;
|
||||
name: string;
|
||||
slug: string;
|
||||
is_global: boolean;
|
||||
}
|
||||
|
||||
export interface GalleryData {
|
||||
event: {
|
||||
id: number;
|
||||
event_name: string;
|
||||
event_type: string;
|
||||
event_date: string;
|
||||
welcome_message?: string;
|
||||
color_theme?: string;
|
||||
expires_at: string;
|
||||
allow_user_uploads?: boolean;
|
||||
upload_category_id?: number | null;
|
||||
hero_photo_id?: number | null;
|
||||
};
|
||||
categories?: PhotoCategory[];
|
||||
photos: Photo[];
|
||||
}
|
||||
|
||||
export interface GalleryStats {
|
||||
total_photos: number;
|
||||
total_views: number;
|
||||
total_downloads: number;
|
||||
unique_visitors: number;
|
||||
}
|
||||
|
||||
// Auth types
|
||||
export interface AdminUser {
|
||||
id: number;
|
||||
username: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
export interface LoginResponse {
|
||||
token: string;
|
||||
user: AdminUser;
|
||||
}
|
||||
|
||||
export interface GalleryAuthResponse {
|
||||
token: string;
|
||||
event: {
|
||||
id: number;
|
||||
event_name: string;
|
||||
event_type: string;
|
||||
event_date: string;
|
||||
welcome_message?: string;
|
||||
color_theme?: string;
|
||||
expires_at: string;
|
||||
allow_user_uploads?: boolean;
|
||||
upload_category_id?: number | null;
|
||||
};
|
||||
}
|
||||
|
||||
// API Error type
|
||||
export interface ApiError {
|
||||
error: string;
|
||||
errors?: Array<{
|
||||
type: string;
|
||||
msg: string;
|
||||
path: string;
|
||||
location: string;
|
||||
}>;
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
// Gallery Layout Types
|
||||
export type GalleryLayoutType = 'grid' | 'masonry' | 'carousel' | 'timeline' | 'hero' | 'mosaic';
|
||||
|
||||
export interface GalleryLayoutSettings {
|
||||
// Common settings
|
||||
spacing?: 'tight' | 'normal' | 'relaxed';
|
||||
photoAnimation?: 'none' | 'fade' | 'scale' | 'slide';
|
||||
photoShape?: 'square' | 'rounded' | 'circle';
|
||||
|
||||
// Grid specific
|
||||
gridColumns?: {
|
||||
mobile: number;
|
||||
tablet: number;
|
||||
desktop: number;
|
||||
};
|
||||
|
||||
// Masonry specific
|
||||
masonryGutter?: number;
|
||||
|
||||
// Carousel specific
|
||||
carouselAutoplay?: boolean;
|
||||
carouselInterval?: number;
|
||||
carouselShowThumbnails?: boolean;
|
||||
|
||||
// Timeline specific
|
||||
timelineGrouping?: 'day' | 'week' | 'month';
|
||||
timelineShowDates?: boolean;
|
||||
|
||||
// Hero specific
|
||||
heroImageId?: number;
|
||||
heroImagePosition?: 'top' | 'center' | 'bottom';
|
||||
heroOverlayOpacity?: number;
|
||||
|
||||
// Mosaic specific
|
||||
mosaicPattern?: 'random' | 'structured' | 'alternating';
|
||||
}
|
||||
|
||||
export interface ThemeConfig {
|
||||
// Colors
|
||||
primaryColor?: string;
|
||||
accentColor?: string;
|
||||
backgroundColor?: string;
|
||||
textColor?: string;
|
||||
|
||||
// Typography
|
||||
fontFamily?: string;
|
||||
headingFontFamily?: string;
|
||||
fontSize?: 'small' | 'normal' | 'large';
|
||||
|
||||
// Styling
|
||||
borderRadius?: 'none' | 'sm' | 'md' | 'lg';
|
||||
buttonStyle?: 'solid' | 'outline' | 'ghost';
|
||||
shadowStyle?: 'none' | 'subtle' | 'normal' | 'dramatic';
|
||||
|
||||
// Gallery Layout
|
||||
galleryLayout?: GalleryLayoutType;
|
||||
gallerySettings?: GalleryLayoutSettings;
|
||||
|
||||
// Header/Footer
|
||||
headerStyle?: 'minimal' | 'standard' | 'full';
|
||||
footerStyle?: 'minimal' | 'standard' | 'full';
|
||||
showEventInfo?: boolean;
|
||||
showBranding?: boolean;
|
||||
|
||||
// Advanced
|
||||
logoUrl?: string;
|
||||
customCss?: string;
|
||||
backgroundPattern?: 'none' | 'dots' | 'grid' | 'waves';
|
||||
}
|
||||
|
||||
export interface EventTheme {
|
||||
id?: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
thumbnail?: string;
|
||||
config: ThemeConfig;
|
||||
isPreset?: boolean;
|
||||
}
|
||||
|
||||
// Preset theme definitions
|
||||
export const GALLERY_THEME_PRESETS: Record<string, EventTheme> = {
|
||||
default: {
|
||||
name: 'Classic Grid',
|
||||
description: 'Clean and organized grid layout',
|
||||
config: {
|
||||
primaryColor: '#5C8762',
|
||||
accentColor: '#22c55e',
|
||||
backgroundColor: '#fafafa',
|
||||
textColor: '#171717',
|
||||
borderRadius: 'md',
|
||||
galleryLayout: 'grid',
|
||||
gallerySettings: {
|
||||
spacing: 'normal',
|
||||
photoAnimation: 'fade',
|
||||
gridColumns: { mobile: 2, tablet: 3, desktop: 4 }
|
||||
},
|
||||
headerStyle: 'standard',
|
||||
footerStyle: 'standard'
|
||||
},
|
||||
isPreset: true
|
||||
},
|
||||
|
||||
elegantWedding: {
|
||||
name: 'Elegant Wedding',
|
||||
description: 'Sophisticated layout with hero image and timeline',
|
||||
config: {
|
||||
primaryColor: '#c9a961',
|
||||
accentColor: '#e6ddd4',
|
||||
backgroundColor: '#fdfcfb',
|
||||
textColor: '#3f3f3f',
|
||||
fontFamily: 'Playfair Display, serif',
|
||||
headingFontFamily: 'Playfair Display, serif',
|
||||
borderRadius: 'lg',
|
||||
shadowStyle: 'subtle',
|
||||
galleryLayout: 'hero',
|
||||
gallerySettings: {
|
||||
spacing: 'relaxed',
|
||||
photoAnimation: 'scale',
|
||||
photoShape: 'rounded',
|
||||
heroOverlayOpacity: 0.3
|
||||
},
|
||||
headerStyle: 'full',
|
||||
footerStyle: 'minimal'
|
||||
},
|
||||
isPreset: true
|
||||
},
|
||||
|
||||
modernMasonry: {
|
||||
name: 'Modern Masonry',
|
||||
description: 'Pinterest-style dynamic layout',
|
||||
config: {
|
||||
primaryColor: '#3b82f6',
|
||||
accentColor: '#1e40af',
|
||||
backgroundColor: '#ffffff',
|
||||
textColor: '#0f172a',
|
||||
fontFamily: 'Inter, sans-serif',
|
||||
borderRadius: 'sm',
|
||||
galleryLayout: 'masonry',
|
||||
gallerySettings: {
|
||||
spacing: 'tight',
|
||||
photoAnimation: 'fade',
|
||||
masonryGutter: 16
|
||||
},
|
||||
headerStyle: 'minimal',
|
||||
footerStyle: 'minimal',
|
||||
shadowStyle: 'normal'
|
||||
},
|
||||
isPreset: true
|
||||
},
|
||||
|
||||
birthdayFun: {
|
||||
name: 'Birthday Celebration',
|
||||
description: 'Vibrant carousel with playful animations',
|
||||
config: {
|
||||
primaryColor: '#ec4899',
|
||||
accentColor: '#fbbf24',
|
||||
backgroundColor: '#fef3c7',
|
||||
textColor: '#451a03',
|
||||
fontFamily: 'Comic Neue, cursive',
|
||||
borderRadius: 'lg',
|
||||
galleryLayout: 'carousel',
|
||||
gallerySettings: {
|
||||
spacing: 'normal',
|
||||
photoAnimation: 'slide',
|
||||
carouselAutoplay: true,
|
||||
carouselInterval: 5000,
|
||||
carouselShowThumbnails: true
|
||||
},
|
||||
headerStyle: 'full',
|
||||
footerStyle: 'standard',
|
||||
backgroundPattern: 'dots'
|
||||
},
|
||||
isPreset: true
|
||||
},
|
||||
|
||||
corporateTimeline: {
|
||||
name: 'Corporate Timeline',
|
||||
description: 'Professional chronological layout',
|
||||
config: {
|
||||
primaryColor: '#1f2937',
|
||||
accentColor: '#059669',
|
||||
backgroundColor: '#f9fafb',
|
||||
textColor: '#111827',
|
||||
fontFamily: 'IBM Plex Sans, sans-serif',
|
||||
borderRadius: 'sm',
|
||||
galleryLayout: 'timeline',
|
||||
gallerySettings: {
|
||||
spacing: 'normal',
|
||||
photoAnimation: 'none',
|
||||
timelineGrouping: 'day',
|
||||
timelineShowDates: true
|
||||
},
|
||||
headerStyle: 'standard',
|
||||
footerStyle: 'full',
|
||||
buttonStyle: 'outline'
|
||||
},
|
||||
isPreset: true
|
||||
},
|
||||
|
||||
artisticMosaic: {
|
||||
name: 'Artistic Mosaic',
|
||||
description: 'Creative layout with varied photo sizes',
|
||||
config: {
|
||||
primaryColor: '#7c3aed',
|
||||
accentColor: '#f59e0b',
|
||||
backgroundColor: '#faf5ff',
|
||||
textColor: '#1e1b4b',
|
||||
fontFamily: 'Montserrat, sans-serif',
|
||||
borderRadius: 'none',
|
||||
galleryLayout: 'mosaic',
|
||||
gallerySettings: {
|
||||
spacing: 'tight',
|
||||
photoAnimation: 'scale',
|
||||
mosaicPattern: 'structured'
|
||||
},
|
||||
headerStyle: 'minimal',
|
||||
footerStyle: 'minimal',
|
||||
shadowStyle: 'dramatic'
|
||||
},
|
||||
isPreset: true
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user