Skip to content

Tham khảo cấu hình

Bảng tra các thiết lập Django riêng của LCOJ, VNOJ và DMOJ: giá trị mặc định trong settings.py, giá trị trên luyencode.net, tác dụng của từng thiết lập và trang tài liệu giải thích chi tiết.

⏱ ~5 phút · 👤 Người vận hành · 🔑 Quyền sửa local_settings.py trên máy chủ

Khi nào cần trang này

  • Bạn muốn biết một hành vi của site (giới hạn nộp bài, số bài test tối đa, điều kiện để bình luận...) do thiết lập nào quyết định.
  • Bạn định bật một tính năng đang tắt (tải dữ liệu kỳ thi, MOSS, API đồng bộ, webhook Discord...).
  • Bạn gặp một thiết lập trong mã nguồn và muốn biết cấu hình đi kèm có ghi đè nó hay không.

Trang này chỉ liệt kê các thiết lập riêng của hệ thống chấm bài. Thiết lập chung của Django (SECRET_KEY, DEBUG, DATABASES, CACHES...) và các biến trong file .env được mô tả ở Biến môi trường.

Cách đọc các bảng:

  • Mặc định: giá trị trong dmoj/repo/dmoj/settings.py. "không khai báo" nghĩa là settings.py không có dòng này, code tự dùng giá trị dự phòng.
  • luyencode.net: giá trị trong local_settings.py đi kèm (bản mẫu dmoj/config/local_settings.py), cũng là cấu hình đang chạy trên luyencode.net. = nghĩa là file này không ghi đè mặc định. env X nghĩa là giá trị được đọc từ biến môi trường X. `<secret>` là giá trị bí mật mà bạn tự đặt.

Cách thay đổi một thiết lập

Django nạp cấu hình theo ba lớp, lớp sau ghi đè lớp trước:

  1. dmoj/repo/dmoj/settings.py chứa giá trị mặc định. Không sửa file này; nó thuộc submodule lcoj-site.
  2. File đang chạy là dmoj/repo/dmoj/local_settings.py. ./scripts/initialize sao chép file này từ bản mẫu dmoj/config/local_settings.py, và chạy lại initialize sẽ ghi đè bản đang chạy. Vì vậy, khi sửa, hãy sửa cả hai file cho giống nhau.
  3. Một số thiết lập trong local_settings.py được đọc từ biến môi trường (HOST, SITE_FULL_URL, MEDIA_URL, EVENT_DAEMON_POST, CELERY_BROKER_URL, BRIDGED_HOST, MOSS_API_KEY, khóa OAuth Google...). Với những thiết lập này, hãy sửa environment/site.env, xem Biến môi trường.

Thêm một thiết lập mới vào cuối local_settings.py (phần Custom Configuration), ví dụ:

python
DMOJ_SUBMISSION_LIMIT = 3

Thiết lập bí mật thì đọc từ môi trường thay vì ghi thẳng giá trị:

python
GLOBAL_API_KEY = os.environ.get('GLOBAL_API_KEY', '')

Sau khi sửa local_settings.py, khởi động lại các dịch vụ chạy Django (chạy trong dmoj/):

sh
docker compose restart site celery
# thêm bridged nếu bạn sửa BRIDGED_* hoặc thiết lập liên quan tới hàng đợi chấm
docker compose restart bridged

Sửa file .env thì phải tạo lại container bằng docker compose up -d ..., vì restart không đọc lại env_file (xem Áp dụng thay đổi).

Site và thương hiệu

