diff --git a/account/serializers.py b/account/serializers.py index 9c2cd15c..f1447679 100644 --- a/account/serializers.py +++ b/account/serializers.py @@ -106,8 +106,8 @@ class TwoFactorAuthCodeSerializer(serializers.Serializer): code = serializers.IntegerField() -class AvatarUploadForm(forms.Form): - file = forms.FileField() +class ImageUploadForm(forms.Form): + image = forms.FileField() class RankInfoSerializer(serializers.ModelSerializer): diff --git a/account/views/oj.py b/account/views/oj.py index de1df67a..abbad3d7 100644 --- a/account/views/oj.py +++ b/account/views/oj.py @@ -23,7 +23,7 @@ from ..serializers import (ApplyResetPasswordSerializer, ResetPasswordSerializer UserRegisterSerializer, UsernameOrEmailCheckSerializer, RankInfoSerializer, UserChangeEmailSerializer) from ..serializers import (TwoFactorAuthCodeSerializer, UserProfileSerializer, - EditUserProfileSerializer, AvatarUploadForm) + EditUserProfileSerializer, ImageUploadForm) from ..tasks import send_email_async @@ -62,9 +62,9 @@ class AvatarUploadAPI(APIView): @login_required def post(self, request): - form = AvatarUploadForm(request.POST, request.FILES) + form = ImageUploadForm(request.POST, request.FILES) if form.is_valid(): - avatar = form.cleaned_data["file"] + avatar = form.cleaned_data["image"] else: return self.error("Invalid file content") if avatar.size > 2 * 1024 * 1024: diff --git a/deploy/run.sh b/deploy/run.sh index e992e966..c95fe35a 100644 --- a/deploy/run.sh +++ b/deploy/run.sh @@ -35,5 +35,5 @@ if [ $n -eq 3 ]; then exit 1 fi -chown -R nobody:nogroup /data/log /data/test_case /data/avatar +chown -R nobody:nogroup /data/log /data/test_case /data/avatar /data/upload exec supervisord -c /app/deploy/supervisor.conf diff --git a/judge/dispatcher.py b/judge/dispatcher.py index 3ae1d665..30b74443 100644 --- a/judge/dispatcher.py +++ b/judge/dispatcher.py @@ -176,13 +176,15 @@ class JudgeDispatcher(object): user_profile = user.userprofile if problem.rule_type == ProblemRuleType.ACM: user_profile.submission_number += 1 - if self.submission.result == JudgeStatus.ACCEPTED: - user_profile.accepted_number += 1 acm_problems_status = user_profile.acm_problems_status.get("problems", {}) if problem_id not in acm_problems_status: acm_problems_status[problem_id] = {"status": self.submission.result, "_id": self.problem._id} + if self.submission.result == JudgeStatus.ACCEPTED: + user_profile.accepted_number += 1 elif acm_problems_status[problem_id]["status"] != JudgeStatus.ACCEPTED: acm_problems_status[problem_id]["status"] = self.submission.result + if self.submission.result == JudgeStatus.ACCEPTED: + user_profile.accepted_number += 1 user_profile.acm_problems_status["problems"] = acm_problems_status user_profile.save(update_fields=["submission_number", "accepted_number", "acm_problems_status"]) diff --git a/oj/dev_settings.py b/oj/dev_settings.py index 448bc8fa..724a5dc4 100644 --- a/oj/dev_settings.py +++ b/oj/dev_settings.py @@ -31,6 +31,9 @@ LOG_PATH = f"{BASE_DIR}/log/" AVATAR_URI_PREFIX = "/static/avatar" AVATAR_UPLOAD_DIR = f"{BASE_DIR}{AVATAR_URI_PREFIX}" +UPLOAD_PREFIX = "/static/upload" +UPLOAD_DIR = f"{BASE_DIR}{UPLOAD_PREFIX}" + STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), ] diff --git a/oj/production_settings.py b/oj/production_settings.py index bf8b3f87..3f9dee66 100644 --- a/oj/production_settings.py +++ b/oj/production_settings.py @@ -28,6 +28,9 @@ ALLOWED_HOSTS = ['*'] AVATAR_URI_PREFIX = "/static/avatar" AVATAR_UPLOAD_DIR = "/data/avatar" +UPLOAD_PREFIX = "/static/upload" +UPLOAD_DIR = "/data/upload" + TEST_CASE_DIR = "/data/test_case" LOG_PATH = "/data/log" DEFAULT_JUDGE_SERVER_SERVICE_URL = "http://judge-server:8080/" diff --git a/oj/settings.py b/oj/settings.py index 9d8ea614..fd216dd2 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -31,7 +31,7 @@ VENDOR_APPS = ( 'rest_framework', ) LOCAL_APPS = ( - 'account', + 'account', 'announcement', 'conf', 'problem', diff --git a/oj/urls.py b/oj/urls.py index 3a2570bc..ffe526fb 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -12,4 +12,5 @@ urlpatterns = [ url(r"^api/admin/", include("contest.urls.admin")), url(r"^api/", include("contest.urls.oj")), url(r"^api/", include("submission.urls.oj")), + url(r"^api/admin/", include("utils.urls")), ] diff --git a/utils/urls.py b/utils/urls.py new file mode 100644 index 00000000..ca9fb0f1 --- /dev/null +++ b/utils/urls.py @@ -0,0 +1,7 @@ +from django.conf.urls import url + +from .views import SimditorImageUploadAPIView + +urlpatterns = [ + url(r"^upload_image/?$", SimditorImageUploadAPIView.as_view(), name="upload_image") +] diff --git a/utils/views.py b/utils/views.py new file mode 100644 index 00000000..c3e3861d --- /dev/null +++ b/utils/views.py @@ -0,0 +1,44 @@ +import os +from django.conf import settings +from account.serializers import ImageUploadForm +from utils.shortcuts import rand_str +from utils.api import CSRFExemptAPIView +import logging + +logger = logging.getLogger(__name__) + + +class SimditorImageUploadAPIView(CSRFExemptAPIView): + request_parsers = () + + def post(self, request): + form = ImageUploadForm(request.POST, request.FILES) + if form.is_valid(): + img = form.cleaned_data["image"] + else: + return self.response({ + "success": False, + "msg": "Upload failed", + "file_path": ""}) + + suffix = os.path.splitext(img.name)[-1].lower() + if suffix not in [".gif", ".jpg", ".jpeg", ".bmp", ".png"]: + return self.response({ + "success": False, + "msg": "Unsupported file format", + "file_path": ""}) + img_name = rand_str(10) + suffix + try: + with open(os.path.join(settings.UPLOAD_DIR, img_name), "wb") as imgFile: + for chunk in img: + imgFile.write(chunk) + except IOError as e: + logger.error(e) + return self.response({ + "success": True, + "msg": "Upload Error", + "file_path": f"{settings.UPLOAD_PREFIX}/{img_name}"}) + return self.response({ + "success": True, + "msg": "Success", + "file_path": f"{settings.UPLOAD_PREFIX}/{img_name}"})