diff --git a/.gitignore b/.gitignore index 75853f15180c..1e7d62fa665c 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ build _mailinglist .tox .cache/ +migrations/ .idea/ db.sqlite3 config.py diff --git a/apps/users/forms.py b/apps/users/forms.py index 96392a932969..47ca32653b5c 100644 --- a/apps/users/forms.py +++ b/apps/users/forms.py @@ -16,7 +16,6 @@ class Meta: help_texts = { 'username': '* required', - 'name': '* required', 'email': '* required', 'groups': '* required' } diff --git a/apps/users/migrations/0003_auto_20160822_1316.py b/apps/users/migrations/0003_auto_20160822_1316.py new file mode 100644 index 000000000000..5a8d39a028f2 --- /dev/null +++ b/apps/users/migrations/0003_auto_20160822_1316.py @@ -0,0 +1,30 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.10 on 2016-08-22 05:16 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0002_auto_20160821_0051'), + ] + + operations = [ + migrations.AlterField( + model_name='user', + name='email', + field=models.EmailField(max_length=30, unique=True, verbose_name='\u90ae\u4ef6'), + ), + migrations.AlterField( + model_name='user', + name='groups', + field=models.ManyToManyField(to='users.UserGroup', verbose_name='\u7528\u6237\u7ec4'), + ), + migrations.AlterField( + model_name='user', + name='name', + field=models.CharField(max_length=20, verbose_name='\u59d3\u540d'), + ), + ] diff --git a/apps/users/models.py b/apps/users/models.py index 51314d27d62d..f5fc7b7ec360 100644 --- a/apps/users/models.py +++ b/apps/users/models.py @@ -3,7 +3,6 @@ from __future__ import unicode_literals import datetime - from django.contrib.auth.hashers import make_password from django.utils import timezone from django.db import models @@ -28,7 +27,7 @@ class Meta: db_table = 'role' @classmethod - def init(cls): + def initial(cls): roles = { 'Administrator': {'permissions': Permission.objects.all(), 'comment': '管理员'}, 'User': {'permissions': [], 'comment': '用户'}, @@ -56,10 +55,10 @@ class Meta: db_table = 'usergroup' @classmethod - def init(cls): - if not cls.objects.all(): - group = cls(name='ALL', comment='Default usergroup for all user', created_by='System') - group.save() + def initial(cls): + group_or_create = cls.objects.get_or_create(name='All', comment='Default user group for all user', + created_by='System') + return group_or_create[0] @classmethod def generate_fake(cls, count=100): @@ -86,7 +85,7 @@ def date_expired_default(): class User(AbstractUser): username = models.CharField(max_length=20, unique=True, verbose_name='用户名') - name = models.CharField(max_length=20, verbose_name='姓名') + name = models.CharField(max_length=20, blank=True, verbose_name='姓名') email = models.EmailField(max_length=30, unique=True, verbose_name='邮件') groups = models.ManyToManyField(UserGroup, verbose_name='用户组') avatar = models.ImageField(upload_to="avatar", verbose_name='头像') @@ -101,8 +100,18 @@ class User(AbstractUser): date_expired = models.DateTimeField(default=date_expired_default, verbose_name='有效期') created_by = models.CharField(max_length=30, default='') - class Meta: - db_table = 'user' + @property + def password_raw(self): + raise AttributeError('Password raw is not readable attribute') + + #: Use this attr to set user object password, example + #: user = User(username='example', password_raw='password', ...) + #: It's equal: + #: user = User(username='example', ...) + #: user.set_password('password') + @password_raw.setter + def password_raw(self, raw_password): + self.set_password(raw_password) def is_expired(self): if self.date_expired > timezone.now(): @@ -110,17 +119,31 @@ def is_expired(self): else: return True + def save(self, *args, **kwargs): + # If user not set name, it's default equal username + if not self.name: + self.name = self.username + super(User, self).save(args, **kwargs) + + # Set user default group 'All' + group = UserGroup.initial() + self.groups.add(group) + + class Meta: + db_table = 'user' + + #: Use this method @classmethod - def init(cls): + def initial(cls): user = cls(username='admin', email='admin@jumpserver.org', name='Administrator', - password=make_password('admin'), + password_raw='admin', role=Role.objects.get(name='Administrator'), comment='Administrator is the super user of system', created_by='System') user.save() - user.groups.add(UserGroup.objects.get(name='ALL')) + user.groups.add(UserGroup.initial()) @classmethod def generate_fake(cls, count=100): @@ -142,7 +165,7 @@ def generate_fake(cls, count=100): try: user.save() except IntegrityError: - print('Error continue') + print('Duplicate Error, continue ...') continue user.groups.add(choice(UserGroup.objects.all())) user.save() @@ -150,8 +173,8 @@ def generate_fake(cls, count=100): def init_all_models(): for model in (Role, UserGroup, User): - if hasattr(model, 'init'): - model.init() + if hasattr(model, 'initial'): + model.initial() def generate_fake(): diff --git a/apps/users/tests.py b/apps/users/tests.py index e10a760d3c7f..b3fac7c25dc7 100644 --- a/apps/users/tests.py +++ b/apps/users/tests.py @@ -1,8 +1,13 @@ +# ~*~ coding: utf-8 ~*~ + +from random import choice import forgery_py -from django.test import TestCase, Client +from django.utils import timezone +from django.test import TestCase, Client, TransactionTestCase from django.test.utils import setup_test_environment -from .models import User, UserGroup +from django.db import IntegrityError, transaction +from .models import User, UserGroup, Role, init_all_models setup_test_environment() @@ -21,5 +26,70 @@ def create_user(username, name, email, groups): pass +def gen_username(): + return forgery_py.internet.user_name(True) + + +def gen_email(): + return forgery_py.internet.email_address() + + +def gen_name(): + return forgery_py.name.full_name() + + +class UserModelTest(TransactionTestCase): + def setUp(self): + init_all_models() + + def test_user_duplicate(self): + # 创建一个基准测试用户 + role = choice(Role.objects.all()) + user = User(name='test', username='test', email='test@email.org', role=role) + user.save() + + # 创建一个姓名一致的用户, 应该创建成功 + user1 = User(name='test', username=gen_username(), password_raw=gen_username(), + email=gen_email(), role=role) + try: + user1.save() + user1.delete() + except IntegrityError: + self.assertTrue(0, 'Duplicate not allowed.') + + # 创建一个用户名一致的用户, 应该创建不成功 + user2 = User(username='test', email=gen_email(), role=role) + + try: + user2.save() + self.assertTrue(0, 'Duplicate allowed.') + except IntegrityError: + pass + + # 创建一个Email一致的用户,应该创建不成功 + user3 = User(username=gen_username(), email='test@email.org', role=role) + try: + user3.save() + self.assertTrue(0, 'Duplicate allowed.') + except IntegrityError: + pass + + def test_user_was_expired(self): + role = choice(Role.objects.all()) + date = timezone.now() - timezone.timedelta(days=1) + user = User(name=gen_name(), username=gen_username(), + email=gen_email(), role=role, date_expired=date) + + self.assertTrue(user.is_expired()) + + def test_user_with_default_group(self): + role = choice(Role.objects.all()) + user = User(username=gen_username(), email=gen_email(), role=role) + user.save() + + self.assertEqual(user.groups.count(), 1) + self.assertEqual(user.groups.first().name, 'All') + + class UserListViewTests(TestCase): pass