diff --git a/.gitignore b/.gitignore
index 8b3b73ff..6dbdf64c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -77,3 +77,5 @@ http_locations.conf
https_locations.conf
venv/
+#test docker-compose
+docker-compose.yml
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index ac84fa0a..5af64802 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,15 +1,16 @@
language: python
python:
- - "3.6"
+ - "3.8"
services:
- docker
+ - postgresql
install:
- pip install -r deploy/requirements.txt
- echo `cat /dev/urandom | head -1 | md5sum | head -c 32` > data/config/secret.key
- ./init_db.sh
script:
- docker ps -a
- - flake8 .
+ - flake8 --config=./.flake8 .
- coverage run --include="$PWD/*" manage.py test
- coverage report
notifications:
diff --git a/Dockerfile b/Dockerfile
index f66305b3..a43e4d6a 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,11 +1,11 @@
-FROM python:3.7-alpine3.9
+FROM python:3.8-alpine3.14
ENV OJ_ENV production
ADD . /app
WORKDIR /app
-HEALTHCHECK --interval=5s --retries=3 CMD python2 /app/deploy/health_check.py
+HEALTHCHECK --interval=5s --retries=3 CMD python3 /app/deploy/health_check.py
RUN apk add --update --no-cache build-base nginx openssl curl unzip supervisor jpeg-dev zlib-dev postgresql-dev freetype-dev && \
pip install --no-cache-dir -r /app/deploy/requirements.txt && \
diff --git a/account/views/admin.py b/account/views/admin.py
index 77b305ae..b207db92 100644
--- a/account/views/admin.py
+++ b/account/views/admin.py
@@ -151,7 +151,7 @@ class GenerateUserAPI(APIView):
raw_data = f.read()
os.remove(file_path)
response = HttpResponse(raw_data)
- response["Content-Disposition"] = f"attachment; filename=users.xlsx"
+ response["Content-Disposition"] = "attachment; filename=users.xlsx"
response["Content-Type"] = "application/xlsx"
return response
diff --git a/account/views/oj.py b/account/views/oj.py
index 2d26e484..2a3c2e09 100644
--- a/account/views/oj.py
+++ b/account/views/oj.py
@@ -305,7 +305,7 @@ class ApplyResetPasswordAPI(APIView):
send_email_async.send(from_name=SysOptions.website_name_shortcut,
to_email=user.email,
to_name=user.username,
- subject=f"Reset your password",
+ subject="Reset your password",
content=email_html)
return self.success("Succeeded")
diff --git a/conf/tests.py b/conf/tests.py
index dce80c68..fbb4022e 100644
--- a/conf/tests.py
+++ b/conf/tests.py
@@ -71,7 +71,7 @@ class WebsiteConfigAPITest(APITestCase):
"allow_register": True, "submission_list_show_all": False}
resp = self.client.post(url, data=data)
self.assertSuccess(resp)
- self.assertEqual(SysOptions.website_footer, "
")
+ self.assertEqual(SysOptions.website_footer, '
')
def test_get_website_config(self):
# do not need to login
diff --git a/deploy/health_check.py b/deploy/health_check.py
index f5065a25..472d9e84 100644
--- a/deploy/health_check.py
+++ b/deploy/health_check.py
@@ -1,11 +1,11 @@
-import xmlrpclib
+import xmlrpc.client
if __name__ == "__main__":
try:
- server = xmlrpclib.Server("http://localhost:9005/RPC2")
- info = server.supervisor.getAllProcessInfo()
- error_states = list(filter(lambda x: x["state"] != 20, info))
- exit(len(error_states))
+ with xmlrpc.client.ServerProxy("http://localhost:9005/RPC2") as server:
+ info = server.supervisor.getAllProcessInfo()
+ error_states = list(filter(lambda x: x["state"] != 20, info))
+ exit(len(error_states))
except Exception as e:
print(e.with_traceback())
exit(1)
diff --git a/deploy/requirements.txt b/deploy/requirements.txt
index b0c6fe9b..ed9a9337 100644
--- a/deploy/requirements.txt
+++ b/deploy/requirements.txt
@@ -1,32 +1,33 @@
certifi==2019.3.9
chardet==3.0.4
-coverage==4.5.3
-Django==2.1.7
-django-redis==4.10.0
-djangorestframework==3.8.2
+coverage==6.1.2
+Django==3.2.9
+django-redis==5.0.0
+djangorestframework==3.12.4
entrypoints==0.3
Envelopes==0.4
-flake8==3.7.7
-flake8-coding==1.3.1
-flake8-quotes==1.0.0
-gunicorn==19.9.0
-idna==2.8
-jsonfield==2.0.2
+flake8==4.0.1
+flake8-coding==1.3.2
+flake8-quotes==3.3.1
+gunicorn==20.1.0
+idna==3.3
+jsonfield==3.1.0
mccabe==0.6.1
otpauth==1.0.1
-Pillow==5.4.1
-psycopg2-binary==2.7.7
-pycodestyle==2.5.0
-pyflakes==2.1.1
-python-dateutil==2.8.0
-pytz==2018.9
-qrcode==6.1
+Pillow==8.4.0
+psycopg2==2.9.2
+pycodestyle==2.8.0
+pyflakes==2.4.0
+python-dateutil==2.8.2
+pytz==2021.3
+qrcode==7.3.1
raven==6.10.0
-redis==3.2.0
-requests==2.21.0
-six==1.12.0
-urllib3==1.24.1
-XlsxWriter==1.1.5
-django-dramatiq==0.5.0
-dramatiq==1.3.0
+redis==3.5.3
+requests==2.26.0
+six==1.16.0
+urllib3==1.26.7
+XlsxWriter==3.0.2
+django-dramatiq==0.10.0
+dramatiq==1.12.0
django-dbconn-retry==0.1.5
+django-cas-ng==4.2.1
diff --git a/docs/data.json b/docs/data.json
index 37edcd52..a80acac1 100644
--- a/docs/data.json
+++ b/docs/data.json
@@ -1,5 +1,16 @@
{
"update": [
+ {
+ "version": "2021-11-20",
+ "level": "Important",
+ "title": "2021-11-20",
+ "details": [
+ "django2.x即将停止支持,更新django到3.x LTS,相应地更新了全部相关依赖",
+ "合并底包版本到python3.8-alpine3.14,为移除python2做准备",
+ "按上游包的生产环境规范,修改依赖psycopg2_binary为psycopg2",
+ "TODO:本地开发环境搭建文档应做相应修改和提交。"
+ ]
+ },
{
"version": "2021-09-28",
"level": "Recommend",
diff --git a/oj/settings.py b/oj/settings.py
index c1141a02..74c559bc 100644
--- a/oj/settings.py
+++ b/oj/settings.py
@@ -244,3 +244,5 @@ RAVEN_CONFIG = {
}
IP_HEADER = "HTTP_X_REAL_IP"
+
+DEFAULT_AUTO_FIELD='django.db.models.AutoField'
\ No newline at end of file
diff --git a/problem/views/admin.py b/problem/views/admin.py
index 280e4fa1..5ce9413b 100644
--- a/problem/views/admin.py
+++ b/problem/views/admin.py
@@ -542,7 +542,7 @@ class ExportProblemAPI(APIView):
delete_files.send_with_options(args=(path,), delay=300_000)
resp = FileResponse(open(path, "rb"))
resp["Content-Type"] = "application/zip"
- resp["Content-Disposition"] = f"attachment;filename=problem-export.zip"
+ resp["Content-Disposition"] = "attachment;filename=problem-export.zip"
return resp
diff --git a/run_test.py b/run_test.py
index cb4c6300..a6c714f6 100644
--- a/run_test.py
+++ b/run_test.py
@@ -21,7 +21,7 @@ print("running flake8...")
if os.system("flake8 --statistics ."):
exit()
-ret = os.system("coverage run --include=\"$PWD/*\" manage.py test {module} --settings={setting}".format(module=test_module, setting=setting))
+ret = os.system('coverage run --include="$PWD/*" manage.py test {module} --settings={setting}'.format(module=test_module, setting=setting))
if not ret and is_coverage:
os.system("coverage html && open htmlcov/index.html")
diff --git a/utils/management/commands/inituser.py b/utils/management/commands/inituser.py
index a1ca73c8..e7769367 100644
--- a/utils/management/commands/inituser.py
+++ b/utils/management/commands/inituser.py
@@ -36,7 +36,7 @@ class Command(BaseCommand):
user = User.objects.get(username=username)
user.set_password(password)
user.save()
- self.stdout.write(self.style.SUCCESS(f"Password is rested"))
+ self.stdout.write(self.style.SUCCESS("Password is rested"))
except User.DoesNotExist:
self.stdout.write(self.style.ERROR(f"User {username} doesnot exist, operation ignored"))
exit(1)
diff --git a/utils/models.py b/utils/models.py
index 9a1cd0ba..7577f1fa 100644
--- a/utils/models.py
+++ b/utils/models.py
@@ -1,4 +1,4 @@
-from django.contrib.postgres.fields import JSONField # NOQA
+from django.db.models import JSONField # NOQA
from django.db import models
from utils.xss_filter import XSSHtml