diff --git a/.idea/django-separate-users.iml b/.idea/django-separate-users.iml
new file mode 100644
index 0000000..ae71067
--- /dev/null
+++ b/.idea/django-separate-users.iml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..dfb77dc
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..fa598c8
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..2af2edf
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,556 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ DEFINITION_ORDER
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1489851499607
+
+
+ 1489851499607
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
new file mode 100644
index 0000000..24def7e
--- /dev/null
+++ b/CHANGELOG.txt
@@ -0,0 +1,11 @@
+
+==== 0.xxx (not yet) ===
+
+- fix for djangocms-admin-styles
+
+
+==== 0.0.1 (not yet) ===
+
+- support for django 1.9
+- refactored tests, to use default manage.py test command
+
diff --git a/MANIFEST.in b/MANIFEST.in
new file mode 100644
index 0000000..0a9b2a3
--- /dev/null
+++ b/MANIFEST.in
@@ -0,0 +1,7 @@
+include LICENSES
+include README.rst
+global-exclude *.orig *.pyc *.log *.swp
+
+recursive-include separate_users/templates *
+recursive-include separate_users/static *
+recursive-include separate_users/locale *
diff --git a/compilemessages.sh b/compilemessages.sh
new file mode 100755
index 0000000..f519a5c
--- /dev/null
+++ b/compilemessages.sh
@@ -0,0 +1,4 @@
+
+cd separate_users
+django-admin.py compilemessages
+cd ..
\ No newline at end of file
diff --git a/makemessages.sh b/makemessages.sh
new file mode 100755
index 0000000..d0185b4
--- /dev/null
+++ b/makemessages.sh
@@ -0,0 +1,5 @@
+
+
+cd separate_users
+django-admin.py makemessages -l en
+cd ..
\ No newline at end of file
diff --git a/manage.py b/manage.py
new file mode 100755
index 0000000..4e42ee0
--- /dev/null
+++ b/manage.py
@@ -0,0 +1,11 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE',
+ 'separate_users.tests.settings_runtestapp')
+
+ from django.core.management import execute_from_command_line
+
+ execute_from_command_line(sys.argv)
diff --git a/release.txt b/release.txt
new file mode 100644
index 0000000..d0b25f3
--- /dev/null
+++ b/release.txt
@@ -0,0 +1,12 @@
+
+
+git flow release start 0.xxx
+version bump in separate_users/__init__.py
+git flow release finish 0.xxx
+git push --all; git push --tags
+python setup.py sdist
+# no wheel for now?! python setup.py bdist_wheel --universal
+python setup.py register -r pypitest
+twine upload dist/* -r pypitest
+python setup.py register -r pypi
+twine upload dist/*
diff --git a/separate_users/__init__.py b/separate_users/__init__.py
new file mode 100644
index 0000000..25fda2c
--- /dev/null
+++ b/separate_users/__init__.py
@@ -0,0 +1,2 @@
+__version__ = '0.1.2'
+__author__ = 'benzkji'
diff --git a/separate_users/admin.py b/separate_users/admin.py
new file mode 100644
index 0000000..451f989
--- /dev/null
+++ b/separate_users/admin.py
@@ -0,0 +1,61 @@
+from django.conf.urls import url
+from django.contrib import admin
+from django.db import models
+from django.http import JsonResponse
+
+
+class DjangoLinkAdmin(admin.ModelAdmin):
+
+ def get_model_perms(self, request):
+ """
+ http://stackoverflow.com/questions/2431727/django-admin-hide-a-model
+ Return empty perms dict thus hiding the model from admin index.
+ """
+ return {}
+
+ def get_urls(self):
+ """
+ add verify url.
+ """
+ my_urls = [
+ url(
+ r'^verify/$',
+ self.admin_site.admin_view(self.verify),
+ name=self._get_verify_url_name()
+ ),
+ ]
+ return my_urls + super(DjangoLinkAdmin, self).get_urls()
+
+ def _get_verify_url_name(self):
+ return '{0}_{1}_verify'.format(self.model._meta.app_label,
+ self.model._meta.model_name)
+
+ def verify(self, request):
+ """
+ verify data with modelform, send through data.
+ :param request:
+ :return:
+ """
+ form = self.get_form(request, )(request.POST)
+ if form.is_valid():
+ verified_data = form.cleaned_data
+ obj = self.model(**verified_data)
+ link_value = ''
+ # prepopulate href
+ if (getattr(obj, 'get_link', None)):
+ link_value = obj.get_link()
+ # basic serialize only
+ for key, value in verified_data.items():
+ if isinstance(value, models.Model):
+ verified_data[key] = value.id
+ return_data = {"valid": 'true', 'data': verified_data, 'link_value': link_value}
+ else:
+ errors = form.errors
+ return_data = {"valid": 'false', 'errors': errors}
+ return JsonResponse(return_data)
+
+ def save_model(self, request, obj, form, change):
+ """
+ no save!
+ """
+ return False
diff --git a/separate_users/models.py b/separate_users/models.py
new file mode 100644
index 0000000..e69de29
diff --git a/separate_users/tests/__init__.py b/separate_users/tests/__init__.py
new file mode 100644
index 0000000..b8c48bd
--- /dev/null
+++ b/separate_users/tests/__init__.py
@@ -0,0 +1 @@
+__author__ = 'benzkji'
diff --git a/separate_users/tests/settings_runtestapp.py b/separate_users/tests/settings_runtestapp.py
new file mode 100644
index 0000000..8533e04
--- /dev/null
+++ b/separate_users/tests/settings_runtestapp.py
@@ -0,0 +1,13 @@
+"""
+These settings are used by the ``manage.py`` command.
+"""
+
+from .settings_test import * # NOQA
+
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': 'db.sqlite',
+ }
+}
diff --git a/separate_users/tests/settings_test.py b/separate_users/tests/settings_test.py
new file mode 100644
index 0000000..e756bf0
--- /dev/null
+++ b/separate_users/tests/settings_test.py
@@ -0,0 +1,151 @@
+"""Settings that need to be set in order to run the tests."""
+import os
+import sys
+import tempfile
+import logging
+
+from django.core.urlresolvers import reverse_lazy
+
+
+DEBUG = True
+
+logging.getLogger("factory").setLevel(logging.WARN)
+
+# from selenium.webdriver.firefox import webdriver
+from selenium.webdriver.phantomjs import webdriver
+SELENIUM_WEBDRIVER = webdriver
+
+
+separate_users_MODEL = 'separate_users.tests.test_app.models.LinkModel'
+separate_users_IFRAME_URL = reverse_lazy('admin:test_app_linkmodel_add')
+separate_users_VERIFY_URL = reverse_lazy('admin:test_app_linkmodel_verify')
+
+CKEDITOR_CONFIGS = {
+ 'default': {
+ 'djangolinkIframeURL': separate_users_IFRAME_URL,
+ 'djangolinkVerifyURL': separate_users_VERIFY_URL,
+ 'linkShowAdvancedTab': False,
+ 'extraPlugins': ','.join(
+ [
+ # your extra plugins here
+ 'djangolink',
+ 'autolink',
+ 'autoembed',
+ 'embedsemantic',
+ 'autogrow',
+ 'devtools',
+ 'widget',
+ 'lineutils',
+ 'clipboard',
+ 'dialog',
+ 'dialogui',
+ 'elementspath'
+ ]),
+ 'toolbar': 'Custom',
+ 'toolbar_Custom': [
+ ['Bold', 'Underline'],
+ ['DjangoLink', 'Unlink'],
+ ['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent', '-', 'JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
+ ['Link', 'Unlink'],
+ ['RemoveFormat', 'Source']
+ ]
+ }
+}
+
+SITE_ID = 1
+
+APP_ROOT = os.path.abspath(
+ os.path.join(os.path.dirname(__file__), ".."))
+
+DATABASES = {
+ 'default': {
+ 'ENGINE': 'django.db.backends.sqlite3',
+ 'NAME': ':memory:',
+ }
+}
+
+LANGUAGE_CODE = 'en'
+LANGUAGES = (
+ ('en', 'ENGLISHS' ),
+)
+
+ROOT_URLCONF = 'separate_users.tests.urls'
+
+# media root is overridden when needed in tests
+MEDIA_ROOT = tempfile.mkdtemp(suffix='ckeditor_media_root')
+MEDIA_URL = "/media/"
+STATIC_URL = '/static/'
+STATIC_ROOT = os.path.join(APP_ROOT, '../test_app_static')
+STATICFILES_DIRS = (
+ os.path.join(APP_ROOT, 'static'),
+)
+
+# TEMPLATE_DIRS = (
+# os.path.join(APP_ROOT, 'tests/test_app/templates'),
+# )
+
+COVERAGE_REPORT_HTML_OUTPUT_DIR = os.path.join(
+ os.path.join(APP_ROOT, 'tests/coverage'))
+COVERAGE_MODULE_EXCLUDES = [
+ 'tests$', 'settings$', 'urls$', 'locale$',
+ 'migrations', 'fixtures', 'admin$', 'django_extensions',
+]
+
+EXTERNAL_APPS = (
+ 'django.contrib.admin',
+ # 'django.contrib.admindocs',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.messages',
+ 'django.contrib.sessions',
+ 'django.contrib.staticfiles',
+ 'django.contrib.sitemaps',
+ 'django.contrib.sites',
+ 'ckeditor',
+ # 'djangocms_text_ckeditor',
+ # 'cms',
+ # 'treebeard',
+ # 'menus',
+)
+
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ 'django.template.context_processors.i18n',
+ 'django.template.context_processors.request',
+ 'django.template.context_processors.media',
+ 'django.template.context_processors.static',
+ ],
+ 'loaders': [
+ 'django.template.loaders.filesystem.Loader',
+ 'django.template.loaders.app_directories.Loader',
+ # 'django.template.loaders.eggs.Loader',
+ ],
+ }
+ },
+]
+
+
+INTERNAL_APPS = (
+ 'separate_users',
+ 'separate_users.tests.test_app',
+)
+
+MIDDLEWARE_CLASSES = (
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+ 'django.contrib.messages.middleware.MessageMiddleware',
+ # Uncomment the next line for simple clickjacking protection:
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ 'django.middleware.locale.LocaleMiddleware',
+)
+
+INSTALLED_APPS = EXTERNAL_APPS + INTERNAL_APPS
+COVERAGE_MODULE_EXCLUDES += EXTERNAL_APPS
+
+SECRET_KEY = 'foobarXXXxxsvXY'
diff --git a/separate_users/tests/test_app/__init__.py b/separate_users/tests/test_app/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/separate_users/tests/test_app/admin.py b/separate_users/tests/test_app/admin.py
new file mode 100644
index 0000000..7058a7d
--- /dev/null
+++ b/separate_users/tests/test_app/admin.py
@@ -0,0 +1,18 @@
+from django import forms
+from django.contrib import admin
+from django.forms.extras.widgets import SelectDateWidget
+
+from separate_users.admin import DjangoLinkAdmin
+
+from .models import TestModel, LinkModel
+
+
+class LinkModelForm(forms.ModelForm):
+ when = forms.DateField(widget=SelectDateWidget, required=False)
+
+
+class CKLinkModelAdmin(DjangoLinkAdmin):
+ form = LinkModelForm
+
+admin.site.register(TestModel)
+admin.site.register(LinkModel, CKLinkModelAdmin)
diff --git a/separate_users/tests/test_app/fixtures/test_app.json b/separate_users/tests/test_app/fixtures/test_app.json
new file mode 100644
index 0000000..b071f53
--- /dev/null
+++ b/separate_users/tests/test_app/fixtures/test_app.json
@@ -0,0 +1 @@
+[{"model": "test_app.testmodel", "pk": 1, "fields": {"title": "Test 2", "richtext": "
None
", "richtext_second": ""}}, {"model": "test_app.testmodel", "pk": 2, "fields": {"title": "Testing different Link Form Widgets", "richtext": "One Two Link One (Date Link, haha)
\r\n\r\nLink Two (Foreign Key)
\r\n\r\nwhat
", "richtext_second": "sdvasdva link
"}}]
\ No newline at end of file
diff --git a/separate_users/tests/test_app/models.py b/separate_users/tests/test_app/models.py
new file mode 100644
index 0000000..f0e2bb0
--- /dev/null
+++ b/separate_users/tests/test_app/models.py
@@ -0,0 +1,61 @@
+from __future__ import unicode_literals
+
+from django.core.urlresolvers import reverse
+from django.utils.encoding import python_2_unicode_compatible
+from django.db import models
+from ckeditor.fields import RichTextField
+# from djangocms_text_ckeditor.fields import HTMLField
+
+
+@python_2_unicode_compatible
+class TestModel(models.Model):
+ title = models.CharField(max_length=255, )
+ richtext = RichTextField(default='')
+ richtext_second = RichTextField(default='')
+
+ def __str__(self):
+ return "%s" % self.title
+
+ def get_absolute_url(self):
+ return reverse('testmodel_detail', args=(self.id, ))
+
+
+# @python_2_unicode_compatible
+# class CMSTestModel(models.Model):
+# title = models.CharField(max_length=255, )
+# richtext = HTMLField()
+#
+# def __str__(self):
+# return "%s" % self.title
+
+
+@python_2_unicode_compatible
+class LinkModelBase(models.Model):
+ target = models.CharField(max_length=255, blank=True, default='', )
+ external_url = models.CharField(max_length=255, blank=True, default='',)
+ email = models.EmailField(blank=True, default='',)
+ # http://stackoverflow.com/questions/12644142/prefill-a-datetimefield-from-url-in-django-admin
+ when = models.DateField(blank=True, null=True)
+ testmodel = models.ForeignKey(TestModel, null=True, default=None, blank=True)
+
+ class Meta:
+ abstract = True
+
+ def __str__(self):
+ return "LINK object: %s" % self.get_link()
+
+ def get_link(self):
+ if self.external_url:
+ return self.external_url
+ else:
+ return "http://no-link-given.com/"
+
+ def get_target(self):
+ return "_blank"
+
+ def get_css_class(self):
+ return "no-css-class"
+
+
+class LinkModel(LinkModelBase):
+ pass
diff --git a/separate_users/tests/test_app/views.py b/separate_users/tests/test_app/views.py
new file mode 100644
index 0000000..526428d
--- /dev/null
+++ b/separate_users/tests/test_app/views.py
@@ -0,0 +1,7 @@
+from django.views.generic import DetailView
+
+from .models import TestModel
+
+
+class TestModelDetailView(DetailView):
+ model = TestModel
diff --git a/separate_users/tests/test_editor.py b/separate_users/tests/test_editor.py
new file mode 100644
index 0000000..6b63656
--- /dev/null
+++ b/separate_users/tests/test_editor.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+from time import sleep
+
+from django.contrib.auth.models import User
+from django.core.urlresolvers import reverse
+from selenium.common.exceptions import NoSuchElementException
+from selenium.webdriver.support.expected_conditions import visibility_of
+from selenium.webdriver.support.wait import WebDriverWait
+
+from separate_users.tests.utils.selenium_utils import SeleniumTestCase, CustomWebDriver
+from separate_users.tests.test_app.models import TestModel, LinkModel
+
+
+class separate_usersEditorTests(SeleniumTestCase):
+ fixtures = ['test_app.json', ]
+ username = 'admin'
+ password = 'admin'
+
+ def setUp(self):
+ superuser = User.objects.create_superuser(self.username, 'admin@free.fr', self.password)
+ self.existing = TestModel.objects.get(pk=1)
+ # Instantiating the WebDriver will load your browser
+ self.wd = CustomWebDriver()
+
+ def tearDown(self):
+ self.wd.quit()
+
+ def test_app_index_get(self):
+ # if this fails, everything is probably broken.
+ self.login()
+ self.open(reverse('admin:index'))
+ self.wd.find_css(".app-test_app")
+
+ def test_editor_has_button_dialog_opens_has_form(self):
+ self.login()
+ sleep(1) # must be a better solution!
+ self.open(reverse('admin:test_app_testmodel_change', args=[self.existing.id]))
+ sleep(1) # argh
+ button = self.wd.wait_for_css(".cke_button__djangolink")
+ button[0].click()
+ dialog_title = self.wd.wait_for_css(".cke_dialog_title")
+ sleep(1) # argh
+ iframe = self.wd.find_css(".cke_dialog_ui_html")
+ self.wd.switch_to.frame(iframe)
+ target = self.wd.wait_for_css("#id_target")
+
+ def test_dialog_form_validation(self):
+ self.login()
+ sleep(1) # must be a better solution!
+ self.open(reverse('admin:test_app_testmodel_change', args=[self.existing.id]))
+ sleep(1) # argh
+ button = self.wd.wait_for_css(".cke_button__djangolink")
+ button[0].click()
+ self.wd.wait_for_css(".cke_dialog_title")
+ sleep(1) # argh
+ iframe = self.wd.find_css(".cke_dialog_ui_html")
+ self.wd.switch_to.frame(iframe)
+ email = self.wd.wait_for_css("#id_email")
+ email.send_keys('what-foo')
+ self.wd.switch_to.default_content()
+ ok = self.wd.wait_for_css(".cke_dialog_ui_button_ok")
+ ok.click()
+ self.wd.switch_to.frame(iframe)
+ self.wd.wait_for_css(".field-email .errorlist")
+ email.send_keys('root@example.com')
+ self.wd.switch_to.default_content()
+ ok = self.wd.wait_for_css(".cke_dialog_ui_button_ok")
+ ok.click()
+ sleep(1) # argh
+ try:
+ title = self.wd.find_css(".cke_dialog_title")
+ self.assertFalse(title.is_displayed())
+ except NoSuchElementException:
+ # ok if removed from the DOM!!
+ pass
+
+ def test_dialog_submit_and_link_attrs(self):
+ self.login()
+ self.open(reverse('admin:test_app_testmodel_change', args=[self.existing.id]))
+
+ def test_remove_foreign_key_attrs(self):
+ self.login()
+ self.open(reverse('admin:test_app_testmodel_change', args=[self.existing.id]))
\ No newline at end of file
diff --git a/separate_users/tests/test_templatetag.py b/separate_users/tests/test_templatetag.py
new file mode 100644
index 0000000..75d033b
--- /dev/null
+++ b/separate_users/tests/test_templatetag.py
@@ -0,0 +1,42 @@
+# -*- coding: utf-8 -*-
+from django.core.urlresolvers import reverse
+from django.test import Client
+from django.test import TestCase
+
+from separate_users.tests.test_app.models import TestModel, LinkModel
+
+
+class separate_usersDialogTests(TestCase):
+ fixtures = ['test_app.json', ]
+
+ def setUp(self):
+ self.test_object = TestModel.objects.get(pk=2)
+
+ def tearDown(self):
+ pass
+
+ def test_tag_link_target_class_value(self):
+ """
+ does it transform everything as it should?
+ """
+ client = Client()
+ url = reverse('testmodel_detail', args=[self.test_object.id])
+ response = client.get(url)
+ content = response.content
+ # check it!
+
+ def test_tag_no_destruction_of_existing_links(self):
+ """
+ normal existing \d+)/$', TestModelDetailView.as_view(), name='testmodel_detail'),
+]
+
+# if settings.DEBUG:
+# urlpatterns += [
+# url(r'^media/(?P.*)$', 'django.views.static.serve', {'document_root': settings.MEDIA_ROOT}),
+# ]
diff --git a/separate_users/tests/utils/__init__.py b/separate_users/tests/utils/__init__.py
new file mode 100644
index 0000000..b8c48bd
--- /dev/null
+++ b/separate_users/tests/utils/__init__.py
@@ -0,0 +1 @@
+__author__ = 'benzkji'
diff --git a/separate_users/tests/utils/django_utils.py b/separate_users/tests/utils/django_utils.py
new file mode 100644
index 0000000..f9a9f8c
--- /dev/null
+++ b/separate_users/tests/utils/django_utils.py
@@ -0,0 +1,8 @@
+from django.contrib.auth.models import User
+
+
+def create_superuser():
+ superuser = User.objects.create_superuser('admin',
+ 'admin@free.fr',
+ 'secret')
+ return superuser
diff --git a/separate_users/tests/utils/selenium_utils.py b/separate_users/tests/utils/selenium_utils.py
new file mode 100644
index 0000000..3eca316
--- /dev/null
+++ b/separate_users/tests/utils/selenium_utils.py
@@ -0,0 +1,55 @@
+from django.conf import settings
+from django.contrib.staticfiles.testing import StaticLiveServerTestCase
+from django.core.urlresolvers import reverse
+from selenium.common.exceptions import NoSuchElementException
+from selenium.webdriver.support.wait import WebDriverWait
+
+
+#determine the WebDriver module. default to Firefox
+try:
+ web_driver_module = settings.SELENIUM_WEBDRIVER
+except AttributeError:
+ from selenium.webdriver.firefox import webdriver as web_driver_module
+
+
+class SeleniumTestCase(StaticLiveServerTestCase):
+ """
+ A base test case for Selenium, providing hepler methods for generating
+ clients and logging in profiles.
+ """
+ def open(self, url):
+ self.wd.get("%s%s" % (self.live_server_url, url))
+
+ def login(self):
+ self.open(reverse('admin:index'))
+ # SeleniFIXTURESum knows it has to wait for page loads (except for AJAX requests)
+ # so we don't need to do anything about that, and can just
+ # call find_css. Since we can chain methods, we can
+ # call the built-in send_keys method right away to change the
+ # value of the field
+ self.wd.find_css('#id_username').send_keys(self.username)
+ # for the password, we can now just call find_css since we know the page
+ # has been rendered
+ self.wd.find_css("#id_password").send_keys(self.password)
+ # You're not limited to CSS selectors only, check
+ # http://seleniumhq.org/docs/03_webdriver.html for
+ # a more compreehensive documentation.
+ self.wd.find_element_by_xpath('//input[@type="submit"]').click()
+
+
+class CustomWebDriver(web_driver_module.WebDriver):
+ """Our own WebDriver with some helpers added"""
+
+ def find_css(self, css_selector):
+ """Shortcut to find elements by CSS. Returns either a list or singleton"""
+ elems = self.find_elements_by_css_selector(css_selector)
+ found = len(elems)
+ if found == 1:
+ return elems[0]
+ elif not elems:
+ raise NoSuchElementException(css_selector)
+ return elems
+
+ def wait_for_css(self, css_selector, timeout=7):
+ """ Shortcut for WebDriverWait"""
+ return WebDriverWait(self, timeout).until(lambda driver : driver.find_css(css_selector))
\ No newline at end of file
diff --git a/setup.cfg b/setup.cfg
new file mode 100644
index 0000000..e0e6708
--- /dev/null
+++ b/setup.cfg
@@ -0,0 +1,3 @@
+[flake8]
+ignore = F999,E501,E128,E124
+exclude = .git,*/migrations/*,*/static/CACHE/*,*/south_migrations/*
diff --git a/setup.py b/setup.py
new file mode 100755
index 0000000..51a7c34
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,39 @@
+# coding: utf-8
+from setuptools import setup, find_packages
+import os
+
+# not so bad: http://joebergantine.com/blog/2015/jul/17/releasing-package-pypi/
+version = __import__('separate_users').__version__
+
+
+def read(fname):
+ # read the contents of a text file
+ return open(os.path.join(os.path.dirname(__file__), fname)).read()
+
+setup(
+ name="django-separate-users",
+ version=version,
+ url='http://github.com/bnzk/django-separate-users',
+ license='MIT',
+ platforms=['OS Independent'],
+ description="separate staff and non staff users with two proxy models",
+ long_description=read('README.rst'),
+ author=u'Ben Stähli',
+ author_email='bnzk@bnzk.ch',
+ packages=find_packages(),
+ install_requires=(
+ # 'Django>=1.3,<1.5', # no need to limit while in development
+ 'Django>=1.8',
+ ),
+ include_package_data=True,
+ zip_safe=False,
+ classifiers=[
+ 'Development Status :: 4 - Beta',
+ 'Framework :: Django',
+ 'Intended Audience :: Developers',
+ 'License :: OSI Approved :: MIT License',
+ 'Operating System :: OS Independent',
+ 'Programming Language :: Python',
+ 'Topic :: Internet :: WWW/HTTP',
+ ],
+)
diff --git a/test_coverage.sh b/test_coverage.sh
new file mode 100755
index 0000000..58bcd3c
--- /dev/null
+++ b/test_coverage.sh
@@ -0,0 +1,2 @@
+coverage run --source='separate_users' ./manage.py test
+coverage report
diff --git a/test_requirements.txt b/test_requirements.txt
new file mode 100644
index 0000000..7602156
--- /dev/null
+++ b/test_requirements.txt
@@ -0,0 +1,14 @@
+# not required by setup.py..
+tox
+coverage
+django-coverage
+flake8
+factory_boy
+mock
+selenium
+
+django==1.9
+django-ckeditor==5.1.1
+
+lxml
+cssselect
\ No newline at end of file
diff --git a/tox.ini b/tox.ini
new file mode 100644
index 0000000..70c99f8
--- /dev/null
+++ b/tox.ini
@@ -0,0 +1,36 @@
+
+[tox]
+envlist = django18, django19, django110
+
+[testenv]
+commands = python manage.py test
+setenv =
+ DJANGO_SETTINGS_MODULE=separate_users.tests.settings_test
+ PYTHONPATH={toxinidir}
+
+[base]
+deps =
+ coverage
+ django-coverage
+ factory_boy
+ mock
+ selenium
+ lxml
+ cssselect
+ django-ckeditor==5.1.1
+ djangocms-text-ckeditor
+
+[testenv:django18]
+deps =
+ django>=1.8, <1.9
+ {[base]deps}
+
+[testenv:django19]
+deps =
+ django>=1.9, <1.10
+ {[base]deps}
+
+[testenv:django110]
+deps =
+ django>=1.10, <1.11
+ {[base]deps}
\ No newline at end of file