OnlineJudge/conf/views.py

193 lines
7.0 KiB
Python
Raw Normal View History

2017-12-23 06:16:39 +00:00
import os
import re
2016-11-20 11:18:25 +00:00
import hashlib
2017-12-23 06:16:39 +00:00
import shutil
2016-11-20 11:18:25 +00:00
from django.utils import timezone
2017-12-23 06:16:39 +00:00
from django.conf import settings
2016-09-25 06:07:45 +00:00
from account.decorators import super_admin_required
2017-12-23 06:16:39 +00:00
from problem.models import Problem
2017-05-10 11:40:26 +00:00
from judge.dispatcher import process_pending_task
2017-10-01 19:54:34 +00:00
from judge.languages import languages, spj_languages
from options.options import SysOptions
2016-11-20 11:18:25 +00:00
from utils.api import APIView, CSRFExemptAPIView, validate_serializer
2017-12-24 03:34:40 +00:00
from utils.shortcuts import send_email
2017-12-24 07:34:22 +00:00
from utils.xss_filter import XSSHtml
2017-10-01 19:54:34 +00:00
from .models import JudgeServer
2017-01-23 08:48:04 +00:00
from .serializers import (CreateEditWebsiteConfigSerializer,
CreateSMTPConfigSerializer, EditSMTPConfigSerializer,
2017-01-23 08:48:04 +00:00
JudgeServerHeartbeatSerializer,
2017-12-24 04:10:02 +00:00
JudgeServerSerializer, TestSMTPConfigSerializer, EditJudgeServerSerializer)
class SMTPAPI(APIView):
@super_admin_required
def get(self, request):
2017-10-01 19:54:34 +00:00
smtp = SysOptions.smtp_config
if not smtp:
return self.success(None)
2017-10-01 19:54:34 +00:00
smtp.pop("password")
return self.success(smtp)
@validate_serializer(CreateSMTPConfigSerializer)
2017-01-23 08:01:56 +00:00
@super_admin_required
def post(self, request):
2017-10-01 19:54:34 +00:00
SysOptions.smtp_config = request.data
return self.success()
@validate_serializer(EditSMTPConfigSerializer)
2017-01-23 08:01:56 +00:00
@super_admin_required
def put(self, request):
2017-10-01 19:54:34 +00:00
smtp = SysOptions.smtp_config
data = request.data
2017-10-01 19:54:34 +00:00
for item in ["server", "port", "email", "tls"]:
smtp[item] = data[item]
if "password" in data:
smtp["password"] = data["password"]
SysOptions.smtp_config = smtp
return self.success()
class SMTPTestAPI(APIView):
@super_admin_required
@validate_serializer(TestSMTPConfigSerializer)
def post(self, request):
2017-12-24 03:34:40 +00:00
if not SysOptions.smtp_config:
return self.error("Please setup SMTP config at first")
try:
send_email(smtp_config=SysOptions.smtp_config,
from_name=SysOptions.website_name_shortcut,
to_name=request.user.username,
to_email=request.data["email"],
subject="You have successfully configured SMTP",
content="You have successfully configured SMTP")
except Exception as e:
# guess error message encoding
msg = e.smtp_error
try:
# qq mail
msg = msg.decode("gbk")
except Exception:
msg = msg.decode("utf-8", "ignore")
return self.error(msg)
return self.success()
class WebsiteConfigAPI(APIView):
def get(self, request):
2017-10-01 19:54:34 +00:00
ret = {key: getattr(SysOptions, key) for key in
["website_base_url", "website_name", "website_name_shortcut",
"website_footer", "allow_register", "submission_list_show_all"]}
return self.success(ret)
@validate_serializer(CreateEditWebsiteConfigSerializer)
@super_admin_required
def post(self, request):
2017-10-01 19:54:34 +00:00
for k, v in request.data.items():
2017-12-24 07:34:22 +00:00
if k == "website_footer":
with XSSHtml() as parser:
v = parser.clean(v)
2017-10-01 19:54:34 +00:00
setattr(SysOptions, k, v)
return self.success()
2016-11-20 11:18:25 +00:00
class JudgeServerAPI(APIView):
@super_admin_required
def get(self, request):
servers = JudgeServer.objects.all().order_by("-last_heartbeat")
2017-10-01 19:54:34 +00:00
return self.success({"token": SysOptions.judge_server_token,
2016-11-20 11:18:25 +00:00
"servers": JudgeServerSerializer(servers, many=True).data})
@super_admin_required
def delete(self, request):
2017-01-24 08:48:39 +00:00
hostname = request.GET.get("hostname")
if hostname:
JudgeServer.objects.filter(hostname=hostname).delete()
return self.success()
2016-11-20 11:18:25 +00:00
2017-12-24 04:10:02 +00:00
@validate_serializer(EditJudgeServerSerializer)
@super_admin_required
def put(self, request):
JudgeServer.objects.filter(id=request.data["id"]).update(is_disabled=request.data["is_disabled"])
return self.success()
2016-11-20 11:18:25 +00:00
class JudgeServerHeartbeatAPI(CSRFExemptAPIView):
@validate_serializer(JudgeServerHeartbeatSerializer)
def post(self, request):
data = request.data
2017-01-26 05:55:31 +00:00
client_token = request.META.get("HTTP_X_JUDGE_SERVER_TOKEN")
2017-10-01 19:54:34 +00:00
if hashlib.sha256(SysOptions.judge_server_token.encode("utf-8")).hexdigest() != client_token:
2016-11-20 11:18:25 +00:00
return self.error("Invalid token")
try:
server = JudgeServer.objects.get(hostname=data["hostname"])
server.judger_version = data["judger_version"]
server.cpu_core = data["cpu_core"]
server.memory_usage = data["memory"]
server.cpu_usage = data["cpu"]
2017-12-24 04:08:56 +00:00
server.service_url = data["service_url"]
2017-12-06 03:10:57 +00:00
server.ip = request.META["HTTP_X_REAL_IP"]
2016-11-20 11:18:25 +00:00
server.last_heartbeat = timezone.now()
server.save()
except JudgeServer.DoesNotExist:
JudgeServer.objects.create(hostname=data["hostname"],
judger_version=data["judger_version"],
cpu_core=data["cpu_core"],
memory_usage=data["memory"],
cpu_usage=data["cpu"],
2017-01-24 08:22:22 +00:00
ip=request.META["REMOTE_ADDR"],
2017-12-24 04:08:56 +00:00
service_url=data["service_url"],
2016-11-20 11:18:25 +00:00
last_heartbeat=timezone.now(),
)
# 新server上线 处理队列中的防止没有新的提交而导致一直waiting
2017-08-15 12:32:14 +00:00
process_pending_task()
2016-11-20 11:18:25 +00:00
return self.success()
class LanguagesAPI(APIView):
def get(self, request):
return self.success({"languages": languages, "spj_languages": spj_languages})
2017-12-23 06:16:39 +00:00
class TestCasePruneAPI(APIView):
@super_admin_required
def get(self, request):
"""
return isolated test_case list
"""
ret_data = []
dir_to_be_removed = self.get_orphan_ids()
# return an iterator
for d in os.scandir(settings.TEST_CASE_DIR):
if d.name in dir_to_be_removed:
ret_data.append({"id": d.name, "create_time": d.stat().st_ctime})
return self.success(ret_data)
@super_admin_required
def delete(self, request):
test_case_id = request.GET.get("id")
if test_case_id:
self.delete_one(test_case_id)
return self.success()
for id in self.get_orphan_ids():
self.delete_one(id)
return self.success()
@staticmethod
def get_orphan_ids():
db_ids = Problem.objects.all().values_list("test_case_id", flat=True)
disk_ids = os.listdir(settings.TEST_CASE_DIR)
test_case_re = re.compile(r"^[a-zA-Z0-9]{32}$")
disk_ids = filter(lambda f: test_case_re.match(f), disk_ids)
return list(set(disk_ids) - set(db_ids))
@staticmethod
def delete_one(id):
test_case_dir = os.path.join(settings.TEST_CASE_DIR, id)
if os.path.isdir(test_case_dir):
shutil.rmtree(test_case_dir, ignore_errors=True)