diff --git a/account/migrations/0003_auto_20150915_2025.py b/account/migrations/0003_auto_20150915_2025.py new file mode 100644 index 0000000..ff6b0ea --- /dev/null +++ b/account/migrations/0003_auto_20150915_2025.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('account', '0002_user_problems_status'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='problems_status', + field=models.TextField(default=b'{}'), + ), + ] diff --git a/account/models.py b/account/models.py index 754e178..3245333 100644 --- a/account/models.py +++ b/account/models.py @@ -31,8 +31,7 @@ class User(AbstractBaseUser): # 0代表不是管理员 1是普通管理员 2是超级管理员 admin_type = models.IntegerField(default=0) # JSON字典用来表示该用户的问题的解决状态 1为ac,2为正在进行 - problems_status = models.TextField(blank=True) - + problems_status = models.TextField(default="{}") USERNAME_FIELD = 'username' REQUIRED_FIELDS = [] diff --git a/account/serializers.py b/account/serializers.py index 4cda3ae..f60e9ca 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -7,6 +7,7 @@ from .models import User class UserLoginSerializer(serializers.Serializer): username = serializers.CharField(max_length=30) password = serializers.CharField(max_length=30) + captcha = serializers.CharField(required=False,min_length=4,max_length=4) class UsernameCheckSerializer(serializers.Serializer): @@ -22,6 +23,7 @@ class UserRegisterSerializer(serializers.Serializer): real_name = serializers.CharField(max_length=30) password = serializers.CharField(max_length=30, min_length=6) email = serializers.EmailField(max_length=254) + captcha = serializers.CharField(max_length=4, min_length=4) class UserChangePasswordSerializer(serializers.Serializer): diff --git a/account/views.py b/account/views.py index 28de0a0..fe9b04a 100644 --- a/account/views.py +++ b/account/views.py @@ -5,15 +5,15 @@ from django.shortcuts import render from django.db.models import Q from rest_framework.views import APIView - +from rest_framework.response import Response from utils.shortcuts import serializer_invalid_response, error_response, success_response, paginate from utils.captcha import Captcha from .decorators import login_required from .models import User from .serializers import (UserLoginSerializer, UsernameCheckSerializer, - UserRegisterSerializer, UserChangePasswordSerializer, - EmailCheckSerializer, UserSerializer, EditUserSerializer) + UserRegisterSerializer, UserChangePasswordSerializer, + EmailCheckSerializer, UserSerializer, EditUserSerializer) class UserLoginAPIView(APIView): @@ -26,6 +26,14 @@ class UserLoginAPIView(APIView): serializer = UserLoginSerializer(data=request.data) if serializer.is_valid(): data = serializer.data + user = User.objects.get(username=data["username"]) + # 只有管理员才适用验证码登录 + if user.admin_type > 0: + if not "captcha" in data: + return error_response(u"请填写验证码!") + captcha = Captcha(request) + if not captcha.check(data["captcha"]): + return error_response(u"验证码错误") user = auth.authenticate(username=data["username"], password=data["password"]) # 用户名或密码错误的话 返回None if user: @@ -64,6 +72,9 @@ class UserRegisterAPIView(APIView): serializer = UserRegisterSerializer(data=request.data) if serializer.is_valid(): data = serializer.data + captcha = Captcha(request) + if not captcha.check(data["captcha"]): + return error_response(u"验证码错误") try: User.objects.get(username=data["username"]) return error_response(u"用户名已存在") @@ -109,39 +120,35 @@ class UserChangePasswordAPIView(APIView): class UsernameCheckAPIView(APIView): - def post(self, request): + def get(self, request): """ - 检测用户名是否存在,存在返回True,不存在返回False + 检测用户名是否存在,存在返回状态码400,不存在返回200 --- - request_serializer: UsernameCheckSerializer """ - serializer = UsernameCheckSerializer(data=request.data) - if serializer.is_valid(): + username = request.GET.get("username", None) + if username: try: - User.objects.get(username=serializer.data["username"]) - return success_response(True) + User.objects.get(username=username) + return Response(status=400) except User.DoesNotExist: - return success_response(False) - else: - return serializer_invalid_response(serializer) + return Response(status=200) + return Response(status=200) class EmailCheckAPIView(APIView): - def post(self, request): + def get(self, request): """ - 检测邮箱是否存在,存在返回True,不存在返回False + 检测邮箱是否存在,存在返回状态码400,不存在返回200 --- - request_serializer: EmailCheckSerializer """ - serializer = EmailCheckSerializer(data=request.data) - if serializer.is_valid(): + email = request.GET.get("email", None) + if email: try: - User.objects.get(email=serializer.data["email"]) - return success_response(True) + User.objects.get(email=email) + return Response(status=400) except User.DoesNotExist: - return success_response(False) - else: - return serializer_invalid_response(serializer) + return Response(status=200) + return Response(status=200) class UserAdminAPIView(APIView): @@ -206,3 +213,19 @@ class UserInfoAPIView(APIView): response_serializer: UserSerializer """ return success_response(UserSerializer(request.user).data) + + +class AccountSecurityAPIView(APIView): + def get(self, request): + """ + 判断用户登录是否需要验证码 + --- + """ + username = request.GET.get("username", None) + if username: + try: + User.objects.get(username=username, admin_type__gt=0) + except User.DoesNotExist: + return success_response({"applied_captcha": False}) + return success_response({"applied_captcha": True}) + return success_response({"applied_captcha": False}) diff --git a/contest/views.py b/contest/views.py index 5bb089b..c1c1958 100644 --- a/contest/views.py +++ b/contest/views.py @@ -391,7 +391,7 @@ def _cmp(x, y): return -1 -def get_the_time_format(seconds): +def get_the_formatted_time(seconds): if not seconds: return "" result = str(seconds % 60) @@ -427,7 +427,7 @@ def contest_rank_page(request, contest_id): "first_achieved": status.first_achieved, "ac": status.ac, "failed_number": status.total_submission_number, - "ac_time": get_the_time_format(status.ac_time)}) + "ac_time": get_the_formatted_time(status.ac_time)}) if status.ac: result[i]["problems"][-1]["failed_number"] -= 1 except ContestSubmission.DoesNotExist: @@ -436,7 +436,8 @@ def contest_rank_page(request, contest_id): user= User.objects.get(id=result[i]["user_id"]) result[i]["username"] = user.username result[i]["real_name"] = user.real_name - result[i]["total_time"] = get_the_time_format(submissions.filter(ac=True).aggregate(total_time=Sum("total_time"))["total_time"]) + result[i]["total_time"] = get_the_formatted_time(submissions.filter(ac=True).aggregate(total_time=Sum("total_time"))["total_time"]) + result = sorted(result, cmp=_cmp, reverse=True) r.set("contest_rank_" + contest_id, json.dumps(list(result))) else: @@ -451,5 +452,5 @@ def contest_rank_page(request, contest_id): {"contest": contest, "contest_problems": contest_problems, "result": result, "auto_refresh": request.GET.get("auto_refresh", None) == "true", - "show_real_name": result.GET.get("show_real_name", None) == "true", + "show_real_name": request.GET.get("show_real_name", None) == "true", "real_time_rank": contest.real_time_rank}) diff --git a/contest_submission/views.py b/contest_submission/views.py index 2358b07..59ee7fa 100644 --- a/contest_submission/views.py +++ b/contest_submission/views.py @@ -1,9 +1,11 @@ # coding=utf-8 import json +from datetime import datetime import redis +import pytz from django.shortcuts import render from django.core.paginator import Paginator - +from django.utils import timezone from rest_framework.views import APIView from judge.judger_controller.tasks import judge @@ -75,7 +77,7 @@ def contest_problem_my_submissions_list_page(request, contest_id, contest_proble {"submissions": submissions, "problem": contest_problem}) -@login_required +@check_user_contest_permission def contest_problem_submissions_list_page(request, contest_id, page=1): """ 单个比赛中的所有提交(包含自己和别人,自己可查提交结果,其他人不可查) @@ -84,9 +86,17 @@ def contest_problem_submissions_list_page(request, contest_id, page=1): contest = Contest.objects.get(id=contest_id) except Contest.DoesNotExist: return error_page(request, u"比赛不存在") - # 以下是本场比赛中所有的提交 - submissions = Submission.objects.filter(contest_id=contest_id). \ - values("id", "contest_id", "problem_id", "result", "create_time", "accepted_answer_time", "language", "user_id").order_by("-create_time") + + submissions = Submission.objects.filter(contest_id=contest_id).\ + values("id", "contest_id", "problem_id", "result", "create_time", + "accepted_answer_time", "language", "user_id").order_by("-create_time") + + + # 封榜的时候只能看到自己的提交 + if not contest.real_time_rank: + if not (request.user.admin_type == SUPER_ADMIN or request.user == contest.created_by): + submissions = submissions.filter(user_id=request.user.id) + language = request.GET.get("language", None) filter = None if language: @@ -131,7 +141,7 @@ def contest_problem_submissions_list_page(request, contest_id, page=1): return render(request, "oj/contest/submissions_list.html", {"submissions": current_page, "page": int(page), "previous_page": previous_page, "next_page": next_page, "start_id": int(page) * 20 - 20, - "contest": contest, "filter":filter}) + "contest": contest, "filter": filter}) class ContestSubmissionAdminAPIView(APIView): diff --git a/judge/Dockerfile b/dockerfiles/judger/Dockerfile similarity index 100% rename from judge/Dockerfile rename to dockerfiles/judger/Dockerfile diff --git a/judge/sources.list b/dockerfiles/judger/sources.list similarity index 100% rename from judge/sources.list rename to dockerfiles/judger/sources.list diff --git a/Dockerfile b/dockerfiles/oj_web_server/Dockerfile similarity index 86% rename from Dockerfile rename to dockerfiles/oj_web_server/Dockerfile index 113ed58..07a73e9 100644 --- a/Dockerfile +++ b/dockerfiles/oj_web_server/Dockerfile @@ -4,4 +4,5 @@ RUN mkdir -p /code/log /code/test_case /code/upload WORKDIR /code ADD requirements.txt /code/ RUN pip install -r requirements.txt -EXPOSE 8010 \ No newline at end of file +EXPOSE 8010 +CMD supervisord \ No newline at end of file diff --git a/dockerfiles/oj_web_server/gunicorn.conf b/dockerfiles/oj_web_server/gunicorn.conf new file mode 100644 index 0000000..3ad6496 --- /dev/null +++ b/dockerfiles/oj_web_server/gunicorn.conf @@ -0,0 +1,16 @@ +[program:gunicorn] + +command=gunicorn oj.wsgi:application -b 0.0.0.0:8080 --reload + +directory=/code/ +user=root +numprocs=1 +stdout_logfile=/code/log/gunicorn.log +stderr_logfile=/code/log/gunicorn.log +autostart=true +autorestart=true +startsecs=5 + +stopwaitsecs = 6 + +killasgroup=true \ No newline at end of file diff --git a/dockerfiles/oj_web_server/mq.conf b/dockerfiles/oj_web_server/mq.conf new file mode 100644 index 0000000..9dbce3e --- /dev/null +++ b/dockerfiles/oj_web_server/mq.conf @@ -0,0 +1,16 @@ +[program:mq] + +command=python manage.py runscript mq + +directory=/code/qduoj/ +user=root +numprocs=1 +stdout_logfile=/code/log/mq.log +stderr_logfile=/code/log/mq.log +autostart=true +autorestart=true +startsecs=5 + +stopwaitsecs = 6 + +killasgroup=true \ No newline at end of file diff --git a/requirements.txt b/dockerfiles/oj_web_server/requirements.txt similarity index 100% rename from requirements.txt rename to dockerfiles/oj_web_server/requirements.txt diff --git a/dockerfiles/oj_web_server/supervisord.conf b/dockerfiles/oj_web_server/supervisord.conf new file mode 100644 index 0000000..420b65f --- /dev/null +++ b/dockerfiles/oj_web_server/supervisord.conf @@ -0,0 +1,26 @@ +[unix_http_server] +file=/tmp/supervisor.sock ; path to your socket file + +[supervisord] +logfile=/code/log/supervisord.log ; supervisord log file +logfile_maxbytes=50MB ; maximum size of logfile before rotation +logfile_backups=10 ; number of backed up logfiles +loglevel=info ; info, debug, warn, trace +pidfile=/code/log/supervisord.pid ; pidfile location +nodaemon=true ; run supervisord as a daemon +minfds=1024 ; number of startup file descriptors +minprocs=200 ; number of process descriptors +user=root ; default user +childlogdir=/code/log/ ; where child log files will live + + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=unix:///tmp/supervisor.sock ; use unix:// schem for a unix sockets. + + +[include] + +files=gunicorn.conf mq.conf \ No newline at end of file diff --git a/judge/judger_controller/settings.py b/judge/judger_controller/settings.py index e141c52..4c155b5 100644 --- a/judge/judger_controller/settings.py +++ b/judge/judger_controller/settings.py @@ -4,9 +4,10 @@ 此文件包含 celery 的部分配置,但是 celery 并不是运行在docker 中的,所以本配置文件中的 redis和 MySQL 的地址就应该是 运行 redis 和 MySQL 的 docker 容器的地址了。怎么获取这个地址见帮助文档。测试用例的路径和源代码路径同理。 """ +import os # 这个redis 是 celery 使用的,包括存储队列信息还有部分统计信息 redis_config = { - "host": "192.168.42.23", + "host": os.environ.get("REDIS_PORT_6379_TCP_ADDR"), "port": 6379, "db": 0 } @@ -30,7 +31,7 @@ log_dir = "/root/log/" # 存储提交信息的数据库,是 celery 使用的,与 oj.settings/local_settings 等区分,那是 web 服务器访问的地址 submission_db = { - "host": "192.168.42.32", + "host": os.environ.get("submission_db_host"), "port": 3306, "db": "oj_submission", "user": "root", diff --git a/judge/judger_controller/tasks.py b/judge/judger_controller/tasks.py index d120ee3..4574982 100644 --- a/judge/judger_controller/tasks.py +++ b/judge/judger_controller/tasks.py @@ -11,7 +11,7 @@ from settings import docker_config, source_code_dir, test_case_dir, log_dir, sub @app.task def judge(submission_id, time_limit, memory_limit, test_case_id): try: - command = "%s run -t -i --privileged --rm " \ + command = "%s run --privileged --rm " \ "--link mysql " \ "-v %s:/var/judger/test_case/ " \ "-v %s:/var/judger/code/ " \ diff --git a/mq/scripts/info.py b/mq/scripts/info.py index 3a5fe18..567eebb 100644 --- a/mq/scripts/info.py +++ b/mq/scripts/info.py @@ -46,10 +46,7 @@ class MessageQueue(object): except User.DoesNotExist: logger.warning("Submission user does not exist, submission_id: " + submission_id) continue - if user.problems_status: - problems_status = json.loads(user.problems_status) - else: - problems_status = {} + problems_status = json.loads(user.problems_status) problems_status[str(problem.id)] = 1 user.problems_status = json.dumps(problems_status) user.save() diff --git a/oj/urls.py b/oj/urls.py index dbc91dd..6d556fc 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -4,7 +4,7 @@ from django.views.generic import TemplateView from account.views import (UserLoginAPIView, UsernameCheckAPIView, UserRegisterAPIView, UserChangePasswordAPIView, EmailCheckAPIView, - UserAdminAPIView, UserInfoAPIView) + UserAdminAPIView, UserInfoAPIView, AccountSecurityAPIView) from announcement.views import AnnouncementAdminAPIView @@ -116,4 +116,5 @@ urlpatterns = [ url(r'^api/submission/share/$', SubmissionShareAPIView.as_view(), name="submission_share_api"), url(r'^captcha/$', "utils.captcha.views.show_captcha", name="show_captcha"), + url(r'^api/account_security_check/$', AccountSecurityAPIView.as_view(), name="account_security_check"), ] diff --git a/problem/views.py b/problem/views.py index 84ca58d..dbe125a 100644 --- a/problem/views.py +++ b/problem/views.py @@ -24,6 +24,7 @@ import logging logger = logging.getLogger("app_info") + def problem_page(request, problem_id): try: problem = Problem.objects.get(id=problem_id, visible=True) @@ -282,7 +283,7 @@ def problem_list_page(request, page=1): except Exception: pass - if request.user.is_authenticated() and request.user.problems_status: + if request.user.is_authenticated(): problems_status = json.loads(request.user.problems_status) else: problems_status = {} diff --git a/static/src/css/global.css b/static/src/css/global.css index 2d4f618..3eebd70 100644 --- a/static/src/css/global.css +++ b/static/src/css/global.css @@ -41,4 +41,5 @@ label { pre { font-family: "Consolas", "Bitstream Vera Sans Mono", "Courier New", Courier, monospace; + background-color: white; } diff --git a/static/src/js/app/oj/account/login.js b/static/src/js/app/oj/account/login.js index 0a05762..32343c9 100644 --- a/static/src/js/app/oj/account/login.js +++ b/static/src/js/app/oj/account/login.js @@ -1,26 +1,31 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, csrfTokenHeader) { + var applied_captcha = false; $('form').validator().on('submit', function (e) { if (!e.isDefaultPrevented()) { var username = $("#username").val(); var password = $("#password").val(); + var ajaxData = {username: username, password: password}; + if (applied_captcha) { + ajaxData.captcha = $("#captcha").val(); + } $.ajax({ beforeSend: csrfTokenHeader, url: "/api/login/", - data: {username: username, password: password}, + data: ajaxData, dataType: "json", method: "post", success: function (data) { if (!data.code) { //成功登陆 var ref = document.referrer; - if(ref){ + if (ref) { // 注册页和本页的来源的跳转回首页,防止死循环 - if(ref.indexOf("register") > -1 || ref.indexOf("login") > -1){ + if (ref.indexOf("register") > -1 || ref.indexOf("login") > -1) { location.href = "/"; return; } // 判断来源,只有同域下才跳转 - if(ref.split("/")[2].split(":")[0] == location.hostname){ + if (ref.split("/")[2].split(":")[0] == location.hostname) { location.href = ref; return; } @@ -28,6 +33,7 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c location.href = "/"; } else { + refresh_captcha(); bsAlert(data.data); } } @@ -35,5 +41,34 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c }); return false; } - }) + }); + + $('#username').blur(function () { + if ($("#username").val()) { + $.ajax({ + beforeSend: csrfTokenHeader, + url: "/api/account_security_check/?username=" + $("#username").val(), + method: "get", + success: function (data) { + if (!data.code) { + if (data.data.applied_captcha) { + $('#captcha-area').html('  

