You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
295 lines
10 KiB
295 lines
10 KiB
import os
|
|
import uuid
|
|
import logging
|
|
from flask import Flask, current_app, session, redirect, url_for, request, flash, render_template, jsonify, send_from_directory
|
|
from flask_sqlalchemy import SQLAlchemy
|
|
from flask_mysqldb import MySQL
|
|
import MySQLdb.cursors
|
|
from werkzeug.utils import secure_filename
|
|
from flask_login import LoginManager, UserMixin, login_user, login_required, current_user
|
|
|
|
# 初始化 Flask 应用
|
|
app = Flask(__name__)
|
|
app.config['SECRET_KEY'] = 'your_secret_key'
|
|
app.secret_key = os.urandom(24) # 生成更安全的会话密钥
|
|
app.config['UPLOAD_FOLDER'] = 'uploads/' # 设置上传文件存储目录
|
|
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True) # 确保目录存在
|
|
|
|
# 配置日志
|
|
logging.basicConfig(filename='app.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
|
|
# MySQL 配置
|
|
app.config['MYSQL_HOST'] = 'localhost'
|
|
app.config['MYSQL_USER'] = 'root' # 替换为你的 MySQL 用户名
|
|
app.config['MYSQL_PASSWORD'] = 'lin556688' # 替换为你的 MySQL 密码
|
|
app.config['MYSQL_DB'] = 'mydatabase'
|
|
app.config['MYSQL_CURSORCLASS'] = 'DictCursor'
|
|
|
|
mysql = MySQL(app)
|
|
|
|
ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'gif'}
|
|
|
|
# 配置日志记录器
|
|
logging.basicConfig(filename='app.log', level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
|
logger = logging.getLogger(__name__)
|
|
|
|
def allowed_file(filename):
|
|
return '.' in filename and \
|
|
filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
|
|
|
|
# 初始化 Flask-Login
|
|
login_manager = LoginManager()
|
|
login_manager.init_app(app)
|
|
login_manager.login_view = 'login'
|
|
|
|
class User(UserMixin):
|
|
def __init__(self, id, username, role):
|
|
self.id = id
|
|
self.username = username
|
|
self.role = role
|
|
|
|
@login_manager.user_loader
|
|
def load_user(user_id):
|
|
cursor = mysql.connection.cursor()
|
|
cursor.execute("SELECT * FROM users WHERE id = %s", (user_id,))
|
|
user_data = cursor.fetchone()
|
|
cursor.close()
|
|
|
|
if user_data:
|
|
return User(user_data['id'], user_data['username'], user_data['role'])
|
|
return None
|
|
|
|
@app.route('/')
|
|
def index():
|
|
current_app.logger.info("Index route accessed")
|
|
return "Welcome to the Home Page!"
|
|
|
|
|
|
@app.route('/view_logs')
|
|
@login_required
|
|
def view_logs():
|
|
with open('app.log', 'r') as log_file:
|
|
logs = log_file.readlines()
|
|
return render_template('logs.html', logs=logs)
|
|
|
|
# 处理文件上传
|
|
@app.route('/upload', methods=['POST'])
|
|
def upload_file():
|
|
logger.info("Handling file upload request")
|
|
if 'file' not in request.files:
|
|
logger.warning("No file part in request")
|
|
return jsonify({'message': 'No file part'}), 400
|
|
file = request.files['file']
|
|
if file.filename == '':
|
|
logger.warning("No selected file")
|
|
return jsonify({'message': 'No selected file'}), 400
|
|
if file and allowed_file(file.filename):
|
|
filename = secure_filename(f"{uuid.uuid4().hex}_{file.filename}")
|
|
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
|
file.save(filepath)
|
|
logger.info(f"File uploaded successfully: {filename}")
|
|
return jsonify({'message': 'File uploaded successfully', 'filepath': filepath}), 201
|
|
else:
|
|
logger.warning("File type not allowed")
|
|
return jsonify({'message': 'File type not allowed'}), 400
|
|
|
|
# 提供上传文件的访问
|
|
@app.route('/uploads/<filename>')
|
|
def uploaded_file(filename):
|
|
logger.info(f"Accessing uploaded file: {filename}")
|
|
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
|
|
|
|
# 登录页面
|
|
@app.route('/login', methods=['GET', 'POST'])
|
|
def login():
|
|
logger.info("Handling login request")
|
|
if request.method == 'POST':
|
|
username = request.form['username']
|
|
password = request.form['password']
|
|
|
|
cursor = mysql.connection.cursor()
|
|
cursor.execute("SELECT * FROM users WHERE username = %s AND password = %s", (username, password))
|
|
user_data = cursor.fetchone()
|
|
cursor.close()
|
|
|
|
if user_data:
|
|
user = User(user_data['id'], user_data['username'], user_data['role'])
|
|
login_user(user)
|
|
logger.info(f"User {username} logged in with role {user_data['role']}")
|
|
|
|
if user_data['role'] == '侦查者':
|
|
return redirect(url_for('scout'))
|
|
elif user_data['role'] == '指挥者':
|
|
return redirect(url_for('commander'))
|
|
elif user_data['role'] == '攻击者':
|
|
return redirect(url_for('attacker'))
|
|
else:
|
|
logger.warning("Invalid credentials")
|
|
return "Invalid credentials. Please try again."
|
|
|
|
return render_template('login.html')
|
|
|
|
# 侦查者页面
|
|
@app.route('/scout')
|
|
@login_required
|
|
def scout():
|
|
logger.info("Accessing scout page")
|
|
if current_user.role != '侦查者':
|
|
logger.warning("Unauthorized access to scout page")
|
|
return redirect(url_for('login'))
|
|
return render_template('scout.html')
|
|
|
|
# 指挥者页面
|
|
@app.route('/commander')
|
|
@login_required
|
|
def commander():
|
|
logger.info("Accessing commander page")
|
|
if current_user.role != '指挥者':
|
|
logger.warning("Unauthorized access to commander page")
|
|
return redirect(url_for('login'))
|
|
|
|
# 获取特定目录下的所有文件和攻击坐标状态
|
|
directory = 'E:/_Ufo/0000jiegou/TheBattleCar/uploads'
|
|
media_items = []
|
|
|
|
try:
|
|
media_items = [f for f in os.listdir(directory)
|
|
if os.path.isfile(os.path.join(directory, f)) and allowed_file(f)]
|
|
except Exception as e:
|
|
logger.error(f"Error accessing directory: {str(e)}")
|
|
flash(f"Error accessing directory: {str(e)}")
|
|
|
|
# 获取攻击状态
|
|
cursor = mysql.connection.cursor()
|
|
cursor.execute("SELECT id, coordinate, attacked, created_at FROM attacks ORDER BY created_at DESC")
|
|
attacks = cursor.fetchall()
|
|
cursor.close()
|
|
|
|
return render_template('commander.html', media_items=media_items, attacks=attacks)
|
|
|
|
# 指挥者发送攻击坐标
|
|
@app.route('/send_attack', methods=['POST'])
|
|
@login_required
|
|
def send_attack():
|
|
logger.info("Handling send attack request")
|
|
if current_user.role != '指挥者':
|
|
logger.warning("Unauthorized access to send attack")
|
|
return redirect(url_for('login'))
|
|
|
|
coordinate = request.form.get('coordinate')
|
|
if not coordinate:
|
|
logger.warning("No coordinate provided")
|
|
return "No coordinate provided", 400
|
|
|
|
# 插入攻击坐标到数据库
|
|
cursor = mysql.connection.cursor()
|
|
cursor.execute("INSERT INTO attacks (coordinate) VALUES (%s)", (coordinate,))
|
|
mysql.connection.commit()
|
|
cursor.close()
|
|
logger.info(f"Attack coordinate sent: {coordinate}")
|
|
|
|
flash('攻击坐标已发送')
|
|
return redirect(url_for('commander'))
|
|
|
|
# 攻击者页面
|
|
@app.route('/attacker')
|
|
@login_required
|
|
def attacker():
|
|
logger.info("Accessing attacker page")
|
|
if current_user.role != '攻击者':
|
|
logger.warning("Unauthorized access to attacker page")
|
|
return redirect(url_for('login'))
|
|
|
|
# 获取攻击坐标列表
|
|
cursor = mysql.connection.cursor()
|
|
cursor.execute("SELECT id, coordinate, created_at FROM attacks ORDER BY created_at DESC")
|
|
attacks = cursor.fetchall()
|
|
cursor.close()
|
|
|
|
return render_template('attacker.html', attacks=attacks)
|
|
|
|
# 攻击者执行攻击
|
|
@app.route('/execute_attack/<int:attack_id>', methods=['POST'])
|
|
@login_required
|
|
def execute_attack(attack_id):
|
|
logger.info(f"Handling execute attack request for ID: {attack_id}")
|
|
if current_user.role != '攻击者':
|
|
logger.warning("Unauthorized access to execute attack")
|
|
return redirect(url_for('login'))
|
|
|
|
cursor = mysql.connection.cursor()
|
|
cursor.execute("UPDATE attacks SET attacked = TRUE WHERE id = %s", (attack_id,))
|
|
mysql.connection.commit()
|
|
cursor.close()
|
|
logger.info(f"Attack executed for ID: {attack_id}")
|
|
|
|
flash(f'已对坐标ID为 {attack_id} 的目标完成打击')
|
|
return redirect(url_for('attacker'))
|
|
|
|
# 退出登录(清除会话)
|
|
@app.route('/logout')
|
|
@login_required
|
|
def logout():
|
|
logger.info("Handling logout request")
|
|
session.pop('username', None)
|
|
session.pop('role', None)
|
|
return redirect(url_for('login'))
|
|
|
|
# 发送消息
|
|
@app.route('/send_message', methods=['GET', 'POST'])
|
|
@login_required
|
|
def send_message():
|
|
logger.info("Handling send message request")
|
|
if request.method == 'POST':
|
|
message = request.form.get('message')
|
|
if not message:
|
|
logger.warning("No message provided")
|
|
return "No message provided", 400
|
|
|
|
photo_url = None
|
|
if 'photo' in request.files:
|
|
file = request.files['photo']
|
|
if file.filename != '':
|
|
if file and allowed_file(file.filename):
|
|
filename = secure_filename(f"{uuid.uuid4().hex}_{file.filename}")
|
|
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
|
|
file.save(filepath)
|
|
photo_url = url_for('uploaded_file', filename=filename, _external=True)
|
|
else:
|
|
logger.warning("Allowed file types are png, jpg, jpeg, gif")
|
|
return "Allowed file types are png, jpg, jpeg, gif", 400
|
|
|
|
# 插入数据到 MySQL
|
|
cursor = mysql.connection.cursor()
|
|
cursor.execute("INSERT INTO messages (message, photo_url) VALUES (%s, %s)", (message, photo_url))
|
|
mysql.connection.commit()
|
|
cursor.close()
|
|
logger.info(f"Message sent: {message}, Photo URL: {photo_url}")
|
|
|
|
return f"Message and photo (if uploaded) have been received. Message: {message}\nPhoto URL: {photo_url if photo_url else 'N/A'}"
|
|
|
|
return render_template('send_message.html')
|
|
|
|
# 获取所有消息
|
|
@app.route('/messages', methods=['GET'])
|
|
@login_required
|
|
def get_messages():
|
|
logger.info("Handling get messages request")
|
|
cursor = mysql.connection.cursor()
|
|
cursor.execute("SELECT id, message, photo_url, created_at FROM messages")
|
|
result = cursor.fetchall()
|
|
cursor.close()
|
|
|
|
messages = []
|
|
for row in result:
|
|
messages.append({
|
|
'id': row['id'],
|
|
'message': row['message'],
|
|
'photo_url': row['photo_url'],
|
|
'created_at': row['created_at']
|
|
})
|
|
|
|
return jsonify(messages)
|
|
|
|
if __name__ == '__main__':
|
|
app.run(debug=True, host='0.0.0.0', port=8000) |