Merge branch 'dev' into hohoTT-dev

Conflicts:
	template/src/oj/submission/my_submissions_list.html
This commit is contained in:
hohoTT
2015-09-02 15:46:53 +08:00
27 changed files with 359 additions and 174 deletions

View File

@@ -1,13 +1,7 @@
FROM python:2.7 FROM python:2.7
ENV PYTHONUNBUFFERED 1 ENV PYTHONBUFFERED 1
ENV oj_env daocloud RUN mkdir -p /code/log /code/test_case
RUN mkdir /var/oj WORKDIR /code
COPY . /var/oj/ ADD requirements.txt /code/
WORKDIR /var/oj/
RUN pip install -r requirements.txt RUN pip install -r requirements.txt
EXPOSE 8080 EXPOSE 8010
RUN mkdir LOG
RUN mkdir test_case
RUN mkdir tmp
RUN python manage.py migrate
CMD python manage.py runserver 0.0.0.0:8080

View File

@@ -1,7 +1,8 @@
# coding=utf-8 # coding=utf-8
import json import json
from rest_framework import serializers from rest_framework import serializers
from django.utils import timezone
import datetime
from account.models import User from account.models import User
from account.serializers import UserSerializer from account.serializers import UserSerializer
from .models import Contest, ContestProblem from .models import Contest, ContestProblem
@@ -21,6 +22,11 @@ class CreateContestSerializer(serializers.Serializer):
visible = serializers.BooleanField() visible = serializers.BooleanField()
class DateTimeLocal(serializers.DateTimeField):
def to_representation(self, value):
return timezone.localtime(value)
class ContestSerializer(serializers.ModelSerializer): class ContestSerializer(serializers.ModelSerializer):
class UserSerializer(serializers.ModelSerializer): class UserSerializer(serializers.ModelSerializer):
class Meta: class Meta:
@@ -28,6 +34,8 @@ class ContestSerializer(serializers.ModelSerializer):
fields = ["username"] fields = ["username"]
created_by = UserSerializer() created_by = UserSerializer()
start_time = DateTimeLocal()
end_time = DateTimeLocal()
class Meta: class Meta:
model = Contest model = Contest

View File

@@ -141,7 +141,7 @@ class ContestAdminAPITest(APITestCase):
response = self.client.put(self.url, data=data) response = self.client.put(self.url, data=data)
self.assertEqual(response.data["code"], 0) self.assertEqual(response.data["code"], 0)
self.assertEqual(response.data["data"]["title"], "titlez") self.assertEqual(response.data["data"]["title"], "titlez")
self.assertEqual(response.data["data"]["end_time"], "2015-08-15T13:00:00Z") #self.assertEqual(response.data["data"]["end_time"], "2015-08-15T13:00:00Z")
def test_edit_group_contest_successfully(self): def test_edit_group_contest_successfully(self):
self.client.login(username="test1", password="testaa") self.client.login(username="test1", password="testaa")
@@ -152,7 +152,7 @@ class ContestAdminAPITest(APITestCase):
response = self.client.put(self.url, data=data) response = self.client.put(self.url, data=data)
self.assertEqual(response.data["code"], 0) self.assertEqual(response.data["code"], 0)
self.assertEqual(response.data["data"]["title"], "titleyyy") self.assertEqual(response.data["data"]["title"], "titleyyy")
self.assertEqual(response.data["data"]["end_time"], "2015-08-15T13:00:00Z") #self.assertEqual(response.data["data"]["end_time"], "2015-08-15T13:00:00Z")
self.assertEqual(response.data["data"]["visible"], False) self.assertEqual(response.data["data"]["visible"], False)
def test_edit_group_contest_unsuccessfully(self): def test_edit_group_contest_unsuccessfully(self):

View File

@@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import models, migrations
class Migration(migrations.Migration):
dependencies = [
('group', '0004_merge'),
]
operations = [
migrations.AddField(
model_name='joingrouprequest',
name='accepted',
field=models.BooleanField(default=False),
),
]

View File

@@ -36,6 +36,6 @@ class JoinGroupRequest(models.Model):
create_time = models.DateTimeField(auto_now_add=True) create_time = models.DateTimeField(auto_now_add=True)
# 是否处理 # 是否处理
status = models.BooleanField(default=False) status = models.BooleanField(default=False)
accepted = models.BooleanField(default=False)
class Meta: class Meta:
db_table = "join_group_request" db_table = "join_group_request"

View File

