Merge remote-tracking branch 'origin/pr/285' into p285
This commit is contained in:
		
							
								
								
									
										15
									
								
								.travis.yml
									
									
									
									
									
								
							
							
						
						
									
										15
									
								
								.travis.yml
									
									
									
									
									
								
							| @@ -7,12 +7,21 @@ python: | |||||||
|     - "3.2" |     - "3.2" | ||||||
|     - "3.3" |     - "3.3" | ||||||
| env: | env: | ||||||
|   - PYMONGO=dev |   - PYMONGO=dev DJANGO=1.5.1 | ||||||
|   - PYMONGO=2.5 |   - PYMONGO=dev DJANGO=1.4.2 | ||||||
|   - PYMONGO=2.4.2 |   - PYMONGO=2.5 DJANGO=1.5.1 | ||||||
|  |   - PYMONGO=2.5 DJANGO=1.4.2 | ||||||
|  |   - PYMONGO=2.4.2 DJANGO=1.4.2 | ||||||
|  | matrix: | ||||||
|  |   exclude: | ||||||
|  |     - python: "2.6" | ||||||
|  |       env: PYMONGO=dev DJANGO=1.5.1 | ||||||
|  |     - python: "2.6" | ||||||
|  |       env: PYMONGO=2.5 DJANGO=1.5.1 | ||||||
| install: | install: | ||||||
|     - if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then cp /usr/lib/*/libz.so $VIRTUAL_ENV/lib/; fi |     - if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then cp /usr/lib/*/libz.so $VIRTUAL_ENV/lib/; fi | ||||||
|     - if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then pip install pil --use-mirrors ; true; fi |     - if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then pip install pil --use-mirrors ; true; fi | ||||||
|  |     - if [[ $TRAVIS_PYTHON_VERSION == '2.'* ]]; then pip install django==$DJANGO --use-mirrors ; true; fi | ||||||
|     - if [[ $PYMONGO == 'dev' ]]; then pip install https://github.com/mongodb/mongo-python-driver/tarball/master; true; fi |     - if [[ $PYMONGO == 'dev' ]]; then pip install https://github.com/mongodb/mongo-python-driver/tarball/master; true; fi | ||||||
|     - if [[ $PYMONGO != 'dev' ]]; then pip install pymongo==$PYMONGO --use-mirrors; true; fi |     - if [[ $PYMONGO != 'dev' ]]; then pip install pymongo==$PYMONGO --use-mirrors; true; fi | ||||||
|     - python setup.py install |     - python setup.py install | ||||||
|   | |||||||
| @@ -42,6 +42,42 @@ The :mod:`~mongoengine.django.auth` module also contains a | |||||||
|  |  | ||||||
| .. versionadded:: 0.1.3 | .. versionadded:: 0.1.3 | ||||||
|  |  | ||||||
|  | Custom User model | ||||||
|  | ================= | ||||||
|  | Django 1.5 introduced `Custom user Models | ||||||
|  | <https://docs.djangoproject.com/en/dev/topics/auth/customizing/#auth-custom-user>` | ||||||
|  | which can be used as an alternative the Mongoengine authentication backend. | ||||||
|  |  | ||||||
|  | The main advantage of this option is that other components relying on | ||||||
|  | :mod:`django.contrib.auth` and supporting the new swappable user model are more | ||||||
|  | likely to work. For example, you can use the ``createsuperuser`` management | ||||||
|  | command as usual. | ||||||
|  |  | ||||||
|  | To enable the custom User model in Django, add ``'mongoengine.django.mongo_auth'`` | ||||||
|  | in your ``INSTALLED_APPS`` and set ``'mongo_auth.MongoUser'`` as the custom user | ||||||
|  | user model to use. In your **settings.py** file you will have:: | ||||||
|  |  | ||||||
|  |     INSTALLED_APPS = ( | ||||||
|  |         ... | ||||||
|  |         'django.contrib.auth', | ||||||
|  |         'mongoengine.django.mongo_auth', | ||||||
|  |         ... | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     AUTH_USER_MODEL = 'mongo_auth.MongoUser' | ||||||
|  |  | ||||||
|  | An additional ``MONGOENGINE_USER_DOCUMENT`` setting enables you to replace the | ||||||
|  | :class:`~mongoengine.django.auth.User` class with another class of your choice:: | ||||||
|  |  | ||||||
|  |     MONGOENGINE_USER_DOCUMENT = 'mongoengine.django.auth.User' | ||||||
|  |  | ||||||
|  | The custom :class:`User` must be a :class:`~mongoengine.Document` class, but | ||||||
|  | otherwise has the same requirements as a standard custom user model, | ||||||
|  | as specified in the `Django Documentation | ||||||
|  | <https://docs.djangoproject.com/en/dev/topics/auth/customizing/>`. | ||||||
|  | In particular, the custom class must define :attr:`USERNAME_FIELD` and | ||||||
|  | :attr:`REQUIRED_FIELDS` attributes. | ||||||
|  |  | ||||||
| Sessions | Sessions | ||||||
| ======== | ======== | ||||||
| Django allows the use of different backend stores for its sessions. MongoEngine | Django allows the use of different backend stores for its sessions. MongoEngine | ||||||
|   | |||||||
| @@ -108,7 +108,7 @@ class Permission(Document): | |||||||
|     created for each Django model. |     created for each Django model. | ||||||
|     """ |     """ | ||||||
|     name = StringField(max_length=50, verbose_name=_('username')) |     name = StringField(max_length=50, verbose_name=_('username')) | ||||||
|     content_type = ReferenceField(ContentType) |     content_type = ReferenceField(ContentType, dbref=True) | ||||||
|     codename = StringField(max_length=100, verbose_name=_('codename')) |     codename = StringField(max_length=100, verbose_name=_('codename')) | ||||||
|         # FIXME: don't access field of the other class |         # FIXME: don't access field of the other class | ||||||
|         # unique_with=['content_type__app_label', 'content_type__model']) |         # unique_with=['content_type__app_label', 'content_type__model']) | ||||||
| @@ -150,7 +150,7 @@ class Group(Document): | |||||||
|     """ |     """ | ||||||
|     name = StringField(max_length=80, unique=True, verbose_name=_('name')) |     name = StringField(max_length=80, unique=True, verbose_name=_('name')) | ||||||
|     # permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True) |     # permissions = models.ManyToManyField(Permission, verbose_name=_('permissions'), blank=True) | ||||||
|     permissions = ListField(ReferenceField(Permission, verbose_name=_('permissions'), required=False)) |     permissions = ListField(ReferenceField(Permission, verbose_name=_('permissions'), required=False, dbref=True)) | ||||||
|  |  | ||||||
|     class Meta: |     class Meta: | ||||||
|         verbose_name = _('group') |         verbose_name = _('group') | ||||||
| @@ -231,6 +231,9 @@ class User(Document): | |||||||
|     date_joined = DateTimeField(default=datetime_now, |     date_joined = DateTimeField(default=datetime_now, | ||||||
|                                 verbose_name=_('date joined')) |                                 verbose_name=_('date joined')) | ||||||
|  |  | ||||||
|  |     USERNAME_FIELD = 'username' | ||||||
|  |     REQUIRED_FIELDS = ['email'] | ||||||
|  |  | ||||||
|     meta = { |     meta = { | ||||||
|         'allow_inheritance': True, |         'allow_inheritance': True, | ||||||
|         'indexes': [ |         'indexes': [ | ||||||
|   | |||||||
							
								
								
									
										0
									
								
								mongoengine/django/mongo_auth/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								mongoengine/django/mongo_auth/__init__.py
									
									
									
									
									
										Normal file
									
								
							
							
								
								
									
										90
									
								
								mongoengine/django/mongo_auth/models.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										90
									
								
								mongoengine/django/mongo_auth/models.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,90 @@ | |||||||
|  | from importlib import import_module | ||||||
|  |  | ||||||
|  | from django.conf import settings | ||||||
|  | from django.contrib.auth.models import UserManager | ||||||
|  | from django.core.exceptions import ImproperlyConfigured | ||||||
|  | from django.db import models | ||||||
|  | from django.utils.translation import ugettext_lazy as _ | ||||||
|  |  | ||||||
|  |  | ||||||
|  | MONGOENGINE_USER_DOCUMENT = getattr( | ||||||
|  |     settings, 'MONGOENGINE_USER_DOCUMENT', 'mongoengine.django.auth.User') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class MongoUserManager(UserManager): | ||||||
|  |     """A User manager wich allows the use of MongoEngine documents in Django. | ||||||
|  |  | ||||||
|  |     To use the manager, you must tell django.contrib.auth to use MongoUser as | ||||||
|  |     the user model. In you settings.py, you need: | ||||||
|  |  | ||||||
|  |         INSTALLED_APPS = ( | ||||||
|  |             ... | ||||||
|  |             'django.contrib.auth', | ||||||
|  |             'mongoengine.django.mongo_auth', | ||||||
|  |             ... | ||||||
|  |         ) | ||||||
|  |         AUTH_USER_MODEL = 'mongo_auth.MongoUser' | ||||||
|  |  | ||||||
|  |     Django will use the model object to access the custom Manager, which will | ||||||
|  |     replace the original queryset with MongoEngine querysets. | ||||||
|  |  | ||||||
|  |     By default, mongoengine.django.auth.User will be used to store users. You | ||||||
|  |     can specify another document class in MONGOENGINE_USER_DOCUMENT in your | ||||||
|  |     settings.py. | ||||||
|  |  | ||||||
|  |     The User Document class has the same requirements as a standard custom user | ||||||
|  |     model: https://docs.djangoproject.com/en/dev/topics/auth/customizing/ | ||||||
|  |  | ||||||
|  |     In particular, the User Document class must define USERNAME_FIELD and | ||||||
|  |     REQUIRED_FIELDS. | ||||||
|  |  | ||||||
|  |     `AUTH_USER_MODEL` has been added in Django 1.5. | ||||||
|  |  | ||||||
|  |     """ | ||||||
|  |  | ||||||
|  |     def contribute_to_class(self, model, name): | ||||||
|  |         super(MongoUserManager, self).contribute_to_class(model, name) | ||||||
|  |         self.dj_model = self.model | ||||||
|  |         self.model = self._get_user_document() | ||||||
|  |  | ||||||
|  |         self.dj_model.USERNAME_FIELD = self.model.USERNAME_FIELD | ||||||
|  |         username = models.CharField(_('username'), max_length=30, unique=True) | ||||||
|  |         username.contribute_to_class(self.dj_model, self.dj_model.USERNAME_FIELD) | ||||||
|  |  | ||||||
|  |         self.dj_model.REQUIRED_FIELDS = self.model.REQUIRED_FIELDS | ||||||
|  |         for name in self.dj_model.REQUIRED_FIELDS: | ||||||
|  |             field = models.CharField(_(name), max_length=30) | ||||||
|  |             field.contribute_to_class(self.dj_model, name) | ||||||
|  |  | ||||||
|  |     def _get_user_document(self): | ||||||
|  |         try: | ||||||
|  |             name = MONGOENGINE_USER_DOCUMENT | ||||||
|  |             dot = name.rindex('.') | ||||||
|  |             module = import_module(name[:dot]) | ||||||
|  |             return getattr(module, name[dot + 1:]) | ||||||
|  |         except ImportError: | ||||||
|  |             raise ImproperlyConfigured("Error importing %s, please check " | ||||||
|  |                                        "settings.MONGOENGINE_USER_DOCUMENT" | ||||||
|  |                                        % name) | ||||||
|  |  | ||||||
|  |     def get(self, *args, **kwargs): | ||||||
|  |         try: | ||||||
|  |             return self.get_query_set().get(*args, **kwargs) | ||||||
|  |         except self.model.DoesNotExist: | ||||||
|  |             # ModelBackend expects this exception | ||||||
|  |             raise self.dj_model.DoesNotExist | ||||||
|  |  | ||||||
|  |     @property | ||||||
|  |     def db(self): | ||||||
|  |         raise NotImplementedError | ||||||
|  |  | ||||||
|  |     def get_empty_query_set(self): | ||||||
|  |         return self.model.objects.none() | ||||||
|  |  | ||||||
|  |     def get_query_set(self): | ||||||
|  |         return self.model.objects | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class MongoUser(models.Model): | ||||||
|  |     objects = MongoUserManager() | ||||||
|  |  | ||||||
							
								
								
									
										2
									
								
								setup.py
									
									
									
									
									
								
							
							
						
						
									
										2
									
								
								setup.py
									
									
									
									
									
								
							| @@ -57,7 +57,7 @@ if sys.version_info[0] == 3: | |||||||
|         extra_opts['packages'].append("tests") |         extra_opts['packages'].append("tests") | ||||||
|         extra_opts['package_data'] = {"tests": ["fields/mongoengine.png", "fields/mongodb_leaf.png"]} |         extra_opts['package_data'] = {"tests": ["fields/mongoengine.png", "fields/mongodb_leaf.png"]} | ||||||
| else: | else: | ||||||
|     extra_opts['tests_require'] = ['nose', 'coverage', 'blinker', 'django==1.4.2', 'PIL'] |     extra_opts['tests_require'] = ['nose', 'coverage', 'blinker', 'django>=1.4.2', 'PIL'] | ||||||
|     extra_opts['packages'] = find_packages(exclude=('tests',)) |     extra_opts['packages'] = find_packages(exclude=('tests',)) | ||||||
|  |  | ||||||
| setup(name='mongoengine', | setup(name='mongoengine', | ||||||
|   | |||||||
| @@ -14,8 +14,19 @@ try: | |||||||
|     from django.conf import settings |     from django.conf import settings | ||||||
|     from django.core.paginator import Paginator |     from django.core.paginator import Paginator | ||||||
|  |  | ||||||
|     settings.configure(USE_TZ=True) |     settings.configure( | ||||||
|  |         USE_TZ=True, | ||||||
|  |         INSTALLED_APPS=('django.contrib.auth', 'mongoengine.django.mongo_auth'), | ||||||
|  |         AUTH_USER_MODEL=('mongo_auth.MongoUser'), | ||||||
|  |     ) | ||||||
|  |  | ||||||
|  |     try: | ||||||
|  |         from django.contrib.auth import authenticate, get_user_model | ||||||
|  |         from mongoengine.django.auth import User | ||||||
|  |         from mongoengine.django.mongo_auth.models import MongoUser, MongoUserManager | ||||||
|  |         DJ15 = True | ||||||
|  |     except Exception: | ||||||
|  |         DJ15 = False | ||||||
|     from django.contrib.sessions.tests import SessionTestsMixin |     from django.contrib.sessions.tests import SessionTestsMixin | ||||||
|     from mongoengine.django.sessions import SessionStore, MongoSession |     from mongoengine.django.sessions import SessionStore, MongoSession | ||||||
| except Exception, err: | except Exception, err: | ||||||
| @@ -156,6 +167,7 @@ class QuerySetTest(unittest.TestCase): | |||||||
|         rendered = template.render(Context({'users': users})) |         rendered = template.render(Context({'users': users})) | ||||||
|         self.assertEqual(rendered, 'AB ABCD CD') |         self.assertEqual(rendered, 'AB ABCD CD') | ||||||
|  |  | ||||||
|  |  | ||||||
| class MongoDBSessionTest(SessionTestsMixin, unittest.TestCase): | class MongoDBSessionTest(SessionTestsMixin, unittest.TestCase): | ||||||
|     backend = SessionStore |     backend = SessionStore | ||||||
|  |  | ||||||
| @@ -184,5 +196,49 @@ class MongoDBSessionTest(SessionTestsMixin, unittest.TestCase): | |||||||
|         session = SessionStore(key) |         session = SessionStore(key) | ||||||
|         self.assertTrue('test_expire' in session, 'Session has expired before it is expected') |         self.assertTrue('test_expire' in session, 'Session has expired before it is expected') | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class MongoAuthTest(unittest.TestCase): | ||||||
|  |     user_data = { | ||||||
|  |         'username': 'user', | ||||||
|  |         'email': 'user@example.com', | ||||||
|  |         'password': 'test', | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     def setUp(self): | ||||||
|  |         if PY3: | ||||||
|  |             raise SkipTest('django does not have Python 3 support') | ||||||
|  |         if not DJ15: | ||||||
|  |             raise SkipTest('mongo_auth requires Django 1.5') | ||||||
|  |         connect(db='mongoenginetest') | ||||||
|  |         User.drop_collection() | ||||||
|  |         super(MongoAuthTest, self).setUp() | ||||||
|  |  | ||||||
|  |     def test_user_model(self): | ||||||
|  |         self.assertEqual(get_user_model(), MongoUser) | ||||||
|  |  | ||||||
|  |     def test_user_manager(self): | ||||||
|  |         manager = get_user_model()._default_manager | ||||||
|  |         self.assertIsInstance(manager, MongoUserManager) | ||||||
|  |  | ||||||
|  |     def test_user_manager_exception(self): | ||||||
|  |         manager = get_user_model()._default_manager | ||||||
|  |         self.assertRaises(MongoUser.DoesNotExist, manager.get, | ||||||
|  |                           username='not found') | ||||||
|  |  | ||||||
|  |     def test_create_user(self): | ||||||
|  |         manager = get_user_model()._default_manager | ||||||
|  |         user = manager.create_user(**self.user_data) | ||||||
|  |         self.assertIsInstance(user, User) | ||||||
|  |         db_user = User.objects.get(username='user') | ||||||
|  |         self.assertEqual(user.id, db_user.id) | ||||||
|  |  | ||||||
|  |     def test_authenticate(self): | ||||||
|  |         get_user_model()._default_manager.create_user(**self.user_data) | ||||||
|  |         user = authenticate(username='user', password='fail') | ||||||
|  |         self.assertIsNone(user) | ||||||
|  |         user = authenticate(username='user', password='test') | ||||||
|  |         db_user = User.objects.get(username='user') | ||||||
|  |         self.assertEqual(user.id, db_user.id) | ||||||
|  |  | ||||||
| if __name__ == '__main__': | if __name__ == '__main__': | ||||||
|     unittest.main() |     unittest.main() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user