Improved backends help texts
This commit is contained in:
parent
eebaee1097
commit
c2b0186034
4
TODO.md
4
TODO.md
|
@ -266,7 +266,6 @@ https://code.djangoproject.com/ticket/24576
|
||||||
|
|
||||||
* MultiCHoiceField proper serialization
|
* MultiCHoiceField proper serialization
|
||||||
|
|
||||||
# Apache restart fails: detect if appache running, and execute start
|
|
||||||
* UNIFY PHP FPM settings name
|
* UNIFY PHP FPM settings name
|
||||||
# virtualhost name: name-account?
|
# virtualhost name: name-account?
|
||||||
* add a delay to changes on the webserver apache to no overwelm it with backend executions?
|
* add a delay to changes on the webserver apache to no overwelm it with backend executions?
|
||||||
|
@ -278,6 +277,7 @@ https://code.djangoproject.com/ticket/24576
|
||||||
* rename resource.monitors to resource.backends ?
|
* rename resource.monitors to resource.backends ?
|
||||||
* abstract model classes that enabling overriding, and ORCHESTRA_DATABASE_MODEL settings + orchestra.get_database_model() instead of explicitly importing from orchestra.contrib.databases.models import Database.. (Admin and REST API are fucked then?)
|
* abstract model classes that enabling overriding, and ORCHESTRA_DATABASE_MODEL settings + orchestra.get_database_model() instead of explicitly importing from orchestra.contrib.databases.models import Database.. (Admin and REST API are fucked then?)
|
||||||
|
|
||||||
|
# billing order list filter detect metrics that are greater from those of billing_date
|
||||||
# Ignore superusers & co on billing: list filter doesn't work nor ignore detection
|
# Ignore superusers & co on billing: list filter doesn't work nor ignore detection
|
||||||
# bill.totals make it 100% computed?
|
# bill.totals make it 100% computed?
|
||||||
* joomla: wget https://github.com/joomla/joomla-cms/releases/download/3.4.1/Joomla_3.4.1-Stable-Full_Package.tar.gz -O - | tar xvfz -
|
* joomla: wget https://github.com/joomla/joomla-cms/releases/download/3.4.1/Joomla_3.4.1-Stable-Full_Package.tar.gz -O - | tar xvfz -
|
||||||
|
@ -285,7 +285,5 @@ https://code.djangoproject.com/ticket/24576
|
||||||
# replace multichoicefield and jsonfield by ArrayField, HStoreField
|
# replace multichoicefield and jsonfield by ArrayField, HStoreField
|
||||||
# Amend lines???
|
# Amend lines???
|
||||||
|
|
||||||
# Add icon on select contact view
|
|
||||||
|
|
||||||
# Determine the difference between data serializer used for validation and used for the rest API!
|
# Determine the difference between data serializer used for validation and used for the rest API!
|
||||||
# Make PluginApiView that fills metadata and other stuff like modeladmin plugin support
|
# Make PluginApiView that fills metadata and other stuff like modeladmin plugin support
|
||||||
|
|
|
@ -122,12 +122,13 @@ class AccountListAdmin(AccountAdmin):
|
||||||
# TODO get query string from request.META['QUERY_STRING'] to preserve filters
|
# TODO get query string from request.META['QUERY_STRING'] to preserve filters
|
||||||
context = {
|
context = {
|
||||||
'url': '../?account=' + str(instance.pk),
|
'url': '../?account=' + str(instance.pk),
|
||||||
'name': instance.username
|
'name': instance.username,
|
||||||
|
'plus': '<strong style="color:green; font-size:12px">+</strong>',
|
||||||
}
|
}
|
||||||
return '<a href="%(url)s">%(name)s</a>' % context
|
return _('<a href="%(url)s">%(plus)s Add to %(name)s</a>') % context
|
||||||
select_account.short_description = _("account")
|
select_account.short_description = _("account")
|
||||||
select_account.allow_tags = True
|
select_account.allow_tags = True
|
||||||
select_account.order_admin_field = 'username'
|
select_account.admin_order_field = 'username'
|
||||||
|
|
||||||
def changelist_view(self, request, extra_context=None):
|
def changelist_view(self, request, extra_context=None):
|
||||||
original_app_label = request.META['PATH_INFO'].split('/')[-5]
|
original_app_label = request.META['PATH_INFO'].split('/')[-5]
|
||||||
|
|
|
@ -14,7 +14,7 @@ from .models import Database, DatabaseUser
|
||||||
class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('name', 'type', 'display_users', 'account_link')
|
list_display = ('name', 'type', 'display_users', 'account_link')
|
||||||
list_filter = ('type',)
|
list_filter = ('type',)
|
||||||
search_fields = ['name']
|
search_fields = ('name', 'account__username')
|
||||||
change_readonly_fields = ('name', 'type')
|
change_readonly_fields = ('name', 'type')
|
||||||
extra = 1
|
extra = 1
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
|
@ -71,7 +71,7 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, ExtendedModelAdmin):
|
class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = ('username', 'type', 'display_databases', 'account_link')
|
list_display = ('username', 'type', 'display_databases', 'account_link')
|
||||||
list_filter = ('type',)
|
list_filter = ('type',)
|
||||||
search_fields = ['username']
|
search_fields = ('username', 'account__username')
|
||||||
form = DatabaseUserChangeForm
|
form = DatabaseUserChangeForm
|
||||||
add_form = DatabaseUserCreationForm
|
add_form = DatabaseUserCreationForm
|
||||||
change_readonly_fields = ('username', 'type')
|
change_readonly_fields = ('username', 'type')
|
||||||
|
|
|
@ -10,14 +10,14 @@ from . import settings
|
||||||
|
|
||||||
class MySQLBackend(ServiceController):
|
class MySQLBackend(ServiceController):
|
||||||
"""
|
"""
|
||||||
Simple backend for creating MySQL databases using `CREATE DATABASE` statement.
|
Simple backend for creating MySQL databases using <tt>CREATE DATABASE</tt> statement.
|
||||||
DATABASES_DEFAULT_HOST = %s
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (settings.DATABASES_DEFAULT_HOST,)
|
|
||||||
|
|
||||||
verbose_name = "MySQL database"
|
verbose_name = "MySQL database"
|
||||||
model = 'databases.Database'
|
model = 'databases.Database'
|
||||||
default_route_match = "database.type == 'mysql'"
|
default_route_match = "database.type == 'mysql'"
|
||||||
|
doc_settings = (settings,
|
||||||
|
('DATABASES_DEFAULT_HOST',)
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, database):
|
def save(self, database):
|
||||||
if database.type != database.MYSQL:
|
if database.type != database.MYSQL:
|
||||||
|
@ -61,13 +61,14 @@ class MySQLBackend(ServiceController):
|
||||||
|
|
||||||
class MySQLUserBackend(ServiceController):
|
class MySQLUserBackend(ServiceController):
|
||||||
"""
|
"""
|
||||||
Simple backend for creating MySQL users using `CREATE USER` statement.
|
Simple backend for creating MySQL users using <tt>CREATE USER</tt> statement.
|
||||||
DATABASES_DEFAULT_HOST = %s
|
"""
|
||||||
""" % settings.DATABASES_DEFAULT_HOST
|
|
||||||
|
|
||||||
verbose_name = "MySQL user"
|
verbose_name = "MySQL user"
|
||||||
model = 'databases.DatabaseUser'
|
model = 'databases.DatabaseUser'
|
||||||
default_route_match = "databaseuser.type == 'mysql'"
|
default_route_match = "databaseuser.type == 'mysql'"
|
||||||
|
doc_settings = (settings,
|
||||||
|
('DATABASES_DEFAULT_HOST',)
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, user):
|
def save(self, user):
|
||||||
if user.type != user.MYSQL:
|
if user.type != user.MYSQL:
|
||||||
|
@ -105,7 +106,7 @@ class MySQLUserBackend(ServiceController):
|
||||||
|
|
||||||
class MysqlDisk(ServiceMonitor):
|
class MysqlDisk(ServiceMonitor):
|
||||||
"""
|
"""
|
||||||
du -bs <database_path>
|
<tt>du -bs <database_path></tt>
|
||||||
Implements triggers for resource limit exceeded and recovery, disabling insert and create privileges.
|
Implements triggers for resource limit exceeded and recovery, disabling insert and create privileges.
|
||||||
"""
|
"""
|
||||||
model = 'databases.Database'
|
model = 'databases.Database'
|
||||||
|
|
|
@ -67,7 +67,7 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
inlines = [RecordInline, DomainInline]
|
inlines = [RecordInline, DomainInline]
|
||||||
list_filter = [TopDomainListFilter]
|
list_filter = [TopDomainListFilter]
|
||||||
change_readonly_fields = ('name',)
|
change_readonly_fields = ('name',)
|
||||||
search_fields = ['name',]
|
search_fields = ('name', 'account__username')
|
||||||
add_form = BatchDomainCreationAdminForm
|
add_form = BatchDomainCreationAdminForm
|
||||||
change_view_actions = [view_zone]
|
change_view_actions = [view_zone]
|
||||||
|
|
||||||
|
|
|
@ -14,14 +14,8 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
"""
|
"""
|
||||||
Bind9 zone and config generation.
|
Bind9 zone and config generation.
|
||||||
It auto-discovers slave Bind9 servers based on your routing configuration or you can use DOMAINS_SLAVES to explicitly configure the slaves.
|
It auto-discovers slave Bind9 servers based on your routing configuration or you can use DOMAINS_SLAVES to explicitly configure the slaves.
|
||||||
DOMAINS_SLAVES = %s
|
|
||||||
DOMAINS_MASTERS_PATH = '%s'
|
|
||||||
"""
|
"""
|
||||||
|
CONF_PATH = settings.DOMAINS_MASTERS_PATH
|
||||||
format_docstring = (
|
|
||||||
str(settings.DOMAINS_SLAVES),
|
|
||||||
settings.DOMAINS_MASTERS_PATH,
|
|
||||||
)
|
|
||||||
|
|
||||||
verbose_name = _("Bind9 master domain")
|
verbose_name = _("Bind9 master domain")
|
||||||
model = 'domains.Domain'
|
model = 'domains.Domain'
|
||||||
|
@ -30,7 +24,9 @@ class Bind9MasterDomainBackend(ServiceController):
|
||||||
('domains.Domain', 'origin'),
|
('domains.Domain', 'origin'),
|
||||||
)
|
)
|
||||||
ignore_fields = ['serial']
|
ignore_fields = ['serial']
|
||||||
CONF_PATH = settings.DOMAINS_MASTERS_PATH
|
doc_settings = (settings,
|
||||||
|
('DOMAINS_SLAVES', 'DOMAINS_MASTERS_PATH')
|
||||||
|
)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def is_main(cls, obj):
|
def is_main(cls, obj):
|
||||||
|
@ -136,15 +132,16 @@ class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
|
||||||
"""
|
"""
|
||||||
Generate the configuartion for slave servers
|
Generate the configuartion for slave servers
|
||||||
It auto-discover the master server based on your routing configuration or you can use DOMAINS_MASTERS to explicitly configure the master.
|
It auto-discover the master server based on your routing configuration or you can use DOMAINS_MASTERS to explicitly configure the master.
|
||||||
DOMAINS_MASTERS = %s
|
"""
|
||||||
""" % str(settings.DOMAINS_MASTERS)
|
CONF_PATH = settings.DOMAINS_SLAVES_PATH
|
||||||
|
|
||||||
verbose_name = _("Bind9 slave domain")
|
verbose_name = _("Bind9 slave domain")
|
||||||
related_models = (
|
related_models = (
|
||||||
('domains.Domain', 'origin'),
|
('domains.Domain', 'origin'),
|
||||||
)
|
)
|
||||||
CONF_PATH = settings.DOMAINS_SLAVES_PATH
|
doc_settings = (settings,
|
||||||
|
('DOMAINS_MASTERS', 'DOMAINS_SLAVES_PATH')
|
||||||
|
)
|
||||||
def save(self, domain):
|
def save(self, domain):
|
||||||
context = self.get_context(domain)
|
context = self.get_context(domain)
|
||||||
self.update_conf(context)
|
self.update_conf(context)
|
||||||
|
|
|
@ -42,8 +42,8 @@ class MessageReadOnlyInline(admin.TabularInline):
|
||||||
model = Message
|
model = Message
|
||||||
extra = 0
|
extra = 0
|
||||||
can_delete = False
|
can_delete = False
|
||||||
fields = ['content_html']
|
fields = ('content_html',)
|
||||||
readonly_fields = ['content_html']
|
readonly_fields = ('content_html',)
|
||||||
|
|
||||||
class Media:
|
class Media:
|
||||||
css = {
|
css = {
|
||||||
|
@ -79,7 +79,7 @@ class MessageInline(admin.TabularInline):
|
||||||
max_num = 1
|
max_num = 1
|
||||||
form = MessageInlineForm
|
form = MessageInlineForm
|
||||||
can_delete = False
|
can_delete = False
|
||||||
fields = ['content']
|
fields = ('content',)
|
||||||
|
|
||||||
def get_formset(self, request, obj=None, **kwargs):
|
def get_formset(self, request, obj=None, **kwargs):
|
||||||
""" hook request.user on the inline form """
|
""" hook request.user on the inline form """
|
||||||
|
@ -93,14 +93,14 @@ class MessageInline(admin.TabularInline):
|
||||||
|
|
||||||
|
|
||||||
class TicketInline(admin.TabularInline):
|
class TicketInline(admin.TabularInline):
|
||||||
fields = [
|
fields = (
|
||||||
'ticket_id', 'subject', 'creator_link', 'owner_link', 'colored_state',
|
'ticket_id', 'subject', 'creator_link', 'owner_link', 'colored_state',
|
||||||
'colored_priority', 'created', 'updated'
|
'colored_priority', 'created', 'updated'
|
||||||
]
|
)
|
||||||
readonly_fields = [
|
readonly_fields = (
|
||||||
'ticket_id', 'subject', 'creator_link', 'owner_link', 'colored_state',
|
'ticket_id', 'subject', 'creator_link', 'owner_link', 'colored_state',
|
||||||
'colored_priority', 'created', 'updated'
|
'colored_priority', 'created', 'updated'
|
||||||
]
|
)
|
||||||
model = Ticket
|
model = Ticket
|
||||||
extra = 0
|
extra = 0
|
||||||
max_num = 0
|
max_num = 0
|
||||||
|
@ -119,35 +119,35 @@ class TicketInline(admin.TabularInline):
|
||||||
|
|
||||||
|
|
||||||
class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin):
|
class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin):
|
||||||
list_display = [
|
list_display = (
|
||||||
'unbold_id', 'bold_subject', 'display_creator', 'display_owner',
|
'unbold_id', 'bold_subject', 'display_creator', 'display_owner',
|
||||||
'display_queue', 'display_priority', 'display_state', 'updated'
|
'display_queue', 'display_priority', 'display_state', 'updated'
|
||||||
]
|
)
|
||||||
list_display_links = ('unbold_id', 'bold_subject')
|
list_display_links = ('unbold_id', 'bold_subject')
|
||||||
list_filter = [
|
list_filter = (
|
||||||
MyTicketsListFilter, 'queue__name', 'priority', TicketStateListFilter,
|
MyTicketsListFilter, 'queue__name', 'priority', TicketStateListFilter,
|
||||||
]
|
)
|
||||||
default_changelist_filters = (
|
default_changelist_filters = (
|
||||||
('my_tickets', lambda r: 'True' if not r.user.is_superuser else 'False'),
|
('my_tickets', lambda r: 'True' if not r.user.is_superuser else 'False'),
|
||||||
('state', 'OPEN')
|
('state', 'OPEN')
|
||||||
)
|
)
|
||||||
date_hierarchy = 'created_at'
|
date_hierarchy = 'created_at'
|
||||||
search_fields = [
|
search_fields = (
|
||||||
'id', 'subject', 'creator__username', 'creator__email', 'queue__name',
|
'id', 'subject', 'creator__username', 'creator__email', 'queue__name',
|
||||||
'owner__username'
|
'owner__username'
|
||||||
]
|
)
|
||||||
actions = [
|
actions = (
|
||||||
mark_as_unread, mark_as_read, 'delete_selected', reject_tickets,
|
mark_as_unread, mark_as_read, 'delete_selected', reject_tickets,
|
||||||
resolve_tickets, close_tickets, take_tickets
|
resolve_tickets, close_tickets, take_tickets
|
||||||
]
|
)
|
||||||
sudo_actions = ['delete_selected']
|
sudo_actions = ('delete_selected',)
|
||||||
change_view_actions = [
|
change_view_actions = (
|
||||||
resolve_tickets, close_tickets, reject_tickets, take_tickets
|
resolve_tickets, close_tickets, reject_tickets, take_tickets
|
||||||
]
|
)
|
||||||
# change_form_template = "admin/orchestra/change_form.html"
|
# change_form_template = "admin/orchestra/change_form.html"
|
||||||
form = TicketForm
|
form = TicketForm
|
||||||
add_inlines = []
|
add_inlines = ()
|
||||||
inlines = [ MessageReadOnlyInline, MessageInline ]
|
inlines = (MessageReadOnlyInline, MessageInline)
|
||||||
readonly_fields = (
|
readonly_fields = (
|
||||||
'display_summary', 'display_queue', 'display_owner', 'display_state',
|
'display_summary', 'display_queue', 'display_owner', 'display_state',
|
||||||
'display_priority'
|
'display_priority'
|
||||||
|
@ -286,10 +286,10 @@ class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin):
|
||||||
|
|
||||||
|
|
||||||
class QueueAdmin(admin.ModelAdmin):
|
class QueueAdmin(admin.ModelAdmin):
|
||||||
list_display = ['name', 'default', 'num_tickets']
|
list_display = ('name', 'default', 'num_tickets')
|
||||||
actions = [set_default_queue]
|
actions = (set_default_queue,)
|
||||||
inlines = [TicketInline]
|
inlines = (TicketInline,)
|
||||||
ordering = ['name']
|
ordering = ('name',)
|
||||||
|
|
||||||
class Media:
|
class Media:
|
||||||
css = {
|
css = {
|
||||||
|
|
|
@ -11,18 +11,8 @@ from .models import List
|
||||||
|
|
||||||
class MailmanBackend(ServiceController):
|
class MailmanBackend(ServiceController):
|
||||||
"""
|
"""
|
||||||
Mailman backend based on `newlist`, it handles custom domains.
|
Mailman 2 backend based on <tt>newlist</tt>, it handles custom domains.
|
||||||
LISTS_VIRTUAL_ALIAS_PATH = '%s'
|
|
||||||
LISTS_VIRTUAL_ALIAS_DOMAINS_PATH = '%s'
|
|
||||||
LISTS_DEFAULT_DOMAIN = '%s'
|
|
||||||
LISTS_MAILMAN_ROOT_DIR = '%s'
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (
|
|
||||||
settings.LISTS_VIRTUAL_ALIAS_PATH,
|
|
||||||
settings.LISTS_VIRTUAL_ALIAS_DOMAINS_PATH,
|
|
||||||
settings.LISTS_DEFAULT_DOMAIN,
|
|
||||||
settings.LISTS_MAILMAN_ROOT_DIR,
|
|
||||||
)
|
|
||||||
verbose_name = "Mailman"
|
verbose_name = "Mailman"
|
||||||
model = 'lists.List'
|
model = 'lists.List'
|
||||||
addresses = [
|
addresses = [
|
||||||
|
@ -37,6 +27,12 @@ class MailmanBackend(ServiceController):
|
||||||
'-subscribe',
|
'-subscribe',
|
||||||
'-unsubscribe'
|
'-unsubscribe'
|
||||||
]
|
]
|
||||||
|
doc_settings = (settings, (
|
||||||
|
'LISTS_VIRTUAL_ALIAS_PATH',
|
||||||
|
'LISTS_VIRTUAL_ALIAS_DOMAINS_PATH',
|
||||||
|
'LISTS_DEFAULT_DOMAIN',
|
||||||
|
'LISTS_MAILMAN_ROOT_DIR'
|
||||||
|
))
|
||||||
|
|
||||||
def include_virtual_alias_domain(self, context):
|
def include_virtual_alias_domain(self, context):
|
||||||
if context['address_domain']:
|
if context['address_domain']:
|
||||||
|
@ -165,16 +161,15 @@ class MailmanBackend(ServiceController):
|
||||||
|
|
||||||
class MailmanTraffic(ServiceMonitor):
|
class MailmanTraffic(ServiceMonitor):
|
||||||
"""
|
"""
|
||||||
Parses mailman log file looking for email size and multiples it by `list_members` count.
|
Parses mailman log file looking for email size and multiples it by <tt>list_members</tt> count.
|
||||||
LISTS_MAILMAN_POST_LOG_PATH = '%s'
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (
|
|
||||||
settings.LISTS_MAILMAN_POST_LOG_PATH,
|
|
||||||
)
|
|
||||||
model = 'lists.List'
|
model = 'lists.List'
|
||||||
resource = ServiceMonitor.TRAFFIC
|
resource = ServiceMonitor.TRAFFIC
|
||||||
verbose_name = _("Mailman traffic")
|
verbose_name = _("Mailman traffic")
|
||||||
script_executable = '/usr/bin/python'
|
script_executable = '/usr/bin/python'
|
||||||
|
doc_settings = (settings,
|
||||||
|
('LISTS_MAILMAN_POST_LOG_PATH',)
|
||||||
|
)
|
||||||
|
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
postlog = settings.LISTS_MAILMAN_POST_LOG_PATH
|
postlog = settings.LISTS_MAILMAN_POST_LOG_PATH
|
||||||
|
@ -272,7 +267,7 @@ class MailmanTraffic(ServiceMonitor):
|
||||||
|
|
||||||
class MailmanSubscribers(ServiceMonitor):
|
class MailmanSubscribers(ServiceMonitor):
|
||||||
"""
|
"""
|
||||||
Monitors number of list subscribers via `list_members`
|
Monitors number of list subscribers via <tt>list_members</tt>
|
||||||
"""
|
"""
|
||||||
model = 'lists.List'
|
model = 'lists.List'
|
||||||
verbose_name = _("Mailman subscribers")
|
verbose_name = _("Mailman subscribers")
|
||||||
|
|
|
@ -3,6 +3,8 @@ from urllib.parse import parse_qs
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
|
from django.db.models import F, Value as V
|
||||||
|
from django.db.models.functions import Concat
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
from orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
|
||||||
|
@ -104,13 +106,15 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
|
||||||
|
|
||||||
class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'email', 'account_link', 'domain_link', 'display_mailboxes', 'display_forward',
|
'display_email', 'account_link', 'domain_link', 'display_mailboxes', 'display_forward',
|
||||||
)
|
)
|
||||||
list_filter = (HasMailboxListFilter, HasForwardListFilter)
|
list_filter = (HasMailboxListFilter, HasForwardListFilter)
|
||||||
fields = ('account_link', 'email_link', 'mailboxes', 'forward')
|
fields = ('account_link', 'email_link', 'mailboxes', 'forward')
|
||||||
add_fields = ('account_link', ('name', 'domain'), 'mailboxes', 'forward')
|
add_fields = ('account_link', ('name', 'domain'), 'mailboxes', 'forward')
|
||||||
inlines = [AutoresponseInline]
|
inlines = [AutoresponseInline]
|
||||||
search_fields = ('name', 'domain__name', 'forward', 'mailboxes__name', 'account__username')
|
search_fields = (
|
||||||
|
'name', 'domain__name', 'forward', 'mailboxes__name', 'account__username', 'computed_email'
|
||||||
|
)
|
||||||
readonly_fields = ('account_link', 'domain_link', 'email_link')
|
readonly_fields = ('account_link', 'domain_link', 'email_link')
|
||||||
filter_by_account_fields = ('domain', 'mailboxes')
|
filter_by_account_fields = ('domain', 'mailboxes')
|
||||||
filter_horizontal = ['mailboxes']
|
filter_horizontal = ['mailboxes']
|
||||||
|
@ -119,6 +123,11 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
|
|
||||||
domain_link = admin_link('domain', order='domain__name')
|
domain_link = admin_link('domain', order='domain__name')
|
||||||
|
|
||||||
|
def display_email(self, address):
|
||||||
|
return address.computed_email
|
||||||
|
display_email.short_description = _("Email")
|
||||||
|
display_email.admin_order_field = 'computed_email'
|
||||||
|
|
||||||
def email_link(self, address):
|
def email_link(self, address):
|
||||||
link = self.domain_link(address)
|
link = self.domain_link(address)
|
||||||
return "%s@%s" % (address.name, link)
|
return "%s@%s" % (address.name, link)
|
||||||
|
@ -154,6 +163,10 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
|
||||||
fields.remove('mailboxes')
|
fields.remove('mailboxes')
|
||||||
return fields
|
return fields
|
||||||
|
|
||||||
|
def get_queryset(self, request):
|
||||||
|
qs = super(AddressAdmin, self).get_queryset(request)
|
||||||
|
return qs.annotate(computed_email=Concat(F('name'), V('@'), F('domain__name')))
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Mailbox, MailboxAdmin)
|
admin.site.register(Mailbox, MailboxAdmin)
|
||||||
admin.site.register(Address, AddressAdmin)
|
admin.site.register(Address, AddressAdmin)
|
||||||
|
|
|
@ -185,21 +185,15 @@ class DovecotPostfixPasswdVirtualUserBackend(ServiceController):
|
||||||
class PostfixAddressBackend(ServiceController):
|
class PostfixAddressBackend(ServiceController):
|
||||||
"""
|
"""
|
||||||
Addresses based on Postfix virtual alias domains.
|
Addresses based on Postfix virtual alias domains.
|
||||||
<tt>MAILBOXES_LOCAL_DOMAIN = '%s'
|
|
||||||
MAILBOXES_VIRTUAL_ALIAS_DOMAINS_PATH = '%s'
|
|
||||||
MAILBOXES_VIRTUAL_ALIAS_MAPS_PATH = '%s'</tt>
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (
|
|
||||||
settings.MAILBOXES_LOCAL_DOMAIN,
|
|
||||||
settings.MAILBOXES_VIRTUAL_ALIAS_DOMAINS_PATH,
|
|
||||||
settings.MAILBOXES_VIRTUAL_ALIAS_MAPS_PATH,
|
|
||||||
)
|
|
||||||
verbose_name = _("Postfix address")
|
verbose_name = _("Postfix address")
|
||||||
model = 'mailboxes.Address'
|
model = 'mailboxes.Address'
|
||||||
related_models = (
|
related_models = (
|
||||||
('mailboxes.Mailbox', 'addresses'),
|
('mailboxes.Mailbox', 'addresses'),
|
||||||
)
|
)
|
||||||
|
doc_settings = (settings,
|
||||||
|
('MAILBOXES_LOCAL_DOMAIN', 'MAILBOXES_VIRTUAL_ALIAS_DOMAINS_PATH', 'MAILBOXES_VIRTUAL_ALIAS_MAPS_PATH',)
|
||||||
|
)
|
||||||
def include_virtual_alias_domain(self, context):
|
def include_virtual_alias_domain(self, context):
|
||||||
if context['domain'] != context['local_domain']:
|
if context['domain'] != context['local_domain']:
|
||||||
self.append(textwrap.dedent("""
|
self.append(textwrap.dedent("""
|
||||||
|
@ -296,15 +290,13 @@ class DovecotMaildirDisk(ServiceMonitor):
|
||||||
"""
|
"""
|
||||||
Maildir disk usage based on Dovecot maildirsize file
|
Maildir disk usage based on Dovecot maildirsize file
|
||||||
http://wiki2.dovecot.org/Quota/Maildir
|
http://wiki2.dovecot.org/Quota/Maildir
|
||||||
|
|
||||||
MAILBOXES_MAILDIRSIZE_PATH = '%s'
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (
|
|
||||||
settings.MAILBOXES_MAILDIRSIZE_PATH,
|
|
||||||
)
|
|
||||||
model = 'mailboxes.Mailbox'
|
model = 'mailboxes.Mailbox'
|
||||||
resource = ServiceMonitor.DISK
|
resource = ServiceMonitor.DISK
|
||||||
verbose_name = _("Dovecot Maildir size")
|
verbose_name = _("Dovecot Maildir size")
|
||||||
|
doc_settings = (settings,
|
||||||
|
('MAILBOXES_MAILDIRSIZE_PATH',)
|
||||||
|
)
|
||||||
|
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
super(DovecotMaildirDisk, self).prepare()
|
super(DovecotMaildirDisk, self).prepare()
|
||||||
|
@ -331,15 +323,14 @@ class PostfixMailscannerTraffic(ServiceMonitor):
|
||||||
"""
|
"""
|
||||||
A high-performance log parser.
|
A high-performance log parser.
|
||||||
Reads the mail.log file only once, for all users.
|
Reads the mail.log file only once, for all users.
|
||||||
MAILBOXES_MAIL_LOG_PATH = '%s'
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (
|
|
||||||
settings.MAILBOXES_MAIL_LOG_PATH,
|
|
||||||
)
|
|
||||||
model = 'mailboxes.Mailbox'
|
model = 'mailboxes.Mailbox'
|
||||||
resource = ServiceMonitor.TRAFFIC
|
resource = ServiceMonitor.TRAFFIC
|
||||||
verbose_name = _("Postfix-Mailscanner traffic")
|
verbose_name = _("Postfix-Mailscanner traffic")
|
||||||
script_executable = '/usr/bin/python'
|
script_executable = '/usr/bin/python'
|
||||||
|
doc_settings = (settings,
|
||||||
|
('MAILBOXES_MAIL_LOG_PATH',)
|
||||||
|
)
|
||||||
|
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
mail_log = settings.MAILBOXES_MAIL_LOG_PATH
|
mail_log = settings.MAILBOXES_MAIL_LOG_PATH
|
||||||
|
|
|
@ -58,7 +58,7 @@ class MiscellaneousAdmin(AccountAdminMixin, SelectPluginAdminMixin, admin.ModelA
|
||||||
)
|
)
|
||||||
list_filter = ('service__name', 'is_active')
|
list_filter = ('service__name', 'is_active')
|
||||||
list_select_related = ('service', 'account')
|
list_select_related = ('service', 'account')
|
||||||
search_fields = ('identifier', 'description')
|
search_fields = ('identifier', 'description', 'account__username')
|
||||||
plugin_field = 'service'
|
plugin_field = 'service'
|
||||||
plugin = MiscServicePlugin
|
plugin = MiscServicePlugin
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,7 @@ class ServiceBackend(plugins.Plugin, metaclass=ServiceMount):
|
||||||
default_route_match = 'True'
|
default_route_match = 'True'
|
||||||
# Force the backend manager to block in multiple backend executions executing them synchronously
|
# Force the backend manager to block in multiple backend executions executing them synchronously
|
||||||
block = False
|
block = False
|
||||||
format_docstring = ()
|
doc_settings = None
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return type(self).__name__
|
return type(self).__name__
|
||||||
|
|
|
@ -11,30 +11,36 @@ from django.utils.translation import ungettext, ugettext_lazy as _
|
||||||
def get_backends_help_text(backends):
|
def get_backends_help_text(backends):
|
||||||
help_texts = {}
|
help_texts = {}
|
||||||
for backend in backends:
|
for backend in backends:
|
||||||
|
help_text = backend.__doc__ or ''
|
||||||
context = {
|
context = {
|
||||||
'model': backend.model,
|
'model': backend.model,
|
||||||
'related_models': str(backend.related_models),
|
'related_models': str(backend.related_models),
|
||||||
'script_executable': backend.script_executable,
|
'script_executable': backend.script_executable,
|
||||||
'script_method': str(backend.script_method),
|
'script_method': '.'.join((backend.script_method.__module__, backend.script_method.__name__)),
|
||||||
'function_method': str(backend.script_method),
|
'function_method': '.'.join((backend.function_method.__module__, backend.function_method.__name__)),
|
||||||
'actions': ', '.join(backend.actions),
|
'actions': str(backend.actions),
|
||||||
}
|
}
|
||||||
help_text = textwrap.dedent("""
|
help_text += textwrap.dedent("""
|
||||||
- Model: '%(model)s'<br>
|
- Model: <tt>'%(model)s'</tt>
|
||||||
- Related models: %(related_models)s<br>
|
- Related models: <tt>%(related_models)s</tt>
|
||||||
- Script executable: %(script_executable)s<br>
|
- Script executable: <tt>%(script_executable)s</tt>
|
||||||
- Script method: %(script_method)s<br>
|
- Script method: <tt>%(script_method)s</tt>
|
||||||
- Function method: %(function_method)s<br>
|
- Function method: <tt>%(function_method)s</tt>
|
||||||
- Actions: %(actions)s<br>"""
|
- Actions: <tt>%(actions)s</tt>
|
||||||
|
"""
|
||||||
) % context
|
) % context
|
||||||
docstring = backend.__doc__
|
help_text = help_text.lstrip().splitlines()
|
||||||
if docstring:
|
help_settings = ['']
|
||||||
try:
|
if backend.doc_settings:
|
||||||
docstring = (docstring % backend.format_docstring).strip().splitlines()
|
module, names = backend.doc_settings
|
||||||
except TypeError as e:
|
for name in names:
|
||||||
raise TypeError(str(backend) + str(e))
|
value = getattr(module, name)
|
||||||
help_text += '<br>' + '<br>'.join(docstring)
|
if isinstance(value, str):
|
||||||
help_texts[backend.get_name()] = help_text
|
help_settings.append("<tt>%s = '%s'</tt>" % (name, value))
|
||||||
|
else:
|
||||||
|
help_settings.append("<tt>%s = %s</tt>" % (name, str(value)))
|
||||||
|
help_text += help_settings
|
||||||
|
help_texts[backend.get_name()] = '<br>'.join(help_text)
|
||||||
return help_texts
|
return help_texts
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,9 @@ class BSCWBackend(ServiceController):
|
||||||
model = 'saas.SaaS'
|
model = 'saas.SaaS'
|
||||||
default_route_match = "saas.service == 'bscw'"
|
default_route_match = "saas.service == 'bscw'"
|
||||||
actions = ('save', 'delete', 'validate_creation')
|
actions = ('save', 'delete', 'validate_creation')
|
||||||
|
doc_settings = (settings,
|
||||||
|
('SAAS_BSCW_BSADMIN_PATH',)
|
||||||
|
)
|
||||||
|
|
||||||
def validate_creation(self, saas):
|
def validate_creation(self, saas):
|
||||||
context = self.get_context(saas)
|
context = self.get_context(saas)
|
||||||
|
|
|
@ -8,8 +8,14 @@ from .. import settings
|
||||||
|
|
||||||
|
|
||||||
class DokuWikiMuBackend(ServiceController):
|
class DokuWikiMuBackend(ServiceController):
|
||||||
|
"""
|
||||||
|
Creates a DokuWiki site on a DokuWiki multisite installation.
|
||||||
|
"""
|
||||||
verbose_name = _("DokuWiki multisite")
|
verbose_name = _("DokuWiki multisite")
|
||||||
model = 'webapps.WebApp'
|
model = 'webapps.WebApp'
|
||||||
|
doc_settings = (settings,
|
||||||
|
('SAAS_DOKUWIKI_TEMPLATE_PATH', 'SAAS_DOKUWIKI_FARM_PATH')
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, webapp):
|
def save(self, webapp):
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
|
@ -25,7 +31,7 @@ class DokuWikiMuBackend(ServiceController):
|
||||||
def get_context(self, webapp):
|
def get_context(self, webapp):
|
||||||
context = super(DokuWikiMuBackend, self).get_context(webapp)
|
context = super(DokuWikiMuBackend, self).get_context(webapp)
|
||||||
context.update({
|
context.update({
|
||||||
'template': settings.WEBAPPS_DOKUWIKIMU_TEMPLATE_PATH,
|
'template': settings.SAAS_DOKUWIKI_TEMPLATE_PATH,
|
||||||
'app_path': os.path.join(settings.WEBAPPS_DOKUWIKIMU_FARM_PATH, webapp.name)
|
'app_path': os.path.join(settings.SAAS_DOKUWIKI_FARM_PATH, webapp.name)
|
||||||
})
|
})
|
||||||
return replace(context, "'", '"')
|
return replace(context, "'", '"')
|
||||||
|
|
|
@ -9,8 +9,14 @@ from .. import settings
|
||||||
|
|
||||||
|
|
||||||
class DrupalMuBackend(ServiceController):
|
class DrupalMuBackend(ServiceController):
|
||||||
|
"""
|
||||||
|
Creates a Drupal site on a Drupal multisite installation
|
||||||
|
"""
|
||||||
verbose_name = _("Drupal multisite")
|
verbose_name = _("Drupal multisite")
|
||||||
model = 'webapps.WebApp'
|
model = 'webapps.WebApp'
|
||||||
|
doc_settings = (settings,
|
||||||
|
('SAAS_DRUPAL_SITES_PATH',)
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, webapp):
|
def save(self, webapp):
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
|
@ -32,6 +38,6 @@ class DrupalMuBackend(ServiceController):
|
||||||
|
|
||||||
def get_context(self, webapp):
|
def get_context(self, webapp):
|
||||||
context = super(DrupalMuBackend, self).get_context(webapp)
|
context = super(DrupalMuBackend, self).get_context(webapp)
|
||||||
context['drupal_path'] = settings.WEBAPPS_DRUPAL_SITES_PATH % context
|
context['drupal_path'] = settings.SAAS_DRUPAL_SITES_PATH % context
|
||||||
context['drupal_settings'] = os.path.join(context['drupal_path'], 'settings.php')
|
context['drupal_settings'] = os.path.join(context['drupal_path'], 'settings.php')
|
||||||
return replace(context, "'", '"')
|
return replace(context, "'", '"')
|
||||||
|
|
|
@ -14,6 +14,9 @@ class GitLabSaaSBackend(ServiceController):
|
||||||
default_route_match = "saas.service == 'gitlab'"
|
default_route_match = "saas.service == 'gitlab'"
|
||||||
block = True
|
block = True
|
||||||
actions = ('save', 'delete', 'validate_creation')
|
actions = ('save', 'delete', 'validate_creation')
|
||||||
|
doc_settings = (settings,
|
||||||
|
('SAAS_GITLAB_DOMAIN', 'SAAS_GITLAB_ROOT_PASSWORD'),
|
||||||
|
)
|
||||||
|
|
||||||
def get_base_url(self):
|
def get_base_url(self):
|
||||||
return 'https://%s/api/v3' % settings.SAAS_GITLAB_DOMAIN
|
return 'https://%s/api/v3' % settings.SAAS_GITLAB_DOMAIN
|
||||||
|
|
|
@ -7,6 +7,14 @@ from orchestra.contrib.orchestration import ServiceController
|
||||||
|
|
||||||
|
|
||||||
class PhpListSaaSBackend(ServiceController):
|
class PhpListSaaSBackend(ServiceController):
|
||||||
|
"""
|
||||||
|
Creates a new phplist instance on a phpList multisite installation.
|
||||||
|
The site is created by means of creating a new database per phpList site, but all sites share the same code.
|
||||||
|
|
||||||
|
<tt>// config/config.php
|
||||||
|
$site = array_shift((explode(".",$_SERVER['HTTP_HOST'])));
|
||||||
|
$database_name = "phplist_mu_{$site}";</tt>
|
||||||
|
"""
|
||||||
verbose_name = _("phpList SaaS")
|
verbose_name = _("phpList SaaS")
|
||||||
model = 'saas.SaaS'
|
model = 'saas.SaaS'
|
||||||
default_route_match = "saas.service == 'phplist'"
|
default_route_match = "saas.service == 'phplist'"
|
||||||
|
|
|
@ -9,16 +9,22 @@ from .. import settings
|
||||||
|
|
||||||
|
|
||||||
class WordpressMuBackend(ServiceController):
|
class WordpressMuBackend(ServiceController):
|
||||||
|
"""
|
||||||
|
Creates a wordpress site on a WordPress MultiSite installation.
|
||||||
|
"""
|
||||||
verbose_name = _("Wordpress multisite")
|
verbose_name = _("Wordpress multisite")
|
||||||
model = 'webapps.WebApp'
|
model = 'webapps.WebApp'
|
||||||
default_route_match = "webapp.type == 'wordpress-mu'"
|
default_route_match = "webapp.type == 'wordpress-mu'"
|
||||||
|
doc_settings = (settings,
|
||||||
|
('SAAS_WORDPRESS_ADMIN_PASSWORD', 'SAAS_WORDPRESS_BASE_URL')
|
||||||
|
)
|
||||||
|
|
||||||
def login(self, session):
|
def login(self, session):
|
||||||
base_url = self.get_base_url()
|
base_url = self.get_base_url()
|
||||||
login_url = base_url + '/wp-login.php'
|
login_url = base_url + '/wp-login.php'
|
||||||
login_data = {
|
login_data = {
|
||||||
'log': 'admin',
|
'log': 'admin',
|
||||||
'pwd': settings.WEBAPPS_WORDPRESSMU_ADMIN_PASSWORD,
|
'pwd': settings.SAAS_WORDPRESS_ADMIN_PASSWORD,
|
||||||
'redirect_to': '/wp-admin/'
|
'redirect_to': '/wp-admin/'
|
||||||
}
|
}
|
||||||
response = session.post(login_url, data=login_data)
|
response = session.post(login_url, data=login_data)
|
||||||
|
@ -26,7 +32,7 @@ class WordpressMuBackend(ServiceController):
|
||||||
raise IOError("Failure login to remote application")
|
raise IOError("Failure login to remote application")
|
||||||
|
|
||||||
def get_base_url(self):
|
def get_base_url(self):
|
||||||
base_url = settings.WEBAPPS_WORDPRESSMU_BASE_URL
|
base_url = settings.SAAS_WORDPRESS_BASE_URL
|
||||||
return base_url.rstrip('/')
|
return base_url.rstrip('/')
|
||||||
|
|
||||||
def validate_response(self, response):
|
def validate_response(self, response):
|
||||||
|
|
|
@ -11,18 +11,14 @@ from . import settings
|
||||||
|
|
||||||
class UNIXUserBackend(ServiceController):
|
class UNIXUserBackend(ServiceController):
|
||||||
"""
|
"""
|
||||||
Basic UNIX system user/group support based on `useradd`, `usermod`, `userdel` and `groupdel`.
|
Basic UNIX system user/group support based on <tt>useradd</tt>, <tt>usermod</tt>, <tt>userdel</tt> and <tt>groupdel</tt>.
|
||||||
<tt>SYSTEMUSERS_DEFAULT_GROUP_MEMBERS = '%s'
|
|
||||||
SYSTEMUSERS_MOVE_ON_DELETE_PATH = '%s'</tt>
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (
|
|
||||||
settings.SYSTEMUSERS_DEFAULT_GROUP_MEMBERS,
|
|
||||||
settings.SYSTEMUSERS_MOVE_ON_DELETE_PATH,
|
|
||||||
)
|
|
||||||
|
|
||||||
verbose_name = _("UNIX user")
|
verbose_name = _("UNIX user")
|
||||||
model = 'systemusers.SystemUser'
|
model = 'systemusers.SystemUser'
|
||||||
actions = ('save', 'delete', 'grant_permission')
|
actions = ('save', 'delete', 'grant_permission')
|
||||||
|
doc_settings = (settings,
|
||||||
|
('SYSTEMUSERS_DEFAULT_GROUP_MEMBERS', 'SYSTEMUSERS_MOVE_ON_DELETE_PATH')
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, user):
|
def save(self, user):
|
||||||
context = self.get_context(user)
|
context = self.get_context(user)
|
||||||
|
@ -95,7 +91,7 @@ class UNIXUserBackend(ServiceController):
|
||||||
|
|
||||||
class UNIXUserDisk(ServiceMonitor):
|
class UNIXUserDisk(ServiceMonitor):
|
||||||
"""
|
"""
|
||||||
`du -bs <home>`
|
<tt>du -bs <home></tt>
|
||||||
"""
|
"""
|
||||||
model = 'systemusers.SystemUser'
|
model = 'systemusers.SystemUser'
|
||||||
resource = ServiceMonitor.DISK
|
resource = ServiceMonitor.DISK
|
||||||
|
@ -123,17 +119,15 @@ class UNIXUserDisk(ServiceMonitor):
|
||||||
|
|
||||||
class Exim4Traffic(ServiceMonitor):
|
class Exim4Traffic(ServiceMonitor):
|
||||||
"""
|
"""
|
||||||
Exim4 mainlog parser for mails sent on the webserver by system users (e.g. via PHP mail())
|
Exim4 mainlog parser for mails sent on the webserver by system users (e.g. via PHP <tt>mail()</tt>)
|
||||||
SYSTEMUSERS_MAIL_LOG_PATH = '%s'
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (
|
|
||||||
settings.SYSTEMUSERS_MAIL_LOG_PATH,
|
|
||||||
)
|
|
||||||
|
|
||||||
model = 'systemusers.SystemUser'
|
model = 'systemusers.SystemUser'
|
||||||
resource = ServiceMonitor.TRAFFIC
|
resource = ServiceMonitor.TRAFFIC
|
||||||
verbose_name = _("Exim4 traffic")
|
verbose_name = _("Exim4 traffic")
|
||||||
script_executable = '/usr/bin/python'
|
script_executable = '/usr/bin/python'
|
||||||
|
doc_settings = (settings,
|
||||||
|
('SYSTEMUSERS_MAIL_LOG_PATH',)
|
||||||
|
)
|
||||||
|
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
mainlog = settings.SYSTEMUSERS_MAIL_LOG_PATH
|
mainlog = settings.SYSTEMUSERS_MAIL_LOG_PATH
|
||||||
|
@ -211,15 +205,14 @@ class Exim4Traffic(ServiceMonitor):
|
||||||
class VsFTPdTraffic(ServiceMonitor):
|
class VsFTPdTraffic(ServiceMonitor):
|
||||||
"""
|
"""
|
||||||
vsFTPd log parser.
|
vsFTPd log parser.
|
||||||
SYSTEMUSERS_FTP_LOG_PATH = '%s'
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (
|
|
||||||
settings.SYSTEMUSERS_FTP_LOG_PATH,
|
|
||||||
)
|
|
||||||
model = 'systemusers.SystemUser'
|
model = 'systemusers.SystemUser'
|
||||||
resource = ServiceMonitor.TRAFFIC
|
resource = ServiceMonitor.TRAFFIC
|
||||||
verbose_name = _('VsFTPd traffic')
|
verbose_name = _('VsFTPd traffic')
|
||||||
script_executable = '/usr/bin/python'
|
script_executable = '/usr/bin/python'
|
||||||
|
doc_settings = (settings,
|
||||||
|
('SYSTEMUSERS_FTP_LOG_PATH',)
|
||||||
|
)
|
||||||
|
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
vsftplog = settings.SYSTEMUSERS_FTP_LOG_PATH
|
vsftplog = settings.SYSTEMUSERS_FTP_LOG_PATH
|
||||||
|
|
|
@ -12,6 +12,9 @@ class WebAppServiceMixin(object):
|
||||||
('webapps.WebAppOption', 'webapp'),
|
('webapps.WebAppOption', 'webapp'),
|
||||||
)
|
)
|
||||||
directive = None
|
directive = None
|
||||||
|
doc_settings = (settings,
|
||||||
|
('WEBAPPS_UNDER_CONSTRUCTION_PATH', 'WEBAPPS_MOVE_ON_DELETE_PATH',)
|
||||||
|
)
|
||||||
|
|
||||||
def create_webapp_dir(self, context):
|
def create_webapp_dir(self, context):
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
|
@ -45,7 +48,7 @@ class WebAppServiceMixin(object):
|
||||||
'type': webapp.type,
|
'type': webapp.type,
|
||||||
'app_path': webapp.get_path(),
|
'app_path': webapp.get_path(),
|
||||||
'banner': self.get_banner(),
|
'banner': self.get_banner(),
|
||||||
'under_construction_path': settings.settings.WEBAPPS_UNDER_CONSTRUCTION_PATH,
|
'under_construction_path': settings.WEBAPPS_UNDER_CONSTRUCTION_PATH,
|
||||||
'is_mounted': webapp.content_set.exists(),
|
'is_mounted': webapp.content_set.exists(),
|
||||||
}
|
}
|
||||||
context['deleted_app_path'] = settings.WEBAPPS_MOVE_ON_DELETE_PATH % context
|
context['deleted_app_path'] = settings.WEBAPPS_MOVE_ON_DELETE_PATH % context
|
||||||
|
|
|
@ -14,29 +14,21 @@ class PHPBackend(WebAppServiceMixin, ServiceController):
|
||||||
"""
|
"""
|
||||||
PHP support for apache-mod-fcgid and php-fpm.
|
PHP support for apache-mod-fcgid and php-fpm.
|
||||||
It handles switching between these two PHP process management systemes.
|
It handles switching between these two PHP process management systemes.
|
||||||
WEBAPPS_MERGE_PHP_WEBAPPS = %s
|
|
||||||
WEBAPPS_FPM_DEFAULT_MAX_CHILDREN = %s
|
|
||||||
WEBAPPS_PHP_CGI_BINARY_PATH = '%s'
|
|
||||||
WEBAPPS_PHP_CGI_RC_DIR = '%s'
|
|
||||||
WEBAPPS_PHP_CGI_INI_SCAN_DIR = '%s'
|
|
||||||
WEBAPPS_FCGID_CMD_OPTIONS_PATH = '%s'
|
|
||||||
WEBAPPS_PHPFPM_POOL_PATH = '%s'
|
|
||||||
WEBAPPS_PHP_MAX_REQUESTS = %s
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (
|
MERGE = settings.WEBAPPS_MERGE_PHP_WEBAPPS
|
||||||
settings.WEBAPPS_MERGE_PHP_WEBAPPS,
|
|
||||||
settings.WEBAPPS_FPM_DEFAULT_MAX_CHILDREN,
|
|
||||||
settings.WEBAPPS_PHP_CGI_BINARY_PATH,
|
|
||||||
settings.WEBAPPS_PHP_CGI_RC_DIR,
|
|
||||||
settings.WEBAPPS_PHP_CGI_INI_SCAN_DIR,
|
|
||||||
settings.WEBAPPS_FCGID_CMD_OPTIONS_PATH,
|
|
||||||
settings.WEBAPPS_PHPFPM_POOL_PATH,
|
|
||||||
settings.WEBAPPS_PHP_MAX_REQUESTS,
|
|
||||||
)
|
|
||||||
|
|
||||||
verbose_name = _("PHP FPM/FCGID")
|
verbose_name = _("PHP FPM/FCGID")
|
||||||
default_route_match = "webapp.type.endswith('php')"
|
default_route_match = "webapp.type.endswith('php')"
|
||||||
MERGE = settings.WEBAPPS_MERGE_PHP_WEBAPPS
|
doc_settings = (settings, (
|
||||||
|
'WEBAPPS_MERGE_PHP_WEBAPPS',
|
||||||
|
'WEBAPPS_FPM_DEFAULT_MAX_CHILDREN',
|
||||||
|
'WEBAPPS_PHP_CGI_BINARY_PATH',
|
||||||
|
'WEBAPPS_PHP_CGI_RC_DIR',
|
||||||
|
'WEBAPPS_PHP_CGI_INI_SCAN_DIR',
|
||||||
|
'WEBAPPS_FCGID_CMD_OPTIONS_PATH',
|
||||||
|
'WEBAPPS_PHPFPM_POOL_PATH',
|
||||||
|
'WEBAPPS_PHP_MAX_REQUESTS',
|
||||||
|
))
|
||||||
|
|
||||||
def save(self, webapp):
|
def save(self, webapp):
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
|
|
|
@ -12,22 +12,16 @@ from .. import settings
|
||||||
|
|
||||||
class uWSGIPythonBackend(WebAppServiceMixin, ServiceController):
|
class uWSGIPythonBackend(WebAppServiceMixin, ServiceController):
|
||||||
"""
|
"""
|
||||||
Emperor mode
|
<a href="http://uwsgi-docs.readthedocs.org/en/latest/Emperor.html">Emperor mode</a>
|
||||||
http://uwsgi-docs.readthedocs.org/en/latest/Emperor.html
|
|
||||||
WEBAPPS_UWSGI_BASE_DIR = '%s'
|
|
||||||
WEBAPPS_PYTHON_MAX_REQUESTS = %s
|
|
||||||
WEBAPPS_PYTHON_DEFAULT_MAX_WORKERS = %s
|
|
||||||
WEBAPPS_PYTHON_DEFAULT_TIMEOUT = %s
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (
|
|
||||||
settings.WEBAPPS_UWSGI_BASE_DIR,
|
|
||||||
settings.WEBAPPS_PYTHON_MAX_REQUESTS,
|
|
||||||
settings.WEBAPPS_PYTHON_DEFAULT_MAX_WORKERS,
|
|
||||||
settings.WEBAPPS_PYTHON_DEFAULT_TIMEOUT,
|
|
||||||
)
|
|
||||||
|
|
||||||
verbose_name = _("Python uWSGI")
|
verbose_name = _("Python uWSGI")
|
||||||
default_route_match = "webapp.type.endswith('python')"
|
default_route_match = "webapp.type.endswith('python')"
|
||||||
|
doc_settings = (settings, (
|
||||||
|
'WEBAPPS_UWSGI_BASE_DIR',
|
||||||
|
'WEBAPPS_PYTHON_MAX_REQUESTS',
|
||||||
|
'WEBAPPS_PYTHON_DEFAULT_MAX_WORKERS',
|
||||||
|
'WEBAPPS_PYTHON_DEFAULT_TIMEOUT',
|
||||||
|
))
|
||||||
|
|
||||||
def save(self, webapp):
|
def save(self, webapp):
|
||||||
context = self.get_context(webapp)
|
context = self.get_context(webapp)
|
||||||
|
|
|
@ -11,7 +11,6 @@ class SymbolicLinkBackend(PHPBackend, ServiceController):
|
||||||
"""
|
"""
|
||||||
Same as PHPBackend but allows you to have the webapps on a directory diferent than the webapps dir.
|
Same as PHPBackend but allows you to have the webapps on a directory diferent than the webapps dir.
|
||||||
"""
|
"""
|
||||||
format_docstring = ()
|
|
||||||
verbose_name = _("Symbolic link webapp")
|
verbose_name = _("Symbolic link webapp")
|
||||||
model = 'webapps.WebApp'
|
model = 'webapps.WebApp'
|
||||||
default_route_match = "webapp.type == 'symbolic-link'"
|
default_route_match = "webapp.type == 'symbolic-link'"
|
||||||
|
|
|
@ -14,15 +14,14 @@ class WordPressBackend(WebAppServiceMixin, ServiceController):
|
||||||
"""
|
"""
|
||||||
Installs the latest version of WordPress available on www.wordpress.org
|
Installs the latest version of WordPress available on www.wordpress.org
|
||||||
It fully configures the wp-config.php (keys included) and sets up the database with initial admin password.
|
It fully configures the wp-config.php (keys included) and sets up the database with initial admin password.
|
||||||
WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST = '%s'
|
|
||||||
"""
|
"""
|
||||||
format_docstring = (
|
|
||||||
settings.WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST,
|
|
||||||
)
|
|
||||||
verbose_name = _("Wordpress")
|
verbose_name = _("Wordpress")
|
||||||
model = 'webapps.WebApp'
|
model = 'webapps.WebApp'
|
||||||
default_route_match = "webapp.type == 'wordpress-php'"
|
default_route_match = "webapp.type == 'wordpress-php'"
|
||||||
script_executable = '/usr/bin/php'
|
script_executable = '/usr/bin/php'
|
||||||
|
doc_settings = (settings,
|
||||||
|
('WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST',)
|
||||||
|
)
|
||||||
|
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
|
|
|
@ -308,7 +308,7 @@ class PHPSuhosinExecutorIncludeWhitelist(PHPAppOption):
|
||||||
|
|
||||||
class PHPUploadMaxFileSize(PHPAppOption):
|
class PHPUploadMaxFileSize(PHPAppOption):
|
||||||
name = 'upload_max_filesize'
|
name = 'upload_max_filesize'
|
||||||
verbose_name = _("Upload max filezise")
|
verbose_name = _("Upload max filesize")
|
||||||
help_text = _("Value between 0M and 999M.")
|
help_text = _("Value between 0M and 999M.")
|
||||||
regex = r'^[0-9]{1,3}M$'
|
regex = r'^[0-9]{1,3}M$'
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,11 @@ from ..utils import normurlpath
|
||||||
|
|
||||||
|
|
||||||
class Apache2Backend(ServiceController):
|
class Apache2Backend(ServiceController):
|
||||||
|
"""
|
||||||
|
Apache 2.4 backend with support for the following directives:
|
||||||
|
<tt>static</tt>, <tt>location</tt>, <tt>fpm</tt>, <tt>fcgid</tt>, <tt>uwsgi</tt>, \
|
||||||
|
<tt>ssl</tt>, <tt>security</tt>, <tt>redirects</tt>, <tt>proxies</tt>, <tt>saas</tt>
|
||||||
|
"""
|
||||||
HTTP_PORT = 80
|
HTTP_PORT = 80
|
||||||
HTTPS_PORT = 443
|
HTTPS_PORT = 443
|
||||||
|
|
||||||
|
@ -22,6 +27,15 @@ class Apache2Backend(ServiceController):
|
||||||
('webapps.WebApp', 'website_set'),
|
('webapps.WebApp', 'website_set'),
|
||||||
)
|
)
|
||||||
verbose_name = _("Apache 2")
|
verbose_name = _("Apache 2")
|
||||||
|
doc_settings = (settings, (
|
||||||
|
'WEBSITES_VHOST_EXTRA_DIRECTIVES',
|
||||||
|
'WEBSITES_DEFAULT_SSL_CERT',
|
||||||
|
'WEBSITES_DEFAULT_SSL_KEY',
|
||||||
|
'WEBSITES_DEFAULT_SSL_CA',
|
||||||
|
'WEBSITES_BASE_APACHE_CONF',
|
||||||
|
'WEBSITES_DEFAULT_IPS',
|
||||||
|
'WEBSITES_SAAS_DIRECTIVES',
|
||||||
|
))
|
||||||
|
|
||||||
def render_virtual_host(self, site, context, ssl=False):
|
def render_virtual_host(self, site, context, ssl=False):
|
||||||
context['port'] = self.HTTPS_PORT if ssl else self.HTTP_PORT
|
context['port'] = self.HTTPS_PORT if ssl else self.HTTP_PORT
|
||||||
|
@ -362,12 +376,14 @@ class Apache2Backend(ServiceController):
|
||||||
class Apache2Traffic(ServiceMonitor):
|
class Apache2Traffic(ServiceMonitor):
|
||||||
"""
|
"""
|
||||||
Parses apache logs,
|
Parses apache logs,
|
||||||
looking for the size of each request on the last word of the log line
|
looking for the size of each request on the last word of the log line.
|
||||||
"""
|
"""
|
||||||
model = 'websites.Website'
|
model = 'websites.Website'
|
||||||
resource = ServiceMonitor.TRAFFIC
|
resource = ServiceMonitor.TRAFFIC
|
||||||
verbose_name = _("Apache 2 Traffic")
|
verbose_name = _("Apache 2 Traffic")
|
||||||
|
doc_settings = (settings,
|
||||||
|
('WEBSITES_TRAFFIC_IGNORE_HOSTS',)
|
||||||
|
)
|
||||||
def prepare(self):
|
def prepare(self):
|
||||||
super(Apache2Traffic, self).prepare()
|
super(Apache2Traffic, self).prepare()
|
||||||
ignore_hosts = '\\|'.join(settings.WEBSITES_TRAFFIC_IGNORE_HOSTS)
|
ignore_hosts = '\\|'.join(settings.WEBSITES_TRAFFIC_IGNORE_HOSTS)
|
||||||
|
|
|
@ -15,6 +15,9 @@ class WebalizerBackend(ServiceController):
|
||||||
verbose_name = _("Webalizer Content")
|
verbose_name = _("Webalizer Content")
|
||||||
model = 'websites.Content'
|
model = 'websites.Content'
|
||||||
default_route_match = "content.webapp.type == 'webalizer'"
|
default_route_match = "content.webapp.type == 'webalizer'"
|
||||||
|
doc_settings = (settings,
|
||||||
|
('WEBSITES_WEBALIZER_PATH',)
|
||||||
|
)
|
||||||
|
|
||||||
def save(self, content):
|
def save(self, content):
|
||||||
context = self.get_context(content)
|
context = self.get_context(content)
|
||||||
|
|
Loading…
Reference in New Issue