diff --git a/account/tests.py b/account/tests.py index 8e5b855f..fd073562 100644 --- a/account/tests.py +++ b/account/tests.py @@ -32,7 +32,7 @@ class PermissionDecoratorTest(APITestCase): class UserLoginAPITest(APITestCase): def setUp(self): self.username = self.password = "test" - self.user = self.create_user(username=self.username, password=self.password) + self.user = self.create_user(username=self.username, password=self.password, login=False) self.login_url = self.reverse("user_login_api") def _set_tfa(self): @@ -152,7 +152,7 @@ class UserChangePasswordAPITest(CaptchaTest): self.username = "test_user" self.old_password = "testuserpassword" self.new_password = "new_password" - self.create_user(username=self.username, password=self.old_password) + self.create_user(username=self.username, password=self.old_password, login=False) self.data = {"old_password": self.old_password, "new_password": self.new_password, "captcha": self._set_captcha(self.client.session)} @@ -178,7 +178,7 @@ class AdminUserTest(APITestCase): def setUp(self): self.user = self.create_super_admin(login=True) self.username = self.password = "test" - self.regular_user = self.create_user(username=self.username, password=self.password) + self.regular_user = self.create_user(username=self.username, password=self.password, login=False) self.url = self.reverse("user_admin_api") self.data = {"id": self.regular_user.id, "username": self.username, "real_name": "test_name", "email": "test@qq.com", "admin_type": AdminType.REGULAR_USER, diff --git a/account/urls/admin.py b/account/urls/admin.py index 4af21f38..8f1b7f18 100644 --- a/account/urls/admin.py +++ b/account/urls/admin.py @@ -3,5 +3,5 @@ from django.conf.urls import url from ..views.admin import UserAdminAPI urlpatterns = [ - url(r'^user/$', UserAdminAPI.as_view(), name="user_admin_api"), + url(r'^user$', UserAdminAPI.as_view(), name="user_admin_api"), ] diff --git a/account/urls/oj.py b/account/urls/oj.py index b9fd5f5a..e7badd92 100644 --- a/account/urls/oj.py +++ b/account/urls/oj.py @@ -3,7 +3,7 @@ from django.conf.urls import url from ..views.oj import UserLoginAPI, UserRegisterAPI, UserChangePasswordAPI urlpatterns = [ - url(r'^login/$', UserLoginAPI.as_view(), name="user_login_api"), - url(r'^register/$', UserRegisterAPI.as_view(), name="user_register_api"), - url(r'^change_password/$', UserChangePasswordAPI.as_view(), name="user_change_password_api") + url(r'^login$', UserLoginAPI.as_view(), name="user_login_api"), + url(r'^register$', UserRegisterAPI.as_view(), name="user_register_api"), + url(r'^change_password$', UserChangePasswordAPI.as_view(), name="user_change_password_api") ] diff --git a/announcement/tests.py b/announcement/tests.py index 5de3179f..c2265974 100644 --- a/announcement/tests.py +++ b/announcement/tests.py @@ -3,7 +3,7 @@ from utils.api.tests import APITestCase, APIClient class AnnouncementAdminTest(APITestCase): def setUp(self): - self.user = self.create_super_admin(login=True) + self.user = self.create_super_admin() self.url = self.reverse("announcement_admin_api") def test_announcement_list(self): @@ -14,15 +14,15 @@ class AnnouncementAdminTest(APITestCase): return self.client.post(self.url, data={"title": "test", "content": "test"}) def test_create_announcement(self): - response = self.create_announcement() - self.assertSuccess(response) + resp = self.create_announcement() + self.assertSuccess(resp) def test_edit_announcement(self): data = {"id": self.create_announcement().data["data"]["id"], "title": "ahaha", "content": "test content", "visible": False} - response = self.client.put(self.url, data=data) - self.assertSuccess(response) - resp_data = response.data["data"] + resp = self.client.put(self.url, data=data) + self.assertSuccess(resp) + resp_data = resp.data["data"] self.assertEqual(resp_data["title"], "ahaha") self.assertEqual(resp_data["content"], "test content") self.assertEqual(resp_data["visible"], False) diff --git a/announcement/urls/admin.py b/announcement/urls/admin.py index 6ba28a67..c3e22033 100644 --- a/announcement/urls/admin.py +++ b/announcement/urls/admin.py @@ -3,5 +3,5 @@ from django.conf.urls import url from ..views import AnnouncementAdminAPI urlpatterns = [ - url(r'^$', AnnouncementAdminAPI.as_view(), name="announcement_admin_api"), + url(r'^announcement$', AnnouncementAdminAPI.as_view(), name="announcement_admin_api"), ] diff --git a/conf/admin.py b/conf/admin.py deleted file mode 100644 index 8c38f3f3..00000000 --- a/conf/admin.py +++ /dev/null @@ -1,3 +0,0 @@ -from django.contrib import admin - -# Register your models here. diff --git a/conf/migrations/0001_initial.py b/conf/migrations/0001_initial.py new file mode 100644 index 00000000..44c393c4 --- /dev/null +++ b/conf/migrations/0001_initial.py @@ -0,0 +1,45 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.10 on 2016-11-19 05:18 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ] + + operations = [ + migrations.CreateModel( + name='SMTPConfig', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('server', models.CharField(max_length=128)), + ('port', models.IntegerField(default=25)), + ('email', models.CharField(max_length=128)), + ('password', models.CharField(max_length=128)), + ('tls', models.BooleanField()), + ], + options={ + 'db_table': 'smtp_config', + }, + ), + migrations.CreateModel( + name='WebsiteConfig', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('base_url', models.CharField(default='http://127.0.0.1', max_length=128)), + ('name', models.CharField(default='Online Judge', max_length=32)), + ('name_shortcut', models.CharField(default='oj', max_length=32)), + ('website_footer', models.TextField(default='Online Judge Footer')), + ('allow_register', models.BooleanField(default=True)), + ('submission_list_show_all', models.BooleanField(default=True)), + ], + options={ + 'db_table': 'website_config', + }, + ), + ] diff --git a/conf/models.py b/conf/models.py index 59f0dc6f..f04e759d 100644 --- a/conf/models.py +++ b/conf/models.py @@ -16,14 +16,14 @@ class SMTPConfig(models.Model): class WebsiteConfig(models.Model): - base_url = models.CharField(max_length=128, default=None) + base_url = models.CharField(max_length=128, default="http://127.0.0.1") name = models.CharField(max_length=32, default="Online Judge") name_shortcut = models.CharField(max_length=32, default="oj") - website_footer = models.TextField(default="Online Judge") + website_footer = models.TextField(default="Online Judge Footer") # allow register allow_register = models.BooleanField(default=True) # submission list show all user's submission - submission_list_show_all = models.BooleanField(default=False) + submission_list_show_all = models.BooleanField(default=True) class Meta: db_table = "website_config" diff --git a/conf/serializers.py b/conf/serializers.py new file mode 100644 index 00000000..2d3ea975 --- /dev/null +++ b/conf/serializers.py @@ -0,0 +1,40 @@ +from utils.api import serializers + +from .models import SMTPConfig, WebsiteConfig + + +class EditSMTPConfigSerializer(serializers.Serializer): + server = serializers.CharField(max_length=128) + port = serializers.IntegerField(default=25) + email = serializers.CharField(max_length=128) + password = serializers.CharField(max_length=128, required=False, allow_null=True, allow_blank=True) + tls = serializers.BooleanField() + + +class CreateSMTPConfigSerializer(EditSMTPConfigSerializer): + password = serializers.CharField(max_length=128) + + +class SMTPConfigSerializer(serializers.ModelSerializer): + class Meta: + model = SMTPConfig + exclude = ["id", "password"] + + +class TestSMTPConfigSerializer(serializers.Serializer): + email = serializers.EmailField() + + +class CreateEditWebsiteConfigSerializer(serializers.Serializer): + base_url = serializers.CharField(max_length=128) + name = serializers.CharField(max_length=32) + name_shortcut = serializers.CharField(max_length=32) + website_footer = serializers.CharField(max_length=1024) + allow_register = serializers.BooleanField() + submission_list_show_all = serializers.BooleanField() + + +class WebsiteConfigSerializer(serializers.ModelSerializer): + class Meta: + model = WebsiteConfig + exclude = ["id"] \ No newline at end of file diff --git a/conf/tests.py b/conf/tests.py index 7ce503c2..f0995c48 100644 --- a/conf/tests.py +++ b/conf/tests.py @@ -1,3 +1,75 @@ -from django.test import TestCase +from utils.api.tests import APITestCase -# Create your tests here. +from .models import SMTPConfig, WebsiteConfig + + +class SMTPConfigTest(APITestCase): + def setUp(self): + self.user = self.create_super_admin() + self.url = self.reverse("smtp_admin_api") + self.password = "testtest" + + def test_create_smtp_config(self): + data = {"server": "smtp.test.com", "email": "test@test.com", "port": 465, + "tls": True, "password": self.password} + resp = self.client.post(self.url, data=data) + self.assertSuccess(resp) + self.assertTrue("password" not in resp.data) + return resp + + def test_edit_without_password(self): + self.test_create_smtp_config() + data = {"server": "smtp1.test.com", "email": "test2@test.com", "port": 465, + "tls": True} + resp = self.client.put(self.url, data=data) + self.assertSuccess(resp) + smtp = SMTPConfig.objects.first() + self.assertEqual(smtp.password, self.password) + self.assertEqual(smtp.server, "smtp1.test.com") + self.assertEqual(smtp.email, "test2@test.com") + + def test_edit_without_password1(self): + self.test_create_smtp_config() + data = {"server": "smtp.test.com", "email": "test@test.com", "port": 465, + "tls": True, "password": ""} + resp = self.client.put(self.url, data=data) + self.assertSuccess(resp) + self.assertEqual(SMTPConfig.objects.first().password, self.password) + + def test_edit_with_password(self): + self.test_create_smtp_config() + data = {"server": "smtp1.test.com", "email": "test2@test.com", "port": 465, + "tls": True, "password": "newpassword"} + resp = self.client.put(self.url, data=data) + self.assertSuccess(resp) + smtp = SMTPConfig.objects.first() + self.assertEqual(smtp.password, "newpassword") + self.assertEqual(smtp.server, "smtp1.test.com") + self.assertEqual(smtp.email, "test2@test.com") + + +class WebsiteConfigAPITest(APITestCase): + def test_create_website_config(self): + user = self.create_super_admin() + url = self.reverse("website_config_api") + data = {"base_url": "http://test.com", "name": "test name", + "name_shortcut": "test oj", "website_footer": "test", + "allow_register": True, "submission_list_show_all": False} + resp = self.client.post(url, data=data) + self.assertSuccess(resp) + + def test_edit_website_config(self): + user = self.create_super_admin() + url = self.reverse("website_config_api") + data = {"base_url": "http://test.com", "name": "test name", + "name_shortcut": "test oj", "website_footer": "test", + "allow_register": True, "submission_list_show_all": False} + resp = self.client.post(url, data=data) + self.assertSuccess(resp) + + def test_get_website_config(self): + # do not need to login + url = self.reverse("website_info_api") + resp = self.client.get(url) + self.assertSuccess(resp) + self.assertEqual(resp.data["data"]["name_shortcut"], "oj") diff --git a/conf/urls/__init__.py b/conf/urls/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/conf/urls/admin.py b/conf/urls/admin.py new file mode 100644 index 00000000..a6e8006a --- /dev/null +++ b/conf/urls/admin.py @@ -0,0 +1,8 @@ +from django.conf.urls import url + +from ..views import WebsiteConfigAPI, SMTPAPI + +urlpatterns = [ + url(r'^smtp$', SMTPAPI.as_view(), name="smtp_admin_api"), + url(r'^website$', WebsiteConfigAPI.as_view(), name="website_config_api"), +] diff --git a/conf/urls/oj.py b/conf/urls/oj.py new file mode 100644 index 00000000..a6cee9af --- /dev/null +++ b/conf/urls/oj.py @@ -0,0 +1,7 @@ +from django.conf.urls import url + +from ..views import WebsiteConfigAPI + +urlpatterns = [ + url(r'^website$', WebsiteConfigAPI.as_view(), name="website_info_api"), +] diff --git a/conf/views.py b/conf/views.py index 91ea44a2..59fce416 100644 --- a/conf/views.py +++ b/conf/views.py @@ -1,3 +1,65 @@ -from django.shortcuts import render +from utils.api import APIView, validate_serializer -# Create your views here. +from account.decorators import super_admin_required + +from .models import SMTPConfig, WebsiteConfig +from .serializers import (WebsiteConfigSerializer, CreateEditWebsiteConfigSerializer, + CreateSMTPConfigSerializer, EditSMTPConfigSerializer, + SMTPConfigSerializer, TestSMTPConfigSerializer) + + +class SMTPAPI(APIView): + @super_admin_required + def get(self, request): + smtp = SMTPConfig.objects.first() + if not smtp: + return self.success(None) + return self.success(SMTPConfigSerializer(smtp).data) + + @super_admin_required + @validate_serializer(CreateSMTPConfigSerializer) + def post(self, request): + SMTPConfig.objects.all().delete() + smtp = SMTPConfig.objects.create(**request.data) + return self.success(SMTPConfigSerializer(smtp).data) + + @super_admin_required + @validate_serializer(EditSMTPConfigSerializer) + def put(self, request): + data = request.data + smtp = SMTPConfig.objects.first() + if not smtp: + return self.error("SMTP config is missing") + smtp.server = data["server"] + smtp.port = data["port"] + smtp.email = data["email"] + smtp.tls = data["tls"] + if data.get("password"): + smtp.password = data["password"] + smtp.save() + return self.success(SMTPConfigSerializer(smtp).data) + + +class SMTPTestAPI(APIView): + @super_admin_required + @validate_serializer(TestSMTPConfigSerializer) + def post(self, request): + email = request.data["email"] + # todo: test send email + return self.success({"result": True}) + + +class WebsiteConfigAPI(APIView): + def get(self, request): + config = WebsiteConfig.objects.first() + if not config: + config = WebsiteConfig.objects.create() + return self.success(WebsiteConfigSerializer(config).data) + + @validate_serializer(CreateEditWebsiteConfigSerializer) + @super_admin_required + def post(self, request): + data = request.data + WebsiteConfig.objects.all().delete() + config = WebsiteConfig.objects.create(**data) + return self.success(WebsiteConfigSerializer(config).data) diff --git a/oj/settings.py b/oj/settings.py index 697bc1fa..e25edd2a 100644 --- a/oj/settings.py +++ b/oj/settings.py @@ -41,6 +41,7 @@ INSTALLED_APPS = ( 'account', 'announcement', + 'conf', 'utils', 'rest_framework', diff --git a/oj/urls.py b/oj/urls.py index 13351cdb..162e4392 100644 --- a/oj/urls.py +++ b/oj/urls.py @@ -3,6 +3,8 @@ from django.conf.urls import include, url urlpatterns = [ url(r'^api/', include("account.urls.oj")), - url(r'^api/admin/account/', include("account.urls.admin")), - url(r'^api/admin/announcement/', include("announcement.urls.admin")), + url(r'^api/admin/', include("account.urls.admin")), + url(r'^api/admin/', include("announcement.urls.admin")), + url(r'^api/', include("conf.urls.oj")), + url(r'^api/admin/', include("conf.urls.admin")) ] diff --git a/utils/api/tests.py b/utils/api/tests.py index 44a03b0f..5cf83c68 100644 --- a/utils/api/tests.py +++ b/utils/api/tests.py @@ -9,7 +9,7 @@ from account.models import User, AdminType class APITestCase(TestCase): client_class = APIClient - def create_user(self, username, password, admin_type=AdminType.REGULAR_USER, login=False): + def create_user(self, username, password, admin_type=AdminType.REGULAR_USER, login=True): user = User.objects.create(username=username, admin_type=admin_type) user.set_password(password) user.save() @@ -17,10 +17,10 @@ class APITestCase(TestCase): self.client.login(username=username, password=password) return user - def create_admin(self, username="admin", password="admin", login=False): + def create_admin(self, username="admin", password="admin", login=True): return self.create_user(username=username, password=password, admin_type=AdminType.ADMIN, login=login) - def create_super_admin(self, username="root", password="root", login=False): + def create_super_admin(self, username="root", password="root", login=True): return self.create_user(username=username, password=password, admin_type=AdminType.SUPER_ADMIN, login=login) def reverse(self, url_name):