'); + applied_captcha = true; + } + else { + $('#captcha-area').html(''); + applied_captcha = false; + } + } + } + }); + } + }); + function refresh_captcha(){ + $("#captcha-img")[0].src = "/captcha/?" + Math.random(); + $("#captcha")[0].value = ""; + } + $("#captcha-img").click(function(){ + refresh_captcha(); + }); }); \ No newline at end of file diff --git a/static/src/js/app/oj/account/register.js b/static/src/js/app/oj/account/register.js index 9537fdb..e5d22d5 100644 --- a/static/src/js/app/oj/account/register.js +++ b/static/src/js/app/oj/account/register.js @@ -5,10 +5,11 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c var realName = $("#real_name").val(); var password = $("#password").val(); var email = $("#email").val(); + var captcha = $("#captcha").val(); $.ajax({ beforeSend: csrfTokenHeader, url: "/api/register/", - data: {username: username, real_name: realName, password: password, email: email}, + data: {username: username, real_name: realName, password: password, email: email, captcha:captcha}, dataType: "json", method: "post", success: function (data) { @@ -16,11 +17,20 @@ require(["jquery", "bsAlert", "csrfToken", "validator"], function ($, bsAlert, c window.location.href = "/login/"; } else { + refresh_captcha(); bsAlert(data.data); } } }); return false; } - }) + }); + function refresh_captcha() { + $("#captcha-img")[0].src = "/captcha/?" + Math.random(); + $("#captcha")[0].value = ""; + } + + $("#captcha-img").click(function () { + refresh_captcha(); + }); }); \ No newline at end of file diff --git a/submission/views.py b/submission/views.py index baa81d4..6eb69fa 100644 --- a/submission/views.py +++ b/submission/views.py @@ -1,5 +1,6 @@ # coding=utf-8 import json +import logging import redis from django.shortcuts import render @@ -21,6 +22,9 @@ from .models import Submission from .serializers import CreateSubmissionSerializer, SubmissionSerializer, SubmissionhareSerializer +logger = logging.getLogger("app_info") + + class SubmissionAPIView(APIView): @login_required def post(self, request): @@ -44,13 +48,11 @@ class SubmissionAPIView(APIView): try: judge.delay(submission.id, problem.time_limit, problem.memory_limit, problem.test_case_id) - except Exception: + except Exception as e: + logger.error(e) return error_response(u"提交判题任务失败") # 修改用户解题状态 - if request.user.problems_status: - problems_status = json.loads(request.user.problems_status) - else: - problems_status = {} + problems_status = json.loads(request.user.problems_status) problems_status[str(data["problem_id"])] = 2 request.user.problems_status = json.dumps(problems_status) request.user.save() diff --git a/template/src/oj/account/change_password.html b/template/src/oj/account/change_password.html index 05f5a10..d69357f 100644 --- a/template/src/oj/account/change_password.html +++ b/template/src/oj/account/change_password.html @@ -24,9 +24,10 @@
- - - + +    +

+
diff --git a/template/src/oj/account/login.html b/template/src/oj/account/login.html index 351cd27..f92142b 100644 --- a/template/src/oj/account/login.html +++ b/template/src/oj/account/login.html @@ -22,6 +22,7 @@
+
diff --git a/template/src/oj/account/register.html b/template/src/oj/account/register.html index 2750122..a5e95e9 100644 --- a/template/src/oj/account/register.html +++ b/template/src/oj/account/register.html @@ -10,7 +10,7 @@
- +
@@ -20,7 +20,7 @@
- +
@@ -34,6 +34,12 @@ placeholder="确认密码" data-match="#password" data-match-error="两个密码不一致" data-error="请填写确认密码" required>
+
+ +   

+ +
+
diff --git a/template/src/oj/contest/contest_problem.html b/template/src/oj/contest/contest_problem.html index 0291a49..64cff29 100644 --- a/template/src/oj/contest/contest_problem.html +++ b/template/src/oj/contest/contest_problem.html @@ -4,107 +4,97 @@ {% endblock %} {% block body %}
- -

{{ contest_problem.title }}

+ +

{{ contest_problem.title }}

-

发布时间 : {{ contest_problem.create_time }}   - 时间限制 : {{ contest_problem.time_limit }}ms   - 内存限制 : {{ contest_problem.memory_limit }}M -