Thiết lậpMặc địnhluyencode.netTác dụngTài liệu
SITE_NAME'DMOJ''LCOJ'Tên ngắn trên tiêu đề trang, thanh điều hướng, emailCấu hình site
SITE_LONG_NAME'DMOJ: Modern Online Judge''LCOJ: Luyện Code Online Judge'Tên đầy đủ của siteCấu hình site
HOSTkhông khai báoenv HOST (mặc định 'localhost')Tên miền của site; dùng để sinh ALLOWED_HOSTSEVENT_DAEMON_GET(_SSL)Biến môi trường
SITE_FULL_URLNoneenv SITE_FULL_URL (mặc định 'http://localhost/')URL gốc tuyệt đối, dùng để dựng link trong webhook Discord và link tới file PDF, file bài nộpBiến môi trường
MEDIA_URL'' (Django)env MEDIA_URLURL gốc của file người dùng tải lênBiến môi trường
SITE_ADMIN_EMAIL'''[email protected]'Email liên hệ quản trị hiển thị trên site
SERVER_EMAIL'root@localhost' (Django)'LCOJ: Luyện Code Online Judge <[email protected]>'Địa chỉ người gửi email báo lỗiBiến môi trường
LANGUAGE_CODE'en''vi'Ngôn ngữ giao diện mặc định
DEFAULT_USER_TIME_ZONE'America/Toronto''Asia/Ho_Chi_Minh'Múi giờ của tài khoản mới
DMOJ_SSL1=Giao thức của link canonical: 0 luôn http, 1 theo request, 2 luôn httpsThiết lập đáng chú ý
DMOJ_CANONICAL'oj.luyencode.net'=Tên miền trong thẻ <link rel="canonical">og:urlThiết lập đáng chú ý
TIMEZONE_MAPảnh trên static.dmoj.caảnh Blue Marble trên WikimediaBản đồ dùng để chọn múi giờ trên trang hồ sơ
ACE_URL, JQUERY_JS, SELECT2_JS_URL, SELECT2_CSS_URLbản trong /static/vnoj/ và Google CDNbản trên cdnjs.cloudflare.comNơi tải trình soạn code Ace, jQuery và Select2
DMOJ_THEME_CSS, DMOJ_THEME_DEFAULT_ACE_THEME, DMOJ_SELECT2_THEMECSS style.css / dark/style.css, Ace github / twilight, Select2 dmoj=File CSS và theme trình soạn code cho giao diện sáng/tối
SITE_THEME_COOKIE_NAME, SITE_THEME_COOKIE_AGE'site_theme', 1 năm=Cookie nhớ giao diện sáng/tối của khách chưa đăng nhập
VNOJ_HOMEPAGE_TOP_USERS_COUNT5=Số người trong bảng xếp hạng thu gọn ở trang chủ
DMOJ_BLOG_NEW_PROBLEM_COUNT7=Số bài mới ở cột bên trang chủ và trang tổ chức

Tài khoản và đăng nhập

Thiết lậpMặc địnhluyencode.netTác dụngTài liệu
OAUTH_ONLYFalseTrueẨn form đăng ký bằng mật khẩu, chỉ còn nút đăng ký bằng GoogleTài khoản
REGISTRATION_OPENTrue=False thì ẩn link Đăng ký và chặn trang /accounts/register/Quản lý người dùng
ACCOUNT_ACTIVATION_DAYS7=Số ngày link kích hoạt qua email còn hiệu lực
SEND_ACTIVATION_EMAILkhông khai báo (code coi là True)=False thì tài khoản đăng ký bằng mật khẩu được kích hoạt ngay, không gửi email
TERMS_OF_SERVICE_URLNoneNoneLink điều khoản sử dụng trên form đăng ký
BAD_MAIL_PROVIDERS, BAD_MAIL_PROVIDER_REGEX(), ()set(), =Tên miền email (hoặc regex) bị từ chối khi đăng ký bằng mật khẩu
SOCIAL_AUTH_GOOGLE_OAUTH2_KEY, SOCIAL_AUTH_GOOGLE_OAUTH2_SECRETkhông khai báo<secret> (env cùng tên)Thông tin ứng dụng OAuth Google cho đăng nhập/đăng kýBiến môi trường
DMOJ_REQUIRE_STAFF_2FATrue=Không cho staff tự tắt xác thực hai lớp (2FA) cuối cùng của mìnhThiết lập đáng chú ý
DMOJ_2FA_HARDCOREFalse=Hiện cảnh báo rằng quản trị viên sẽ không khôi phục 2FA giúp người dùng
DMOJ_TOTP_TOLERANCE_HALF_MINUTES1=Độ lệch thời gian cho phép của mã TOTP, tính theo bước 30 giâyTài khoản
DMOJ_SCRATCH_CODES_COUNT5=Số mã dự phòng sinh ra khi bật 2FATài khoản
WEBAUTHN_RP_IDNone=Tên miền cho khóa bảo mật (WebAuthn); None thì ẩn tính năng nàyTài khoản
DMOJ_PASSWORD_RESET_LIMIT_WINDOW, DMOJ_PASSWORD_RESET_LIMIT_COUNT3600, 10=Mỗi địa chỉ IP gửi tối đa 10 yêu cầu đặt lại mật khẩu trong 3600 giây
IMPERSONATE_REQUIRE_SUPERUSER, IMPERSONATE_DISABLE_LOGGINGTrue, True=Dự định giới hạn mạo danh cho superuser và tắt nhật ký, nhưng không có tác dụngQuản lý người dùng
DMOJ_USER_DATA_DOWNLOADFalseTrueCho người dùng tải về dữ liệu của mìnhTải dữ liệu người dùng
DMOJ_USER_DATA_CACHE, DMOJ_USER_DATA_INTERNAL'', '''/userdatacache', '/userdatacache'Thư mục lưu file ZIP và đường dẫn nội bộ nginx (X-Accel-Redirect) để gửi fileTải dữ liệu người dùng
DMOJ_USER_DATA_DOWNLOAD_RATELIMIT1 ngày1 ngàyKhoảng cách tối thiểu giữa hai lần yêu cầu dữ liệuTải dữ liệu người dùng
VNOJ_DISPLAY_RANKSuser, setter, daor, staff, banned, admin, teacher=Danh sách danh hiệu hiển thị cạnh tên người dùngQuản lý người dùng
DMOJ_NEWSLETTER_ID_ON_REGISTERNone=Tự đăng ký người dùng mới vào một bản tin (cần app newsletter, không được cài sẵn)
IP_BASED_AUTHENTICATION_HEADER'REMOTE_ADDR'=Header chứa IP cho đăng nhập theo IP; chỉ có tác dụng khi thêm IPBasedAuthMiddleware (không có trong MIDDLEWARE mặc định)

Bài tập và dữ liệu test

Thiết lậpMặc địnhluyencode.netTác dụngTài liệu
DMOJ_PROBLEM_DATA_ROOTNone'/problems/'Thư mục chứa dữ liệu test trong container, khớp với volume problemsQuản lý bài tập
DMOJ_PROBLEM_DATA_INTERNALkhông khai báo=Đường dẫn nội bộ nginx để gửi file test; không khai báo thì Django tự gửi file
DMOJ_PROBLEM_MIN_TIME_LIMIT, DMOJ_PROBLEM_MAX_TIME_LIMIT0.01, 60 (giây)=Khoảng hợp lệ của giới hạn thời gianQuản lý bài tập
DMOJ_PROBLEM_MIN_MEMORY_LIMIT, DMOJ_PROBLEM_MAX_MEMORY_LIMIT0, 1048576 (KB)=Khoảng hợp lệ của giới hạn bộ nhớQuản lý bài tập
DMOJ_PROBLEM_MIN_PROBLEM_POINTS0=Điểm tối thiểu của một bài
VNOJ_PROBLEM_TIMELIMIT_LIMIT5 (giây)=Giới hạn thời gian tối đa được đặt nếu không có quyền high_problem_timelimitPhân quyền
VNOJ_TESTCASE_HARD_LIMIT100=Số test tối đa nếu không có quyền create_mass_testcasesPhân quyền
VNOJ_TESTCASE_SOFT_LIMIT50=Vượt số test này thì hiện cảnh báo (với người không có quyền trên)Phân quyền
VNOJ_TESTCASE_VISIBLE_LENGTH60=Số byte đầu của file test được hiển thị khi xem trước
DMOJ_PROBLEM_STATEMENT_DISALLOWED_CHARACTERSngoặc kép cong, dấu trừ Unicode, chữ ghép , ...=Ký tự bị cấm trong đề bài, lưu đề sẽ báo lỗi nếu cóQuản lý bài tập
DMOJ_PROBLEM_HOT_PROBLEM_COUNT7=Số "bài hot" (tính theo 24 giờ gần nhất) trên danh sách bài
VNOJ_TAG_PROBLEM_MIN_RATING1900=Rating tối thiểu để được gắn tag cho bàiCộng đồng
ENABLE_FTSFalseFalseBật tìm kiếm toàn văn trong danh sách bài
DATA_UPLOAD_MAX_NUMBER_FIELDS3000=Số trường tối đa của một form, được nâng lên để lưu bảng test dài
VNOJ_PROBLEM_DELETION_GRACE_PERIOD7 ngày=Bài bị xóa mềm quá thời gian này thì tác vụ dọn rác được phép xóa hẳnTổ chức
VNOJ_PROBLEM_GARBAGE_COLLECTOR_TIME_LIMIT1 giờ=Thời gian chạy tối đa của một lần dọn rác
VNOJ_PROBLEM_GARBAGE_COLLECTOR_CRONTAB_KWARGS{'minute': 0, 'hour': 0}=Lịch chạy dọn rác (cần Celery beat, xem lưu ý)

Nộp bài và chấm bài

