from flask import Flask, send_from_directory, jsonify, request import os import json from datetime import datetime import sqlite3 app = Flask(__name__) # Configuration app.config['SECRET_KEY'] = 'your-secret-key-here' DATABASE = 'visitor_counter.db' VISITOR_LOG_FILE = 'visitor_log.json' def init_db(): """Initialize the SQLite database and create the visitor_count table if it doesn't exist""" with sqlite3.connect(DATABASE) as conn: cursor = conn.cursor() cursor.execute(''' CREATE TABLE IF NOT EXISTS visitor_count ( id INTEGER PRIMARY KEY, count INTEGER NOT NULL ) ''') # Check if the table is empty, and if so, initialize with count 0 cursor.execute('SELECT COUNT(*) FROM visitor_count') if cursor.fetchone()[0] == 0: cursor.execute('INSERT INTO visitor_count (count) VALUES (0)') conn.commit() def get_visitor_count(): """Get current visitor count from the database""" try: with sqlite3.connect(DATABASE) as conn: cursor = conn.cursor() cursor.execute('SELECT count FROM visitor_count WHERE id = 1') result = cursor.fetchone() return result[0] if result else 0 except Exception as e: print(f"Error retrieving visitor count: {e}") return 0 def increment_visitor_count(): """Increment visitor count in the database""" try: with sqlite3.connect(DATABASE) as conn: cursor = conn.cursor() cursor.execute('UPDATE visitor_count SET count = count + 1 WHERE id = 1') conn.commit() cursor.execute('SELECT count FROM visitor_count WHERE id = 1') return cursor.fetchone()[0] except Exception as e: print(f"Error updating visitor count: {e}") return get_visitor_count() def log_visitor(request): """Log visitor information""" try: visitor_info = { 'timestamp': datetime.now().isoformat(), 'ip': request.environ.get('HTTP_X_FORWARDED_FOR', request.remote_addr), 'user_agent': request.headers.get('User-Agent', ''), 'referrer': request.headers.get('Referer', ''), 'method': request.method, 'path': request.path } # Read existing logs logs = [] if os.path.exists(VISITOR_LOG_FILE): try: with open(VISITOR_LOG_FILE, 'r') as f: logs = json.load(f) except json.JSONDecodeError: logs = [] # Add new log entry logs.append(visitor_info) # Keep only last 1000 entries if len(logs) > 1000: logs = logs[-1000:] # Save logs with open(VISITOR_LOG_FILE, 'w') as f: json.dump(logs, f, indent=2) except Exception as e: print(f"Error logging visitor: {e}") @app.route('/') def home(): """Serve the main portfolio page""" try: # Log visitor and increment counter log_visitor(request) increment_visitor_count() # Serve the HTML file return send_from_directory('.', 'index.html') except Exception as e: print(f"Error serving home page: {e}") return "Error loading page", 500 @app.route('/visitor_count') def visitor_count(): """Return current visitor count""" try: count = get_visitor_count() return str(count) except Exception as e: print(f"Error getting visitor count: {e}") return "0" @app.route('/api/visitor_stats') def visitor_stats(): """Return visitor statistics (optional API endpoint)""" try: count = get_visitor_count() # Read visitor logs for additional stats stats = { 'total_visitors': count, 'last_updated': datetime.now().isoformat() } if os.path.exists(VISITOR_LOG_FILE): try: with open(VISITOR_LOG_FILE, 'r') as f: logs = json.load(f) # Calculate additional stats today = datetime.now().date() today_visitors = sum(1 for log in logs if datetime.fromisoformat(log['timestamp']).date() == today) stats['today_visitors'] = today_visitors stats['recent_visits'] = len(logs) except json.JSONDecodeError: pass return jsonify(stats) except Exception as e: print(f"Error getting visitor stats: {e}") return jsonify({'error': 'Unable to fetch stats'}), 500 # Static file routes for different directories @app.route('/projects/') def serve_projects(filename): """Serve project images""" try: return send_from_directory('projects', filename) except FileNotFoundError: # Return a placeholder image if file not found return send_from_directory('.', 'placeholder.jpg'), 404 @app.route('/certificates/') def serve_certificates(filename): """Serve certificate images""" try: return send_from_directory('certificates', filename) except FileNotFoundError: return send_from_directory('.', 'placeholder.jpg'), 404 @app.route('/logos/') def serve_logos(filename): """Serve company/organization logos""" try: return send_from_directory('logos', filename) except FileNotFoundError: return send_from_directory('.', 'placeholder.jpg'), 404 @app.route('/others/') def serve_others(filename): """Serve other static files""" try: return send_from_directory('others', filename) except FileNotFoundError: return send_from_directory('.', 'placeholder.jpg'), 404 @app.route('/assets/') def serve_assets(filename): """Serve general assets""" try: return send_from_directory('assets', filename) except FileNotFoundError: return "File not found", 404 # Contact form endpoint (optional) @app.route('/contact', methods=['POST']) def contact(): """Handle contact form submissions""" try: data = request.get_json() # Basic validation required_fields = ['name', 'email', 'message'] if not all(field in data for field in required_fields): return jsonify({'error': 'Missing required fields'}), 400 # Log the contact submission contact_info = { 'timestamp': datetime.now().isoformat(), 'name': data.get('name'), 'email': data.get('email'), 'message': data.get('message'), 'ip': request.environ.get('HTTP_X_FORWARDED_FOR', request.remote_addr) } # Save to file contact_file = 'contact_submissions.json' contacts = [] if os.path.exists(contact_file): try: with open(contact_file, 'r') as f: contacts = json.load(f) except json.JSONDecodeError: contacts = [] contacts.append(contact_info) with open(contact_file, 'w') as f: json.dump(contacts, f, indent=2) return jsonify({'message': 'Thank you for your message! I will get back to you soon.'}), 200 except Exception as e: print(f"Error handling contact form: {e}") return jsonify({'error': 'Unable to process your request'}), 500 # Health check endpoint @app.route('/health') def health_check(): """Health check endpoint""" return jsonify({ 'status': 'healthy', 'timestamp': datetime.now().isoformat(), 'version': '1.0.0' }) # Service worker for PWA @app.route('/sw.js') def service_worker(): """Serve service worker for PWA functionality""" sw_content = ''' const CACHE_NAME = 'portfolio-v1'; const urlsToCache = [ '/', '/static/css/style.css', '/static/js/script.js', 'https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Playfair+Display:wght@400;500;600;700&display=swap', 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css' ]; self.addEventListener('install', function(event) { event.waitUntil( caches.open(CACHE_NAME) .then(function(cache) { return cache.addAll(urlsToCache); }) ); }); self.addEventListener('fetch', function(event) { event.respondWith( caches.match(event.request) .then(function(response) { if (response) { return response; } return fetch(event.request); } ) ); }); ''' response = app.response_class( response=sw_content, status=200, mimetype='application/javascript' ) return response # Error handlers @app.errorhandler(404) def not_found_error(error): """Handle 404 errors""" return jsonify({'error': 'Page not found'}), 404 @app.errorhandler(500) def internal_error(error): """Handle 500 errors""" return jsonify({'error': 'Internal server error'}), 500 if __name__ == '__main__': # Initialize database init_db() # Create necessary directories if they don't exist directories = ['projects', 'certificates', 'logos', 'others', 'assets'] for directory in directories: os.makedirs(directory, exist_ok=True) # Run the application app.run(debug=True, host='0.0.0.0', port=7860)