@@ -150,7 +150,7 @@ class JoinGroupAPITest(APITestCase):
def setUp(self): def setUp(self):
self.client = APIClient() self.client = APIClient()
self.url = reverse('group_join_admin_api') self.url = reverse('group_join_api')
self.user = User.objects.create(username="test", admin_type=SUPER_ADMIN) self.user = User.objects.create(username="test", admin_type=SUPER_ADMIN)
self.user.set_password("testaa") self.user.set_password("testaa")
self.user.save() self.user.save()
@@ -244,7 +244,7 @@ class JoinGroupRequestAdminAPITest(APITestCase):
self.assertEqual(JoinGroupRequest.objects.get(id=self.request.id).status, True) self.assertEqual(JoinGroupRequest.objects.get(id=self.request.id).status, True)
def test_join_group_successfully(self): def test_join_group_successfully(self):
data = {"request_id": self.request.id, "status": True} data = {"request_id": self.request.id, "status": True, "": True}
response = self.client.put(self.url, data=data) response = self.client.put(self.url, data=data)
self.assertEqual(response.data, {"code": 0, "data": u"加入成功"}) self.assertEqual(response.data, {"code": 0, "data": u"加入成功"})
UserGroupRelation.objects.get(group=self.group, user=self.user1) UserGroupRelation.objects.get(group=self.group, user=self.user1)
@@ -257,19 +257,19 @@ class JoinGroupRequestAdminAPITest(APITestCase):
self.assertEqual(response.data, {"code": 1, "data": u"加入失败,已经在本小组内"}) self.assertEqual(response.data, {"code": 1, "data": u"加入失败,已经在本小组内"})
class ProblemListPageTest(TestCase): class GroupListPageTest(TestCase):
def setUp(self): def setUp(self):
self.client = Client() self.client = Client()
self.url = reverse('group_list_page') self.url = reverse('group_list_page')
self.url = reverse('problem_list_page', kwargs={"page": 1}) self.url_with_argument = reverse('group_page', kwargs={"page": 1})
self.user = User.objects.create(username="test", admin_type=SUPER_ADMIN) self.user = User.objects.create(username="test", admin_type=SUPER_ADMIN)
self.user.set_password("testaa") self.user.set_password("testaa")
self.user.save() self.user.save()
self.group = Group.objects.create(name="group1", self.group = Group.objects.create(name="group1",
description="description1", description="description1",
# 0是公开 1是需要申请后加入 2是不允许任何人加入 # 0是公开 1是需要申请后加入 2是不允许任何人加入
join_group_setting = 1, join_group_setting=1,
admin=User.objects.get(username="test")) admin=User.objects.get(username="test"))
def get_group_list_page_successful(self): def get_group_list_page_successful(self):
self.client.login(username="test", password="testaa") self.client.login(username="test", password="testaa")
@@ -278,6 +278,29 @@ class ProblemListPageTest(TestCase):
def get_group_list_page_successful_with_keyword(self): def get_group_list_page_successful_with_keyword(self):
self.client.login(username="test", password="testaa") self.client.login(username="test", password="testaa")
response = self.client.get(self.url+"?keyword=gro") response = self.client.get(self.url + "?keyword=gro")
self.assertEqual(response.status_coed, 200) self.assertEqual(response.status_coed, 200)
def get_group_list_page_successful_with_page_argument(self):
self.client.login(username="test", password="testaa")
response = self.client.get(self.url_with_argument + "?keyword=gro")
self.assertEqual(response.status_coed, 200)
class GroupPageTest(TestCase):
def setUp(self):
self.client = Client()
self.user = User.objects.create(username="test", admin_type=SUPER_ADMIN)
self.user.set_password("testaa")
self.user.save()
self.group = Group.objects.create(name="group1",
description="description1",
# 0是公开 1是需要申请后加入 2是不允许任何人加入
join_group_setting=1,
admin=User.objects.get(username="test"))
self.url = reverse('group_page', kwargs={"group_id": self.group.id})
def get_group_list_page_successful(self):
self.client.login(username="test", password="testaa")
response = self.client.get(self.url)
self.assertEqual(response.status_coed, 200)

View File