Thiết lậpMặc địnhluyencode.netTác dụngTài liệu
DMOJ_SUBMISSION_LIMIT2=Số bài nộp đang chờ chấm tối đa của một người, nếu không có quyền spam_submissionPhân quyền
DMOJ_SUBMISSIONS_REJUDGE_LIMIT10=Số bài nộp chấm lại một lần trong trang quản trị, nếu không có quyền rejudge_submission_lotPhân quyền
DMOJ_SUBMISSION_SOURCE_VISIBILITY'all-solved'=Ai xem được mã nguồn người khác với bài để chế độ "theo cấu hình chung": 'all', 'all-solved' hoặc 'only-own'Quản lý bài tập
DEFAULT_USER_LANGUAGE'CPP20'=Ngôn ngữ lập trình mặc định của tài khoản mới
BRIDGED_JUDGE_ADDRESS[('localhost', 9999)][(env BRIDGED_HOST, 9999)], mặc định host bridgedĐịa chỉ bridged lắng nghe kết nối từ máy chấmCài đặt máy chấm
BRIDGED_DJANGO_ADDRESS[('localhost', 9998)][(env BRIDGED_HOST, 9998)], mặc định host bridgedĐịa chỉ bridged nhận lệnh chấm từ siteKiến trúc
BRIDGED_DJANGO_CONNECT, BRIDGED_JUDGE_PROXIESNone, None=Địa chỉ site dùng để gọi bridged (nếu khác địa chỉ lắng nghe); danh sách proxy tin cậy trước máy chấm
VNOJ_LONG_QUEUE_ALERT_THRESHOLD10=Hàng đợi chấm vượt ngưỡng này thì gửi webhook on_long_queue
VNOJ_LOW_POWER_MODEFalse=Chế độ tiết kiệm: giới hạn số trang danh sách bài nộp và bỏ bản đồ nhiệt với người nộp quá nhiều
VNOJ_LOW_POWER_MODE_CONFIG{'max_page': 5, 'heat_map_limit': 20000}=Tham số của chế độ tiết kiệm
DMOJ_STATS_SUBMISSION_RESULT_COLORSmàu cho AC, WA, TLE...=Màu các kết quả trong biểu đồ thống kê

Kỳ thi và xếp hạng

