Extract website to SREBOT-web repo: remove web/, move seasons/locales/constants to repo root, fix imports

This commit is contained in:
clxud
2026-07-02 02:45:22 +00:00
parent c0214eaaae
commit 246a29f695
149 changed files with 4 additions and 137956 deletions
+2 -2
View File
@@ -77,7 +77,7 @@ import BOT # noqa: F401, E402 — side effect: adds BOTS/SHARED to sys.path
from data_parser import apply_vehicle_name_filters # noqa: E402 from data_parser import apply_vehicle_name_filters # noqa: E402
LOCALES_DIR = Path(__file__).resolve().parent.parent / "web" / "locales" LOCALES_DIR = Path(__file__).resolve().parent.parent / "locales"
DEFAULT_LANG = "en" DEFAULT_LANG = "en"
@@ -238,7 +238,7 @@ _STORAGE = Path(_storage_env)
SQUADRONS_DB = _STORAGE / "squadrons.db" SQUADRONS_DB = _STORAGE / "squadrons.db"
SQ_BATTLES_DB = _STORAGE / "sq_battles.db" SQ_BATTLES_DB = _STORAGE / "sq_battles.db"
SEASONS_TXT = (Path(__file__).resolve().parent.parent SEASONS_TXT = (Path(__file__).resolve().parent.parent
/ "web" / "constants" / "seasons") / "constants" / "seasons")
_BR_LINE_RE = re.compile(r"<t:(\d+):\w+>.*?max BR\s+(\d+(?:\.\d+)?)", _BR_LINE_RE = re.compile(r"<t:(\d+):\w+>.*?max BR\s+(\d+(?:\.\d+)?)",
re.IGNORECASE) re.IGNORECASE)
+1 -1
View File
@@ -1919,7 +1919,7 @@ async def guild_lang(guild_id: int) -> str:
# SEASON SCHEDULE (shared with web/utils/seasons.js) # SEASON SCHEDULE (shared with web/utils/seasons.js)
# ============================================================================ # ============================================================================
SEASONS_FILE = Path(__file__).resolve().parent.parent / "web" / "constants" / "seasons" SEASONS_FILE = Path(__file__).resolve().parent.parent / "constants" / "seasons"
_SEASON_HEADER_RE = re.compile(r"^\s*(\d{4})-(I{1,3}|IV|VI{0,3}|IX|X)\s*$") _SEASON_HEADER_RE = re.compile(r"^\s*(\d{4})-(I{1,3}|IV|VI{0,3}|IX|X)\s*$")
_WEEK_LINE_RE = re.compile( _WEEK_LINE_RE = re.compile(
-19
View File
@@ -136,25 +136,6 @@ module.exports = {
merge_logs: true, merge_logs: true,
kill_timeout: 3000, kill_timeout: 3000,
restart_delay: 2000 restart_delay: 2000
},
// Website (reads SREBOT_WEB_PORT from .env)
{
name: 'srebot-web',
...RESTART_POLICY,
script: 'server.js',
cwd: `${DEPLOY_PATH}/web`,
instances: 3,
exec_mode: 'cluster',
autorestart: true,
watch: false,
max_memory_restart: '500M',
log_file: './logs/web_combined.log',
out_file: './logs/web_out.log',
error_file: './logs/web_error.log',
log_date_format: 'YYYY-MM-DD HH:mm:ss Z',
merge_logs: true,
kill_timeout: 5000
} }
] ]
}; };
-41
View File
@@ -145,47 +145,6 @@ def pull_and_restart(changed_files: list[str], before: str = '', after: str = ''
processes_to_restart.append('tssbot-api') processes_to_restart.append('tssbot-api')
logger.info("TSSBOT API files changed, will restart tssbot-api") logger.info("TSSBOT API files changed, will restart tssbot-api")
# Web frontend: restart if SREBOT/web/ files changed
web_changed = any(f.startswith('SREBOT/web/') for f in changed_files)
if web_changed:
# Rebuild CSS if tailwind source or config changed
css_changed = any(
f in ('SREBOT/web/public/css/tailwind.css', 'SREBOT/web/tailwind.config.js')
for f in changed_files
)
if css_changed:
logger.info("Tailwind source changed, rebuilding CSS...")
build_result = subprocess.run(
['npm', 'run', 'build:css'],
capture_output=True, text=True, timeout=60,
cwd=os.path.join(REPO_PATH, 'SREBOT', 'web')
)
if build_result.returncode != 0:
logger.error(f"CSS build failed: {build_result.stderr}")
return False, f"CSS build failed: {build_result.stderr}"
logger.info("CSS build successful")
# Rebuild obfuscated JS if any JS source files changed
js_changed = any(
f.startswith('SREBOT/web/public/js/') and f.endswith('.js') and '/dist/' not in f
for f in changed_files
)
if js_changed:
logger.info("JS source files changed, rebuilding obfuscated JS...")
build_result = subprocess.run(
['node', 'build.js'],
capture_output=True, text=True, timeout=120,
cwd=os.path.join(REPO_PATH, 'SREBOT', 'web')
)
if build_result.returncode != 0:
logger.warning(f"JS build failed (non-fatal): {build_result.stderr}")
logger.warning("Continuing deploy — unobfuscated JS will be served as fallback")
else:
logger.info("JS build successful")
processes_to_restart.append('srebot-web')
logger.info("Web files changed, will restart srebot-web")
# Webhook: restart if this file changed # Webhook: restart if this file changed
webhook_changed = any(WEBHOOK_FILENAME in f for f in changed_files) webhook_changed = any(WEBHOOK_FILENAME in f for f in changed_files)
if webhook_changed: if webhook_changed:
+1 -1
View File
@@ -5,7 +5,7 @@ const cors = require('cors');
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
const zlib = require('zlib'); const zlib = require('zlib');
const seasonsUtil = require('./web/utils/seasons'); const seasonsUtil = require('./utils/seasons');
const http = require('http'); const http = require('http');
/** Parse a JSON column that may be gzip-compressed (Buffer) or plain text (string). */ /** Parse a JSON column that may be gzip-compressed (Buffer) or plain text (string). */
-18
View File
@@ -1,18 +0,0 @@
# Environment
NODE_ENV=production
# Server Configuration
PORT=3000
# Domain Configuration (CORS)
PRODUCTION_DOMAIN=https://sre.pawjob.us
# External API Configuration
EXTERNAL_API_URL=http://localhost:6000
# Logging Configuration
LOG_LEVEL=info
# Rate Limiting
RATE_LIMIT_WINDOW_MS=60000
RATE_LIMIT_MAX_REQUESTS=100
-2
View File
@@ -1,2 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto
-55
View File
@@ -1,55 +0,0 @@
# Dependencies
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Environment variables
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# Logs
logs
*.log
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Coverage directory used by tools like istanbul
coverage/
*.lcov
# Operating System Files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Editor directories and files
.vscode/
.idea/
*.swp
*.swo
*~
# Temporary files
*.tmp
*.temp
temp/
# Debug and test files
debug-*.js
test-*.js
# Build output (obfuscated files and generated CSS)
public/js/dist/
public/css/output.css.map
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 692 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 593 B

-21
View File
@@ -1,21 +0,0 @@
MIT License
Copyright (c) 2025 Sop
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 627 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 460 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 574 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 574 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 819 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 786 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1012 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 773 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1006 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 777 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 818 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 927 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 948 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 849 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 829 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 929 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 858 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 885 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 477 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 921 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 818 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 MiB

-56
View File
@@ -1,56 +0,0 @@
const fs = require('fs');
const postcss = require('postcss');
const tailwindcss = require('tailwindcss');
const autoprefixer = require('autoprefixer');
const cssnano = require('cssnano');
const inputPath = './public/css/tailwind.css';
const outputPath = './public/css/output.css';
const isProduction = process.env.NODE_ENV === 'production';
async function buildCSS() {
console.log('[CSS Build] Reading input file...');
const css = fs.readFileSync(inputPath, 'utf8');
console.log(`[CSS Build] Processing with PostCSS and Tailwind... (${isProduction ? 'production' : 'development'} mode)`);
const plugins = [
tailwindcss(),
autoprefixer()
];
// Only minify in production
if (isProduction) {
plugins.push(cssnano({
preset: ['default', {
discardComments: {
removeAll: true,
},
normalizeWhitespace: true,
}]
}));
}
const result = await postcss(plugins).process(css, {
from: inputPath,
to: outputPath,
map: !isProduction ? { inline: false } : false
});
console.log('[CSS Build] Writing output file...');
fs.writeFileSync(outputPath, result.css);
if (result.map && !isProduction) {
fs.writeFileSync(outputPath + '.map', result.map.toString());
}
const sizeKB = (Buffer.byteLength(result.css, 'utf8') / 1024).toFixed(2);
console.log('[CSS Build] ✓ CSS build complete!');
console.log(`[CSS Build] Output: ${outputPath} (${sizeKB} KB)`);
}
buildCSS().catch(err => {
console.error('[CSS Build] Error:', err);
process.exit(1);
});
-81
View File
@@ -1,81 +0,0 @@
const JavaScriptObfuscator = require('javascript-obfuscator');
const fs = require('fs');
const path = require('path');
const PUBLIC_JS_DIR = path.join(__dirname, 'public', 'js');
const OUTPUT_DIR = path.join(__dirname, 'public', 'js', 'dist');
// Obfuscation options - balanced between security and performance
const obfuscationOptions = {
compact: true,
controlFlowFlattening: true,
controlFlowFlatteningThreshold: 0.75,
deadCodeInjection: true,
deadCodeInjectionThreshold: 0.4,
debugProtection: false,
debugProtectionInterval: 0,
disableConsoleOutput: true,
identifierNamesGenerator: 'hexadecimal',
log: false,
numbersToExpressions: true,
renameGlobals: false,
selfDefending: true,
simplify: true,
splitStrings: true,
splitStringsChunkLength: 10,
stringArray: true,
stringArrayCallsTransform: true,
stringArrayEncoding: ['base64'],
stringArrayIndexShift: true,
stringArrayRotate: true,
stringArrayShuffle: true,
stringArrayWrappersCount: 2,
stringArrayWrappersChainedCalls: true,
stringArrayWrappersParametersMaxCount: 4,
stringArrayWrappersType: 'function',
stringArrayThreshold: 0.75,
transformObjectKeys: true,
unicodeEscapeSequence: false
};
// Create output directory if it doesn't exist
if (!fs.existsSync(OUTPUT_DIR)) {
fs.mkdirSync(OUTPUT_DIR, { recursive: true });
}
console.log('[BUILD] Starting JavaScript obfuscation...');
// Get all JS files in the public/js directory
const SKIP_FILES = ['replay-canvas.js', 'replay-canvas-3d.js'];
const jsFiles = fs.readdirSync(PUBLIC_JS_DIR).filter(file =>
file.endsWith('.js') && !file.startsWith('.') && !SKIP_FILES.includes(file)
);
let obfuscatedCount = 0;
jsFiles.forEach(file => {
const inputPath = path.join(PUBLIC_JS_DIR, file);
const outputPath = path.join(OUTPUT_DIR, file);
try {
console.log(`[BUILD] Obfuscating ${file}...`);
const sourceCode = fs.readFileSync(inputPath, 'utf8');
const obfuscationResult = JavaScriptObfuscator.obfuscate(sourceCode, obfuscationOptions);
fs.writeFileSync(outputPath, obfuscationResult.getObfuscatedCode());
const originalSize = (fs.statSync(inputPath).size / 1024).toFixed(2);
const obfuscatedSize = (fs.statSync(outputPath).size / 1024).toFixed(2);
console.log(`[BUILD] ✓ ${file} (${originalSize}KB → ${obfuscatedSize}KB)`);
obfuscatedCount++;
} catch (error) {
console.error(`[BUILD] ✗ Failed to obfuscate ${file}:`, error.message);
}
});
console.log(`\n[BUILD] Obfuscation complete! ${obfuscatedCount}/${jsFiles.length} files processed.`);
console.log(`[BUILD] Obfuscated files saved to: ${OUTPUT_DIR}`);
console.log('[BUILD] To use obfuscated files in production, set NODE_ENV=production');
-65
View File
@@ -1,65 +0,0 @@
#!/bin/bash
echo "[DEPLOY] Starting deployment process..."
echo "[DEPLOY] Deployment started at: $(date)"
cd "$(dirname "$0")"
echo ""
echo "[DEPLOY] Pulling latest changes from Git..."
git pull origin main
if [ $? -ne 0 ]; then
echo "[ERROR] Git pull failed!"
exit 1
fi
echo ""
echo "[DEPLOY] Checking for package.json changes..."
PACKAGE_CHANGED=$(git diff HEAD@{1} HEAD --name-only | grep -q "package.json" && echo "yes" || echo "no")
if [ "$PACKAGE_CHANGED" = "yes" ]; then
echo "[DEPLOY] package.json has changed, running npm install..."
npm install
if [ $? -ne 0 ]; then
echo "[ERROR] npm install failed!"
exit 1
fi
echo ""
echo "[DEPLOY] Running npm audit fix..."
npm audit fix
else
echo "[DEPLOY] No package.json changes detected, skipping npm install"
fi
echo ""
echo "[DEPLOY] Building CSS with Tailwind..."
npm run build:css
if [ $? -ne 0 ]; then
echo "[ERROR] CSS build failed!"
exit 1
fi
echo ""
echo "[DEPLOY] Building obfuscated JavaScript files..."
npm run build
if [ $? -ne 0 ]; then
echo "[WARN] JS build failed, but continuing deployment..."
fi
echo ""
echo "[DEPLOY] Restarting PM2 process 3..."
pm2 restart 3
if [ $? -ne 0 ]; then
echo "[ERROR] PM2 restart failed!"
exit 1
fi
echo ""
echo "[DEPLOY] Deployment completed successfully!"
echo "[DEPLOY] Deployment finished at: $(date)"
File diff suppressed because it is too large Load Diff
-46
View File
@@ -1,46 +0,0 @@
# ============================================
# Environment Configuration Example
# Copy this file to .env and fill in your actual values
# ============================================
# Server Configuration
NODE_ENV=production
PORT=3001
# External API Configuration
# For Docker: use host.docker.internal to reach services on host machine
# For Docker Compose with API in same network: use the service name
EXTERNAL_API_URL=http://localhost:6000
# Domain Config (used for CORS)
PRODUCTION_DOMAIN=https://sre.pawjob.us
# API Security (optional - auto-generates if not set)
# Generate with: openssl rand -hex 32
API_SECRET=
# IP Whitelist (optional - comma-separated IPs for production)
ALLOWED_IPS=
# Webhook Configuration (optional - for GitHub auto-deployment)
# Generate a secure random string for this
WEBHOOK_SECRET=
# ============================================
# PM2 Commands:
# ============================================
# Start with PM2:
# npm run pm2:start
#
# Other PM2 commands:
# npm run pm2:stop - Stop the app
# npm run pm2:restart - Restart the app
# npm run pm2:reload - Zero-downtime reload
# npm run pm2:logs - View logs
# npm run pm2:monit - Monitor dashboard
# npm run pm2:delete - Remove from PM2
#
# Auto-start on reboot:
# pm2 startup
# pm2 save
# ============================================
-5912
View File
File diff suppressed because it is too large Load Diff
-53
View File
@@ -1,53 +0,0 @@
{
"name": "toothless-sqb-bot-web",
"version": "1.0.0",
"description": "Website for Toothless SQB Discord Bot",
"main": "server.js",
"scripts": {
"start": "cross-env NODE_ENV=production node server.js",
"dev": "npm run build:css && concurrently \"npm run watch:css\" \"cross-env NODE_ENV=development nodemon server.js\"",
"build": "npm run build:css && node build.js",
"build:css": "node build-css.js",
"watch:css": "nodemon --watch public/css/tailwind.css --watch tailwind.config.js --exec \"node build-css.js\"",
"build:prod": "npm run build:css && node build.js && cross-env NODE_ENV=production node server.js",
"pm2:start": "npm run build && pm2 start ecosystem.config.js",
"pm2:stop": "pm2 stop toothless-sqb-web",
"pm2:restart": "pm2 restart toothless-sqb-web",
"pm2:reload": "pm2 reload toothless-sqb-web",
"pm2:delete": "pm2 delete toothless-sqb-web",
"pm2:logs": "pm2 logs toothless-sqb-web",
"pm2:monit": "pm2 monit",
"test": "echo \"No tests specified yet. Please run 'npm run dev' to start the development server.\""
},
"keywords": [
"discord",
"bot",
"website",
"express",
"node"
],
"author": "Sophie :3",
"license": "MIT",
"dependencies": {
"compression": "^1.8.1",
"cors": "^2.8.5",
"dotenv": "^16.3.1",
"ejs": "^3.1.9",
"express": "^4.18.2",
"node-fetch": "^2.7.0",
"sqlite3": "^5.1.7"
},
"devDependencies": {
"autoprefixer": "^10.4.22",
"concurrently": "^9.2.1",
"cross-env": "^10.1.0",
"cssnano": "^7.1.2",
"javascript-obfuscator": "^4.1.0",
"nodemon": "^3.0.1",
"postcss": "^8.5.6",
"tailwindcss": "^3.4.18"
},
"engines": {
"node": ">=16.0.0"
}
}
-7
View File
@@ -1,7 +0,0 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More