mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
+1
-1
@@ -38,7 +38,7 @@ before_script:
|
||||
script:
|
||||
- python ./tests.py
|
||||
- cd test_project
|
||||
- coverage run --source ../modoboa manage.py test modoboa.core modoboa.lib modoboa.admin.tests modoboa.limits modoboa.relaydomains
|
||||
- coverage run --source ../modoboa manage.py test modoboa.core modoboa.admin.tests modoboa.limits modoboa.relaydomains
|
||||
|
||||
after_success:
|
||||
- codecov
|
||||
|
||||
@@ -15,14 +15,7 @@ from . import constants
|
||||
|
||||
|
||||
def enabled_applications():
|
||||
"""Return the list of installed extensions.
|
||||
|
||||
We check if the table exists before trying to fetch activated
|
||||
extensions because the admin module is always imported by Django,
|
||||
even before the database exists (example: the first ``syncdb``).
|
||||
|
||||
:return: a list
|
||||
"""
|
||||
"""Return the list of installed extensions."""
|
||||
from modoboa.core.extensions import exts_pool
|
||||
|
||||
result = [("user", "user")]
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
* @constructor
|
||||
* @param {Object} options - instance options
|
||||
*/
|
||||
/* global TwocolsNav */
|
||||
|
||||
var Settings = function(options) {
|
||||
TwocolsNav.call(this, options);
|
||||
};
|
||||
@@ -40,7 +42,7 @@ Settings.prototype = {
|
||||
* Navigation callback: extensions.
|
||||
*/
|
||||
extensions_callback: function(data) {
|
||||
this.select_left_menu();
|
||||
this.select_left_menu();
|
||||
if (data.content) {
|
||||
$('#' + this.options.divid).html(data.content);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
{% load i18n lib_tags %}
|
||||
<h2>{% trans "Parameters" %} <small>{% trans "Configure Modoboa" %}</small></h2><hr />
|
||||
<form id="settings_form" method="POST" action="{% url 'core:parameter_save' %}" class="form-horizontal">{% csrf_token %}
|
||||
<form id="parameters_form" method="POST" action="{% url 'core:parameters' %}" class="form-horizontal">{% csrf_token %}
|
||||
{% include "parameters/base_form.html" %}
|
||||
<hr>
|
||||
<button type="submit" class="btn btn-primary col-xs-offset-4 col-xs-4" id="update" name="update">{% trans 'Save' %}</button>
|
||||
<button type="submit" class="btn btn-primary col-xs-offset-4 col-xs-4" name="update">{% trans 'Save' %}</button>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
<hr>
|
||||
{% if forms %}
|
||||
<form class="form-horizontal" method="POST" action="{% url 'core:user_preferences' %}"
|
||||
id="uprefs_form">
|
||||
id="parameters_form">
|
||||
{% csrf_token %}
|
||||
{% include "parameters/base_form.html" %}
|
||||
<hr>
|
||||
<button type="submit" class="btn btn-primary col-xs-offset-4 col-xs-4" id="update" name="update">{% trans 'Save' %}</button>
|
||||
<button type="submit" class="btn btn-primary col-xs-offset-4 col-xs-4" name="update">{% trans 'Save' %}</button>
|
||||
</form>
|
||||
{% else %}
|
||||
<div class="alert alert-info">
|
||||
|
||||
@@ -57,44 +57,6 @@ class ChangeDefaultAdminTestCase(TestCase):
|
||||
self.client.login(username="modoadmin", password="password"))
|
||||
|
||||
|
||||
class DashboardTestCase(ModoTestCase):
|
||||
"""Dashboard tests."""
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
"""Create some data."""
|
||||
super(DashboardTestCase, cls).setUpTestData()
|
||||
cls.dadmin = factories.UserFactory(
|
||||
username="admin@test.com", groups=("DomainAdmins",)
|
||||
)
|
||||
cls.user = factories.UserFactory(
|
||||
username="user@test.com", groups=("SimpleUsers",)
|
||||
)
|
||||
|
||||
def test_access(self):
|
||||
"""Load dashboard."""
|
||||
url = reverse("core:dashboard")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("Latest news", response.content)
|
||||
self.client.logout()
|
||||
self.client.login(username=self.dadmin.username, password="toto")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("Latest news", response.content)
|
||||
self.client.logout()
|
||||
self.client.login(username=self.user.username, password="toto")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
def test_root_dispatch(self):
|
||||
"""Check root dispatching."""
|
||||
url = reverse("core:root")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertTrue(response.url.endswith(reverse("core:dashboard")))
|
||||
|
||||
|
||||
@skipIf(NO_LDAP, 'No ldap module installed')
|
||||
class LDAPTestCaseMixin(object):
|
||||
"""Set of methods used to test LDAP features."""
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
"""Core views test cases."""
|
||||
|
||||
from testfixtures import compare
|
||||
|
||||
from django import forms
|
||||
from django.core.urlresolvers import reverse
|
||||
|
||||
from modoboa.lib.tests import ModoTestCase
|
||||
from modoboa.parameters import forms as param_forms
|
||||
from modoboa.parameters import tools as param_tools
|
||||
|
||||
from .. import factories
|
||||
from .. import models
|
||||
|
||||
|
||||
class DashboardTestCase(ModoTestCase):
|
||||
"""Dashboard tests."""
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
"""Create some data."""
|
||||
super(DashboardTestCase, cls).setUpTestData()
|
||||
cls.dadmin = factories.UserFactory(
|
||||
username="admin@test.com", groups=("DomainAdmins",)
|
||||
)
|
||||
cls.user = factories.UserFactory(
|
||||
username="user@test.com", groups=("SimpleUsers",)
|
||||
)
|
||||
|
||||
def test_access(self):
|
||||
"""Load dashboard."""
|
||||
url = reverse("core:dashboard")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("Latest news", response.content)
|
||||
self.client.logout()
|
||||
self.client.login(username=self.dadmin.username, password="toto")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("Latest news", response.content)
|
||||
self.client.logout()
|
||||
self.client.login(username=self.user.username, password="toto")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
|
||||
def test_root_dispatch(self):
|
||||
"""Check root dispatching."""
|
||||
url = reverse("core:root")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 302)
|
||||
self.assertTrue(response.url.endswith(reverse("core:dashboard")))
|
||||
|
||||
|
||||
class SettingsTestCase(ModoTestCase):
|
||||
"""Settings tests."""
|
||||
|
||||
settings_sample = {
|
||||
"core-check_new_versions": "True",
|
||||
"core-log_maximum_age": "365",
|
||||
"core-ldap_auth_method": "searchbind",
|
||||
"limits-deflt_domain_mailbox_aliases_limit": "0",
|
||||
"core-send_statistics": "True",
|
||||
"core-default_top_redirection": "user",
|
||||
"core-sender_address": "noreply@modoboa.org",
|
||||
"admin-auto_account_removal": "False",
|
||||
"core-ldap_server_port": "389",
|
||||
"core-rounds_number": "70000",
|
||||
"core-ldap_bind_password": "",
|
||||
"limits-deflt_domain_domain_aliases_limit": "0",
|
||||
"core-secret_key": ":?j3]QPWo!.'_c4n",
|
||||
"relaydomains-master_cf_path": "/etc/postfix/master.cf",
|
||||
"limits-deflt_domain_domain_admins_limit": "0",
|
||||
"limits-enable_admin_limits": "True",
|
||||
"core-ldap_bind_dn": "",
|
||||
"core-enable_api_communication": "True",
|
||||
"limits-deflt_user_domain_admins_limit": "0",
|
||||
"limits-enable_domain_limits": "False",
|
||||
"csrfmiddlewaretoken": "SGgMVZsA4TPqoiV786TMST6xgOlhAf4F",
|
||||
"limits-deflt_user_mailboxes_limit": "0",
|
||||
"core-password_scheme": "sha512crypt",
|
||||
"core-items_per_page": "30",
|
||||
"limits-deflt_user_mailbox_aliases_limit": "0",
|
||||
"limits-deflt_domain_mailboxes_limit": "0",
|
||||
"core-ldap_is_active_directory": "False",
|
||||
"core-ldap_group_type": "posixgroup",
|
||||
"limits-deflt_user_domain_aliases_limit": "0",
|
||||
"core-top_notifications_check_interval": "30",
|
||||
"core-ldap_password_attribute": "userPassword",
|
||||
"admin-auto_create_domain_and_mailbox": "True",
|
||||
"admin-enable_dnsbl_checks": "True",
|
||||
"admin-default_domain_quota": "0",
|
||||
"core-ldap_server_address": "localhost",
|
||||
"core-authentication_type": "local",
|
||||
"core-ldap_admin_groups": "",
|
||||
"core-ldap_groups_search_base": "",
|
||||
"admin-enable_mx_checks": "True",
|
||||
"core-ldap_search_base": "",
|
||||
"admin-valid_mxs": "",
|
||||
"limits-deflt_user_domains_limit": "0",
|
||||
"core-ldap_search_filter": "(mail=%(user)s)",
|
||||
"core-ldap_secured": "False",
|
||||
"core-ldap_user_dn_template": ""
|
||||
}
|
||||
|
||||
def test_get_settings(self):
|
||||
"""Test settings display."""
|
||||
url = reverse("core:parameters")
|
||||
response = self.ajax_get(url)
|
||||
for app in ["core", "admin", "limits", "relaydomains"]:
|
||||
self.assertIn('data-app="{}"'.format(app), response["content"])
|
||||
|
||||
def test_save_settings(self):
|
||||
"""Test settings save."""
|
||||
url = reverse("core:parameters")
|
||||
response = self.client.post(url, self.settings_sample, format="json")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.settings_sample["core-rounds_number"] = ""
|
||||
response = self.client.post(url, self.settings_sample, format="json")
|
||||
self.assertEqual(response.status_code, 400)
|
||||
compare(response.json(), {
|
||||
"form_errors": {"rounds_number": ["This field is required."]},
|
||||
"prefix": "core"
|
||||
})
|
||||
|
||||
|
||||
class UserSettings(param_forms.UserParametersForm):
|
||||
"""Stupid user settings form."""
|
||||
|
||||
app = "core"
|
||||
|
||||
test = forms.CharField()
|
||||
|
||||
|
||||
class PreferencesTestCase(ModoTestCase):
|
||||
"""Test user preferences."""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
"""Register user form."""
|
||||
super(PreferencesTestCase, cls).setUpClass()
|
||||
param_tools.registry.add("user", UserSettings, "Test")
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
"""Remove user class."""
|
||||
super(PreferencesTestCase, cls).tearDownClass()
|
||||
del param_tools.registry._registry["user"]["core"]
|
||||
|
||||
def test_get_preferences(self):
|
||||
"""Test preferences display."""
|
||||
url = reverse("core:user_preferences")
|
||||
self.ajax_get(url)
|
||||
|
||||
def test_save_preferences(self):
|
||||
"""Test preferences save."""
|
||||
url = reverse("core:user_preferences")
|
||||
response = self.client.post(url, {"core-test": "toto"}, format="json")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.json(), "Preferences saved")
|
||||
|
||||
admin = models.User.objects.get(username="admin")
|
||||
self.assertEqual(admin.parameters.get_value("test"), "toto")
|
||||
@@ -17,10 +17,8 @@ urlpatterns = patterns(
|
||||
|
||||
url(r'^core/$', 'modoboa.core.views.admin.viewsettings',
|
||||
name="index"),
|
||||
url(r'^core/parameters/$', 'modoboa.core.views.admin.viewparameters',
|
||||
name="parameter_listl"),
|
||||
url(r'^core/parameters/save/$', 'modoboa.core.views.admin.saveparameters',
|
||||
name="parameter_save"),
|
||||
url(r'^core/parameters/$', 'modoboa.core.views.admin.parameters',
|
||||
name="parameters"),
|
||||
url(r'^core/info/$', 'modoboa.core.views.admin.information',
|
||||
name="information"),
|
||||
url(r'^core/logs/$', 'modoboa.core.views.admin.logs', name="log_list"),
|
||||
|
||||
+16
-20
@@ -28,7 +28,22 @@ def viewsettings(request, tplname='core/settings_header.html'):
|
||||
|
||||
@login_required
|
||||
@user_passes_test(lambda u: u.is_superuser)
|
||||
def viewparameters(request, tplname='core/parameters.html'):
|
||||
def parameters(request, tplname="core/parameters.html"):
|
||||
"""View to display and save global parameters."""
|
||||
if request.method == "POST":
|
||||
forms = param_tools.registry.get_forms(
|
||||
"global", request.POST, localconfig=request.localconfig)
|
||||
for formdef in forms:
|
||||
form = formdef["form"]
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
form.to_django_settings()
|
||||
continue
|
||||
return render_to_json_response(
|
||||
{"form_errors": form.errors, "prefix": form.app}, status=400
|
||||
)
|
||||
request.localconfig.save()
|
||||
return render_to_json_response(_("Parameters saved"))
|
||||
return render_to_json_response({
|
||||
"left_selection": "parameters",
|
||||
"content": _render_to_string(request, tplname, {
|
||||
@@ -38,25 +53,6 @@ def viewparameters(request, tplname='core/parameters.html'):
|
||||
})
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(lambda u: u.is_superuser)
|
||||
def saveparameters(request):
|
||||
"""Save all parameters."""
|
||||
forms = param_tools.registry.get_forms(
|
||||
"global", request.POST, localconfig=request.localconfig)
|
||||
for formdef in forms:
|
||||
form = formdef["form"]
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
form.to_django_settings()
|
||||
continue
|
||||
return render_to_json_response(
|
||||
{'form_errors': form.errors, 'prefix': form.app}, status=400
|
||||
)
|
||||
request.localconfig.save()
|
||||
return render_to_json_response(_("Parameters saved"))
|
||||
|
||||
|
||||
@login_required
|
||||
@user_passes_test(lambda u: u.is_superuser)
|
||||
def information(request, tplname="core/information.html"):
|
||||
|
||||
@@ -232,9 +232,8 @@ class DynamicForm(object):
|
||||
|
||||
|
||||
class TabForms(object):
|
||||
|
||||
"""
|
||||
Simple forms container
|
||||
Simple forms container.
|
||||
|
||||
This class tries to encapsulate multiple forms that will be
|
||||
displayed using tabs. It is different from a classical formset
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{% load form_tags %}
|
||||
<div class="tabbable">
|
||||
<ul class="nav nav-tabs">
|
||||
{% for form in forms %}<li{% if forloop.first %} class="active"{% endif %}><a href="#{{ forloop.counter }}" data-toggle="tab">{{ form.label }}</a></li>
|
||||
{% for form in forms %}<li{% if forloop.first %} class="active"{% endif %}><a href="#{{ forloop.counter }}" data-app="{{ form.app }}" data-toggle="tab">{{ form.label }}</a></li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
<div class="tab-content">{% for form in forms %}
|
||||
|
||||
@@ -63,6 +63,7 @@ class Registry(object):
|
||||
if not data["formclass"].has_access(**kwargs):
|
||||
continue
|
||||
result.append({
|
||||
"app": app,
|
||||
"label": data["label"],
|
||||
"form": data["formclass"](*args, **kwargs)
|
||||
})
|
||||
|
||||
@@ -3,6 +3,9 @@
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
|
||||
/* global Listing */
|
||||
|
||||
var TwocolsNav = function(options) {
|
||||
Listing.call(this, options);
|
||||
};
|
||||
@@ -33,6 +36,17 @@ TwocolsNav.prototype = {
|
||||
success_cb: $.proxy(this.save_cb, this)
|
||||
});
|
||||
}, this));
|
||||
$(document).on('submit', '#parameters_form', function(evt) {
|
||||
simple_ajax_form_post(evt, {
|
||||
formid: $(this).attr('id'),
|
||||
modal: false,
|
||||
reload_on_success: false,
|
||||
success_cb: $.proxy(this.save_cb, this),
|
||||
error_cb: function(data) {
|
||||
$('a[data-app="' + data.prefix + '"]').tab('show');
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
update_content: function(data) {
|
||||
|
||||
@@ -60,6 +60,7 @@ MODOBOA_APPS = (
|
||||
'modoboa.admin',
|
||||
'modoboa.limits',
|
||||
'modoboa.relaydomains',
|
||||
'modoboa.parameters',
|
||||
)
|
||||
|
||||
INSTALLED_APPS += MODOBOA_APPS
|
||||
@@ -75,6 +76,7 @@ MIDDLEWARE_CLASSES = (
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'modoboa.core.middleware.LocalConfigMiddleware',
|
||||
'modoboa.lib.middleware.AjaxLoginRedirect',
|
||||
'modoboa.lib.middleware.CommonExceptionCatcher',
|
||||
'modoboa.lib.middleware.RequestCatcherMiddleware',
|
||||
|
||||
Reference in New Issue
Block a user