diff --git a/account/templates/reset_password_email.html b/account/templates/reset_password_email.html index 5a0b5915..b2f76f88 100644 --- a/account/templates/reset_password_email.html +++ b/account/templates/reset_password_email.html @@ -8,7 +8,7 @@ - {{ website_name }} 登录信息找回 + {{ website_name }} @@ -32,18 +32,18 @@ - 您刚刚在 {{ website_name }} 申请了找回登录信息服务。 + We received a request to reset your password for {{ website_name }}. - 请在30分钟内点击下面链接设置您的新密码: + You can use the following link to reset your password in 20 minutes. 重置密码 + style="color: rgb(255,255,255);text-decoration: none;display: block;min-height: 39px;width: 158px;line-height: 39px;background-color:rgb(80,165,230);font-size:20px;text-align:center;">Reset Password @@ -51,7 +51,7 @@ - 如果上面的链接点击无效,请复制以下链接至浏览器的地址栏直接打开。 + If the button above doesn't work, please copy the following link to your browser and press enter. @@ -63,8 +63,7 @@ - 如果您没有提出过该申请,请忽略此邮件。有可能是其他用户误填了您的邮件地址,我们不会对你的帐户进行任何修改。 - 请不要向他人透露本邮件的内容,否则可能会导致您的账号被盗。 + If you did not ask that, please ignore this email. It will expire and become useless in 20 minutes. diff --git a/deploy/Dockerfile b/deploy/Dockerfile index 4b8bfced..7f819aee 100644 --- a/deploy/Dockerfile +++ b/deploy/Dockerfile @@ -1,10 +1,13 @@ FROM python:3.6-alpine3.6 -ADD requirements.txt /tmp -RUN apk add --no-cache --virtual .build-deps build-base jpeg-dev zlib-dev postgresql-dev && \ - pip install -r /tmp/requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple && \ - apk del .build-deps --purge +ENV OJ_ENV production +RUN apk add --no-cache nginx supervisor jpeg-dev zlib-dev postgresql-dev freetype-dev -Volume ["/app"] +ADD requirements.txt /tmp +RUN apk add --no-cache build-base && \ + pip install --no-cache-dir -r /tmp/requirements.txt -i https://pypi.doubanio.com/simple && \ + apk del build-base --purge + +VOLUME [ "/app" ] CMD sh /app/deploy/run.sh diff --git a/deploy/nginx.conf b/deploy/nginx.conf index 82098072..bdaf1de8 100644 --- a/deploy/nginx.conf +++ b/deploy/nginx.conf @@ -46,7 +46,7 @@ http { # Timeout for keep-alive connections. Server will close connections after # this time. - keepalive_timeout 65; + keepalive_timeout 10; # Sendfile copies data between one FD and other from within the kernel, # which is more efficient than read() + write(). @@ -89,12 +89,11 @@ http { # Sets the path, format, and configuration for a buffered log write. # access_log /var/log/nginx/access.log main; - access_log off + access_log off; server { listen 80 default_server; server_name _; - keetalive_timeout 5; location /static/avatar { expires max; diff --git a/deploy/requirements.txt b/deploy/requirements.txt index 70aa2e56..559cce86 100644 --- a/deploy/requirements.txt +++ b/deploy/requirements.txt @@ -13,3 +13,5 @@ flake8-coding requests django-redis psycopg2 +gunicorn +jsonfield diff --git a/deploy/run.sh b/deploy/run.sh index fbc4b3ca..8082c217 100644 --- a/deploy/run.sh +++ b/deploy/run.sh @@ -12,11 +12,29 @@ fi cd $BASE find . -name "*.pyc" -delete +chown -R nobody:nogroup $BASE/log +# wait for postgresql start +sleep 5 + +n=0 +while [ $n -lt 3 ] +do python manage.py migrate if [ $? -ne 0 ]; then - echo "Can't start server" - exit 1 + echo "Can't start server, try again in 3 seconds.." + sleep 3 + let "n+=1" + continue fi python manage.py initadmin -python manage.py runserver 0.0.0.0:8080 +break + +done + +if [ $n -eq 3 ]; then + echo "Can't start server, please check log file for details." + exit 1 +fi + +exec supervisord -c /app/deploy/supervisor.conf diff --git a/deploy/supervisor.conf b/deploy/supervisor.conf index 55f53139..1bbc52fc 100644 --- a/deploy/supervisor.conf +++ b/deploy/supervisor.conf @@ -11,7 +11,7 @@ childlogdir=/app/log/ serverurl=unix:///tmp/supervisor.sock [program:gunicorn] -command=gunicorn oj.wsgi --user nobody -b 127.0.0.1:8080 --reload -w `grep -c ^processor /proc/cpuinfo` +command=sh -c "gunicorn oj.wsgi --user nobody -b 127.0.0.1:8080 --reload -w `grep -c ^processor /proc/cpuinfo`" directory=/app/ stdout_logfile=/app/log/gunicorn.log stderr_logfile=/app/log/gunicorn.log @@ -21,7 +21,7 @@ startsecs=5 stopwaitsecs = 5 killasgroup=true -[program:task_queue] +[program:celery] command=celery -A oj worker -l warning directory=/app/ user=nobody @@ -42,4 +42,4 @@ autostart=true autorestart=true startsecs=5 stopwaitsecs = 5 -killasgroup=true \ No newline at end of file +killasgroup=true diff --git a/oj/dev_settings.py b/oj/dev_settings.py index cb409383..85719f6e 100644 --- a/oj/dev_settings.py +++ b/oj/dev_settings.py @@ -26,6 +26,8 @@ ALLOWED_HOSTS = ["*"] TEST_CASE_DIR = "/tmp" +LOG_PATH = "/tmp/" + STATICFILES_DIRS = [ os.path.join(BASE_DIR, "static"), ] diff --git a/oj/production_settings.py b/oj/production_settings.py index 7d892769..7b1b1e1c 100644 --- a/oj/production_settings.py +++ b/oj/production_settings.py @@ -8,11 +8,11 @@ def get_env(name, default=""): DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', - 'HOST': get_env("POSTGRESQL_HOST", "postgresql"), - 'PORT': get_env("POSTGRESQL_PORT", "5433"), - 'NAME': get_env("POSTGRESQL_DBNAME"), - 'USER': get_env("POSTGRESQL_USER"), - 'PASSWORD': get_env("POSTGRESQL_PASSWORD") + 'HOST': get_env("POSTGRES_HOST", "postgres"), + 'PORT': get_env("POSTGRES_PORT", "5433"), + 'NAME': get_env("POSTGRES_DB"), + 'USER': get_env("POSTGRES_USER"), + 'PASSWORD': get_env("POSTGRES_PASSWORD") } } @@ -25,4 +25,5 @@ DEBUG = False ALLOWED_HOSTS = ['*'] -TEST_CASE_DIR = "/test_case" +TEST_CASE_DIR = "/app/test_case" +LOG_PATH = "log/" diff --git a/oj/settings.py b/oj/settings.py index a5fe7db4..47f0b78f 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -13,7 +13,7 @@ import os from .custom_settings import * -if os.environ.get("NODE_ENV") == "production": +if os.environ.get("OJ_ENV") == "production": from .production_settings import * else: from .dev_settings import * @@ -108,7 +108,6 @@ USE_TZ = True STATIC_URL = '/static/' AUTH_USER_MODEL = 'account.User' -LOG_PATH = "log/" LOGGING = { 'version': 1, diff --git a/options/migrations/0001_initial.py b/options/migrations/0001_initial.py index db40e1e8..a109c915 100644 --- a/options/migrations/0001_initial.py +++ b/options/migrations/0001_initial.py @@ -1,8 +1,8 @@ # -*- coding: utf-8 -*- -# Generated by Django 1.11.3 on 2017-10-01 19:19 +# Generated by Django 1.11.4 on 2017-10-23 08:11 from __future__ import unicode_literals -import jsonfield.fields +import django.contrib.postgres.fields.jsonb from django.db import migrations, models @@ -19,7 +19,7 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('key', models.CharField(db_index=True, max_length=128, unique=True)), - ('value', jsonfield.fields.JSONField()), + ('value', django.contrib.postgres.fields.jsonb.JSONField()), ], ), ] diff --git a/options/migrations/0002_auto_20171011_1214.py b/options/migrations/0002_auto_20171011_1214.py deleted file mode 100644 index ee52ffa4..00000000 --- a/options/migrations/0002_auto_20171011_1214.py +++ /dev/null @@ -1,21 +0,0 @@ -# -*- coding: utf-8 -*- -# Generated by Django 1.11.4 on 2017-10-11 12:14 -from __future__ import unicode_literals - -import django.contrib.postgres.fields.jsonb -from django.db import migrations - - -class Migration(migrations.Migration): - - dependencies = [ - ('options', '0001_initial'), - ] - - operations = [ - migrations.AlterField( - model_name='sysoptions', - name='value', - field=django.contrib.postgres.fields.jsonb.JSONField(), - ), - ] diff --git a/reset_password_email.html b/reset_password_email.html deleted file mode 100644 index e69de29b..00000000 diff --git a/utils/management/commands/initadmin.py b/utils/management/commands/initadmin.py index 1ff9d6b8..c29463ad 100644 --- a/utils/management/commands/initadmin.py +++ b/utils/management/commands/initadmin.py @@ -1,3 +1,4 @@ +import os from django.core.management.base import BaseCommand from account.models import AdminType, ProblemPermission, User, UserProfile @@ -9,18 +10,17 @@ class Command(BaseCommand): try: admin = User.objects.get(username="root") if admin.admin_type == AdminType.SUPER_ADMIN: - self.stdout.write(self.style.WARNING("Super admin user 'root' already exists, " - "would you like to reset it's password?\n" - "Input yes to confirm: ")) - if input() == "yes": - # todo remove this in product env - # rand_password = rand_str(length=6) - rand_password = "rootroot" - admin.save() - self.stdout.write(self.style.SUCCESS("Successfully created super admin user password.\n" - "Username: root\nPassword: %s\n" - "Remember to change password and turn on two factors auth " - "after installation." % rand_password)) + if os.environ.get("OJ_ENV") != "production": + self.stdout.write(self.style.WARNING("Super admin user 'root' already exists, " + "would you like to reset it's password?\n" + "Input yes to confirm: ")) + if input() == "yes": + rand_password = "rootroot" + admin.save() + self.stdout.write(self.style.SUCCESS("Successfully created super admin user password.\n" + "Username: root\nPassword: %s\n" + "Remember to change password and turn on two factors auth " + "after installation." % rand_password)) else: self.stdout.write(self.style.SUCCESS("Nothing happened")) else: