Merge pull request #1333 from fyfe/upgrade-django

Upgrade Django (Django-1.10 no longer supported)
This commit is contained in:
Antoine Nguyen
2017-12-21 09:46:57 +01:00
committed by GitHub
70 changed files with 337 additions and 278 deletions
+20 -13
View File
@@ -1,10 +1,19 @@
sudo: false
language: python
cache: pip
python:
- "2.7"
- "3.4"
- "3.5"
- "3.6"
env:
global:
- PYTHONWARNINGS="default,ignore::PendingDeprecationWarning,ignore::ResourceWarning"
matrix:
- DB="POSTGRESQL"
- DB="MYSQL"
sudo: false
addons:
apt:
packages:
@@ -12,30 +21,28 @@ addons:
- postfix
- slapd
env:
- DB="POSTGRESQL"
- DB="MYSQL"
cache: pip
services:
- mysql
- postgres
- mysql
before_install:
- pip install codecov
- if [[ $DB = 'POSTGRESQL' ]]; then pip install -q psycopg2; fi
- if [[ $DB = 'MYSQL' ]]; then pip install -q mysqlclient; fi
- if [[ $DB = "POSTGRESQL" ]]; then pip install -q psycopg2; fi
- if [[ $DB = "MYSQL" ]]; then pip install -q mysqlclient; fi
install:
- pip install -q -r requirements.txt
- pip install -q -r ldap-requirements.txt
- pip install -q -r test-requirements.txt
- pip install -e .
- python setup.py -q develop
before_script:
- if [[ $DB = 'POSTGRESQL' ]]; then psql -c 'create database modoboa_test;' -U postgres; fi
- if [[ $DB = 'MYSQL' ]]; then mysql -e "create database IF NOT EXISTS modoboa_test;" -uroot; fi
- if [[ $DB = 'MYSQL' ]]; then mysql -e "CREATE USER 'modoboa'@'localhost' IDENTIFIED BY 'modoboa'" -uroot; fi
- if [[ $DB = 'MYSQL' ]]; then mysql -e "GRANT ALL PRIVILEGES ON * . * TO 'modoboa'@'localhost';" -uroot; fi
- if [[ $DB = "POSTGRESQL" ]]; then psql -c "CREATE DATABASE modoboa_test;" -U postgres; fi
- if [[ $DB = "MYSQL" ]]; then mysql -e "CREATE DATABASE IF NOT EXISTS modoboa_test;" -uroot; fi
- if [[ $DB = "MYSQL" ]]; then mysql -e "CREATE USER 'modoboa'@'localhost' IDENTIFIED BY 'modoboa'" -uroot; fi
- if [[ $DB = "MYSQL" ]]; then mysql -e "GRANT ALL PRIVILEGES ON * . * TO 'modoboa'@'localhost';" -uroot; fi
- mkdir /tmp/slapd
- slapd -f test_data/slapd.conf -h ldap://localhost:3389 &
- sleep 3
+1 -1
View File
@@ -1 +1 @@
django-auth-ldap>=1.2.13
django-auth-ldap>=1.3.0
+1 -3
View File
@@ -6,7 +6,7 @@ from collections import OrderedDict
from functools import reduce
from django import forms
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.http import QueryDict
from django.utils.translation import ugettext as _, ugettext_lazy
@@ -607,8 +607,6 @@ class AccountWizard(WizardForm):
})
def done(self):
from modoboa.lib.web_utils import render_to_json_response
account = self.first_step.form.save()
account.post_create(self.request.user)
mailform = self.steps[1].form
+1 -1
View File
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
from functools import reduce
from django import forms
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.http import QueryDict
from django.utils.translation import ugettext as _, ugettext_lazy
from django.utils.encoding import force_text
+1 -1
View File
@@ -2,7 +2,7 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.db.models import signals
from django.dispatch import receiver
from django.utils.translation import ugettext as _
+12 -12
View File
@@ -31,8 +31,8 @@ class Migration(migrations.Migration):
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('address', models.EmailField(max_length=75)),
('alias', models.ForeignKey(to='admin.Alias')),
('r_alias', models.ForeignKey(related_name='alias_recipient_aliases', blank=True, to='admin.Alias', null=True)),
('alias', models.ForeignKey(to='admin.Alias', on_delete=models.CASCADE)),
('r_alias', models.ForeignKey(related_name='alias_recipient_aliases', blank=True, to='admin.Alias', null=True, on_delete=models.CASCADE)),
],
options={
'db_table': 'modoboa_admin_aliasrecipient',
@@ -85,7 +85,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('type', models.CharField(max_length=20, choices=[(b'rename', b'rename'), (b'delete', b'delete')])),
('argument', models.TextField()),
('mailbox', models.ForeignKey(blank=True, to='admin.Mailbox', null=True)),
('mailbox', models.ForeignKey(blank=True, to='admin.Mailbox', null=True, on_delete=models.CASCADE)),
],
options={
},
@@ -116,43 +116,43 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='mailbox',
name='dates',
field=models.ForeignKey(to='admin.ObjectDates'),
field=models.ForeignKey(to='admin.ObjectDates', on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AddField(
model_name='mailbox',
name='domain',
field=models.ForeignKey(to='admin.Domain'),
field=models.ForeignKey(to='admin.Domain', on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AddField(
model_name='mailbox',
name='user',
field=models.OneToOneField(to=settings.AUTH_USER_MODEL),
field=models.OneToOneField(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AddField(
model_name='domainalias',
name='dates',
field=models.ForeignKey(to='admin.ObjectDates'),
field=models.ForeignKey(to='admin.ObjectDates', on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AddField(
model_name='domainalias',
name='target',
field=models.ForeignKey(verbose_name='target', to='admin.Domain', help_text='The domain this alias points to'),
field=models.ForeignKey(verbose_name='target', to='admin.Domain', help_text='The domain this alias points to', on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AddField(
model_name='domain',
name='dates',
field=models.ForeignKey(to='admin.ObjectDates'),
field=models.ForeignKey(to='admin.ObjectDates', on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AddField(
model_name='aliasrecipient',
name='r_mailbox',
field=models.ForeignKey(blank=True, to='admin.Mailbox', null=True),
field=models.ForeignKey(blank=True, to='admin.Mailbox', null=True, on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AlterUniqueTogether(
@@ -162,13 +162,13 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='alias',
name='dates',
field=models.ForeignKey(to='admin.ObjectDates'),
field=models.ForeignKey(to='admin.ObjectDates', on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AddField(
model_name='alias',
name='domain',
field=models.ForeignKey(to='admin.Domain', null=True),
field=models.ForeignKey(to='admin.Domain', null=True, on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AlterUniqueTogether(
+7 -5
View File
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import hashlib
import random
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.db import models
from django.utils.encoding import (
python_2_unicode_compatible, smart_text, force_str, force_bytes
@@ -37,7 +37,7 @@ class Alias(AdminObject):
"The alias address."
)
)
domain = models.ForeignKey(Domain, null=True)
domain = models.ForeignKey(Domain, null=True, on_delete=models.CASCADE)
enabled = models.BooleanField(
ugettext_lazy("enabled"),
help_text=ugettext_lazy("Check to activate this alias"),
@@ -210,13 +210,15 @@ class AliasRecipient(models.Model):
"""An alias recipient."""
address = models.EmailField()
alias = models.ForeignKey(Alias)
alias = models.ForeignKey(Alias, on_delete=models.CASCADE)
# if recipient is a local mailbox
r_mailbox = models.ForeignKey(Mailbox, blank=True, null=True)
r_mailbox = models.ForeignKey(Mailbox, blank=True, null=True,
on_delete=models.CASCADE)
# if recipient is a local alias
r_alias = models.ForeignKey(
Alias, related_name="alias_recipient_aliases", blank=True, null=True)
Alias, related_name="alias_recipient_aliases", blank=True, null=True,
on_delete=models.CASCADE)
class Meta:
app_label = "admin"
+2 -1
View File
@@ -40,7 +40,8 @@ class DomainAlias(AdminObject):
help_text=ugettext_lazy("The alias name"))
target = models.ForeignKey(
Domain, verbose_name=ugettext_lazy('target'),
help_text=ugettext_lazy("The domain this alias points to")
help_text=ugettext_lazy("The domain this alias points to"),
on_delete=models.CASCADE
)
enabled = models.BooleanField(
ugettext_lazy('enabled'),
+5 -4
View File
@@ -100,8 +100,8 @@ class Mailbox(AdminObject):
)
quota = models.PositiveIntegerField(default=0)
use_domain_quota = models.BooleanField(default=False)
domain = models.ForeignKey(Domain)
user = models.OneToOneField(User)
domain = models.ForeignKey(Domain, on_delete=models.CASCADE)
user = models.OneToOneField(User, on_delete=models.CASCADE)
objects = MailboxManager()
@@ -354,7 +354,7 @@ class SenderAddress(models.Model):
"""Extra sender address for Mailbox."""
address = models.EmailField()
mailbox = models.ForeignKey(Mailbox)
mailbox = models.ForeignKey(Mailbox, on_delete=models.CASCADE)
class Meta:
app_label = "admin"
@@ -373,7 +373,8 @@ reversion.register(SenderAddress)
class MailboxOperation(models.Model):
"""An operation on a mailbox."""
mailbox = models.ForeignKey(Mailbox, blank=True, null=True)
mailbox = models.ForeignKey(Mailbox, blank=True, null=True,
on_delete=models.CASCADE)
type = models.CharField(
max_length=20, choices=(('rename', 'rename'), ('delete', 'delete'))
)
+5 -5
View File
@@ -37,14 +37,14 @@ class MXRecordManager(models.Manager):
if records.exists():
for record in records:
yield record
raise StopIteration()
return
self.get_queryset().filter(domain=domain).delete()
delta = datetime.timedelta(seconds=ttl)
domain_mxs = lib.get_domain_mx_list(domain.name)
if len(domain_mxs) == 0:
raise StopIteration
return
for mx_addr, mx_ip_addr in domain_mxs:
record = self.get_queryset().create(
domain=domain,
@@ -58,7 +58,7 @@ class MXRecordManager(models.Manager):
class MXRecord(models.Model):
"""A model used to store MX records for Domain."""
domain = models.ForeignKey("admin.Domain")
domain = models.ForeignKey("admin.Domain", on_delete=models.CASCADE)
name = models.CharField(max_length=254)
address = models.GenericIPAddressField()
managed = models.BooleanField(default=False)
@@ -86,9 +86,9 @@ class DNSBLQuerySet(models.QuerySet):
class DNSBLResult(models.Model):
"""Store a DNSBL query result."""
domain = models.ForeignKey("admin.Domain")
domain = models.ForeignKey("admin.Domain", on_delete=models.CASCADE)
provider = models.CharField(max_length=254, db_index=True)
mx = models.ForeignKey(MXRecord)
mx = models.ForeignKey(MXRecord, on_delete=models.CASCADE)
status = models.CharField(max_length=45, blank=True, db_index=True)
objects = models.Manager.from_queryset(DNSBLQuerySet)()
+1 -1
View File
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
from functools import reduce
from django import template
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.template.loader import render_to_string
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _, ugettext_lazy
+1 -1
View File
@@ -4,7 +4,7 @@ from __future__ import unicode_literals
from unittest import skipIf
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.test import override_settings
from modoboa.core import factories as core_factories
+1 -1
View File
@@ -4,7 +4,7 @@ from __future__ import unicode_literals
"""Admin test cases."""
from django.core.urlresolvers import reverse
from django.urls import reverse
from modoboa.core.models import User
from modoboa.lib.tests import ModoTestCase
+1 -1
View File
@@ -9,7 +9,7 @@ import json
import dns.resolver
from mock import patch
from django.core.urlresolvers import reverse
from django.urls import reverse
from rest_framework.authtoken.models import Token
+1 -1
View File
@@ -7,7 +7,7 @@ from __future__ import unicode_literals
import dns.resolver
from mock import patch
from django.core.urlresolvers import reverse
from django.urls import reverse
from modoboa.core import factories as core_factories
from modoboa.core.models import User
+1 -1
View File
@@ -2,7 +2,7 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse
from django.urls import reverse
from modoboa.lib.tests import ModoTestCase
+1 -1
View File
@@ -4,7 +4,7 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.utils.encoding import force_text
from modoboa.lib.tests import ModoTestCase
+1 -1
View File
@@ -6,7 +6,7 @@ from mock import patch
import dns.resolver
from django.core.files.base import ContentFile
from django.core.urlresolvers import reverse
from django.urls import reverse
from modoboa.core import factories as core_factories
from modoboa.core.models import User
@@ -9,7 +9,7 @@ import tempfile
import mock
from django.core.management import call_command
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.test import override_settings
from modoboa.lib.tests import ModoTestCase
+1 -1
View File
@@ -6,7 +6,7 @@ from mock import patch
from django.core import mail
from django.core import management
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.test import override_settings
from modoboa.core import factories as core_factories
+1 -1
View File
@@ -1,6 +1,6 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse
from django.urls import reverse
from modoboa.core.models import User
from modoboa.lib.tests import ModoTestCase
+1 -1
View File
@@ -2,7 +2,7 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse
from django.urls import reverse
from modoboa.core.models import User
from modoboa.lib.tests import ModoTestCase
+1 -1
View File
@@ -2,7 +2,7 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.db import IntegrityError
from django.shortcuts import render
from django.utils.translation import ugettext as _, ungettext
+1 -1
View File
@@ -4,7 +4,7 @@ from __future__ import unicode_literals
from functools import reduce
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.db.models import Sum
from django.http import HttpResponseRedirect
from django.shortcuts import render
+1 -1
View File
@@ -9,7 +9,7 @@ from rfc6266 import build_header
from django.contrib.auth.decorators import (
login_required, permission_required, user_passes_test
)
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.http import HttpResponse
from django.shortcuts import render
from django.utils.translation import ugettext as _
+1 -1
View File
@@ -9,7 +9,7 @@ from io import StringIO
from django.contrib.auth.decorators import (
login_required, permission_required, user_passes_test
)
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.db import transaction
from django.shortcuts import render
from django.utils.translation import ugettext as _
+2 -2
View File
@@ -11,7 +11,7 @@ from django.contrib.auth import password_validation
from modoboa.lib import fields as lib_fields
from modoboa.lib.cryptutils import random_key
from modoboa.lib.form_utils import (
YesNoField, SeparatorField, InlineRadioSelect
YesNoField, SeparatorField, HorizontalRadioSelect
)
from modoboa.parameters import forms as param_forms
from modoboa.parameters import tools as param_tools
@@ -44,7 +44,7 @@ class GeneralParametersForm(param_forms.AdminParametersForm):
('ldap', "LDAP")],
initial="local",
help_text=ugettext_lazy("The backend used for authentication"),
widget=InlineRadioSelect
widget=HorizontalRadioSelect()
)
password_scheme = forms.ChoiceField(
+1 -1
View File
@@ -28,7 +28,7 @@ from modoboa.core.commands import Command
from modoboa.lib.api_client import ModoAPIClient
if sys.version_info < (3, 0, 0):
input = raw_input
input = raw_input
DBCONN_TPL = """
'{{ conn_name }}': {
+22 -17
View File
@@ -1,26 +1,31 @@
"""
Django settings for {{ name }} project.
Generated by 'django-admin startproject' using Django 1.11.8.
For more information on this file, see
https://docs.djangoproject.com/en/1.6/topics/settings/
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.6/ref/settings/
https://docs.djangoproject.com/en/1.11/ref/settings/
"""
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
from logging.handlers import SysLogHandler
from __future__ import unicode_literals
from logging.handlers import SysLogHandler
import os
{% if devmode %}
from modoboa.core.dev_settings import *
from modoboa.core.dev_settings import * # noqa
{% endif %}
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.realpath(os.path.dirname(os.path.dirname(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '{{ secret_key }}'
@@ -29,7 +34,7 @@ SECRET_KEY = '{{ secret_key }}'
DEBUG = {{ devmode }}
ALLOWED_HOSTS = [
'{{ allowed_host }}'
'{{ allowed_host }}',
]
SITE_ID = 1
@@ -76,7 +81,7 @@ INSTALLED_APPS += MODOBOA_APPS
AUTH_USER_MODEL = 'core.User'
MIDDLEWARE_CLASSES = (
MIDDLEWARE = (
'x_forwarded_for.middleware.XForwardedForMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
@@ -131,14 +136,14 @@ WSGI_APPLICATION = '{{ name }}.wsgi.application'
# Database
# https://docs.djangoproject.com/en/1.6/ref/settings/#databases
# https://docs.djangoproject.com/en/1.11/ref/settings/#databases
DATABASES = {
{% for conn in db_connections.values %}{{ conn|safe }}{% endfor %}
}
# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = '{{ lang }}'
@@ -150,9 +155,8 @@ USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.6/howto/static-files/
# https://docs.djangoproject.com/en/1.11/howto/static-files/
STATIC_URL = '/sitestatic/'
STATIC_ROOT = os.path.join(BASE_DIR, 'sitestatic')
@@ -173,13 +177,14 @@ REST_FRAMEWORK = {
}
# Modoboa settings
#MODOBOA_CUSTOM_LOGO = os.path.join(MEDIA_URL, "custom_logo.png")
# MODOBOA_CUSTOM_LOGO = os.path.join(MEDIA_URL, "custom_logo.png")
#DOVECOT_LOOKUP_PATH = ('/path/to/dovecot', )
# DOVECOT_LOOKUP_PATH = ('/path/to/dovecot', )
MODOBOA_API_URL = 'https://api.modoboa.org/1/'
# Password validation rules
# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
@@ -276,5 +281,5 @@ try:
from {{ extension }} import settings as {{ extension }}_settings
{{ extension }}_settings.apply(globals())
except AttributeError:
from {{ extension }}.settings import *
from {{ extension }}.settings import * # noqa
{% endfor %}
+4 -7
View File
@@ -4,7 +4,7 @@ from __future__ import unicode_literals
import logging
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.db.models import signals
from django.dispatch import receiver
from django.utils.encoding import smart_text
@@ -13,6 +13,7 @@ from django.utils.translation import ugettext as _
from django.contrib.sites import models as sites_models
from reversion import revisions as reversion
from reversion.models import Version
from modoboa.lib import exceptions
from modoboa.lib import permissions
@@ -32,14 +33,12 @@ def post_revision_commit(sender, **kwargs):
django-reversion for that.
"""
from modoboa.lib.signals import get_request
current_user = get_request().user.username
logger = logging.getLogger("modoboa.admin")
for version in kwargs["versions"]:
if version.object is None:
continue
prev_revisions = reversion.get_for_object(version.object)
prev_revisions = Version.objects.get_for_object(version.object)
if prev_revisions.count() == 1:
action = _("added")
level = "info"
@@ -60,11 +59,9 @@ def log_object_removal(sender, instance, **kwargs):
We want to know who was responsible for an object deletion.
"""
from reversion.models import Version
if not reversion.is_registered(sender):
return
del_list = reversion.get_deleted(sender)
del_list = Version.objects.get_deleted(sender)
try:
version = del_list.get(object_id=instance.id)
except Version.DoesNotExist:
+3 -1
View File
@@ -2,10 +2,12 @@
from __future__ import unicode_literals
from django.utils.deprecation import MiddlewareMixin
from . import models
class LocalConfigMiddleware(object):
class LocalConfigMiddleware(MiddlewareMixin):
"""A middleware to inject LocalConfig into request."""
def process_request(self, request):
+2 -2
View File
@@ -67,8 +67,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('object_id', models.PositiveIntegerField()),
('is_owner', models.BooleanField(default=False)),
('content_type', models.ForeignKey(to='contenttypes.ContentType')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('content_type', models.ForeignKey(to='contenttypes.ContentType', on_delete=models.CASCADE)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
],
options={
},
+4 -4
View File
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
from email.header import Header
import re
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.db import models
from django.utils.encoding import (
python_2_unicode_compatible, smart_bytes, smart_text, force_str
@@ -407,8 +407,8 @@ def populate_callback(user, group="SimpleUsers"):
@python_2_unicode_compatible
class ObjectAccess(models.Model):
user = models.ForeignKey(User)
content_type = models.ForeignKey(ContentType)
user = models.ForeignKey(User, on_delete=models.CASCADE)
content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
object_id = models.PositiveIntegerField()
content_object = GenericForeignKey('content_type', 'object_id')
is_owner = models.BooleanField(default=False)
@@ -435,7 +435,7 @@ class LocalConfig(models.Model):
"""Store instance configuration here."""
api_pk = models.PositiveIntegerField(null=True)
site = models.ForeignKey("sites.Site")
site = models.ForeignKey("sites.Site", on_delete=models.CASCADE)
# API results cache
api_versions = jsonfield.JSONField()
+7 -4
View File
@@ -34,7 +34,8 @@ class BLFCRYPTHasher(PasswordHasher):
# rounds = parameters.get_global_parameter("rounds_number")
# To get around this, I use the default of 12.
rounds = 12
return bcrypt.encrypt(clearvalue, rounds=rounds)
bcrypt.using(rounds=rounds)
return bcrypt.hash(clearvalue)
def verify(self, clearvalue, hashed_value):
return bcrypt.verify(clearvalue, hashed_value)
@@ -55,7 +56,7 @@ class MD5CRYPTHasher(PasswordHasher):
return pwhash
def _encrypt(self, clearvalue, salt=None):
return md5_crypt.encrypt(clearvalue)
return md5_crypt.hash(clearvalue)
def verify(self, clearvalue, hashed_value):
return md5_crypt.verify(clearvalue, hashed_value)
@@ -78,7 +79,8 @@ class SHA256CRYPTHasher(PasswordHasher):
def _encrypt(self, clearvalue, salt=None):
rounds = param_tools.get_global_parameter("rounds_number")
return sha256_crypt.encrypt(clearvalue, rounds=rounds)
sha256_crypt.using(rounds=rounds)
return sha256_crypt.hash(clearvalue)
def verify(self, clearvalue, hashed_value):
return sha256_crypt.verify(clearvalue, hashed_value)
@@ -101,7 +103,8 @@ class SHA512CRYPTHasher(PasswordHasher):
def _encrypt(self, clearvalue, salt=None):
rounds = param_tools.get_global_parameter("rounds_number")
return sha512_crypt.encrypt(clearvalue, rounds=rounds)
sha512_crypt.using(rounds=rounds)
return sha512_crypt.hash(clearvalue)
def verify(self, clearvalue, hashed_value):
return sha512_crypt.verify(clearvalue, hashed_value)
+2 -2
View File
@@ -10,7 +10,7 @@ import re
from django import template
from django.conf import settings
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.template.loader import render_to_string
from django.utils import timezone
from django.utils.encoding import smart_text
@@ -158,7 +158,7 @@ def colorize_level(level):
@register.filter
def tohtml(message):
"""Simple tag to format a text using HTML."""
return re.sub(r"'(.*?)'", "<strong>\g<1></strong>", message)
return re.sub(r"'(.*?)'", r"<strong>\g<1></strong>", message)
@register.simple_tag
+1 -1
View File
@@ -10,7 +10,7 @@ from unittest import skipIf
from mock import patch
from django.core import mail
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.test import override_settings
from modoboa.lib.tests import ModoTestCase
+1 -1
View File
@@ -8,7 +8,7 @@ from dateutil.relativedelta import relativedelta
from six import StringIO
from django.core import management
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.test import TestCase
from django.utils import timezone
+1 -1
View File
@@ -4,7 +4,7 @@ from __future__ import unicode_literals
from unittest import skipIf
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.test import override_settings
from django.utils.functional import cached_property
+1 -1
View File
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
from testfixtures import compare
from django import forms
from django.core.urlresolvers import reverse
from django.urls import reverse
from modoboa.lib.tests import ModoTestCase
from modoboa.parameters import forms as param_forms
+1 -1
View File
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
import logging
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.http import HttpResponse, HttpResponseRedirect
from django.template.loader import render_to_string
from django.utils import translation
+1 -1
View File
@@ -2,7 +2,7 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.utils.http import is_safe_url
from django.views import generic
+3 -3
View File
@@ -29,9 +29,9 @@ class SMTPBackend(object):
smtp.login(username, password)
except smtplib.SMTPException:
return None
return self.get_or_create_user(username)
return self.get_or_build_user(username)
def get_or_create_user(self, username):
def get_or_build_user(self, username):
"""Get a user or create it the first time.
.. note::
@@ -71,7 +71,7 @@ try:
self.global_params = dict(
param_tools.get_global_parameters("core"))
def get_or_create_user(self, username, ldap_user):
def get_or_build_user(self, username, ldap_user):
"""
This must return a (User, created) 2-tuple for the given
LDAP user. username is the Django-friendly username of
+8 -41
View File
@@ -11,12 +11,8 @@ import re
from django.forms import TypedChoiceField
from django.forms.fields import Field
from django.forms.widgets import RadioSelect
from django.forms.widgets import RadioChoiceInput
from django.shortcuts import render
from django.utils.encoding import (
python_2_unicode_compatible, force_text, force_str)
from django.utils.html import conditional_escape
from django.utils.safestring import mark_safe
from django.utils.encoding import force_str
from django.utils.translation import ugettext as _, ugettext_lazy
from modoboa.lib.exceptions import BadRequest
@@ -198,6 +194,9 @@ class DynamicForm(object):
"""
fields = {}
data = {}
def _create_field(self, typ, name, value=None, pos=None):
"""Create a new form field.
"""
@@ -371,41 +370,9 @@ class TabForms(object):
#
@python_2_unicode_compatible
class CustomRadioInput(RadioChoiceInput):
"""Custom radio input."""
def __str__(self):
if "id" in self.attrs:
label_for = ' for="%s"' % self.attrs["id"]
else:
label_for = ""
choice_label = conditional_escape(force_text(self.choice_label))
return mark_safe(
"<label class='radio-inline' %s>%s %s</label>"
% (label_for, self.tag(), choice_label)
)
class InlineRadioRenderer(RadioSelect.renderer):
"""Custom inline radio renderer."""
def __iter__(self):
for i, choice in enumerate(self.choices):
yield CustomRadioInput(
self.name, self.value, self.attrs.copy(), choice, i
)
def render(self):
return mark_safe(
u"\n".join([u"%s\n" % force_text(w) for w in self])
)
class InlineRadioSelect(RadioSelect):
"""Custom inline radio widget."""
renderer = InlineRadioRenderer
class HorizontalRadioSelect(RadioSelect):
template_name = "common/horizontal_select.html"
option_template_name = "common/horizontal_select_option.html"
class SeparatorField(Field):
@@ -426,7 +393,7 @@ class YesNoField(TypedChoiceField):
(True, ugettext_lazy("Yes")),
(False, ugettext_lazy("No"))
),
"widget": InlineRadioSelect,
"widget": HorizontalRadioSelect(),
"coerce": lambda x: x == "True"
})
super(YesNoField, self).__init__(*args, **kwargs)
+4 -3
View File
@@ -6,6 +6,7 @@ from __future__ import unicode_literals
from django.http import HttpResponseRedirect
from django.utils.encoding import smart_text
from django.utils.deprecation import MiddlewareMixin
from modoboa.lib.exceptions import ModoboaException
from modoboa.lib import signals as lib_signals
@@ -14,7 +15,7 @@ from modoboa.lib.web_utils import (
)
class AjaxLoginRedirect(object):
class AjaxLoginRedirect(MiddlewareMixin):
def process_response(self, request, response):
if request.is_ajax():
@@ -23,7 +24,7 @@ class AjaxLoginRedirect(object):
return response
class CommonExceptionCatcher(object):
class CommonExceptionCatcher(MiddlewareMixin):
"""Modoboa exceptions catcher."""
def process_exception(self, request, exception):
@@ -44,7 +45,7 @@ class CommonExceptionCatcher(object):
)
class RequestCatcherMiddleware(object):
class RequestCatcherMiddleware(MiddlewareMixin):
"""Simple middleware to store the current request."""
def process_request(self, request):
+1 -1
View File
@@ -29,7 +29,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=255)),
('value', models.CharField(max_length=255)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
],
options={
},
-2
View File
@@ -51,8 +51,6 @@ def grant_access_to_object(user, obj, is_owner=False):
:param obj: an admin. object (Domain, Mailbox, ...)
:param is_owner: the user is the unique object's owner
"""
from modoboa.core.models import User
ct = ContentType.objects.get_for_model(obj)
entry, created = ObjectAccess.objects.get_or_create(
user=user, content_type=ct, object_id=obj.id)
+7 -4
View File
@@ -34,6 +34,7 @@ class HostnameValidator(object):
if not self.regex.match(value):
raise ValidationError(self.message, self.code)
validate_hostname = HostnameValidator()
@@ -42,15 +43,16 @@ class UTF8EmailValidator(EmailValidator):
"""Validator for addresses using non-ASCII characters."""
# unicode letters range (must be a unicode string, not a raw string)
ul = u"\u00a1-\uffff"
ascii_set = u"-!#$%&'*+/=?^_`{}|~0-9A-Z"
ul = "\u00a1-\uffff"
ascii_set = "-!#$%&'*+/=?^_`{}|~0-9A-Z"
user_regex_raw = (
# dot-atom
r"^[" + ascii_set + ul + "]+(\.[" + ascii_set + ul + "]+)*\Z"
r"^[" + ascii_set + ul + r"]+(\.[" + ascii_set + ul + r"]+)*\Z"
# quoted-string
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]|\\[\001-\011\013\014\016-\177])*"\Z)'
)
user_regex = re.compile("(" + user_regex_raw, re.IGNORECASE)
user_regex = re.compile(r"(" + user_regex_raw, re.IGNORECASE)
validate_utf8_email = UTF8EmailValidator()
@@ -62,4 +64,5 @@ class UTF8AndEmptyUserEmailValidator(UTF8EmailValidator):
user_regex = re.compile(
r"(^$|" + UTF8EmailValidator.user_regex_raw, re.IGNORECASE)
validate_utf8_and_empty_user_email = UTF8AndEmptyUserEmailValidator()
+2 -2
View File
@@ -114,9 +114,9 @@ def size2integer(value):
:param value: the string to convert
:return: the corresponding integer value
"""
m = re.match("(\d+)\s*(\w+)", value)
m = re.match(r"(\d+)\s*(\w+)", value)
if m is None:
if re.match("\d+", value):
if re.match(r"\d+", value):
return int(value)
return 0
if m.group(2)[0] in ["K", "k"]:
+2 -2
View File
@@ -29,7 +29,7 @@ class Migration(migrations.Migration):
name='LimitsPool',
fields=[
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL)),
('user', models.OneToOneField(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
],
options={
'db_table': 'limits_limitspool',
@@ -39,7 +39,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='limit',
name='pool',
field=models.ForeignKey(to='limits.LimitsPool'),
field=models.ForeignKey(to='limits.LimitsPool', on_delete=models.CASCADE),
preserve_default=True,
),
migrations.AlterUniqueTogether(
@@ -58,8 +58,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=254)),
('max_value', models.IntegerField(default=-2)),
('content_type', models.ForeignKey(to='contenttypes.ContentType')),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL)),
('content_type', models.ForeignKey(to='contenttypes.ContentType', on_delete=models.CASCADE)),
('user', models.ForeignKey(to=settings.AUTH_USER_MODEL, on_delete=models.CASCADE)),
],
),
migrations.AlterUniqueTogether(
@@ -33,7 +33,7 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('name', models.CharField(max_length=254)),
('max_value', models.IntegerField(default=0)),
('domain', models.ForeignKey(to='admin.Domain')),
('domain', models.ForeignKey(to='admin.Domain', on_delete=models.CASCADE)),
],
bases=(modoboa.limits.models.ObjectLimitMixin, models.Model),
),
+4 -3
View File
@@ -69,9 +69,10 @@ class ObjectLimitMixin(object):
class UserObjectLimit(ObjectLimitMixin, models.Model):
"""Object level limit."""
user = models.ForeignKey(settings.AUTH_USER_MODEL)
user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
name = models.CharField(max_length=254)
content_type = models.ForeignKey("contenttypes.ContentType")
content_type = models.ForeignKey("contenttypes.ContentType",
on_delete=models.CASCADE)
max_value = models.IntegerField(default=0)
class Meta(object):
@@ -132,7 +133,7 @@ class UserObjectLimit(ObjectLimitMixin, models.Model):
class DomainObjectLimit(ObjectLimitMixin, models.Model):
"""Per-domain limits on object creation."""
domain = models.ForeignKey("admin.Domain")
domain = models.ForeignKey("admin.Domain", on_delete=models.CASCADE)
name = models.CharField(max_length=254)
max_value = models.IntegerField(default=0)
+1 -1
View File
@@ -5,7 +5,7 @@ from __future__ import unicode_literals
from testfixtures import compare
from django.core.urlresolvers import reverse
from django.urls import reverse
from rest_framework.authtoken.models import Token
+1 -1
View File
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse
from django.urls import reverse
from modoboa.admin import factories as admin_factories
from modoboa.admin.models import Domain
+1 -1
View File
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
from django.core.files.base import ContentFile
from django.core.urlresolvers import reverse
from django.urls import reverse
from modoboa.admin import factories as admin_factories
from modoboa.admin import models as admin_models
+1 -1
View File
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse
from django.urls import reverse
from modoboa.admin.factories import populate_database
from modoboa.admin.models import Alias, Domain
@@ -17,8 +17,8 @@ class Migration(migrations.Migration):
('id', models.AutoField(verbose_name='ID', serialize=False, auto_created=True, primary_key=True)),
('target_host', models.CharField(help_text='Remote destination of this domain', max_length=255, verbose_name='target host')),
('verify_recipients', models.BooleanField(default=False, help_text='Check for valid recipients', verbose_name='verify recipients')),
('dates', models.ForeignKey(to='admin.ObjectDates')),
('domain', models.OneToOneField(null=True, to='admin.Domain')),
('dates', models.ForeignKey(to='admin.ObjectDates', on_delete=models.CASCADE)),
('domain', models.OneToOneField(null=True, to='admin.Domain', on_delete=models.CASCADE)),
],
options={
'ordering': ['domain__name'],
@@ -40,7 +40,7 @@ class Migration(migrations.Migration):
migrations.AddField(
model_name='relaydomain',
name='service',
field=models.ForeignKey(to='relaydomains.Service'),
field=models.ForeignKey(to='relaydomains.Service', on_delete=models.CASCADE),
preserve_default=True,
),
]
+1 -1
View File
@@ -3,7 +3,7 @@
from __future__ import unicode_literals
from django.core.files.base import ContentFile
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.test import TestCase
from modoboa.admin import factories as admin_factories
@@ -0,0 +1,7 @@
{% with id=widget.attrs.id %}<div{% if id %} id="{{ id }}"{% endif %}{% if widget.attrs.class %} class="{{ widget.attrs.class }}"{% endif %}>
{% for group, options, index in widget.optgroups %}
{% for option in options %}
{% include option.template_name with widget=option %}
{% endfor %}
{% endfor %}
</div>{% endwith %}
@@ -0,0 +1,2 @@
{% if wrap_label %}<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %} class="radio-inline">{% endif %}{% include "django/forms/widgets/input.html" %}{% if wrap_label %} {{ widget.label }}</label>{% endif %}
+1 -1
View File
@@ -2,7 +2,7 @@
from __future__ import unicode_literals
from django.core.urlresolvers import reverse
from django.urls import reverse
from django.dispatch import receiver
from django.utils.translation import ugettext as _
+1 -1
View File
@@ -2,7 +2,7 @@
import json
from django.core.urlresolvers import reverse
from django.urls import reverse
from modoboa.lib.tests import ModoAPITestCase, ModoTestCase
+3 -3
View File
@@ -8,10 +8,10 @@ from . import views
urlpatterns = [
url(r"^$", views.TransportListView.as_view(),
name="transport_list"),
url("^create/$", views.TransportCreateView.as_view(),
url(r"^create/$", views.TransportCreateView.as_view(),
name="transport_create"),
url("^update/(?P<pk>\d+)/$", views.TransportUpdateView.as_view(),
url(r"^update/(?P<pk>\d+)/$", views.TransportUpdateView.as_view(),
name="transport_update"),
url("^delete/(?P<pk>\d+)/$", views.TransportDeleteView.as_view(),
url(r"^delete/(?P<pk>\d+)/$", views.TransportDeleteView.as_view(),
name="transport_delete"),
]
+1 -1
View File
@@ -1,7 +1,7 @@
"""Transport views."""
from django import http
from django.core.urlresolvers import reverse, reverse_lazy
from django.urls import reverse, reverse_lazy
from django.utils.translation import ugettext as _, ugettext_lazy
from django.views import generic
+6 -6
View File
@@ -1,23 +1,23 @@
django>=1.10,<=1.10.99
django>=1.11.8,<=1.11.99
django-braces==1.11.0
django-ckeditor==5.2.1
django-reversion==1.10.2
django-ckeditor==5.2.2
django-reversion==2.0.12
django-subcommand2==0.1.1
django-versionfield2>=0.5.0
django-xforwardedfor-middleware
dj-database-url
coreapi==2.3.1
coreapi==2.3.3
coreapi-cli==1.0.6
djangorestframework==3.7.1
djangorestframework==3.7.3
argparse
# bcrypt requires libffi-dev
bcrypt==3.1.4
dnspython==1.15.0
feedparser==5.2.1
gevent==1.2.1
gevent==1.2.2
ipaddress
jsonfield==2.0.2
passlib==1.7.1
+15 -3
View File
@@ -7,7 +7,19 @@ import sys
if __name__ == "__main__":
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings")
from django.core.management import execute_from_command_line
try:
from django.core.management import execute_from_command_line
except ImportError:
# The above import may fail for some other reason. Ensure that the
# issue is really that Django is missing to avoid masking other
# exceptions on Python 2.
try:
import django # noqa
except ImportError:
raise ImportError(
"Couldn't import Django. Are you sure it's installed and "
"available on your PYTHONPATH environment variable? Did you "
"forget to activate a virtual environment?"
)
raise
execute_from_command_line(sys.argv)
-1
View File
@@ -1 +0,0 @@
from __future__ import unicode_literals
+130 -79
View File
@@ -1,26 +1,29 @@
"""
Django settings for test_project project.
Generated by 'django-admin startproject' using Django 1.11.8.
For more information on this file, see
https://docs.djangoproject.com/en/1.6/topics/settings/
https://docs.djangoproject.com/en/1.11/topics/settings/
For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.6/ref/settings/
https://docs.djangoproject.com/en/1.11/ref/settings/
"""
from __future__ import unicode_literals
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
import os
from logging.handlers import SysLogHandler
import os
from modoboa.test_settings import * # NOQA
from modoboa.test_settings import * # noqa
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.realpath(os.path.dirname(os.path.dirname(__file__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.6/howto/deployment/checklist/
# See https://docs.djangoproject.com/en/1.11/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = '!8o(-dbbl3e+*bh7nx-^xysdt)1gso*%@4ze4-9_9o+i&amp;t--u_'
@@ -37,6 +40,10 @@ ALLOWED_HOSTS = [
SITE_ID = 1
# Security settings
X_FRAME_OPTIONS = "SAMEORIGIN"
# Application definition
INSTALLED_APPS = (
@@ -47,8 +54,10 @@ INSTALLED_APPS = (
'django.contrib.sites',
'django.contrib.staticfiles',
'reversion',
'ckeditor',
'ckeditor_uploader',
'rest_framework',
'rest_framework.authtoken'
'rest_framework.authtoken',
)
# A dedicated place to register Modoboa applications
@@ -59,17 +68,18 @@ MODOBOA_APPS = (
'modoboa.core',
'modoboa.lib',
'modoboa.admin',
'modoboa.limits',
'modoboa.transport',
'modoboa.relaydomains',
'modoboa.limits',
'modoboa.parameters',
# Modoboa extensions here.
)
INSTALLED_APPS += MODOBOA_APPS
AUTH_USER_MODEL = 'core.User'
MIDDLEWARE_CLASSES = (
MIDDLEWARE = (
'x_forwarded_for.middleware.XForwardedForMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
@@ -85,10 +95,88 @@ MIDDLEWARE_CLASSES = (
)
AUTHENTICATION_BACKENDS = (
# 'modoboa.lib.authbackends.LDAPBackend',
# 'modoboa.lib.authbackends.SMTPBackend',
'django.contrib.auth.backends.ModelBackend',
)
# Password validation rules
# SMTP authentication
# AUTH_SMTP_SERVER_ADDRESS = 'localhost'
# AUTH_SMTP_SERVER_PORT = 25
# AUTH_SMTP_SECURED_MODE = None # 'ssl' or 'starttls' are accepted
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'modoboa.core.context_processors.top_notifications',
],
'debug': TEMPLATE_DEBUG,
},
},
]
ROOT_URLCONF = 'test_project.urls'
WSGI_APPLICATION = 'test_project.wsgi.application'
# Internationalization
# https://docs.djangoproject.com/en/1.11/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.11/howto/static-files/
STATIC_URL = '/sitestatic/'
STATIC_ROOT = os.path.join(BASE_DIR, 'sitestatic')
STATICFILES_DIRS = (
os.path.join(BASE_DIR, '..', 'modoboa', 'bower_components'),
)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# Rest framework settings
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
}
# Modoboa settings
# MODOBOA_CUSTOM_LOGO = os.path.join(MEDIA_URL, "custom_logo.png")
# DOVECOT_LOOKUP_PATH = ('/path/to/dovecot', )
MODOBOA_API_URL = 'https://api.modoboa.org/1/'
# Password validation
# https://docs.djangoproject.com/en/1.11/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
@@ -113,77 +201,38 @@ AUTH_PASSWORD_VALIDATORS = [
},
]
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.i18n',
'django.template.context_processors.media',
'django.template.context_processors.static',
'django.template.context_processors.tz',
'django.contrib.messages.context_processors.messages',
'modoboa.core.context_processors.top_notifications',
],
'debug': False,
},
# CKeditor
CKEDITOR_UPLOAD_PATH = "uploads/"
CKEDITOR_IMAGE_BACKEND = "pillow"
CKEDITOR_RESTRICT_BY_USER = True
CKEDITOR_BROWSE_SHOW_DIRS = True
CKEDITOR_ALLOW_NONIMAGE_FILES = False
CKEDITOR_CONFIGS = {
'default': {
'allowedContent': True,
'toolbar': 'Modoboa',
'width': None,
'toolbar_Modoboa': [
['Bold', 'Italic', 'Underline'],
['JustifyLeft', 'JustifyCenter', 'JustifyRight', 'JustifyBlock'],
['BidiLtr', 'BidiRtl', 'Language'],
['NumberedList', 'BulletedList', '-', 'Outdent', 'Indent'],
['Undo', 'Redo'],
['Link', 'Unlink', 'Anchor', '-', 'Smiley'],
['TextColor', 'BGColor', '-', 'Source'],
['Font', 'FontSize'],
['Image', ],
['SpellChecker']
],
},
]
ROOT_URLCONF = 'test_project.urls'
WSGI_APPLICATION = 'test_project.wsgi.application'
# Internationalization
# https://docs.djangoproject.com/en/1.6/topics/i18n/
LANGUAGE_CODE = 'en-us'
TIME_ZONE = 'UTC'
USE_I18N = True
USE_L10N = False
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.6/howto/static-files/
STATIC_URL = '/sitestatic/'
STATIC_ROOT = os.path.join(BASE_DIR, 'sitestatic')
STATICFILES_DIRS = (
os.path.join(BASE_DIR, '..', 'modoboa', 'bower_components'),
)
MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
# Rest framework settings
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
# Modoboa settings
# MODOBOA_CUSTOM_LOGO = os.path.join(MEDIA_URL, "custom_logo.png")
# DOVECOT_LOOKUP_PATH = ('/path/to/dovecot', )
MODOBOA_API_URL = 'http://api.modoboa.org/1/'
# Logging configuration
LOGGING = {
@@ -216,3 +265,5 @@ LOGGING = {
}
}
}
# Load settings from extensions
+1 -1
View File
@@ -3,5 +3,5 @@ from __future__ import unicode_literals
from django.conf.urls import include, url
urlpatterns = [
url(r'', include('modoboa.urls')),
url(r"", include("modoboa.urls")),
]
+4 -2
View File
@@ -4,13 +4,15 @@ WSGI config for test_project project.
It exposes the WSGI callable as a module-level variable named ``application``.
For more information on this file, see
https://docs.djangoproject.com/en/1.7/howto/deployment/wsgi/
https://docs.djangoproject.com/en/1.11/howto/deployment/wsgi/
"""
from __future__ import unicode_literals
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings")
from django.core.wsgi import get_wsgi_application
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "test_project.settings")
application = get_wsgi_application()