Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,333 +1,333 @@
|
|
| 1 |
-
from flask import Flask, request, jsonify, render_template, send_from_directory, redirect, url_for, flash, session, Response
|
| 2 |
-
import os
|
| 3 |
-
import json
|
| 4 |
-
import subprocess
|
| 5 |
-
import sys
|
| 6 |
-
from datetime import datetime, timedelta
|
| 7 |
-
import sqlite3
|
| 8 |
-
from werkzeug.security import generate_password_hash, check_password_hash
|
| 9 |
-
import jwt
|
| 10 |
-
import secrets
|
| 11 |
-
import requests
|
| 12 |
-
|
| 13 |
-
app = Flask(__name__)
|
| 14 |
-
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', secrets.token_hex(32))
|
| 15 |
-
app.config['JWT_SECRET'] = os.environ.get('JWT_SECRET', secrets.token_hex(32))
|
| 16 |
-
|
| 17 |
-
# Database setup
|
| 18 |
-
def init_db():
|
| 19 |
-
conn = sqlite3.connect('softedge.db')
|
| 20 |
-
c = conn.cursor()
|
| 21 |
-
c.execute('''CREATE TABLE IF NOT EXISTS users
|
| 22 |
-
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 23 |
-
email TEXT UNIQUE NOT NULL,
|
| 24 |
-
password TEXT NOT NULL,
|
| 25 |
-
name TEXT,
|
| 26 |
-
role TEXT DEFAULT 'user',
|
| 27 |
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
|
| 28 |
-
c.execute('''CREATE TABLE IF NOT EXISTS contact_submissions
|
| 29 |
-
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 30 |
-
name TEXT NOT NULL,
|
| 31 |
-
email TEXT NOT NULL,
|
| 32 |
-
message TEXT NOT NULL,
|
| 33 |
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
|
| 34 |
-
c.execute('''CREATE TABLE IF NOT EXISTS projects
|
| 35 |
-
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 36 |
-
title TEXT NOT NULL,
|
| 37 |
-
description TEXT NOT NULL,
|
| 38 |
-
status TEXT DEFAULT 'active',
|
| 39 |
-
technologies TEXT,
|
| 40 |
-
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
|
| 41 |
-
conn.commit()
|
| 42 |
-
conn.close()
|
| 43 |
-
|
| 44 |
-
init_db()
|
| 45 |
-
|
| 46 |
-
# Helper functions
|
| 47 |
-
def get_db_connection():
|
| 48 |
-
conn = sqlite3.connect('softedge.db')
|
| 49 |
-
conn.row_factory = sqlite3.Row
|
| 50 |
-
return conn
|
| 51 |
-
|
| 52 |
-
def create_token(user_id):
|
| 53 |
-
payload = {
|
| 54 |
-
'user_id': user_id,
|
| 55 |
-
'exp': datetime.utcnow() + timedelta(hours=24)
|
| 56 |
-
}
|
| 57 |
-
return
|
| 58 |
-
|
| 59 |
-
# PHP Integration
|
| 60 |
-
def call_php_script(script_name, method='GET', data=None):
|
| 61 |
-
"""Call PHP script and return response"""
|
| 62 |
-
try:
|
| 63 |
-
php_path = os.path.join(os.getcwd(), script_name)
|
| 64 |
-
if not os.path.exists(php_path):
|
| 65 |
-
return None
|
| 66 |
-
|
| 67 |
-
# For simple GET requests, we can execute PHP directly
|
| 68 |
-
if method == 'GET':
|
| 69 |
-
result = subprocess.run(['php', php_path],
|
| 70 |
-
capture_output=True, text=True, timeout=30)
|
| 71 |
-
if result.returncode == 0:
|
| 72 |
-
return result.stdout
|
| 73 |
-
return None
|
| 74 |
-
except Exception as e:
|
| 75 |
-
print(f"PHP execution error: {e}")
|
| 76 |
-
return None
|
| 77 |
-
|
| 78 |
-
# Routes
|
| 79 |
-
@app.route('/')
|
| 80 |
-
def home():
|
| 81 |
-
# Get dynamic stats
|
| 82 |
-
stats = {'projects': 0, 'contacts': 0, 'satisfaction': 4.9}
|
| 83 |
-
try:
|
| 84 |
-
conn = get_db_connection()
|
| 85 |
-
stats['projects'] = conn.execute('SELECT COUNT(*) as count FROM projects').fetchone()['count']
|
| 86 |
-
stats['contacts'] = conn.execute('SELECT COUNT(*) as count FROM contact_submissions').fetchone()['count']
|
| 87 |
-
conn.close()
|
| 88 |
-
except Exception as e:
|
| 89 |
-
print(f"Stats error: {e}")
|
| 90 |
-
|
| 91 |
-
return render_template('index.html', stats=stats)
|
| 92 |
-
|
| 93 |
-
@app.route('/sobre')
|
| 94 |
-
def sobre():
|
| 95 |
-
return render_template('sobre.html')
|
| 96 |
-
|
| 97 |
-
@app.route('/servicos')
|
| 98 |
-
def servicos():
|
| 99 |
-
return render_template('servicos.html')
|
| 100 |
-
|
| 101 |
-
@app.route('/projetos')
|
| 102 |
-
def projetos():
|
| 103 |
-
# Get projects from database
|
| 104 |
-
projects = []
|
| 105 |
-
try:
|
| 106 |
-
conn = get_db_connection()
|
| 107 |
-
projects = conn.execute('SELECT * FROM projects ORDER BY created_at DESC').fetchall()
|
| 108 |
-
conn.close()
|
| 109 |
-
projects = [dict(project) for project in projects]
|
| 110 |
-
except Exception as e:
|
| 111 |
-
print(f"Projects error: {e}")
|
| 112 |
-
|
| 113 |
-
return render_template('projetos.html', projects=projects)
|
| 114 |
-
|
| 115 |
-
@app.route('/contato')
|
| 116 |
-
def contato():
|
| 117 |
-
return render_template('contato.html')
|
| 118 |
-
|
| 119 |
-
@app.route('/login')
|
| 120 |
-
def login():
|
| 121 |
-
return render_template('login.html')
|
| 122 |
-
|
| 123 |
-
@app.route('/register')
|
| 124 |
-
def register():
|
| 125 |
-
return render_template('register.html')
|
| 126 |
-
|
| 127 |
-
@app.route('/admin')
|
| 128 |
-
def admin():
|
| 129 |
-
# Check authentication
|
| 130 |
-
if 'user_id' not in session:
|
| 131 |
-
return redirect(url_for('login'))
|
| 132 |
-
|
| 133 |
-
# Get admin stats
|
| 134 |
-
stats = {'total_users': 0, 'total_contacts': 0, 'recent_users': [], 'recent_contacts': []}
|
| 135 |
-
try:
|
| 136 |
-
conn = get_db_connection()
|
| 137 |
-
stats['total_users'] = conn.execute('SELECT COUNT(*) as count FROM users').fetchone()['count']
|
| 138 |
-
stats['total_contacts'] = conn.execute('SELECT COUNT(*) as count FROM contact_submissions').fetchone()['count']
|
| 139 |
-
|
| 140 |
-
# Recent users
|
| 141 |
-
stats['recent_users'] = conn.execute(
|
| 142 |
-
'SELECT name, email, created_at FROM users ORDER BY created_at DESC LIMIT 5'
|
| 143 |
-
).fetchall()
|
| 144 |
-
|
| 145 |
-
# Recent contacts
|
| 146 |
-
stats['recent_contacts'] = conn.execute(
|
| 147 |
-
'SELECT name, email, message, created_at FROM contact_submissions ORDER BY created_at DESC LIMIT 5'
|
| 148 |
-
).fetchall()
|
| 149 |
-
|
| 150 |
-
conn.close()
|
| 151 |
-
stats['recent_users'] = [dict(user) for user in stats['recent_users']]
|
| 152 |
-
stats['recent_contacts'] = [dict(contact) for contact in stats['recent_contacts']]
|
| 153 |
-
except Exception as e:
|
| 154 |
-
print(f"Admin stats error: {e}")
|
| 155 |
-
|
| 156 |
-
return render_template('admin.html', stats=stats)
|
| 157 |
-
|
| 158 |
-
# API Routes
|
| 159 |
-
@app.route('/api/health')
|
| 160 |
-
def health():
|
| 161 |
-
return jsonify({
|
| 162 |
-
'status': 'ok',
|
| 163 |
-
'timestamp': datetime.now().isoformat(),
|
| 164 |
-
'service': 'SoftEdge Hybrid API',
|
| 165 |
-
'version': '3.0.0',
|
| 166 |
-
'technologies': ['Flask', 'PHP', 'Node.js', 'MySQL']
|
| 167 |
-
})
|
| 168 |
-
|
| 169 |
-
@app.route('/api/stats')
|
| 170 |
-
def stats():
|
| 171 |
-
try:
|
| 172 |
-
conn = get_db_connection()
|
| 173 |
-
projects_count = conn.execute('SELECT COUNT(*) as count FROM projects').fetchone()['count']
|
| 174 |
-
contact_count = conn.execute('SELECT COUNT(*) as count FROM contact_submissions').fetchone()['count']
|
| 175 |
-
conn.close()
|
| 176 |
-
|
| 177 |
-
return jsonify({
|
| 178 |
-
'projects': projects_count,
|
| 179 |
-
'contacts': contact_count,
|
| 180 |
-
'satisfaction': 4.9,
|
| 181 |
-
'uptime': '99.9%'
|
| 182 |
-
})
|
| 183 |
-
except Exception as e:
|
| 184 |
-
return jsonify({'error': 'Database error'}), 500
|
| 185 |
-
|
| 186 |
-
@app.route('/api/contact', methods=['POST'])
|
| 187 |
-
def contact():
|
| 188 |
-
data = request.get_json()
|
| 189 |
-
|
| 190 |
-
if not data or not all(k in data for k in ['name', 'email', 'message']):
|
| 191 |
-
return jsonify({'error': 'Missing required fields'}), 400
|
| 192 |
-
|
| 193 |
-
try:
|
| 194 |
-
conn = get_db_connection()
|
| 195 |
-
conn.execute('INSERT INTO contact_submissions (name, email, message) VALUES (?, ?, ?)',
|
| 196 |
-
(data['name'], data['email'], data['message']))
|
| 197 |
-
conn.commit()
|
| 198 |
-
conn.close()
|
| 199 |
-
|
| 200 |
-
return jsonify({'message': 'Message sent successfully', 'status': 'success'}), 200
|
| 201 |
-
except Exception as e:
|
| 202 |
-
return jsonify({'error': 'Database error'}), 500
|
| 203 |
-
|
| 204 |
-
@app.route('/api/auth/login', methods=['POST'])
|
| 205 |
-
def api_login():
|
| 206 |
-
data = request.get_json()
|
| 207 |
-
|
| 208 |
-
if not data or not all(k in data for k in ['email', 'password']):
|
| 209 |
-
return jsonify({'error': 'Missing credentials'}), 400
|
| 210 |
-
|
| 211 |
-
try:
|
| 212 |
-
conn = get_db_connection()
|
| 213 |
-
user = conn.execute('SELECT * FROM users WHERE email = ?', (data['email'],)).fetchone()
|
| 214 |
-
conn.close()
|
| 215 |
-
|
| 216 |
-
if user and check_password_hash(user['password'], data['password']):
|
| 217 |
-
session['user_id'] = user['id']
|
| 218 |
-
session['user_email'] = user['email']
|
| 219 |
-
session['user_name'] = user['name']
|
| 220 |
-
session['user_role'] = user['role']
|
| 221 |
-
token = create_token(user['id'])
|
| 222 |
-
|
| 223 |
-
return jsonify({
|
| 224 |
-
'message': 'Login successful',
|
| 225 |
-
'token': token,
|
| 226 |
-
'user': {
|
| 227 |
-
'id': user['id'],
|
| 228 |
-
'email': user['email'],
|
| 229 |
-
'name': user['name'],
|
| 230 |
-
'role': user['role']
|
| 231 |
-
}
|
| 232 |
-
}), 200
|
| 233 |
-
else:
|
| 234 |
-
return jsonify({'error': 'Invalid credentials'}), 401
|
| 235 |
-
except Exception as e:
|
| 236 |
-
return jsonify({'error': 'Database error'}), 500
|
| 237 |
-
|
| 238 |
-
@app.route('/api/auth/register', methods=['POST'])
|
| 239 |
-
def api_register():
|
| 240 |
-
data = request.get_json()
|
| 241 |
-
|
| 242 |
-
if not data or not all(k in data for k in ['email', 'password', 'name']):
|
| 243 |
-
return jsonify({'error': 'Missing required fields'}), 400
|
| 244 |
-
|
| 245 |
-
try:
|
| 246 |
-
hashed_password = generate_password_hash(data['password'])
|
| 247 |
-
|
| 248 |
-
conn = get_db_connection()
|
| 249 |
-
conn.execute('INSERT INTO users (email, password, name) VALUES (?, ?, ?)',
|
| 250 |
-
(data['email'], hashed_password, data['name']))
|
| 251 |
-
conn.commit()
|
| 252 |
-
user_id = conn.execute('SELECT last_insert_rowid()').fetchone()[0]
|
| 253 |
-
conn.close()
|
| 254 |
-
|
| 255 |
-
token = create_token(user_id)
|
| 256 |
-
return jsonify({
|
| 257 |
-
'message': 'Registration successful',
|
| 258 |
-
'token': token,
|
| 259 |
-
'user': {
|
| 260 |
-
'id': user_id,
|
| 261 |
-
'email': data['email'],
|
| 262 |
-
'name': data['name']
|
| 263 |
-
}
|
| 264 |
-
}), 201
|
| 265 |
-
except sqlite3.IntegrityError:
|
| 266 |
-
return jsonify({'error': 'Email already exists'}), 409
|
| 267 |
-
except Exception as e:
|
| 268 |
-
return jsonify({'error': 'Database error'}), 500
|
| 269 |
-
|
| 270 |
-
@app.route('/api/auth/logout')
|
| 271 |
-
def logout():
|
| 272 |
-
session.clear()
|
| 273 |
-
return jsonify({'message': 'Logged out successfully'})
|
| 274 |
-
|
| 275 |
-
# PHP Integration Routes
|
| 276 |
-
@app.route('/php/<path:script>')
|
| 277 |
-
def php_route(script):
|
| 278 |
-
"""Route to execute PHP scripts"""
|
| 279 |
-
result = call_php_script(f'{script}.php')
|
| 280 |
-
if result:
|
| 281 |
-
return Response(result, mimetype='text/html')
|
| 282 |
-
return jsonify({'error': 'PHP script not found'}), 404
|
| 283 |
-
|
| 284 |
-
# Static files
|
| 285 |
-
@app.route('/assets/<path:filename>')
|
| 286 |
-
def assets(filename):
|
| 287 |
-
return send_from_directory('assets', filename)
|
| 288 |
-
|
| 289 |
-
@app.route('/css/<path:filename>')
|
| 290 |
-
def css_files(filename):
|
| 291 |
-
return send_from_directory('css', filename)
|
| 292 |
-
|
| 293 |
-
@app.route('/js/<path:filename>')
|
| 294 |
-
def js_files(filename):
|
| 295 |
-
return send_from_directory('js', filename)
|
| 296 |
-
|
| 297 |
-
# React integration
|
| 298 |
-
@app.route('/react-app')
|
| 299 |
-
def react_app():
|
| 300 |
-
return render_template('react-app.html')
|
| 301 |
-
|
| 302 |
-
if __name__ == '__main__':
|
| 303 |
-
# Seed initial data
|
| 304 |
-
conn = get_db_connection()
|
| 305 |
-
if not conn.execute('SELECT COUNT(*) FROM projects').fetchone()[0]:
|
| 306 |
-
projects = [
|
| 307 |
-
('AKIRA IA', 'Assistente virtual angolano com processamento de linguagem natural', 'Concluído', 'Python, TensorFlow, FastAPI'),
|
| 308 |
-
('ERP Gestão Total', 'Sistema completo de gestão empresarial', 'Concluído', 'Laravel, Vue.js, MySQL'),
|
| 309 |
-
('E-commerce ShopFast', 'Plataforma de vendas online de alta performance', 'Concluído', 'Next.js, Stripe, Prisma'),
|
| 310 |
-
('Sistema de Gestão Escolar', 'Plataforma completa para gestão educacional', 'Em desenvolvimento', 'React, Node.js, PostgreSQL'),
|
| 311 |
-
('App Mobile Delivery', 'Aplicativo de delivery com geolocalização', 'Em desenvolvimento', 'Flutter, Firebase, Google Maps')
|
| 312 |
-
]
|
| 313 |
-
conn.executemany('INSERT INTO projects (title, description, status, technologies) VALUES (?, ?, ?, ?)', projects)
|
| 314 |
-
conn.commit()
|
| 315 |
-
|
| 316 |
-
# Create admin user
|
| 317 |
-
admin_email = os.environ.get('ADMIN_EMAIL', 'admin@softedge.com')
|
| 318 |
-
admin_password = os.environ.get('ADMIN_PASSWORD', 'Admin@123456')
|
| 319 |
-
admin_name = os.environ.get('ADMIN_NAME', 'Isaac Quarenta')
|
| 320 |
-
|
| 321 |
-
if not conn.execute('SELECT id FROM users WHERE email = ?', (admin_email,)).fetchone():
|
| 322 |
-
hashed_password = generate_password_hash(admin_password)
|
| 323 |
-
conn.execute('INSERT INTO users (email, password, name, role) VALUES (?, ?, ?, ?)',
|
| 324 |
-
(admin_email, hashed_password, admin_name, 'super_admin'))
|
| 325 |
-
conn.commit()
|
| 326 |
-
|
| 327 |
-
conn.close()
|
| 328 |
-
|
| 329 |
-
print("🚀 SoftEdge Corporation - Hybrid Architecture Started!")
|
| 330 |
-
print("Technologies: Flask (Python) + PHP + Node.js + MySQL")
|
| 331 |
-
print("Server running on http://localhost:7860")
|
| 332 |
-
|
| 333 |
-
app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))
|
|
|
|
| 1 |
+
from flask import Flask, request, jsonify, render_template, send_from_directory, redirect, url_for, flash, session, Response
|
| 2 |
+
import os
|
| 3 |
+
import json
|
| 4 |
+
import subprocess
|
| 5 |
+
import sys
|
| 6 |
+
from datetime import datetime, timedelta
|
| 7 |
+
import sqlite3
|
| 8 |
+
from werkzeug.security import generate_password_hash, check_password_hash
|
| 9 |
+
import jwt
|
| 10 |
+
import secrets
|
| 11 |
+
import requests
|
| 12 |
+
|
| 13 |
+
app = Flask(__name__)
|
| 14 |
+
app.config['SECRET_KEY'] = os.environ.get('SECRET_KEY', secrets.token_hex(32))
|
| 15 |
+
app.config['JWT_SECRET'] = os.environ.get('JWT_SECRET', secrets.token_hex(32))
|
| 16 |
+
|
| 17 |
+
# Database setup
|
| 18 |
+
def init_db():
|
| 19 |
+
conn = sqlite3.connect('softedge.db')
|
| 20 |
+
c = conn.cursor()
|
| 21 |
+
c.execute('''CREATE TABLE IF NOT EXISTS users
|
| 22 |
+
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 23 |
+
email TEXT UNIQUE NOT NULL,
|
| 24 |
+
password TEXT NOT NULL,
|
| 25 |
+
name TEXT,
|
| 26 |
+
role TEXT DEFAULT 'user',
|
| 27 |
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
|
| 28 |
+
c.execute('''CREATE TABLE IF NOT EXISTS contact_submissions
|
| 29 |
+
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 30 |
+
name TEXT NOT NULL,
|
| 31 |
+
email TEXT NOT NULL,
|
| 32 |
+
message TEXT NOT NULL,
|
| 33 |
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
|
| 34 |
+
c.execute('''CREATE TABLE IF NOT EXISTS projects
|
| 35 |
+
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
| 36 |
+
title TEXT NOT NULL,
|
| 37 |
+
description TEXT NOT NULL,
|
| 38 |
+
status TEXT DEFAULT 'active',
|
| 39 |
+
technologies TEXT,
|
| 40 |
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP)''')
|
| 41 |
+
conn.commit()
|
| 42 |
+
conn.close()
|
| 43 |
+
|
| 44 |
+
init_db()
|
| 45 |
+
|
| 46 |
+
# Helper functions
|
| 47 |
+
def get_db_connection():
|
| 48 |
+
conn = sqlite3.connect('softedge.db')
|
| 49 |
+
conn.row_factory = sqlite3.Row
|
| 50 |
+
return conn
|
| 51 |
+
|
| 52 |
+
def create_token(user_id):
|
| 53 |
+
payload = {
|
| 54 |
+
'user_id': user_id,
|
| 55 |
+
'exp': datetime.utcnow() + timedelta(hours=24)
|
| 56 |
+
}
|
| 57 |
+
return pyjwt.encode(payload, app.config['JWT_SECRET'], algorithm='HS256')
|
| 58 |
+
|
| 59 |
+
# PHP Integration
|
| 60 |
+
def call_php_script(script_name, method='GET', data=None):
|
| 61 |
+
"""Call PHP script and return response"""
|
| 62 |
+
try:
|
| 63 |
+
php_path = os.path.join(os.getcwd(), script_name)
|
| 64 |
+
if not os.path.exists(php_path):
|
| 65 |
+
return None
|
| 66 |
+
|
| 67 |
+
# For simple GET requests, we can execute PHP directly
|
| 68 |
+
if method == 'GET':
|
| 69 |
+
result = subprocess.run(['php', php_path],
|
| 70 |
+
capture_output=True, text=True, timeout=30)
|
| 71 |
+
if result.returncode == 0:
|
| 72 |
+
return result.stdout
|
| 73 |
+
return None
|
| 74 |
+
except Exception as e:
|
| 75 |
+
print(f"PHP execution error: {e}")
|
| 76 |
+
return None
|
| 77 |
+
|
| 78 |
+
# Routes
|
| 79 |
+
@app.route('/')
|
| 80 |
+
def home():
|
| 81 |
+
# Get dynamic stats
|
| 82 |
+
stats = {'projects': 0, 'contacts': 0, 'satisfaction': 4.9}
|
| 83 |
+
try:
|
| 84 |
+
conn = get_db_connection()
|
| 85 |
+
stats['projects'] = conn.execute('SELECT COUNT(*) as count FROM projects').fetchone()['count']
|
| 86 |
+
stats['contacts'] = conn.execute('SELECT COUNT(*) as count FROM contact_submissions').fetchone()['count']
|
| 87 |
+
conn.close()
|
| 88 |
+
except Exception as e:
|
| 89 |
+
print(f"Stats error: {e}")
|
| 90 |
+
|
| 91 |
+
return render_template('index.html', stats=stats)
|
| 92 |
+
|
| 93 |
+
@app.route('/sobre')
|
| 94 |
+
def sobre():
|
| 95 |
+
return render_template('sobre.html')
|
| 96 |
+
|
| 97 |
+
@app.route('/servicos')
|
| 98 |
+
def servicos():
|
| 99 |
+
return render_template('servicos.html')
|
| 100 |
+
|
| 101 |
+
@app.route('/projetos')
|
| 102 |
+
def projetos():
|
| 103 |
+
# Get projects from database
|
| 104 |
+
projects = []
|
| 105 |
+
try:
|
| 106 |
+
conn = get_db_connection()
|
| 107 |
+
projects = conn.execute('SELECT * FROM projects ORDER BY created_at DESC').fetchall()
|
| 108 |
+
conn.close()
|
| 109 |
+
projects = [dict(project) for project in projects]
|
| 110 |
+
except Exception as e:
|
| 111 |
+
print(f"Projects error: {e}")
|
| 112 |
+
|
| 113 |
+
return render_template('projetos.html', projects=projects)
|
| 114 |
+
|
| 115 |
+
@app.route('/contato')
|
| 116 |
+
def contato():
|
| 117 |
+
return render_template('contato.html')
|
| 118 |
+
|
| 119 |
+
@app.route('/login')
|
| 120 |
+
def login():
|
| 121 |
+
return render_template('login.html')
|
| 122 |
+
|
| 123 |
+
@app.route('/register')
|
| 124 |
+
def register():
|
| 125 |
+
return render_template('register.html')
|
| 126 |
+
|
| 127 |
+
@app.route('/admin')
|
| 128 |
+
def admin():
|
| 129 |
+
# Check authentication
|
| 130 |
+
if 'user_id' not in session:
|
| 131 |
+
return redirect(url_for('login'))
|
| 132 |
+
|
| 133 |
+
# Get admin stats
|
| 134 |
+
stats = {'total_users': 0, 'total_contacts': 0, 'recent_users': [], 'recent_contacts': []}
|
| 135 |
+
try:
|
| 136 |
+
conn = get_db_connection()
|
| 137 |
+
stats['total_users'] = conn.execute('SELECT COUNT(*) as count FROM users').fetchone()['count']
|
| 138 |
+
stats['total_contacts'] = conn.execute('SELECT COUNT(*) as count FROM contact_submissions').fetchone()['count']
|
| 139 |
+
|
| 140 |
+
# Recent users
|
| 141 |
+
stats['recent_users'] = conn.execute(
|
| 142 |
+
'SELECT name, email, created_at FROM users ORDER BY created_at DESC LIMIT 5'
|
| 143 |
+
).fetchall()
|
| 144 |
+
|
| 145 |
+
# Recent contacts
|
| 146 |
+
stats['recent_contacts'] = conn.execute(
|
| 147 |
+
'SELECT name, email, message, created_at FROM contact_submissions ORDER BY created_at DESC LIMIT 5'
|
| 148 |
+
).fetchall()
|
| 149 |
+
|
| 150 |
+
conn.close()
|
| 151 |
+
stats['recent_users'] = [dict(user) for user in stats['recent_users']]
|
| 152 |
+
stats['recent_contacts'] = [dict(contact) for contact in stats['recent_contacts']]
|
| 153 |
+
except Exception as e:
|
| 154 |
+
print(f"Admin stats error: {e}")
|
| 155 |
+
|
| 156 |
+
return render_template('admin.html', stats=stats)
|
| 157 |
+
|
| 158 |
+
# API Routes
|
| 159 |
+
@app.route('/api/health')
|
| 160 |
+
def health():
|
| 161 |
+
return jsonify({
|
| 162 |
+
'status': 'ok',
|
| 163 |
+
'timestamp': datetime.now().isoformat(),
|
| 164 |
+
'service': 'SoftEdge Hybrid API',
|
| 165 |
+
'version': '3.0.0',
|
| 166 |
+
'technologies': ['Flask', 'PHP', 'Node.js', 'MySQL']
|
| 167 |
+
})
|
| 168 |
+
|
| 169 |
+
@app.route('/api/stats')
|
| 170 |
+
def stats():
|
| 171 |
+
try:
|
| 172 |
+
conn = get_db_connection()
|
| 173 |
+
projects_count = conn.execute('SELECT COUNT(*) as count FROM projects').fetchone()['count']
|
| 174 |
+
contact_count = conn.execute('SELECT COUNT(*) as count FROM contact_submissions').fetchone()['count']
|
| 175 |
+
conn.close()
|
| 176 |
+
|
| 177 |
+
return jsonify({
|
| 178 |
+
'projects': projects_count,
|
| 179 |
+
'contacts': contact_count,
|
| 180 |
+
'satisfaction': 4.9,
|
| 181 |
+
'uptime': '99.9%'
|
| 182 |
+
})
|
| 183 |
+
except Exception as e:
|
| 184 |
+
return jsonify({'error': 'Database error'}), 500
|
| 185 |
+
|
| 186 |
+
@app.route('/api/contact', methods=['POST'])
|
| 187 |
+
def contact():
|
| 188 |
+
data = request.get_json()
|
| 189 |
+
|
| 190 |
+
if not data or not all(k in data for k in ['name', 'email', 'message']):
|
| 191 |
+
return jsonify({'error': 'Missing required fields'}), 400
|
| 192 |
+
|
| 193 |
+
try:
|
| 194 |
+
conn = get_db_connection()
|
| 195 |
+
conn.execute('INSERT INTO contact_submissions (name, email, message) VALUES (?, ?, ?)',
|
| 196 |
+
(data['name'], data['email'], data['message']))
|
| 197 |
+
conn.commit()
|
| 198 |
+
conn.close()
|
| 199 |
+
|
| 200 |
+
return jsonify({'message': 'Message sent successfully', 'status': 'success'}), 200
|
| 201 |
+
except Exception as e:
|
| 202 |
+
return jsonify({'error': 'Database error'}), 500
|
| 203 |
+
|
| 204 |
+
@app.route('/api/auth/login', methods=['POST'])
|
| 205 |
+
def api_login():
|
| 206 |
+
data = request.get_json()
|
| 207 |
+
|
| 208 |
+
if not data or not all(k in data for k in ['email', 'password']):
|
| 209 |
+
return jsonify({'error': 'Missing credentials'}), 400
|
| 210 |
+
|
| 211 |
+
try:
|
| 212 |
+
conn = get_db_connection()
|
| 213 |
+
user = conn.execute('SELECT * FROM users WHERE email = ?', (data['email'],)).fetchone()
|
| 214 |
+
conn.close()
|
| 215 |
+
|
| 216 |
+
if user and check_password_hash(user['password'], data['password']):
|
| 217 |
+
session['user_id'] = user['id']
|
| 218 |
+
session['user_email'] = user['email']
|
| 219 |
+
session['user_name'] = user['name']
|
| 220 |
+
session['user_role'] = user['role']
|
| 221 |
+
token = create_token(user['id'])
|
| 222 |
+
|
| 223 |
+
return jsonify({
|
| 224 |
+
'message': 'Login successful',
|
| 225 |
+
'token': token,
|
| 226 |
+
'user': {
|
| 227 |
+
'id': user['id'],
|
| 228 |
+
'email': user['email'],
|
| 229 |
+
'name': user['name'],
|
| 230 |
+
'role': user['role']
|
| 231 |
+
}
|
| 232 |
+
}), 200
|
| 233 |
+
else:
|
| 234 |
+
return jsonify({'error': 'Invalid credentials'}), 401
|
| 235 |
+
except Exception as e:
|
| 236 |
+
return jsonify({'error': 'Database error'}), 500
|
| 237 |
+
|
| 238 |
+
@app.route('/api/auth/register', methods=['POST'])
|
| 239 |
+
def api_register():
|
| 240 |
+
data = request.get_json()
|
| 241 |
+
|
| 242 |
+
if not data or not all(k in data for k in ['email', 'password', 'name']):
|
| 243 |
+
return jsonify({'error': 'Missing required fields'}), 400
|
| 244 |
+
|
| 245 |
+
try:
|
| 246 |
+
hashed_password = generate_password_hash(data['password'])
|
| 247 |
+
|
| 248 |
+
conn = get_db_connection()
|
| 249 |
+
conn.execute('INSERT INTO users (email, password, name) VALUES (?, ?, ?)',
|
| 250 |
+
(data['email'], hashed_password, data['name']))
|
| 251 |
+
conn.commit()
|
| 252 |
+
user_id = conn.execute('SELECT last_insert_rowid()').fetchone()[0]
|
| 253 |
+
conn.close()
|
| 254 |
+
|
| 255 |
+
token = create_token(user_id)
|
| 256 |
+
return jsonify({
|
| 257 |
+
'message': 'Registration successful',
|
| 258 |
+
'token': token,
|
| 259 |
+
'user': {
|
| 260 |
+
'id': user_id,
|
| 261 |
+
'email': data['email'],
|
| 262 |
+
'name': data['name']
|
| 263 |
+
}
|
| 264 |
+
}), 201
|
| 265 |
+
except sqlite3.IntegrityError:
|
| 266 |
+
return jsonify({'error': 'Email already exists'}), 409
|
| 267 |
+
except Exception as e:
|
| 268 |
+
return jsonify({'error': 'Database error'}), 500
|
| 269 |
+
|
| 270 |
+
@app.route('/api/auth/logout')
|
| 271 |
+
def logout():
|
| 272 |
+
session.clear()
|
| 273 |
+
return jsonify({'message': 'Logged out successfully'})
|
| 274 |
+
|
| 275 |
+
# PHP Integration Routes
|
| 276 |
+
@app.route('/php/<path:script>')
|
| 277 |
+
def php_route(script):
|
| 278 |
+
"""Route to execute PHP scripts"""
|
| 279 |
+
result = call_php_script(f'{script}.php')
|
| 280 |
+
if result:
|
| 281 |
+
return Response(result, mimetype='text/html')
|
| 282 |
+
return jsonify({'error': 'PHP script not found'}), 404
|
| 283 |
+
|
| 284 |
+
# Static files
|
| 285 |
+
@app.route('/assets/<path:filename>')
|
| 286 |
+
def assets(filename):
|
| 287 |
+
return send_from_directory('assets', filename)
|
| 288 |
+
|
| 289 |
+
@app.route('/css/<path:filename>')
|
| 290 |
+
def css_files(filename):
|
| 291 |
+
return send_from_directory('css', filename)
|
| 292 |
+
|
| 293 |
+
@app.route('/js/<path:filename>')
|
| 294 |
+
def js_files(filename):
|
| 295 |
+
return send_from_directory('js', filename)
|
| 296 |
+
|
| 297 |
+
# React integration
|
| 298 |
+
@app.route('/react-app')
|
| 299 |
+
def react_app():
|
| 300 |
+
return render_template('react-app.html')
|
| 301 |
+
|
| 302 |
+
if __name__ == '__main__':
|
| 303 |
+
# Seed initial data
|
| 304 |
+
conn = get_db_connection()
|
| 305 |
+
if not conn.execute('SELECT COUNT(*) FROM projects').fetchone()[0]:
|
| 306 |
+
projects = [
|
| 307 |
+
('AKIRA IA', 'Assistente virtual angolano com processamento de linguagem natural', 'Concluído', 'Python, TensorFlow, FastAPI'),
|
| 308 |
+
('ERP Gestão Total', 'Sistema completo de gestão empresarial', 'Concluído', 'Laravel, Vue.js, MySQL'),
|
| 309 |
+
('E-commerce ShopFast', 'Plataforma de vendas online de alta performance', 'Concluído', 'Next.js, Stripe, Prisma'),
|
| 310 |
+
('Sistema de Gestão Escolar', 'Plataforma completa para gestão educacional', 'Em desenvolvimento', 'React, Node.js, PostgreSQL'),
|
| 311 |
+
('App Mobile Delivery', 'Aplicativo de delivery com geolocalização', 'Em desenvolvimento', 'Flutter, Firebase, Google Maps')
|
| 312 |
+
]
|
| 313 |
+
conn.executemany('INSERT INTO projects (title, description, status, technologies) VALUES (?, ?, ?, ?)', projects)
|
| 314 |
+
conn.commit()
|
| 315 |
+
|
| 316 |
+
# Create admin user
|
| 317 |
+
admin_email = os.environ.get('ADMIN_EMAIL', 'admin@softedge.com')
|
| 318 |
+
admin_password = os.environ.get('ADMIN_PASSWORD', 'Admin@123456')
|
| 319 |
+
admin_name = os.environ.get('ADMIN_NAME', 'Isaac Quarenta')
|
| 320 |
+
|
| 321 |
+
if not conn.execute('SELECT id FROM users WHERE email = ?', (admin_email,)).fetchone():
|
| 322 |
+
hashed_password = generate_password_hash(admin_password)
|
| 323 |
+
conn.execute('INSERT INTO users (email, password, name, role) VALUES (?, ?, ?, ?)',
|
| 324 |
+
(admin_email, hashed_password, admin_name, 'super_admin'))
|
| 325 |
+
conn.commit()
|
| 326 |
+
|
| 327 |
+
conn.close()
|
| 328 |
+
|
| 329 |
+
print("🚀 SoftEdge Corporation - Hybrid Architecture Started!")
|
| 330 |
+
print("Technologies: Flask (Python) + PHP + Node.js + MySQL")
|
| 331 |
+
print("Server running on http://localhost:7860")
|
| 332 |
+
|
| 333 |
+
app.run(debug=True, host='0.0.0.0', port=int(os.environ.get('PORT', 7860)))
|