Thiết lậpMặc địnhluyencode.netTác dụngTài liệu
VNOJ_CONTEST_DURATION_LIMIT14 (ngày)=Thời lượng kỳ thi tối đa nếu không có quyền long_contest_durationTạo kỳ thi
MAX_CONTEST_PROBLEMS_COUNTNone=Số bài tối đa trong một kỳ thi; None là không giới hạnTạo kỳ thi
VNOJ_OFFICIAL_CONTEST_MODEFalse=Chế độ thi chính thức: khóa sửa tên và phần giới thiệu, ghi IP mỗi lần nộp, không bắt đổi mật khẩuTạo kỳ thi
VNOJ_SHOULD_BAN_FOR_CHEATING_IN_CONTESTSFalse=Tự khóa tài khoản bị loại (disqualify) nhiều lầnQuản lý người dùng
VNOJ_MAX_DISQUALIFICATIONS_BEFORE_BANNING3=Số lần bị loại trước khi bị khóaQuản lý người dùng
VNOJ_CONTEST_CHEATING_BAN_MESSAGE'Banned for multiple cheating offenses during contests'=Lý do khóa ghi vào hồ sơQuản lý người dùng
VNOJ_BAN_COUNT_FROM_DATE1/1/2026 (UTC)=Chỉ đếm các lần bị loại từ kỳ thi bắt đầu sau ngày này; None là đếm tất cảQuản lý người dùng
DMOJ_CONTEST_DATA_DOWNLOADFalseTrueCho phép tải dữ liệu kỳ thiTải dữ liệu kỳ thi
DMOJ_CONTEST_DATA_CACHE, DMOJ_CONTEST_DATA_INTERNAL'', '''/contestdatacache', '/contestdatacache'Thư mục lưu file ZIP và đường dẫn nội bộ nginx để gửi fileTải dữ liệu kỳ thi
DMOJ_CONTEST_DATA_DOWNLOAD_RATELIMIT1 ngày1 ngàyKhoảng cách tối thiểu giữa hai lần yêu cầu dữ liệu kỳ thiTải dữ liệu kỳ thi
CONTEST_REPLAY_MEDIA_DIR, DMOJ_CONTEST_REPLAY_INTERNAL'contest_replay', None=Thư mục (trong MEDIA_ROOT) chứa dữ liệu replay bảng xếp hạng; đường dẫn nội bộ nginx để gửi fileTạo kỳ thi
DMOJ_PP_STEP, DMOJ_PP_ENTRIES0.98514, 300=Hệ số giảm dần và số bài tốt nhất được tính vào điểm (performance points) của người dùng
DMOJ_PP_BONUS_FUNCTION0.05 * n=Điểm thưởng theo số bài đã giải n
DMOJ_RATING_COLORSTrue=Tô màu tên người dùng theo rating

Tổ chức và hạn mức

Thiết lậpMặc địnhluyencode.netTác dụngTài liệu
DMOJ_USER_MAX_ORGANIZATION_COUNT3=Số tổ chức công khai (mở) tối đa một người được tham giaTổ chức
VNOJ_ORGANIZATION_ADMIN_LIMIT3=Số tổ chức tối đa một người làm quản trị mà vẫn được tạo tổ chức mới, nếu không có quyền spam_organizationTổ chức
VNOJ_ORG_PP_STEP, VNOJ_ORG_PP_ENTRIES, VNOJ_ORG_PP_SCALE0.95, 100, 1=Công thức điểm của tổ chức, tính từ điểm của các thành viên tốt nhấtTổ chức
VNOJ_ENABLE_ORGANIZATION_CREDIT_LIMITATIONFalse=Bật hệ thống credit: tổ chức hết credit thì không nộp được bài riêngTổ chức
VNOJ_MONTHLY_FREE_CREDIT10800 (3 giờ chấm)=Credit miễn phí mỗi tháng của một tổ chứcTổ chức
VNOJ_PRICE_PER_HOUR50=Đơn giá (nghìn đồng) mỗi giờ chấm vượt credit miễn phí, dùng cho biểu đồ chi phíTổ chức
VNOJ_ORGANIZATION_DEFAULT_MAX_PROBLEMS, VNOJ_ORGANIZATION_DEFAULT_MAX_STORAGE1000, 5 GB=Hạn mức mặc định về số bài và dung lượng test của tổ chức mớiTổ chức
VNOJ_QUOTA_WARNING_THRESHOLD0.8=Dùng quá 80% hạn mức thì hiện cảnh báoTổ chức
VNOJ_QUOTA_WARNING_SUFFIX''=Đoạn HTML thêm vào cuối mọi cảnh báo hạn mức (ví dụ link hướng dẫn)Tổ chức
VNOJ_QUOTA_ENFORCEMENT_ENABLEDFalse=True thì chặn tạo bài / tải test khi vượt hạn mức; False chỉ cảnh báoTổ chức
VNOJ_QUOTA_PACKAGE_STORAGE, VNOJ_QUOTA_PACKAGE_PROBLEMS5 GB, 1000=Dung lượng và số bài mỗi gói hạn mức cộng thêmTổ chức
GROUP_PERMISSION_FOR_ORG_ADMIN'Org Admin'=Nhóm quyền Django tự gán cho quản trị viên tổ chứcPhân quyền
DESCRIPTION_MAX_LENGTH200=Độ dài mô tả (thẻ meta) lấy từ phần giới thiệu tổ chức
VNOJ_IGNORED_ORGANIZATION_SUBDOMAINS['oj', 'www', 'localhost']=Tên miền con không bị coi là tổ chức; chỉ có tác dụng khi thêm OrganizationSubdomainMiddleware (không có trong MIDDLEWARE mặc định)

Bình luận, blog và điểm đóng góp

Thiết lậpMặc địnhluyencode.netTác dụngTài liệu
VNOJ_INTERACT_MIN_PROBLEM_COUNT5=Số bài phải giải để được bình luận, bình chọn và sửa hồ sơCộng đồng
VNOJ_BLOG_MIN_PROBLEM_COUNT10=Số bài phải giải để được viết blogCộng đồng
VNOJ_COMMENT_MIN_CONTRIBUTION-20=Điểm đóng góp tối thiểu để bình luận (không áp dụng cho staff)Cộng đồng
VNOJ_COMMENT_MIN_LENGTH, VNOJ_COMMENT_MAX_LENGTH10, 8196=Độ dài bình luận tối thiểu/tối đa (không áp dụng cho staff)Cộng đồng
VNOJ_COMMENT_BLACKLIST_TERMS[]=Từ bị cấm trong bình luận, không phân biệt hoa thường
VNOJ_COMMENT_RATE_LIMIT_COUNT, VNOJ_COMMENT_RATE_LIMIT_WINDOWNone, 600 giây=Số bình luận tối đa trong một khoảng thời gian; None là không giới hạn
DMOJ_COMMENT_VOTE_HIDE_THRESHOLD-5=Bình luận có điểm từ ngưỡng này trở xuống bị thu gọnCộng đồng
DMOJ_COMMENT_REPLY_TIMEFRAME365 ngày=Chỉ được trả lời bình luận đăng trong khoảng thời gian này (trừ người có quyền sửa bình luận)Cộng đồng
VNOJ_CP_COMMENT1=Điểm đóng góp cho mỗi điểm bình chọn của bình luận và blogCộng đồng
VNOJ_CP_TICKET105Điểm đóng góp cho mỗi ticket được đánh dấu có íchCộng đồng
VNOJ_CP_EDITORIAL_REVEALkhông khai báo (code dùng 1)=Điểm đóng góp bị trừ mỗi lần mở lời giải khi chưa giải bàiLời giải
TICKET_AUTOFILL_REPLIESdanh sách câu trả lời mẫu=Câu trả lời soạn sẵn khi xử lý ticket của người khác
NOFOLLOW_EXCLUDEDset()=Tên miền không bị gắn rel="nofollow" khi hiển thị Markdown
GOOGLE_SEARCH_ENGINE_URLNone=URL Google Custom Search để hiện ô tìm kiếm trên trang chủ

Quiz không có thiết lập riêng; mọi cấu hình quiz nằm trong trang quản trị (xem Soạn quiz).

Thiết lậpMặc địnhluyencode.netTác dụngTài liệu
URLSHORTENER_DOMAINkhông khai báo=Tên miền riêng cho link rút gọn; không đặt thì link sao chép ra chỉ là /<mã>Rút gọn link
PDF_STATEMENT_MAX_FILE_SIZE5242880 (5 MB)=Dung lượng tối đa của file PDF đề bài và đề trong thư việnThư viện đề
PDF_STATEMENT_SAFE_EXTS{'pdf'}=Đuôi file được phép tải lênThư viện đề
PDF_STATEMENT_UPLOAD_MEDIA_DIR, PDF_STATEMENT_UPLOAD_URL_PREFIX'pdf', '/pdf'=Thư mục (trong MEDIA_ROOT) và tiền tố URL của file PDF đã tải lênThư viện đề

Hiển thị (công thức, PDF, hình ảnh)

Thiết lậpMặc địnhluyencode.netTác dụngTài liệu
MATHOID_URLFalse=URL dịch vụ Mathoid; False thì công thức được MathJax hiển thị trên trình duyệtMathoid
MATHOID_GZIP, MATHOID_MML_CACHE, MATHOID_CSS_CACHE, MATHOID_DEFAULT_TYPE, MATHOID_MML_CACHE_TTL, MATHOID_CACHE_ROOT, MATHOID_CACHE_URLFalse, None, 'default', 'auto', 86400, '', False=Cache và kiểu kết quả của MathoidMathoid
TEXOID_URLkhông khai báo=URL dịch vụ Texoid (vẽ TikZ); hiện chưa được nối vào bộ render đềTexoid
TEXOID_GZIP, TEXOID_META_CACHE, TEXOID_META_CACHE_TTL, TEXOID_CACHE_ROOT, TEXOID_CACHE_URLFalse, 'default', 86400, không khai báo, không khai báo=Cache của TexoidTexoid
DMOJ_PDF_PDFOID_URLNone=URL dịch vụ Pdfoid; khác None thì bật tải đề bài dạng PDFPdfoid
DMOJ_PDF_PROBLEM_CACHE, DMOJ_PDF_PROBLEM_INTERNALNone, None=Thư mục cache PDF và đường dẫn nội bộ nginx để gửi filePdfoid
DMOJ_CAMO_URL, DMOJ_CAMO_KEYNone, None=Proxy ảnh Camo cho ảnh bên ngoài trong Markdown; khóa là <secret>Proxy nội dung SSL
DMOJ_CAMO_HTTPS, DMOJ_CAMO_EXCLUDEFalse, ()=Dùng https cho link không ghi giao thức; tên miền không đi qua CamoProxy nội dung SSL

Tích hợp và API

Thiết lậpMặc địnhluyencode.netTác dụngTài liệu
MOSS_API_KEYNone<secret> (env MOSS_API_KEY, mặc định '')Khóa MOSS để kiểm tra đạo code trong kỳ thiTạo kỳ thi
MOSS_HOST, MOSS_PORT'moss.stanford.edu', 7690=Máy chủ MOSS
OPENAI_API_KEY, OPENAI_BASE_URLkhông phải thiết lập Djangobiến môi trường khi chạy lệnhKhóa và URL API tương thích OpenAI mà lệnh generate_editorials đọc trực tiếp từ môi trườngLời giải, Lệnh quản trị
VNOJ_ENABLE_SYNC_APIFalse=Bật API đồng bộ kỳ thi dưới /api/v2/API
GLOBAL_API_KEYgiá trị thử nghiệm công khai=Khóa chung mà mọi request API đồng bộ phải gửi kèmAPI
DISCORD_WEBHOOKmọi khóa là None=URL webhook Discord cho từng sự kiện (ticket, bình luận, bài mới, hàng đợi dài...); giá trị là <secret>Thiết lập đáng chú ý
VNOJ_DISCORD_WEBHOOK_THROTTLING(10, 60)=Tối đa 10 tin báo lỗi qua Discord trong 60 giây
OJ_PROBLEM_PRESET, OJ_LISTCodeforces, Codeforces Gym, AtCoder, VNOJ, Kattis=Các OJ ngoài và mẫu link bài tương ứng mà tính năng tag bài nhận diện
OJ_REQUESTS_TIMEOUT, OJAPI_CACHE_TIMEOUT5 giây, 3600 giây=Thời gian chờ và thời gian cache khi gọi API của OJ ngoài

Tác vụ nền và cache

Thiết lậpMặc địnhluyencode.netTác dụngTài liệu
CELERY_BROKER_URL, CELERY_RESULT_BACKENDkhông khai báoenv cùng tên, mặc định redis://redis:6379/1Hàng đợi và nơi lưu kết quả tác vụ CeleryBiến môi trường
CELERY_BROKER_URL_SECRETkhông khai báo=Nếu có, ghi đè URL broker (dùng khi URL chứa mật khẩu)
CELERY_TIMEZONE, CELERY_WORKER_HIJACK_ROOT_LOGGER'UTC', False=Múi giờ lịch tác vụ định kỳ; không để Celery chiếm logger gốc
CACHES{}Redis, env REDIS_CACHING_URLCache của DjangoBiến môi trường
EVENT_DAEMON_USEFalseTrueBật cập nhật trực tiếp (kết quả chấm, bảng xếp hạng) qua wseventKiến trúc
EVENT_DAEMON_POST'ws://localhost:9997/'env EVENT_DAEMON_POST (mặc định 'ws://wsevent:15101/')Địa chỉ site gửi sự kiện tới wseventBiến môi trường
EVENT_DAEMON_GET, EVENT_DAEMON_GET_SSL'ws://localhost:9996/', không khai báows://{HOST}/event/, wss://{HOST}/event/Địa chỉ WebSocket mà trình duyệt kết nốiBiến môi trường
EVENT_DAEMON_POLL'/channels/''/channels/'Đường dẫn long polling khi WebSocket không dùng được
EVENT_DAEMON_KEY, EVENT_DAEMON_AMQP, EVENT_DAEMON_AMQP_EXCHANGENone, không khai báo, 'dmoj-events'=Khóa xác thực với wsevent; cấu hình event server dạng AMQP (không dùng khi chạy wsevent)
EVENT_DAEMON_SUBMISSION_KEY, EVENT_DAEMON_CONTEST_KEY, EVENT_DAEMON_TICKET_KEY, EVENT_DAEMON_NOTIFICATION_KEYchuỗi cố định trong settings.py=Khóa HMAC để sinh tên kênh sự kiện riêng của từng bài nộp, kỳ thi, ticket, thông báoThiết lập đáng chú ý
DMOJ_EMAIL_THROTTLING(10, 60)=Tối đa 10 email báo lỗi trong 60 giây

Thiết lập đáng chú ý

  • IMPERSONATE_* bị bỏ qua. django-impersonate (bản 1.9.x trong image) chỉ đọc dict IMPERSONATE = {...}, không đọc IMPERSONATE_REQUIRE_SUPERUSER hay IMPERSONATE_DISABLE_LOGGING. Kết quả là mọi staff đều mạo danh được người dùng không phải superuser, và nhật ký mạo danh vẫn được ghi. Cách sửa có trong Quản lý người dùng.
  • Đặt MATHOID_URL làm hỏng công thức. Khi có MATHOID_URL, bộ render chuyển sang kiểu mml và MathJax không được nạp, nên nhiều trình duyệt hiện nguyên ~a+b~. Giữ mặc định False (xem Mathoid).
  • TEXOID_URL được kiểm tra bằng hasattr. Muốn tắt thì xóa hẳn dòng này; đặt TEXOID_URL = None vẫn bị coi là đã bật.
  • GLOBAL_API_KEY mặc định là giá trị công khai. Giá trị trong settings.py nằm trong kho mã công khai và local_settings.py đi kèm không ghi đè. API đồng bộ đang tắt nên chưa sao, nhưng trước khi đặt VNOJ_ENABLE_SYNC_API = True phải đặt khóa riêng, đọc từ biến môi trường (xem API).
  • Các khóa EVENT_DAEMON_*_KEY cũng là giá trị công khai. Chúng dùng để sinh tên kênh sự kiện riêng; ai biết khóa thì tự tính được tên kênh. Nên đặt giá trị riêng, đọc từ biến môi trường.
  • DMOJ_REQUIRE_STAFF_2FA chỉ chặn việc tắt 2FA. Staff chưa bật 2FA vẫn đăng nhập và làm việc bình thường; thiết lập này chỉ ngăn staff tắt phương thức 2FA cuối cùng (TOTP hoặc khóa bảo mật).
  • OAUTH_ONLY chỉ ẩn form. Thiết lập này chỉ được template trang đăng ký dùng để ẩn các ô nhập; view /accounts/register/ vẫn nhận POST. Muốn chặn hẳn đăng ký bằng mật khẩu, đặt thêm REGISTRATION_OPEN = False (việc này cũng ẩn link Đăng ký trên thanh điều hướng). Form đăng nhập bằng mật khẩu vẫn hoạt động trong cả hai trường hợp.
  • MOSS_API_KEY rỗng vẫn bị coi là đã cấu hình. Code kiểm tra MOSS_API_KEY is not None, còn local_settings.py đi kèm đọc os.environ.get('MOSS_API_KEY', ''). Khi chưa đặt biến môi trường, giá trị là '' nên tab MOSS vẫn hiện với người có quyền moss_contest, nhưng chạy MOSS sẽ lỗi.
  • DMOJ_SSL = 1 khi HTTPS được xử lý trước nginx. Nếu một proxy, CDN hay load balancer đứng trước nginx xử lý HTTPS rồi chuyển tiếp bằng HTTP, Django không biết request gốc là HTTPS (SECURE_PROXY_SSL_HEADER không được đặt). Hệ quả: link canonical dùng http://, và trang nhận địa chỉ EVENT_DAEMON_GET (ws://) thay vì EVENT_DAEMON_GET_SSL. Nếu site chỉ phục vụ qua HTTPS, đặt DMOJ_SSL = 2; muốn trang dùng wss://, hãy cấu hình proxy gửi header giao thức và đặt SECURE_PROXY_SSL_HEADER tương ứng. Dòng #DMOJ_HTTPS trong local_settings.py chỉ là chú thích; code đọc DMOJ_SSL.
  • DMOJ_CANONICAL mặc định là oj.luyencode.net. Giá trị này nằm trong settings.py, không phải HOST. Nếu bạn tự chạy site trên tên miền khác, đặt DMOJ_CANONICAL thành tên miền của bạn, nếu không link canonical và og:url sẽ trỏ sang tên miền khác.
  • Không có Celery beat. Container celery chỉ chạy celery worker, không chạy beat. Các tác vụ định kỳ (dọn bài đã xóa mềm theo VNOJ_PROBLEM_GARBAGE_COLLECTOR_CRONTAB_KWARGS, cấp lại credit tổ chức ngày 1 hằng tháng, thống kê thời gian chờ hằng ngày) không tự chạy, nên sửa các thiết lập lịch này không có tác dụng.
  • DISCORD_WEBHOOK['default'] không phải giá trị dự phòng. Code chỉ đọc đúng khóa của từng sự kiện (on_new_ticket, on_new_ticket_message, on_new_comment, on_new_problem, on_new_tag_problem, on_new_tag, on_new_contest, on_new_blogpost, on_long_queue, queue_time_stats, on_error). Webhook cũng chỉ gửi khi SITE_FULL_URL khác None; link trong tin nhắn được ghép kiểu SITE_FULL_URL + '/user/...', nên URL có dấu / ở cuối sẽ sinh ra //.
  • VNOJ_DISPLAY_RANKS được dùng trong migration. Đổi danh sách này cần tạo migration mới (./scripts/manage.py makemigrations).
  • NGINX_PORT không phải thiết lập Django. Đây là biến của Docker Compose, đặt trong dmoj/.env, không phải trong local_settings.py hay site.env (xem Biến môi trường).

Tiếp theo

  • Biến môi trường: các thiết lập đọc từ site.env và cách áp dụng khi sửa.
  • Kiến trúc: các dịch vụ site, celery, bridged, wsevent dùng những thiết lập trên như thế nào.
  • Cấu hình site: những cấu hình đổi được ngay trong trang quản trị, không cần sửa file.
  • Lệnh quản trị: các lệnh như generate_editorials, backfill_current_credit.