- -
-
- - -
{{ contest_problem.description|safe }}
-
-
- - -

{{ contest_problem.input_description }}

+

发布时间 : {{ contest_problem.create_time }}   + 时间限制 : {{ contest_problem.time_limit }}ms   + 内存限制 : {{ contest_problem.memory_limit }}M +

-
- + -

{{ contest_problem.output_description }}

+
{{ contest_problem.description|safe }}
- {% for item in samples %} -
- - 复制 -
-{{ item.input }}
+
+ -
-
+

{{ contest_problem.input_description }}

- -
-{{ item.output }}
-
- {% endfor %} - {% if problem.hint %} -
- - -

{{ contest_problem.hint|safe }}

-
- {% endif %} - {% if contest_problem.hint %} -
- - -
{{ contest_problem.hint|safe }}
-
- {% endif %} - - {% ifequal contest.status 0 %}
- -
- - - +
+ + +

{{ contest_problem.output_description }}

+ {% for item in samples %} +
+ + 复制 +
{{ item.input }}
+
+
+ +
{{ item.output }}
+
+ {% endfor %} + {% if problem.hint %} +
+ +

{{ contest_problem.hint|safe }}

+
+ {% endif %} + {% if contest_problem.hint %} +
+ +
{{ contest_problem.hint|safe }}
+
+ {% endif %} + {% ifequal contest.status 0 %} +
+ +
+ + + +
+
+
+ + +
+
+
+ + +
+ {% endifequal %} + {% if show_warning %} + + {% endif %} +
+
+
- -
- - -
-
- -
- - - -
- {% endifequal %} - - {% if show_warning %} - - {% endif %} - -
-
{% endblock %} diff --git a/tools/celeryd.conf b/tools/celeryd.conf new file mode 100644 index 0000000..60e3fc2 --- /dev/null +++ b/tools/celeryd.conf @@ -0,0 +1,15 @@ +[program:celery] +command=celery worker -A judge.judger_controller --loglevel=DEBUG + +directory=/root/qduoj/ +user=root +numprocs=1 +stdout_logfile=/root/log/celery_worker.log +stderr_logfile=/root/log/celery_worker.log +autostart=true +autorestart=true +startsecs=5 + +stopwaitsecs = 6 + +killasgroup=true diff --git a/tools/supervisord.conf b/tools/supervisord.conf new file mode 100644 index 0000000..1494d7c --- /dev/null +++ b/tools/supervisord.conf @@ -0,0 +1,26 @@ +[unix_http_server] +file=/tmp/supervisor.sock ; path to your socket file + +[supervisord] +logfile=/root/log/supervisord.log ; supervisord log file +logfile_maxbytes=50MB ; maximum size of logfile before rotation +logfile_backups=10 ; number of backed up logfiles +loglevel=info ; info, debug, warn, trace +pidfile=/root/log/supervisord.pid ; pidfile location +nodaemon=false ; run supervisord as a daemon +minfds=1024 ; number of startup file descriptors +minprocs=200 ; number of process descriptors +user=root ; default user +childlogdir=/root/log/ ; where child log files will live + + +[rpcinterface:supervisor] +supervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface + +[supervisorctl] +serverurl=unix:///tmp/supervisor.sock ; use unix:// schem for a unix sockets. + + +[include] + +files=*.conf \ No newline at end of file