Portal files have been copied to: src/html/portal/
- All HTML pages (login, dashboard, robot-status, robot-planning, meeting-minutes, project-docs)
- All JavaScript modules (auth.js, common.js, robot-status.js, etc.)
- CSS styles (styles.css)
- Data folder (Excel, Word, PDF files)
- Videos folder (3 video files)
Main website updated:
src/html/index.html- Login link changed to "Team Portal" →/portal/login.html
Open Git Bash (not PowerShell) and run:
cd "/c/Users/Anony/OneDrive/Desktop/RM/irm_frontpage"
# Add all changes
git add .
# Commit with message
git commit -m "Add 2026 season team portal with 5 modules
- Add team login system (40 users)
- Add dashboard with countdown to Jan 29 2026
- Add meeting minutes page
- Add robot planning data viewer (26 robots)
- Add project documentation links
- Add robot status page with video upload
- Update main page navigation to include portal link"
# Push to GitHub
git push origin mainNote: The auto-deployment system will pull changes every 5 minutes, so your portal will appear on illinirobomaster.com within 5 minutes after pushing.
The portal's video upload feature requires a Flask backend server. Follow these steps:
SSH to illinirobomaster.com server:
ssh user@illinirobomaster.com
cd /var/www/html/src/portal
mkdir backend
cd backendCreate upload_server.py on server:
from flask import Flask, request, jsonify
from flask_cors import CORS
from werkzeug.utils import secure_filename
import os
import hashlib
app = Flask(__name__)
CORS(app)
# Configure upload folder - use absolute path on server
UPLOAD_FOLDER = '/var/www/html/src/portal/videos'
ALLOWED_EXTENSIONS = {'mp4', 'avi', 'mov', 'webm', 'mkv'}
MAX_FILE_SIZE = 500 * 1024 * 1024 # 500MB
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = MAX_FILE_SIZE
def allowed_file(filename):
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS
@app.route('/health', methods=['GET'])
def health_check():
return jsonify({'status': 'healthy'}), 200
@app.route('/upload', methods=['POST'])
def upload_file():
if 'file' not in request.files:
return jsonify({'error': 'No file part'}), 400
file = request.files['file']
if file.filename == '':
return jsonify({'error': 'No selected file'}), 400
if not allowed_file(file.filename):
return jsonify({'error': 'Invalid file type'}), 400
try:
original_filename = secure_filename(file.filename)
file_content = file.read()
# Generate hash-based filename
file_hash = hashlib.md5(file_content).hexdigest()
file_extension = original_filename.rsplit('.', 1)[1].lower()
new_filename = f"{file_hash}.{file_extension}"
file_path = os.path.join(app.config['UPLOAD_FOLDER'], new_filename)
# Save file
with open(file_path, 'wb') as f:
f.write(file_content)
return jsonify({
'success': True,
'filename': new_filename,
'original_name': original_filename
}), 200
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/delete', methods=['POST'])
def delete_file():
data = request.json
if not data or 'filename' not in data:
return jsonify({'error': 'No filename provided'}), 400
filename = secure_filename(data['filename'])
file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
try:
if os.path.exists(file_path):
os.remove(file_path)
return jsonify({'success': True}), 200
else:
return jsonify({'error': 'File not found'}), 404
except Exception as e:
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
os.makedirs(app.config['UPLOAD_FOLDER'], exist_ok=True)
app.run(host='0.0.0.0', port=5000, debug=False)flask>=3.0.0
flask-cors>=4.0.0
gunicorn>=21.2.0# Install Python dependencies
pip install -r requirements.txt
# Or use venv:
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txtCreate /etc/systemd/system/robomaster-upload.service:
[Unit]
Description=RoboMaster Portal Upload Server
After=network.target
[Service]
Type=simple
User=www-data
WorkingDirectory=/var/www/html/src/portal/backend
Environment="PATH=/var/www/html/src/portal/backend/venv/bin"
ExecStart=/var/www/html/src/portal/backend/venv/bin/gunicorn \
--workers 2 \
--bind 0.0.0.0:5000 \
--timeout 300 \
--max-requests 1000 \
--max-requests-jitter 50 \
upload_server:app
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable robomaster-upload.service
sudo systemctl start robomaster-upload.service
# Check status
sudo systemctl status robomaster-upload.serviceYou need to configure Lighttpd (or Nginx if you switch) to proxy API requests to the Flask backend.
Edit /etc/lighttpd/lighttpd.conf or create /etc/lighttpd/conf-available/robomaster-proxy.conf:
server.modules += ( "mod_proxy" )
$HTTP["url"] =~ "^/api/" {
proxy.server = ( "" => (
(
"host" => "127.0.0.1",
"port" => 5000
)
))
}
Then:
sudo ln -s /etc/lighttpd/conf-available/robomaster-proxy.conf /etc/lighttpd/conf-enabled/
sudo systemctl reload lighttpdlocation /api/ {
proxy_pass http://127.0.0.1:5000/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# Allow large uploads (500MB)
client_max_body_size 500M;
proxy_read_timeout 300s;
proxy_connect_timeout 300s;
}Edit src/portal/robot-status.js, change line ~2:
// Change from:
const UPLOAD_SERVER = 'http://localhost:5000';
// To:
const UPLOAD_SERVER = '/api';This makes the frontend use relative URLs which will be proxied to the Flask backend.
# Ensure web server can write to videos folder
sudo chown -R www-data:www-data /var/www/html/src/portal/videos
sudo chmod -R 755 /var/www/html/src/portal/videosAfter deployment:
- Visit
https://illinirobomaster.com - Click "Team Portal" button in navigation
- Login with any of the 40 user accounts (see auth.js for credentials)
- Navigate to "Robot Status" page
- Try uploading a video file
- Verify video appears in the list
- Test delete functionality
# Check service status
sudo systemctl status robomaster-upload.service
# View logs
sudo journalctl -u robomaster-upload.service -f
# Test health endpoint
curl http://localhost:5000/health- Check videos folder permissions:
ls -la /var/www/html/src/portal/videos - Verify video files exist:
ls /var/www/html/src/portal/videos - Check browser console for errors
- Verify the auto-pull cron job is running:
crontab -l - Check git pull works manually:
cd /var/www/html && git pull - Ensure no merge conflicts:
git status
See src/portal/auth.js for all 40 users. Example accounts:
- 赵一 / Zhao Yi
- 钱二 / Qian Er
- 孙三 / Sun San ...
All users have password: (their names are both username and password)
- Dashboard: Countdown to Jan 29, 2026 15:00 Beijing time
- Project Docs: Links to 4 PDFs and Onshape 3D model
- Robot Status: Video upload/delete for robot demonstrations
- Robot Planning: View 26 robots across 4 schools with filtering
- Meeting Minutes: 89 paragraphs of meeting notes with inline editing
- Videos folder currently has 3 test videos totaling ~50MB
- Upload limit is 500MB per file
- Auto-deployment runs every 5 minutes
- Portal uses localStorage for metadata persistence
- Backend must be running for upload/delete to work