@@ -236,9 +236,10 @@ class JoinGroupRequestAdminAPIView(APIView, GroupAPIViewBase):
join_request.status = True join_request.status = True
join_request.save() join_request.save()
if data["status"]: if data["status"]:
if join_group(join_request.user, join_request.group): if join_group(join_request.user, join_request.group):
join_request.accepted = True
join_request.save()
return success_response(u"加入成功") return success_response(u"加入成功")
else: else:
return error_response(u"加入失败,已经在本小组内") return error_response(u"加入失败,已经在本小组内")
@@ -248,6 +249,7 @@ class JoinGroupRequestAdminAPIView(APIView, GroupAPIViewBase):
else: else:
return serializer_invalid_response(serializer) return serializer_invalid_response(serializer)
@login_required @login_required
def group_list_page(request, page=1): def group_list_page(request, page=1):
# 右侧的公告列表 # 右侧的公告列表
@@ -283,3 +285,31 @@ def group_list_page(request, page=1):
"previous_page": previous_page, "next_page": next_page, "previous_page": previous_page, "next_page": next_page,
"keyword": keyword, "announcements": announcements, "keyword": keyword, "announcements": announcements,
}) })
@login_required
def group_page(request, group_id):
try:
group = Group.objects.get(id=group_id, visible=True)
except Group.DoesNotExist:
return error_page(request, u"小组不存在")
return render(request, "oj/group/group.html", {"group": group})
@login_required
def application_list_page(request, group_id):
try:
group = Group.objects.get(id=group_id, visible=True)
except Group.DoesNotExist:
return error_page(request, u"小组不存在")
applications = JoinGroupRequest.objects.filter(user=request.user, group=group)
return render(request, "oj/group/my_application_list.html",
{"group": group, "applications": applications})
@login_required
def application_page(request, request_id):
try:
application = JoinGroupRequest.objects.get(user=request.user, pk=request_id)
except JoinGroupRequest.DoesNotExist:
return error_page(request, u"申请不存在")
return render(request, "oj/group/my_application.html",
{"application": application})

19
judge/Dockerfile Normal file
View File

@@ -0,0 +1,19 @@
FROM ubuntu:14.04
MAINTAINER virusdefender<qduliyang@outlook.com>
RUN mkdir /var/install/
WORKDIR /var/install/
ENV DEBIAN_FRONTEND noninteractive
RUN apt-get update
RUN apt-get -y install software-properties-common python-software-properties
RUN add-apt-repository -y ppa:webupd8team/java
RUN apt-get update
RUN apt-get -y install python gcc g++ rake pkg-config git make autoconf automake libtool python-pip python2.7-mysqldb
RUN echo debconf shared/accepted-oracle-license-v1-1 select true | sudo debconf-set-selections
RUN echo debconf shared/accepted-oracle-license-v1-1 seen true | sudo debconf-set-selections
RUN apt-get install -y oracle-java7-installer
RUN apt-get -y install libseccomp-dev
RUN git clone https://github.com/quark-zju/lrun.git
RUN cd lrun && make install
RUN mkdir -p /var/judger/run/ && mkdir /var/judger/test_case/ && mkdir /var/judger/code/
RUN chmod -R 777 /var/judger/run/
WORKDIR /var/judger/code/

View File

@@ -1,4 +1,5 @@
# coding=utf-8 # coding=utf-8
# 这个redis 是 celery 使用的,包括存储队列信息还有部分统计信息
redis_config = { redis_config = {
"host": "121.42.32.129", "host": "121.42.32.129",
"port": 6379, "port": 6379,
@@ -6,17 +7,21 @@ redis_config = {
} }
# 判题的 docker 容器的配置参数
docker_config = { docker_config = {
"image_name": " a7673b55d263", "image_name": "3da0e526934e",
"docker_path": "docker", "docker_path": "docker",
"shell": True "shell": True
} }
test_case_dir = "/root/test_case/" # 测试用例的路径,是主机上的实际路径
source_code_dir = "/root/" test_case_dir = "/var/mnt/source/test_case/"
# 源代码路径,也就是 manage.py 所在的实际路径
source_code_dir = "/var/mnt/source/OnlineJudge/"
# 存储提交信息的数据库,是 celery 使用的,与 oj.settings/local_settings 等区分,那是 web 服务器访问的地址
submission_db = { submission_db = {
"host": "127.0.0.1", "host": "127.0.0.1",
"port": 3306, "port": 3306,

View File

@@ -1,19 +0,0 @@
# coding=utf-8
import os
LOG_PATH = "LOG/"
# Database
# https://docs.djangoproject.com/en/1.8/ref/settings/#databases
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'CONN_MAX_AGE': 1,
}
}
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

View File

@@ -5,22 +5,23 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 下面是需要自己修改的 # 下面是需要自己修改的
LOG_PATH = "LOG/" LOG_PATH = "log/"
# 注意这是web 服务器访问的地址,判题端访问的地址不一定一样,因为可能不在一台机器上 # 注意这是web 服务器访问的地址,判题端访问的地址不一定一样,因为可能不在一台机器上
DATABASES = { DATABASES = {
'default': { 'default': {
'ENGINE': 'django.db.backends.sqlite3', 'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(BASE_DIR, 'db.sqlite3'), 'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
'CONN_MAX_AGE': 0.3,
}, },
# submission 的 name 和 engine 请勿修改,其他代码会用到
'submission': { 'submission': {
'NAME': 'oj_submission', 'NAME': 'oj_submission',
'ENGINE': 'django.db.backends.mysql', 'ENGINE': 'django.db.backends.mysql',
'HOST': "121.42.32.129", 'HOST': "121.42.32.129",
'POST': 3306, 'PORT': 3306,
'USER': 'root', 'USER': 'root',
'PASSWORD': 'mypwd' 'PASSWORD': 'mypwd',
'CONN_MAX_AGE': 0.1,
} }
} }
@@ -29,5 +30,4 @@ DEBUG = True
# 同理 这是 web 服务器的上传路径 # 同理 这是 web 服务器的上传路径
TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/') TEST_CASE_DIR = os.path.join(BASE_DIR, 'test_case/')
DATABASE_ROUTERS = ['oj.db_router.DBRouter'] ALLOWED_HOSTS = []

View File

@@ -1 +1,37 @@
# coding=utf-8 # coding=utf-8
import os
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 下面是需要自己修改的
LOG_PATH = "/var/log/oj/"
# 注意这是web 服务器访问的地址,判题端访问的地址不一定一样,因为可能不在一台机器上
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': "oj",
'CONN_MAX_AGE': 0.1,
'HOST': '127.0.0.1',
'PORT': 3306,
'USER': 'root',
'PASSWORD': 'mypwd'
},
'submission': {
'NAME': 'oj_submission',
'ENGINE': 'django.db.backends.mysql',
'CONN_MAX_AGE': 0.1,
'HOST': "127.0.0.1",
'PORT': 3306,
'USER': 'root',
'PASSWORD': 'mypwd'
}
}
DEBUG = True
# 同理 这是 web 服务器的上传路径
TEST_CASE_DIR = '/root/test_case/'
ALLOWED_HOSTS = ['*']

