Fixes onmailbox filtering

This commit is contained in:
Marc Aymerich 2015-04-29 10:51:30 +00:00
parent 948a4ced8f
commit 52be2e3bb1
11 changed files with 87 additions and 77 deletions

View file

@ -37,7 +37,7 @@ If you are planing to do some development or perhaps just checking out this proj
1. Create a basic [LXC](http://linuxcontainers.org/) container, start it and get inside. 1. Create a basic [LXC](http://linuxcontainers.org/) container, start it and get inside.
```bash ```bash
wget -O /tmp/create.sh \ wget -O /tmp/create.sh \
https://raw2.github.com/glic3rinu/django-orchestra/master/scripts/container/create.sh https://raw.github.com/glic3rinu/django-orchestra/master/scripts/container/create.sh
sudo bash /tmp/create.sh sudo bash /tmp/create.sh
sudo lxc-start -n orchestra sudo lxc-start -n orchestra
``` ```
@ -45,7 +45,7 @@ If you are planing to do some development or perhaps just checking out this proj
2. Deploy Django-orchestra development environment inside the container 2. Deploy Django-orchestra development environment inside the container
```bash ```bash
wget -O /tmp/deploy.sh \ wget -O /tmp/deploy.sh \
https://raw2.github.com/glic3rinu/django-orchestra/master/scripts/container/deploy.sh https://raw.github.com/glic3rinu/django-orchestra/master/scripts/container/deploy.sh
cd /tmp/ # Moving away from /root before running deploy.sh cd /tmp/ # Moving away from /root before running deploy.sh
bash /tmp/deploy.sh bash /tmp/deploy.sh
``` ```

13
TODO.md
View file

@ -170,14 +170,11 @@ require_once(/etc/moodles/.$moodle_host.config.php);``` moodle/drupl
* budgets: no undo feature * budgets: no undo feature
* Autocomplete admin fields like <site_name>.phplist... with js * Autocomplete admin fields like <site_name>.phplist... with js
* autoexpand mailbox.filter according to filtering options (js)
* allow empty metric pack for default rates? changes on rating algo * allow empty metric pack for default rates? changes on rating algo
# don't produce lines with cost == 0 or quantity 0 ? maybe minimal quantity for billing? like 0.1 ? or minimal price? per line or per bill? # don't produce lines with cost == 0 or quantity 0 ? maybe minimal quantity for billing? like 0.1 ? or minimal price? per line or per bill?
# lines too long on invoice, double lines or cut, and make margin wider # lines too long on invoice, double lines or cut, and make margin wider
* PHP_TIMEOUT env variable in sync with fcgid idle timeout
http://foaa.de/old-blog/2010/11/php-apache-and-fastcgi-a-comprehensive-overview/trackback/index.html#pni-top0
* payment methods icons * payment methods icons
* use server.name | server.address on python backends, like gitlab instead of settings? * use server.name | server.address on python backends, like gitlab instead of settings?
@ -243,14 +240,11 @@ https://code.djangoproject.com/ticket/24576
# FIXME address name change does not remove old one :P, readonly or perhaps we can regenerate all addresses using backend.prepare()? # FIXME address name change does not remove old one :P, readonly or perhaps we can regenerate all addresses using backend.prepare()?
* read https://docs.djangoproject.com/en/dev/releases/1.8/ and fix deprecation warnings * read https://docs.djangoproject.com/en/dev/releases/1.8/ and fix deprecation warnings
* remove admin object display_links , like contents webapps
* SaaS and WebApp types and services fieldsets, and helptexts ! * create nice fieldsets for SaaS, WebApp types and services, and helptexts too!
* replace make_option in management commands * replace make_option in management commands
* welcome, pangea linke doesnt work
# FIXME model contact info and account info (email, name, etc) correctly/unredundant/dry # FIXME model contact info and account info (email, name, etc) correctly/unredundant/dry
* Use the new django.contrib.admin.RelatedOnlyFieldListFilter in ModelAdmin.list_filter to limit the list_filter choices to foreign objects which are attached to those from the ModelAdmin. * Use the new django.contrib.admin.RelatedOnlyFieldListFilter in ModelAdmin.list_filter to limit the list_filter choices to foreign objects which are attached to those from the ModelAdmin.
@ -296,3 +290,8 @@ https://code.djangoproject.com/ticket/24576
# @ something database names # @ something database names
# password validation cracklib on change password form=????? # password validation cracklib on change password form=?????
# reset setting buton # reset setting buton
# periodic cleaning of spam mailboxes
# admin edit relevant djanog settings
# django SITE_NAME vs ORCHESTRA_SITE_NAME ?

View file

@ -1,3 +1,4 @@
from django.core.urlresolvers import reverse
from fluent_dashboard import dashboard from fluent_dashboard import dashboard
from fluent_dashboard.modules import CmsAppIconList from fluent_dashboard.modules import CmsAppIconList
@ -5,6 +6,14 @@ from orchestra.core import services
class OrchestraIndexDashboard(dashboard.FluentIndexDashboard): class OrchestraIndexDashboard(dashboard.FluentIndexDashboard):
_registry = {}
@classmethod
def register_link(cls, module, view_name, title):
registered = cls._registry.get(module, [])
registered.append((view_name, title))
cls._registry[module] = registered
def get_application_modules(self): def get_application_modules(self):
modules = super(OrchestraIndexDashboard, self).get_application_modules() modules = super(OrchestraIndexDashboard, self).get_application_modules()
models = [] models = []
@ -12,20 +21,25 @@ class OrchestraIndexDashboard(dashboard.FluentIndexDashboard):
if options.get('menu', True): if options.get('menu', True):
models.append("%s.%s" % (model.__module__, model._meta.object_name)) models.append("%s.%s" % (model.__module__, model._meta.object_name))
# TODO make this dynamic
for module in modules: for module in modules:
if module.title == 'Administration': registered = self._registry.get(module.title, None)
module.children.append({ if registered:
'models': [{ for view_name, title in registered:
'add_url': '/admin/settings/', # This values are shit, but it is how fluent dashboard will look for the icon
'app_name': 'settings', app_name, name = view_name.split('_')[:-1]
'change_url': '/admin/settings/setting/', url = reverse('admin:' + view_name)
'name': 'setting', add_url = '/'.join(url.split('/')[:-2])
'title': "Settings" }], module.children.append({
'name': 'settings', 'models': [{
'title': 'Settings', 'add_url': add_url,
'url': '/admin/settings/' 'app_name': app_name,
}) 'change_url': url,
'name': name,
'title': title }],
'name': app_name,
'title': title,
'url': add_url,
})
service_icon_list = CmsAppIconList('Services', models=models, collapsible=True) service_icon_list = CmsAppIconList('Services', models=models, collapsible=True)
modules.append(service_icon_list) modules.append(service_icon_list)
return modules return modules

View file

@ -1,4 +1,5 @@
import logging import logging
import os
import re import re
import textwrap import textwrap
@ -24,14 +25,25 @@ class SieveFilteringMixin(object):
def generate_filter(self, mailbox, context): def generate_filter(self, mailbox, context):
name, content = mailbox.get_filtering() name, content = mailbox.get_filtering()
for box in re.findall(r'fileinto\s+"([^"]+)"', content): for box in re.findall(r'fileinto\s+"([^"]+)"', content):
# create mailboxes if fileinfo is provided witout ':create' option
context['box'] = box context['box'] = box
# TODO create mailbox without doveadm (not always installed) self.append(textwrap.dedent("""\
self.append("doveadm mailbox create -u %(user)s %(box)s" % context) mkdir -p %(maildir)s/.%(box)s
chown %(user)s:%(group)s %(maildir)s/.%(box)s
if [[ ! $(grep '%(box)s' %(maildir)s/subscriptions) ]]; then
echo '%(box)s' >> %(maildir)s/subscriptions
fi
""") % context
)
context['filtering_path'] = settings.MAILBOXES_SIEVE_PATH % context context['filtering_path'] = settings.MAILBOXES_SIEVE_PATH % context
if content: if content:
context['filtering'] = ('# %(banner)s\n' + filtering) % context context['filtering'] = ('# %(banner)s\n' + content) % context
self.append("mkdir -p $(dirname '%(filtering_path)s')" % context) self.append(textwrap.dedent("""\
self.append("echo '%(filtering)s' > %(filtering_path)s" % context) mkdir -p $(dirname '%(filtering_path)s')
echo '%(filtering)s' > %(filtering_path)s
chown %(user)s:%(group)s %(filtering_path)s
""") % context
)
else: else:
self.append("echo '' > %(filtering_path)s" % context) self.append("echo '' > %(filtering_path)s" % context)
@ -41,6 +53,8 @@ class UNIXUserMaildirBackend(SieveFilteringMixin, ServiceController):
Assumes that all system users on this servers all mail accounts. Assumes that all system users on this servers all mail accounts.
If you want to have system users AND mailboxes on the same server you should consider using virtual mailboxes If you want to have system users AND mailboxes on the same server you should consider using virtual mailboxes
""" """
SHELL = '/dev/null'
verbose_name = _("UNIX maildir user") verbose_name = _("UNIX maildir user")
model = 'mailboxes.Mailbox' model = 'mailboxes.Mailbox'
@ -64,13 +78,13 @@ class UNIXUserMaildirBackend(SieveFilteringMixin, ServiceController):
context['quota'] = mailbox.resources.disk.allocated * mailbox.resources.disk.resource.get_scale() context['quota'] = mailbox.resources.disk.allocated * mailbox.resources.disk.resource.get_scale()
#unit_to_bytes(mailbox.resources.disk.unit) #unit_to_bytes(mailbox.resources.disk.unit)
self.append(textwrap.dedent(""" self.append(textwrap.dedent("""
mkdir -p %(home)s/Maildir mkdir -p %(maildir)s
chown %(user)s:%(group)s %(home)s/Maildir chown %(user)s:%(group)s %(maildir)s
if [[ ! -f %(home)s/Maildir/maildirsize ]]; then if [[ ! -f %(maildir)s/maildirsize ]]; then
echo "%(quota)iS" > %(home)s/Maildir/maildirsize echo "%(quota)iS" > %(maildir)s/maildirsize
chown %(user)s:%(group)s %(home)s/Maildir/maildirsize chown %(user)s:%(group)s %(maildir)s/maildirsize
else else
sed -i '1s/.*/%(quota)iS/' %(home)s/Maildir/maildirsize sed -i '1s/.*/%(quota)iS/' %(maildir)s/maildirsize
fi""") % context fi""") % context
) )
@ -91,7 +105,8 @@ class UNIXUserMaildirBackend(SieveFilteringMixin, ServiceController):
'name': mailbox.name, 'name': mailbox.name,
'password': mailbox.password if mailbox.active else '*%s' % mailbox.password, 'password': mailbox.password if mailbox.active else '*%s' % mailbox.password,
'home': mailbox.get_home(), 'home': mailbox.get_home(),
'initial_shell': '/dev/null', 'maildir': os.path.join(mailbox.get_home(), 'Maildir'),
'initial_shell': self.SHELL,
'banner': self.get_banner(), 'banner': self.get_banner(),
} }
return replace(context, "'", '"') return replace(context, "'", '"')
@ -363,20 +378,8 @@ class PostfixMailscannerTraffic(ServiceMonitor):
maillogs = {mail_logs} maillogs = {mail_logs}
end_datetime = to_local_timezone('{current_date}') end_datetime = to_local_timezone('{current_date}')
end_date = int(end_datetime.strftime('%Y%m%d%H%M%S')) end_date = int(end_datetime.strftime('%Y%m%d%H%M%S'))
months = {{ months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
"Jan": "01", months = dict((m, '%02d' % n) for n, m in enumerate(months, 1))
"Feb": "02",
"Mar": "03",
"Apr": "04",
"May": "05",
"Jun": "06",
"Jul": "07",
"Aug": "08",
"Sep": "09",
"Oct": "10",
"Nov": "11",
"Dec": "12",
}}
def inside_period(month, day, time, ini_date): def inside_period(month, day, time, ini_date):
global months global months

View file

@ -61,7 +61,7 @@ class Mailbox(models.Model):
def get_filtering(self): def get_filtering(self):
name, content = settings.MAILBOXES_MAILBOX_FILTERINGS[self.filtering] name, content = settings.MAILBOXES_MAILBOX_FILTERINGS[self.filtering]
if callable(content): if callable(content):
return content(self) content = content(self)
return (name, content) return (name, content)
def delete(self, *args, **kwargs): def delete(self, *args, **kwargs):

View file

@ -1,6 +1,8 @@
import os import os
import textwrap import textwrap
from django.utils.functional import lazy
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from orchestra.core.validators import validate_name from orchestra.core.validators import validate_name
@ -9,6 +11,7 @@ from orchestra.settings import ORCHESTRA_BASE_DOMAIN, Setting
_names = ('name', 'username',) _names = ('name', 'username',)
_backend_names = _names + ('user', 'group', 'home') _backend_names = _names + ('user', 'group', 'home')
mark_safe_lazy = lazy(mark_safe, str)
MAILBOXES_DOMAIN_MODEL = Setting('MAILBOXES_DOMAIN_MODEL', 'domains.Domain', MAILBOXES_DOMAIN_MODEL = Setting('MAILBOXES_DOMAIN_MODEL', 'domains.Domain',
@ -72,15 +75,15 @@ MAILBOXES_MAILBOX_FILTERINGS = Setting('MAILBOXES_MAILBOX_FILTERINGS',
{ {
# value: (verbose_name, filter) # value: (verbose_name, filter)
'DISABLE': (_("Disable"), ''), 'DISABLE': (_("Disable"), ''),
'REJECT': (_("Reject spam"), textwrap.dedent(""" 'REJECT': (mark_safe_lazy(_("Reject spam (X-Spam-Score&ge;9)")), textwrap.dedent("""
require ["fileinto","regex","envelope","vacation","reject","relational","comparator-i;ascii-numeric"]; require ["fileinto","regex","envelope","vacation","reject","relational","comparator-i;ascii-numeric"];
if header :value "ge" :comparator "i;ascii-numeric" "X-Spam-Score" "5" { if header :value "ge" :comparator "i;ascii-numeric" "X-Spam-Score" "9" {
discard; discard;
stop; stop;
}""")), }""")),
'REDIRECT': (_("Archive spam"), textwrap.dedent(""" 'REDIRECT': (mark_safe_lazy(_("Archive spam (X-Spam-Score&ge;9)")), textwrap.dedent("""
require ["fileinto","regex","envelope","vacation","reject","relational","comparator-i;ascii-numeric"]; require ["fileinto","regex","envelope","vacation","reject","relational","comparator-i;ascii-numeric"];
if header :value "ge" :comparator "i;ascii-numeric" "X-Spam-Score" "5" { if header :value "ge" :comparator "i;ascii-numeric" "X-Spam-Score" "9" {
fileinto "Spam"; fileinto "Spam";
stop; stop;
}""")), }""")),

View file

@ -32,7 +32,7 @@ ORDERS_EXCLUDED_APPS = Setting('ORDERS_EXCLUDED_APPS',
ORDERS_METRIC_ERROR = Setting('ORDERS_METRIC_ERROR', ORDERS_METRIC_ERROR = Setting('ORDERS_METRIC_ERROR',
0.01, 0.05,
help_text=("Only account for significative changes.<br>" help_text=("Only account for significative changes.<br>"
"metric_storage new value: <tt>lastvalue*(1+threshold) > currentvalue or lastvalue*threshold < currentvalue</tt>."), "metric_storage new value: <tt>lastvalue*(1+threshold) > currentvalue or lastvalue*threshold < currentvalue</tt>."),
) )

View file

@ -20,7 +20,8 @@ SERVICES_SERVICE_DEFAULT_TAX = Setting('SERVICES_SERVICE_DEFAULT_TAX',
SERVICES_SERVICE_ANUAL_BILLING_MONTH = Setting('SERVICES_SERVICE_ANUAL_BILLING_MONTH', SERVICES_SERVICE_ANUAL_BILLING_MONTH = Setting('SERVICES_SERVICE_ANUAL_BILLING_MONTH',
1, 1,
choices=tuple((n, n) for n in range(1, 13)) choices=tuple(enumerate(
('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'), 1))
) )

View file

@ -6,6 +6,7 @@ from django.shortcuts import render_to_response
from django.views import generic from django.views import generic
from django.utils.translation import ngettext, ugettext_lazy as _ from django.utils.translation import ngettext, ugettext_lazy as _
from orchestra.admin.dashboard import OrchestraIndexDashboard
from orchestra.settings import Setting from orchestra.settings import Setting
from orchestra.utils import sys, paths from orchestra.utils import sys, paths
@ -104,4 +105,5 @@ class SettingFileView(generic.TemplateView):
admin.site.register_url(r'^settings/setting/view/$', SettingFileView.as_view(), 'settings_setting_view') admin.site.register_url(r'^settings/setting/view/$', SettingFileView.as_view(), 'settings_setting_view')
admin.site.register_url(r'^settings/setting/$', SettingView.as_view(), 'settings_setting_change') admin.site.register_url(r'^settings/setting/$', SettingView.as_view(), 'settings_setting_change')
OrchestraIndexDashboard.register_link('Administration', 'settings_setting_change', _("Settings"))

View file

@ -237,20 +237,8 @@ class VsFTPdTraffic(ServiceMonitor):
end_date = to_local_timezone('{current_date}') end_date = to_local_timezone('{current_date}')
end_date = int(end_date.strftime('%Y%m%d%H%M%S')) end_date = int(end_date.strftime('%Y%m%d%H%M%S'))
users = {{}} users = {{}}
months = {{ months = ('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec')
'Jan': '01', months = dict((m, '%02d' % n) for n, m in enumerate(months, 1))
'Feb': '02',
'Mar': '03',
'Apr': '04',
'May': '05',
'Jun': '06',
'Jul': '07',
'Aug': '08',
'Sep': '09',
'Oct': '10',
'Nov': '11',
'Dec': '12',
}}
def prepare(object_id, username, ini_date): def prepare(object_id, username, ini_date):
global users global users

View file

@ -81,15 +81,15 @@ class PHPApp(AppType):
if webapp.type_instance.get_php_version() == php_version: if webapp.type_instance.get_php_version() == php_version:
options += list(webapp.options.all()) options += list(webapp.options.all())
init_vars = OrderedDict((opt.name, opt.value) for opt in options) init_vars = OrderedDict((opt.name, opt.value) for opt in options)
# Enabled functions # Enable functions
enabled_functions = init_vars.pop('enabled_functions', None) enable_functions = init_vars.pop('enable_functions', None)
if enabled_functions: if enable_functions:
enabled_functions = set(enabled_functions.split(',')) enable_functions = set(enable_functions.split(','))
disabled_functions = [] disable_functions = []
for function in self.PHP_DISABLED_FUNCTIONS: for function in self.PHP_DISABLED_FUNCTIONS:
if function not in enabled_functions: if function not in enable_functions:
disabled_functions.append(function) disable_functions.append(function)
init_vars['disable_functions'] = ','.join(disabled_functions) init_vars['disable_functions'] = ','.join(disable_functions)
# process timeout # process timeout
timeout = self.instance.options.filter(name='timeout').first() timeout = self.instance.options.filter(name='timeout').first()
if timeout: if timeout: