Compare commits

...

2 Commits

Author SHA1 Message Date
min
ba71f5f4b9 fix(studio): убрать лишний escape \[ в docsLang regex (CI lint error из влитого main)
All checks were successful
CI / Lint (pull_request) Successful in 1m8s
CI / Build (pull_request) Successful in 1m58s
CI / Secret scan (pull_request) Successful in 30s
CI / PR size check (pull_request) Successful in 12s
CI / Deploy to S1 + S2 (pull_request) Has been skipped
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-10 01:41:04 +03:00
min
2f9d6a21f6 fix(rbxl-importer): CORS preflight + открыт для всех
Фронт студии (studio.rublox.pro) делал POST /import/rbxl/analyze
на minecraftia-school.ru/api-rbxl, preflight (OPTIONS) не получал
Access-Control-Allow-Origin → CORS ошибка.

Фиксы:
- after_request гарантированно ставит CORS-заголовки на ВСЕ ответы
  (включая OPTIONS) — раньше flask-cors иногда их не отдавал
- Явный handler для OPTIONS /import/rbxl/analyze + create
- Headers: Allow-Origin=*, Allow-Methods, Allow-Headers content-type+x-user-id
- Убрал ALLOWED_USER_IDS=[1] (импорт открыт всем — кнопка
  в UI уже без гейтинга, см. вики «Импорт из Roblox»)

Деплой: вручную через SSH на VM 130 (rbxl-importer не имеет CI/CD).
2026-06-10 01:27:48 +03:00
2 changed files with 22 additions and 5 deletions

View File

@ -59,10 +59,28 @@ STORAGE_ROOT = os.environ.get('STORAGE_ROOT', '/opt/roblox-assets')
PUBLIC_ASSET_BASE = os.environ.get('PUBLIC_ASSET_BASE', 'https://assets.rublox.pro/roblox')
MAX_RBXL_SIZE = 50 * 1024 * 1024 # 50 MB
ALLOWED_USER_IDS = [1] # пока только МИН
app = Flask(__name__)
CORS(app, resources={r'/*': {'origins': '*'}})
# CORS открыт для всех источников — фронт студии живёт на studio.rublox.pro,
# api-rbxl проксируется через NPM на minecraftia-school.ru/api-rbxl/*.
# Поддерживаем preflight (OPTIONS) явно через after_request — иногда
# flask-cors не отдавал заголовки для OPTIONS если NPM их перекрывал.
CORS(app, resources={r'/*': {'origins': '*'}}, supports_credentials=False)
@app.after_request
def _add_cors_headers(resp):
resp.headers['Access-Control-Allow-Origin'] = '*'
resp.headers['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
resp.headers['Access-Control-Allow-Headers'] = 'Content-Type, X-User-Id, X-User-Login'
resp.headers['Access-Control-Max-Age'] = '3600'
return resp
@app.route('/import/rbxl/analyze', methods=['OPTIONS'])
@app.route('/import/rbxl/create', methods=['OPTIONS'])
def _preflight():
return '', 204
# Devlog для удалённой отладки dev-сессий студии: фронт пушит сюда
# console.error/warn, failed network requests, неожиданные exceptions.
@ -93,8 +111,7 @@ def auth_check(req) -> int:
uid = int(user_id_str)
except ValueError:
raise RuntimeError(f'Bad X-User-Id: {user_id_str!r}')
if uid not in ALLOWED_USER_IDS:
raise RuntimeError(f'User {uid} not allowed (only МИН)')
# Импорт открыт всем (см. вики «Импорт из Roblox»).
return uid

View File

@ -83,7 +83,7 @@ export function highlightCode(text, lang) {
// Классифицируем
if (tok.startsWith('--') || tok.startsWith('//') || tok.startsWith('/*')) {
tokens.push({ type: 'comment', text: tok });
} else if (/^["'`\[]/.test(tok)) {
} else if (/^["'`[]/.test(tok)) {
tokens.push({ type: 'string', text: tok });
} else if (/^\d/.test(tok)) {
tokens.push({ type: 'number', text: tok });