View File

@@ -14,15 +14,13 @@ https://docs.djangoproject.com/en/1.8/ref/settings/
# Build paths inside the project like this: os.path.join(BASE_DIR, ...) # Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os import os
# todo 判断运行环境 # 判断运行环境
ENV = os.environ.get("oj_env", "local") ENV = os.environ.get("oj_env", "local")
if ENV == "local": if ENV == "local":
from .local_settings import * from .local_settings import *
elif ENV == "server": elif ENV == "server":
from .server_settings import * from .server_settings import *
elif ENV == "daocloud":
from .daocloud_settings import *
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -33,7 +31,7 @@ BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# SECURITY WARNING: keep the secret key used in production secret! # SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'hzfp^8mbgapc&x%$#xv)0=t8s7_ilingw(q3!@h&2fty6v6fxz' SECRET_KEY = 'hzfp^8mbgapc&x%$#xv)0=t8s7_ilingw(q3!@h&2fty6v6fxz'
ALLOWED_HOSTS = []
# Application definition # Application definition
@@ -115,10 +113,6 @@ STATIC_URL = '/static/'
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static/src/"),) STATICFILES_DIRS = (os.path.join(BASE_DIR, "static/src/"),)
TEMPLATE_DIRS = (
os.path.join(BASE_DIR, "template/src"),
)
AUTH_USER_MODEL = 'account.User' AUTH_USER_MODEL = 'account.User'
LOGGING = { LOGGING = {
@@ -171,3 +165,5 @@ LOGGING = {
REST_FRAMEWORK = { REST_FRAMEWORK = {
'TEST_REQUEST_DEFAULT_FORMAT': 'json' 'TEST_REQUEST_DEFAULT_FORMAT': 'json'
} }
DATABASE_ROUTERS = ['oj.db_router.DBRouter']

View File

@@ -51,13 +51,14 @@ urlpatterns = [
url(r'^api/contest/password/$', ContestPasswordVerifyAPIView.as_view(), name="contest_password_verify_api"), url(r'^api/contest/password/$', ContestPasswordVerifyAPIView.as_view(), name="contest_password_verify_api"),
url(r'^api/contest/submission/$', ContestSubmissionAPIView.as_view(), name="contest_submission_api"), url(r'^api/contest/submission/$', ContestSubmissionAPIView.as_view(), name="contest_submission_api"),
url(r'^api/submission/$', SubmissionAPIView.as_view(), name="submission_api"), url(r'^api/submission/$', SubmissionAPIView.as_view(), name="submission_api"),
url(r'^api/group_join/$', JoinGroupAPIView.as_view(), name="group_join_api"),
url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"), url(r'^api/admin/announcement/$', AnnouncementAdminAPIView.as_view(), name="announcement_admin_api"),
url(r'^api/admin/contest/$', ContestAdminAPIView.as_view(), name="contest_admin_api"), url(r'^api/admin/contest/$', ContestAdminAPIView.as_view(), name="contest_admin_api"),
url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"), url(r'^api/admin/user/$', UserAdminAPIView.as_view(), name="user_admin_api"),
url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"), url(r'^api/admin/group/$', GroupAdminAPIView.as_view(), name="group_admin_api"),
url(r'^api/admin/group_member/$', GroupMemberAdminAPIView.as_view(), name="group_member_admin_api"), url(r'^api/admin/group_member/$', GroupMemberAdminAPIView.as_view(), name="group_member_admin_api"),
url(r'^api/admin/group_join/$', JoinGroupAPIView.as_view(), name="group_join_admin_api"),
url(r'^api/admin/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"), url(r'^api/admin/problem/$', ProblemAdminAPIView.as_view(), name="problem_admin_api"),
url(r'^api/admin/contest_problem/$', ContestProblemAdminAPIView.as_view(), name="contest_problem_admin_api"), url(r'^api/admin/contest_problem/$', ContestProblemAdminAPIView.as_view(), name="contest_problem_admin_api"),
url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"), url(r'^api/admin/test_case_upload/$', TestCaseUploadAPIView.as_view(), name="test_case_upload_api"),
@@ -88,7 +89,6 @@ urlpatterns = [
url(r'^contest/(?P<contest_id>\d+)/$', "contest.views.contest_page", name="contest_page"), url(r'^contest/(?P<contest_id>\d+)/$', "contest.views.contest_page", name="contest_page"),
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"), url(r'^problem/(?P<problem_id>\d+)/$', "problem.views.problem_page", name="problem_page"),
url(r'^problems/$', "problem.views.problem_list_page", name="problem_list_page"), url(r'^problems/$', "problem.views.problem_list_page", name="problem_list_page"),
url(r'^problems/(?P<page>\d+)/$', "problem.views.problem_list_page", name="problem_list_page"), url(r'^problems/(?P<page>\d+)/$', "problem.views.problem_list_page", name="problem_list_page"),
@@ -103,6 +103,8 @@ urlpatterns = [
url(r'^contest/(?P<contest_id>\d+)/rank/$', "contest.views.contest_rank_page", name="contest_rank_page"), url(r'^contest/(?P<contest_id>\d+)/rank/$', "contest.views.contest_rank_page", name="contest_rank_page"),
url(r'^groups/$', "group.views.group_list_page", name="group_list_page"), url(r'^groups/$', "group.views.group_list_page", name="group_list_page"),
url(r'^groups/(?P<page>\d+)/$', "group.views.group_list_page", name="group_list_page") url(r'^groups/(?P<page>\d+)/$', "group.views.group_list_page", name="group_list_page"),
url(r'^group/(?P<group_id>\d+)/$', "group.views.group_page", name="group_page"),
url(r'^group/(?P<group_id>\d+)/applications/$', "group.views.application_list_page", name="group_application_page"),
url(r'^group/application/(?P<request_id>\d+)/$', "group.views.application_page", name="group_application")
] ]

View File

@@ -26,8 +26,8 @@ class CreateProblemSerializer(serializers.Serializer):
samples = ProblemSampleSerializer() samples = ProblemSampleSerializer()
test_case_id = serializers.CharField(max_length=40) test_case_id = serializers.CharField(max_length=40)
source = serializers.CharField(max_length=30, required=False, default=None) source = serializers.CharField(max_length=30, required=False, default=None)
time_limit = serializers.IntegerField() time_limit = serializers.IntegerField(min_value=1)
memory_limit = serializers.IntegerField() memory_limit = serializers.IntegerField(min_value=1)
difficulty = serializers.IntegerField() difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.CharField(max_length=10)) tags = serializers.ListField(child=serializers.CharField(max_length=10))
hint = serializers.CharField(max_length=3000, allow_blank=True) hint = serializers.CharField(max_length=3000, allow_blank=True)
@@ -61,8 +61,8 @@ class EditProblemSerializer(serializers.Serializer):
output_description = serializers.CharField(max_length=10000) output_description = serializers.CharField(max_length=10000)
test_case_id = serializers.CharField(max_length=40) test_case_id = serializers.CharField(max_length=40)
source = serializers.CharField(max_length=30) source = serializers.CharField(max_length=30)
time_limit = serializers.IntegerField() time_limit = serializers.IntegerField(min_value=1)
memory_limit = serializers.IntegerField() memory_limit = serializers.IntegerField(min_value=1)
difficulty = serializers.IntegerField() difficulty = serializers.IntegerField()
tags = serializers.ListField(child=serializers.CharField(max_length=20)) tags = serializers.ListField(child=serializers.CharField(max_length=20))
samples = ProblemSampleSerializer() samples = ProblemSampleSerializer()

View File

@@ -8,3 +8,4 @@ celery
gunicorn gunicorn
coverage coverage
django-extensions django-extensions
supervisor

View File

@@ -149,16 +149,8 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
vm.editingContestId = contestId; vm.editingContestId = contestId;
vm.editTitle = vm.contestList[contestId-1].title; vm.editTitle = vm.contestList[contestId-1].title;
vm.editPassword = vm.contestList[contestId-1].password; vm.editPassword = vm.contestList[contestId-1].password;
//var startTime = new Date(), endTime = new Date(); vm.editStartTime = vm.contestList[contestId-1].start_time.substring(0,16).replace("T"," ");
//startTime.setFullYear(parseInt(vm.contestList[contestId-1].start_time.substring(0,4))) vm.editEndTime = vm.contestList[contestId-1].end_time.substring(0,16).replace("T"," ");
//startTime.setMonth(parseInt(vm.contestList[contestId-1].start_time.substring(5,7)))
//startTime.setDate(parseInt(vm.contestList[contestId-1].start_time.substring(8,10)))
//startTime.setHours(parseInt(vm.contestList[contestId-1].start_time.substring(11,13)))
//startTime.setMinutes(parseInt(vm.contestList[contestId-1].start_time.substring(14,16)))
//startTime = new Date(startTime + 8 * 60 * 60 * 1000)
vm.editStartTime = add8Hours(vm.contestList[contestId-1].start_time);
vm.editEndTime = add8Hours(vm.contestList[contestId-1].end_time);//.substring(0,16).replace("T"," ");
vm.editMode = vm.contestList[contestId-1].mode; vm.editMode = vm.contestList[contestId-1].mode;
vm.editVisible = vm.contestList[contestId-1].visible; vm.editVisible = vm.contestList[contestId-1].visible;
if (vm.contestList[contestId-1].contest_type == 0) { //contest type == 0, contest in group if (vm.contestList[contestId-1].contest_type == 0) { //contest type == 0, contest in group
@@ -300,39 +292,6 @@ require(["jquery", "avalon", "csrfToken", "bsAlert", "editor", "datetimePicker",
}); });
} }
function add8Hours(UtcString) {
console.log(UtcString);
var M = [31, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
/*time.setFullYear(parseInt(UtcString.substring(0,4)))
time.setMonth(parseInt(UtcString.substring(5,7)))
time.setDate(parseInt(UtcString.substring(8,10)))
time.setHours(parseInt(UtcString.substring(11,13)))
time.setMinutes(parseInt(UtcString.substring(14,16)))
time = new Date(time + 8 * 60 * 60 * 1000)*/
var year =UtcString.substring(0,4);
var month =UtcString.substring(5,7);
var day =UtcString.substring(8,10);
var hour =parseInt(UtcString.substring(11,13)) + 8;
var minute = UtcString.substring(14,16);
if (hour > 23) {
hour -= 24; day = parseInt(day)+1; month = parseInt(month);
if (month == 2) if (!(year%400)||(!(year%4)&&year%100)) M[2] = 29;
if (day > M[month]) {
day = 1;
month = parseInt(month)+1;
if (month > 12) {
year=parseInt(year)+1; month = 1;
}
}
month = month.toString();
day = day.toString();
if (month.length==1) month = "0"+month;
if (day.length==1) day = "0"+day;
}
hour = hour.toString();
if (hour.length==1) hour="0"+hour;
return year+"-"+month+"-"+day+" "+hour+":"+minute;
}
// Get group list // Get group list
$.ajax({ // Get current user type $.ajax({ // Get current user type
url: "/api/user/", url: "/api/user/",

View File

@@ -13,10 +13,6 @@ require(["jquery", "avalon", "editor", "uploader", "bsAlert", "csrfToken", "tagE
bsAlert("题目描述不能为空!"); bsAlert("题目描述不能为空!");
return false; return false;
} }
if (vm.timeLimit < 1000 || vm.timeLimit > 5000) {
bsAlert("保证时间限制是一个1000-5000的合法整数");
return false;
}
if (vm.samples.length == 0) { if (vm.samples.length == 0) {
bsAlert("请至少添加一组样例!"); bsAlert("请至少添加一组样例!");
return false; return false;

View File

@@ -0,0 +1,25 @@
require(["jquery", "csrfToken", "bsAlert"], function ($, csrfTokenHeader, bsAlert) {
$("#sendApplication").click(function (){
var message = $("#applyMessage").val();
console.log(message);
var groupId = window.location.pathname.split("/")[2];
console.log(groupId);
data = {group_id: groupId,message:message}
$.ajax({
url: "/api/group_join/",
method: "post",
dataType: "json",
beforeSend: csrfTokenHeader,
data: JSON.stringify(data),
contentType: "application/json",
success: function (data) {
if (data.code) {
bsAlert(data.data);
}
else {
bsAlert("申请已提交!");
}
}
})
})
})

View File

@@ -0,0 +1,40 @@
{% extends 'oj_base.html' %}
{% block body %}
<div class="container main">
<ul class="nav nav-tabs nav-tabs-google">
<li role="presentation" class="active">
<a href="/group/{{ group.id }}/">详细信息</a></li>
<li role="presentation"><a href="/group/{{ group.id }}/applications/">我的申请</a></li>
</ul>
<h2 class="text-center">{{ group.name }}</h2>
<p class="text-muted text-center">发布时间 : {{ group.create_time }}&nbsp;&nbsp;
创建者 : {{ group.admin }}
</p>
<div>
<div class="group-section">
<label class="group-label">描述</label>
<p class="group-detail">{{ group.description|safe }}</p>
</div>
</div>
<hr>
<div>
{% if group.join_group_setting %}
<div class="form-group">
<input id="groupId" value="{{ group.id }" type="hidden">
<label>申请信息</label>
<textarea class="form-control" id="applyMessage" rows="10"></textarea>
</div>
{% endif %}
<div class="form-group">
<button class="btn btn-primary" id="sendApplication">申请加入</button>
</div>
</div>
</div>
{% endblock %}
{% block js_block %}
<script src="/static/js/app/oj/group/group.js"></script>
{% endblock %}

View File

@@ -0,0 +1,26 @@
{% extends 'oj_base.html' %}
{% block body %}
<div class="container main">
<ul class="nav nav-tabs nav-tabs-google">
<li role="presentation">
<a href="/group/{{ application.group.id }}/">详细信息</a></li>
<li role="presentation" class="active">
<a href="/group/{{ application.group.id }}/applications/">我的申请</a>
</li>
</ul>
<label>内容</label>
<p>{{ application.message|safe }}</p>
<label>结果</label>
{% if application.status %}
{% if application.accepted %}
<p>管理员接受了你的请求</p>
{% else %}
<p>管理员拒绝了你的请求</p>
{% endif %}
{% else %}
<p>待审核</p>
{% endif %}
</div>
{% endblock %}

View File

@@ -0,0 +1,44 @@
{% extends 'oj_base.html' %}
{% block body %}
<div class="container main">
<ul class="nav nav-tabs nav-tabs-google">
<li role="presentation">
<a href="/group/{{ group.id }}/">详细信息</a></li>
<li role="presentation" class="active">
<a href="/group/{{ group.id }}/applications/">我的申请</a></li>
</ul>
{% if applications %}
<table class="table table-bordered">
<thead>
<tr>
<th>#</th>
<th>提交时间</th>
<th>结果</th>
</tr>
</thead>
<tbody>
{% for item in applications %}
<tr>
<th scope="row"><a href="/group/application/{{ item.id }}/">{{ forloop.counter }}</a></th>
<td>{{ item.create_time }}</td>
{% if item.status %}
{% if item.accepted %}
<td class="alert-success">通过</td>
{% else %}
<td class="alert-danger">拒绝</td>
{% endif %}
{% else %}
<td class="alert-warning">未处理</td>
{% endif %}
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>你还没有申请该小组</p>
{% endif %}
</div>
{% endblock %}

View File

@@ -8,71 +8,65 @@
<link rel="stylesheet" type="text/css" href="/static/css/fullpage/jquery.fullPage.css"> <link rel="stylesheet" type="text/css" href="/static/css/fullpage/jquery.fullPage.css">
<style> <style>
html, textarea, input, option, select, button { html, textarea, input, option, select, button {
font: 1em "Helvetica Neue", Helvetica, "Lantinghei SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", font: 1em "Helvetica Neue", Helvetica, "Lantinghei SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑",
"STHeiti", "WenQuanYi Micro Hei", SimSun, sans-serif; "STHeiti", "WenQuanYi Micro Hei", SimSun, sans-serif;
color: #FFF; color: #FFF;
} }
a { a {
text-decoration: none; text-decoration: none;
color: #FFF; color: #FFF;
} }
#header { #header {
position: fixed; position: fixed;
height: 30px; height: 30px;
display: block; display: block;
width: 100%; width: 100%;
background: transparent; background: transparent;
z-index: 10; z-index: 10;
padding: 20px 20px 0 20px; padding: 20px 20px 0 20px;
} }
#name { #name {
font-size: 45px; font-size: 45px;
margin-right: 20px; margin-right: 20px;
} }
#nav-left{
display: inline;
position:relative;
float: right;
margin-right: 28px;
}
.section { .section {
position: relative; position: relative;
} }
.section h1 { .section h1 {
font-size: 60px; font-size: 60px;
} }
.section h3 { .section h3 {
font-size: 30px; font-size: 30px;
font-weight: normal; font-weight: normal;
} }
.bottom-pointer { .bottom-pointer {
top: auto; top: auto;
bottom: 20px; bottom: 20px;
position: absolute; position: absolute;
left: 48%; left: 48%;
} }
.index-section-text { .index-section-text {
position: absolute; position: absolute;
top: 30%; top: 30%;
width: 100%; width: 100%;
text-align: center; text-align: center;
} }
.section-text { .section-text {
text-align: center; text-align: center;
} }
.icon { .icon {
max-height: 300px; max-height: 300px;
max-width: 300px; max-width: 300px;
} }
</style> </style>
@@ -103,20 +97,7 @@
<a href="/submissions/">提交</a>&nbsp;&nbsp; <a href="/submissions/">提交</a>&nbsp;&nbsp;
<a href="/contests/">比赛</a>&nbsp;&nbsp; <a href="/contests/">比赛</a>&nbsp;&nbsp;
<a href="/groups/">小组</a>&nbsp;&nbsp; <a href="/groups/">小组</a>&nbsp;&nbsp;
<a href="/about/">关于</a>&nbsp;&nbsp; <a href="/about/">关于</a>
<div id="nav-left">
{% if request.user.is_authenticated %}
<a href="#">{{ request.user.username }}</a>
<a href="/logout/">退出</a>
{% else %}
<a href="/login/">
登录
</a>
<a href="/register/">
注册
</a>
{% endif %}
</div>
</div> </div>
@@ -124,9 +105,9 @@
<div id="fullpage"> <div id="fullpage">
<div class="section" id="section0"> <div class="section" id="section0">
<div class="index-section-text animated bounceInUp"> <div class="index-section-text animated bounceInUp">
<h1>青岛大学在线评测平台</h1> <h1>青岛大学 Online Judge</h1>
<h3>新面貌,新的开始~</h3> <h3>面貌,新的开始~</h3>
</div> </div>
<div class="bottom-pointer">↓继续滚动~</div> <div class="bottom-pointer">↓继续滚动~</div>
</div> </div>
@@ -156,7 +137,7 @@
<div class="section-text"> <div class="section-text">
<img class="icon" id="img3" src="/static/img/index/m.png"> <img class="icon" id="img3" src="/static/img/index/m.png">
<h1>自由举办小组赛</h1> <h1>自由举办小组赛(10月上线)</h1>
<h3>内部比赛,日常作业,期末考试,通通搞定</h3> <h3>内部比赛,日常作业,期末考试,通通搞定</h3>
</div> </div>

View File

@@ -23,7 +23,7 @@
<div class="problem-section"> <div class="problem-section">
<label class="problem-label">输出</label> <label class="problem-label">输出</label>
<p class="problem-detail">{{ problem.output_description }}k</p> <p class="problem-detail">{{ problem.output_description }}</p>
</div> </div>
{% for item in samples %} {% for item in samples %}
<div class="problem-section"> <div class="problem-section">

View File

@@ -46,7 +46,7 @@
</thead> </thead>
<tbody> <tbody>
{% for item in submissions %} {% for item in submissions %}
<tr class="{{ item.result|translate_result_class }}"> <tr>
<th scope="row"><a href="/submission/{{ item.id }}/" id="id_{{ forloop.counter }}"> <th scope="row"><a href="/submission/{{ item.id }}/" id="id_{{ forloop.counter }}">
{{ forloop.counter |add:start_id }}</a></th> {{ forloop.counter |add:start_id }}</a></th>
<td>{{ item.create_time }}</td> <td>{{ item.create_time }}</td>

View File

@@ -56,7 +56,7 @@
{{ request.user.username }} {{ request.user.username }}
<span class="caret"></span></a> <span class="caret"></span></a>
<ul class="dropdown-menu"> <ul class="dropdown-menu">
<li><a href="/submission/">我的提交</a></li> <li><a href="/submissions/">我的提交</a></li>
<li><a href="#">我的资料</a></li> <li><a href="#">我的资料</a></li>
<li role="separator" class="divider"></li> <li role="separator" class="divider"></li>
<li><a href="/logout/">退出</a></li> <li><a href="/logout/">退出</a></li>

View File

@@ -4,7 +4,7 @@
def get_problem_accepted_radio(problem): def get_problem_accepted_radio(problem):
if problem.total_submit_number: if problem.total_submit_number:
return str(int((problem.total_accepted_number * 100) / problem.total_submit_number)) \ return str(int((problem.total_accepted_number * 100) / problem.total_submit_number)) \
+ "% (" + str(problem.total_accepted_number) + "/" + str(problem.total_submit_number) + ")" + "% (" + str(problem.total_accepted_number) + " / " + str(problem.total_submit_number) + ")"
return "0%" return "0%"