Improved backends help texts

This commit is contained in:
Marc Aymerich 2015-04-24 11:39:20 +00:00
parent eebaee1097
commit c2b0186034
28 changed files with 210 additions and 177 deletions

View file

@ -266,7 +266,6 @@ https://code.djangoproject.com/ticket/24576
* MultiCHoiceField proper serialization
# Apache restart fails: detect if appache running, and execute start
* UNIFY PHP FPM settings name
# virtualhost name: name-account?
* 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 ?
* 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
# 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 -
@ -285,7 +285,5 @@ https://code.djangoproject.com/ticket/24576
# replace multichoicefield and jsonfield by ArrayField, HStoreField
# Amend lines???
# Add icon on select contact view
# 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

View file

@ -122,12 +122,13 @@ class AccountListAdmin(AccountAdmin):
# TODO get query string from request.META['QUERY_STRING'] to preserve filters
context = {
'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.allow_tags = True
select_account.order_admin_field = 'username'
select_account.admin_order_field = 'username'
def changelist_view(self, request, extra_context=None):
original_app_label = request.META['PATH_INFO'].split('/')[-5]

View file

@ -14,7 +14,7 @@ from .models import Database, DatabaseUser
class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
list_display = ('name', 'type', 'display_users', 'account_link')
list_filter = ('type',)
search_fields = ['name']
search_fields = ('name', 'account__username')
change_readonly_fields = ('name', 'type')
extra = 1
fieldsets = (
@ -71,7 +71,7 @@ class DatabaseAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
class DatabaseUserAdmin(SelectAccountAdminMixin, ChangePasswordAdminMixin, ExtendedModelAdmin):
list_display = ('username', 'type', 'display_databases', 'account_link')
list_filter = ('type',)
search_fields = ['username']
search_fields = ('username', 'account__username')
form = DatabaseUserChangeForm
add_form = DatabaseUserCreationForm
change_readonly_fields = ('username', 'type')

View file

@ -10,14 +10,14 @@ from . import settings
class MySQLBackend(ServiceController):
"""
Simple backend for creating MySQL databases using `CREATE DATABASE` statement.
DATABASES_DEFAULT_HOST = %s
Simple backend for creating MySQL databases using <tt>CREATE DATABASE</tt> statement.
"""
format_docstring = (settings.DATABASES_DEFAULT_HOST,)
verbose_name = "MySQL database"
model = 'databases.Database'
default_route_match = "database.type == 'mysql'"
doc_settings = (settings,
('DATABASES_DEFAULT_HOST',)
)
def save(self, database):
if database.type != database.MYSQL:
@ -61,13 +61,14 @@ class MySQLBackend(ServiceController):
class MySQLUserBackend(ServiceController):
"""
Simple backend for creating MySQL users using `CREATE USER` statement.
DATABASES_DEFAULT_HOST = %s
""" % settings.DATABASES_DEFAULT_HOST
Simple backend for creating MySQL users using <tt>CREATE USER</tt> statement.
"""
verbose_name = "MySQL user"
model = 'databases.DatabaseUser'
default_route_match = "databaseuser.type == 'mysql'"
doc_settings = (settings,
('DATABASES_DEFAULT_HOST',)
)
def save(self, user):
if user.type != user.MYSQL:
@ -105,7 +106,7 @@ class MySQLUserBackend(ServiceController):
class MysqlDisk(ServiceMonitor):
"""
du -bs <database_path>
<tt>du -bs &lt;database_path&gt;</tt>
Implements triggers for resource limit exceeded and recovery, disabling insert and create privileges.
"""
model = 'databases.Database'

View file

@ -67,7 +67,7 @@ class DomainAdmin(AccountAdminMixin, ExtendedModelAdmin):
inlines = [RecordInline, DomainInline]
list_filter = [TopDomainListFilter]
change_readonly_fields = ('name',)
search_fields = ['name',]
search_fields = ('name', 'account__username')
add_form = BatchDomainCreationAdminForm
change_view_actions = [view_zone]

View file

@ -14,14 +14,8 @@ class Bind9MasterDomainBackend(ServiceController):
"""
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.
DOMAINS_SLAVES = %s
DOMAINS_MASTERS_PATH = '%s'
"""
format_docstring = (
str(settings.DOMAINS_SLAVES),
settings.DOMAINS_MASTERS_PATH,
)
CONF_PATH = settings.DOMAINS_MASTERS_PATH
verbose_name = _("Bind9 master domain")
model = 'domains.Domain'
@ -30,7 +24,9 @@ class Bind9MasterDomainBackend(ServiceController):
('domains.Domain', 'origin'),
)
ignore_fields = ['serial']
CONF_PATH = settings.DOMAINS_MASTERS_PATH
doc_settings = (settings,
('DOMAINS_SLAVES', 'DOMAINS_MASTERS_PATH')
)
@classmethod
def is_main(cls, obj):
@ -136,15 +132,16 @@ class Bind9SlaveDomainBackend(Bind9MasterDomainBackend):
"""
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.
DOMAINS_MASTERS = %s
""" % str(settings.DOMAINS_MASTERS)
"""
CONF_PATH = settings.DOMAINS_SLAVES_PATH
verbose_name = _("Bind9 slave domain")
related_models = (
('domains.Domain', 'origin'),
)
CONF_PATH = settings.DOMAINS_SLAVES_PATH
doc_settings = (settings,
('DOMAINS_MASTERS', 'DOMAINS_SLAVES_PATH')
)
def save(self, domain):
context = self.get_context(domain)
self.update_conf(context)

View file

@ -42,8 +42,8 @@ class MessageReadOnlyInline(admin.TabularInline):
model = Message
extra = 0
can_delete = False
fields = ['content_html']
readonly_fields = ['content_html']
fields = ('content_html',)
readonly_fields = ('content_html',)
class Media:
css = {
@ -79,7 +79,7 @@ class MessageInline(admin.TabularInline):
max_num = 1
form = MessageInlineForm
can_delete = False
fields = ['content']
fields = ('content',)
def get_formset(self, request, obj=None, **kwargs):
""" hook request.user on the inline form """
@ -93,14 +93,14 @@ class MessageInline(admin.TabularInline):
class TicketInline(admin.TabularInline):
fields = [
fields = (
'ticket_id', 'subject', 'creator_link', 'owner_link', 'colored_state',
'colored_priority', 'created', 'updated'
]
readonly_fields = [
)
readonly_fields = (
'ticket_id', 'subject', 'creator_link', 'owner_link', 'colored_state',
'colored_priority', 'created', 'updated'
]
)
model = Ticket
extra = 0
max_num = 0
@ -119,35 +119,35 @@ class TicketInline(admin.TabularInline):
class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin):
list_display = [
list_display = (
'unbold_id', 'bold_subject', 'display_creator', 'display_owner',
'display_queue', 'display_priority', 'display_state', 'updated'
]
)
list_display_links = ('unbold_id', 'bold_subject')
list_filter = [
list_filter = (
MyTicketsListFilter, 'queue__name', 'priority', TicketStateListFilter,
]
)
default_changelist_filters = (
('my_tickets', lambda r: 'True' if not r.user.is_superuser else 'False'),
('state', 'OPEN')
)
date_hierarchy = 'created_at'
search_fields = [
search_fields = (
'id', 'subject', 'creator__username', 'creator__email', 'queue__name',
'owner__username'
]
actions = [
)
actions = (
mark_as_unread, mark_as_read, 'delete_selected', reject_tickets,
resolve_tickets, close_tickets, take_tickets
]
sudo_actions = ['delete_selected']
change_view_actions = [
)
sudo_actions = ('delete_selected',)
change_view_actions = (
resolve_tickets, close_tickets, reject_tickets, take_tickets
]
)
# change_form_template = "admin/orchestra/change_form.html"
form = TicketForm
add_inlines = []
inlines = [ MessageReadOnlyInline, MessageInline ]
add_inlines = ()
inlines = (MessageReadOnlyInline, MessageInline)
readonly_fields = (
'display_summary', 'display_queue', 'display_owner', 'display_state',
'display_priority'
@ -286,10 +286,10 @@ class TicketAdmin(ChangeListDefaultFilter, ExtendedModelAdmin):
class QueueAdmin(admin.ModelAdmin):
list_display = ['name', 'default', 'num_tickets']
actions = [set_default_queue]
inlines = [TicketInline]
ordering = ['name']
list_display = ('name', 'default', 'num_tickets')
actions = (set_default_queue,)
inlines = (TicketInline,)
ordering = ('name',)
class Media:
css = {

View file

@ -11,18 +11,8 @@ from .models import List
class MailmanBackend(ServiceController):
"""
Mailman backend based on `newlist`, it handles custom domains.
LISTS_VIRTUAL_ALIAS_PATH = '%s'
LISTS_VIRTUAL_ALIAS_DOMAINS_PATH = '%s'
LISTS_DEFAULT_DOMAIN = '%s'
LISTS_MAILMAN_ROOT_DIR = '%s'
Mailman 2 backend based on <tt>newlist</tt>, it handles custom domains.
"""
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"
model = 'lists.List'
addresses = [
@ -37,6 +27,12 @@ class MailmanBackend(ServiceController):
'-subscribe',
'-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):
if context['address_domain']:
@ -165,16 +161,15 @@ class MailmanBackend(ServiceController):
class MailmanTraffic(ServiceMonitor):
"""
Parses mailman log file looking for email size and multiples it by `list_members` count.
LISTS_MAILMAN_POST_LOG_PATH = '%s'
Parses mailman log file looking for email size and multiples it by <tt>list_members</tt> count.
"""
format_docstring = (
settings.LISTS_MAILMAN_POST_LOG_PATH,
)
model = 'lists.List'
resource = ServiceMonitor.TRAFFIC
verbose_name = _("Mailman traffic")
script_executable = '/usr/bin/python'
doc_settings = (settings,
('LISTS_MAILMAN_POST_LOG_PATH',)
)
def prepare(self):
postlog = settings.LISTS_MAILMAN_POST_LOG_PATH
@ -272,7 +267,7 @@ class MailmanTraffic(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'
verbose_name = _("Mailman subscribers")

View file

@ -3,6 +3,8 @@ from urllib.parse import parse_qs
from django import forms
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 orchestra.admin import ExtendedModelAdmin, ChangePasswordAdminMixin
@ -104,13 +106,15 @@ class MailboxAdmin(ChangePasswordAdminMixin, SelectAccountAdminMixin, ExtendedMo
class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
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)
fields = ('account_link', 'email_link', 'mailboxes', 'forward')
add_fields = ('account_link', ('name', 'domain'), 'mailboxes', 'forward')
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')
filter_by_account_fields = ('domain', 'mailboxes')
filter_horizontal = ['mailboxes']
@ -119,6 +123,11 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
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):
link = self.domain_link(address)
return "%s@%s" % (address.name, link)
@ -153,6 +162,10 @@ class AddressAdmin(SelectAccountAdminMixin, ExtendedModelAdmin):
fields = list(fields)
fields.remove('mailboxes')
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)

View file

@ -185,21 +185,15 @@ class DovecotPostfixPasswdVirtualUserBackend(ServiceController):
class PostfixAddressBackend(ServiceController):
"""
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")
model = 'mailboxes.Address'
related_models = (
('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):
if context['domain'] != context['local_domain']:
self.append(textwrap.dedent("""
@ -296,15 +290,13 @@ class DovecotMaildirDisk(ServiceMonitor):
"""
Maildir disk usage based on Dovecot maildirsize file
http://wiki2.dovecot.org/Quota/Maildir
MAILBOXES_MAILDIRSIZE_PATH = '%s'
"""
format_docstring = (
settings.MAILBOXES_MAILDIRSIZE_PATH,
)
model = 'mailboxes.Mailbox'
resource = ServiceMonitor.DISK
verbose_name = _("Dovecot Maildir size")
doc_settings = (settings,
('MAILBOXES_MAILDIRSIZE_PATH',)
)
def prepare(self):
super(DovecotMaildirDisk, self).prepare()
@ -331,15 +323,14 @@ class PostfixMailscannerTraffic(ServiceMonitor):
"""
A high-performance log parser.
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'
resource = ServiceMonitor.TRAFFIC
verbose_name = _("Postfix-Mailscanner traffic")
script_executable = '/usr/bin/python'
doc_settings = (settings,
('MAILBOXES_MAIL_LOG_PATH',)
)
def prepare(self):
mail_log = settings.MAILBOXES_MAIL_LOG_PATH

View file

@ -58,7 +58,7 @@ class MiscellaneousAdmin(AccountAdminMixin, SelectPluginAdminMixin, admin.ModelA
)
list_filter = ('service__name', 'is_active')
list_select_related = ('service', 'account')
search_fields = ('identifier', 'description')
search_fields = ('identifier', 'description', 'account__username')
plugin_field = 'service'
plugin = MiscServicePlugin

View file

@ -45,7 +45,7 @@ class ServiceBackend(plugins.Plugin, metaclass=ServiceMount):
default_route_match = 'True'
# Force the backend manager to block in multiple backend executions executing them synchronously
block = False
format_docstring = ()
doc_settings = None
def __str__(self):
return type(self).__name__

View file

@ -11,30 +11,36 @@ from django.utils.translation import ungettext, ugettext_lazy as _
def get_backends_help_text(backends):
help_texts = {}
for backend in backends:
help_text = backend.__doc__ or ''
context = {
'model': backend.model,
'related_models': str(backend.related_models),
'script_executable': backend.script_executable,
'script_method': str(backend.script_method),
'function_method': str(backend.script_method),
'actions': ', '.join(backend.actions),
'script_method': '.'.join((backend.script_method.__module__, backend.script_method.__name__)),
'function_method': '.'.join((backend.function_method.__module__, backend.function_method.__name__)),
'actions': str(backend.actions),
}
help_text = textwrap.dedent("""
- Model: '%(model)s'<br>
- Related models: %(related_models)s<br>
- Script executable: %(script_executable)s<br>
- Script method: %(script_method)s<br>
- Function method: %(function_method)s<br>
- Actions: %(actions)s<br>"""
help_text += textwrap.dedent("""
- Model: <tt>'%(model)s'</tt>
- Related models: <tt>%(related_models)s</tt>
- Script executable: <tt>%(script_executable)s</tt>
- Script method: <tt>%(script_method)s</tt>
- Function method: <tt>%(function_method)s</tt>
- Actions: <tt>%(actions)s</tt>
"""
) % context
docstring = backend.__doc__
if docstring:
try:
docstring = (docstring % backend.format_docstring).strip().splitlines()
except TypeError as e:
raise TypeError(str(backend) + str(e))
help_text += '<br>' + '<br>'.join(docstring)
help_texts[backend.get_name()] = help_text
help_text = help_text.lstrip().splitlines()
help_settings = ['']
if backend.doc_settings:
module, names = backend.doc_settings
for name in names:
value = getattr(module, name)
if isinstance(value, str):
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

View file

@ -12,6 +12,9 @@ class BSCWBackend(ServiceController):
model = 'saas.SaaS'
default_route_match = "saas.service == 'bscw'"
actions = ('save', 'delete', 'validate_creation')
doc_settings = (settings,
('SAAS_BSCW_BSADMIN_PATH',)
)
def validate_creation(self, saas):
context = self.get_context(saas)

View file

@ -8,8 +8,14 @@ from .. import settings
class DokuWikiMuBackend(ServiceController):
"""
Creates a DokuWiki site on a DokuWiki multisite installation.
"""
verbose_name = _("DokuWiki multisite")
model = 'webapps.WebApp'
doc_settings = (settings,
('SAAS_DOKUWIKI_TEMPLATE_PATH', 'SAAS_DOKUWIKI_FARM_PATH')
)
def save(self, webapp):
context = self.get_context(webapp)
@ -25,7 +31,7 @@ class DokuWikiMuBackend(ServiceController):
def get_context(self, webapp):
context = super(DokuWikiMuBackend, self).get_context(webapp)
context.update({
'template': settings.WEBAPPS_DOKUWIKIMU_TEMPLATE_PATH,
'app_path': os.path.join(settings.WEBAPPS_DOKUWIKIMU_FARM_PATH, webapp.name)
'template': settings.SAAS_DOKUWIKI_TEMPLATE_PATH,
'app_path': os.path.join(settings.SAAS_DOKUWIKI_FARM_PATH, webapp.name)
})
return replace(context, "'", '"')

View file

@ -9,9 +9,15 @@ from .. import settings
class DrupalMuBackend(ServiceController):
"""
Creates a Drupal site on a Drupal multisite installation
"""
verbose_name = _("Drupal multisite")
model = 'webapps.WebApp'
doc_settings = (settings,
('SAAS_DRUPAL_SITES_PATH',)
)
def save(self, webapp):
context = self.get_context(webapp)
self.append(textwrap.dedent("""\
@ -32,6 +38,6 @@ class DrupalMuBackend(ServiceController):
def get_context(self, 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')
return replace(context, "'", '"')

View file

@ -14,6 +14,9 @@ class GitLabSaaSBackend(ServiceController):
default_route_match = "saas.service == 'gitlab'"
block = True
actions = ('save', 'delete', 'validate_creation')
doc_settings = (settings,
('SAAS_GITLAB_DOMAIN', 'SAAS_GITLAB_ROOT_PASSWORD'),
)
def get_base_url(self):
return 'https://%s/api/v3' % settings.SAAS_GITLAB_DOMAIN

View file

@ -7,6 +7,14 @@ from orchestra.contrib.orchestration import 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")
model = 'saas.SaaS'
default_route_match = "saas.service == 'phplist'"

View file

@ -9,16 +9,22 @@ from .. import settings
class WordpressMuBackend(ServiceController):
"""
Creates a wordpress site on a WordPress MultiSite installation.
"""
verbose_name = _("Wordpress multisite")
model = 'webapps.WebApp'
default_route_match = "webapp.type == 'wordpress-mu'"
doc_settings = (settings,
('SAAS_WORDPRESS_ADMIN_PASSWORD', 'SAAS_WORDPRESS_BASE_URL')
)
def login(self, session):
base_url = self.get_base_url()
login_url = base_url + '/wp-login.php'
login_data = {
'log': 'admin',
'pwd': settings.WEBAPPS_WORDPRESSMU_ADMIN_PASSWORD,
'pwd': settings.SAAS_WORDPRESS_ADMIN_PASSWORD,
'redirect_to': '/wp-admin/'
}
response = session.post(login_url, data=login_data)
@ -26,7 +32,7 @@ class WordpressMuBackend(ServiceController):
raise IOError("Failure login to remote application")
def get_base_url(self):
base_url = settings.WEBAPPS_WORDPRESSMU_BASE_URL
base_url = settings.SAAS_WORDPRESS_BASE_URL
return base_url.rstrip('/')
def validate_response(self, response):

View file

@ -11,18 +11,14 @@ from . import settings
class UNIXUserBackend(ServiceController):
"""
Basic UNIX system user/group support based on `useradd`, `usermod`, `userdel` and `groupdel`.
<tt>SYSTEMUSERS_DEFAULT_GROUP_MEMBERS = '%s'
SYSTEMUSERS_MOVE_ON_DELETE_PATH = '%s'</tt>
Basic UNIX system user/group support based on <tt>useradd</tt>, <tt>usermod</tt>, <tt>userdel</tt> and <tt>groupdel</tt>.
"""
format_docstring = (
settings.SYSTEMUSERS_DEFAULT_GROUP_MEMBERS,
settings.SYSTEMUSERS_MOVE_ON_DELETE_PATH,
)
verbose_name = _("UNIX user")
model = 'systemusers.SystemUser'
actions = ('save', 'delete', 'grant_permission')
doc_settings = (settings,
('SYSTEMUSERS_DEFAULT_GROUP_MEMBERS', 'SYSTEMUSERS_MOVE_ON_DELETE_PATH')
)
def save(self, user):
context = self.get_context(user)
@ -95,7 +91,7 @@ class UNIXUserBackend(ServiceController):
class UNIXUserDisk(ServiceMonitor):
"""
`du -bs <home>`
<tt>du -bs &lt;home&gt;</tt>
"""
model = 'systemusers.SystemUser'
resource = ServiceMonitor.DISK
@ -123,17 +119,15 @@ class UNIXUserDisk(ServiceMonitor):
class Exim4Traffic(ServiceMonitor):
"""
Exim4 mainlog parser for mails sent on the webserver by system users (e.g. via PHP mail())
SYSTEMUSERS_MAIL_LOG_PATH = '%s'
Exim4 mainlog parser for mails sent on the webserver by system users (e.g. via PHP <tt>mail()</tt>)
"""
format_docstring = (
settings.SYSTEMUSERS_MAIL_LOG_PATH,
)
model = 'systemusers.SystemUser'
resource = ServiceMonitor.TRAFFIC
verbose_name = _("Exim4 traffic")
script_executable = '/usr/bin/python'
doc_settings = (settings,
('SYSTEMUSERS_MAIL_LOG_PATH',)
)
def prepare(self):
mainlog = settings.SYSTEMUSERS_MAIL_LOG_PATH
@ -211,15 +205,14 @@ class Exim4Traffic(ServiceMonitor):
class VsFTPdTraffic(ServiceMonitor):
"""
vsFTPd log parser.
SYSTEMUSERS_FTP_LOG_PATH = '%s'
"""
format_docstring = (
settings.SYSTEMUSERS_FTP_LOG_PATH,
)
model = 'systemusers.SystemUser'
resource = ServiceMonitor.TRAFFIC
verbose_name = _('VsFTPd traffic')
script_executable = '/usr/bin/python'
doc_settings = (settings,
('SYSTEMUSERS_FTP_LOG_PATH',)
)
def prepare(self):
vsftplog = settings.SYSTEMUSERS_FTP_LOG_PATH

View file

@ -12,6 +12,9 @@ class WebAppServiceMixin(object):
('webapps.WebAppOption', 'webapp'),
)
directive = None
doc_settings = (settings,
('WEBAPPS_UNDER_CONSTRUCTION_PATH', 'WEBAPPS_MOVE_ON_DELETE_PATH',)
)
def create_webapp_dir(self, context):
self.append(textwrap.dedent("""\
@ -45,7 +48,7 @@ class WebAppServiceMixin(object):
'type': webapp.type,
'app_path': webapp.get_path(),
'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(),
}
context['deleted_app_path'] = settings.WEBAPPS_MOVE_ON_DELETE_PATH % context

View file

@ -14,29 +14,21 @@ class PHPBackend(WebAppServiceMixin, ServiceController):
"""
PHP support for apache-mod-fcgid and php-fpm.
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 = (
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,
)
MERGE = settings.WEBAPPS_MERGE_PHP_WEBAPPS
verbose_name = _("PHP FPM/FCGID")
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):
context = self.get_context(webapp)

View file

@ -12,22 +12,16 @@ from .. import settings
class uWSGIPythonBackend(WebAppServiceMixin, ServiceController):
"""
Emperor mode
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
<a href="http://uwsgi-docs.readthedocs.org/en/latest/Emperor.html">Emperor mode</a>
"""
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")
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):
context = self.get_context(webapp)

View file

@ -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.
"""
format_docstring = ()
verbose_name = _("Symbolic link webapp")
model = 'webapps.WebApp'
default_route_match = "webapp.type == 'symbolic-link'"

View file

@ -14,15 +14,14 @@ class WordPressBackend(WebAppServiceMixin, ServiceController):
"""
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.
WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST = '%s'
"""
format_docstring = (
settings.WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST,
)
verbose_name = _("Wordpress")
model = 'webapps.WebApp'
default_route_match = "webapp.type == 'wordpress-php'"
script_executable = '/usr/bin/php'
doc_settings = (settings,
('WEBAPPS_DEFAULT_MYSQL_DATABASE_HOST',)
)
def prepare(self):
self.append(textwrap.dedent("""\

View file

@ -308,7 +308,7 @@ class PHPSuhosinExecutorIncludeWhitelist(PHPAppOption):
class PHPUploadMaxFileSize(PHPAppOption):
name = 'upload_max_filesize'
verbose_name = _("Upload max filezise")
verbose_name = _("Upload max filesize")
help_text = _("Value between 0M and 999M.")
regex = r'^[0-9]{1,3}M$'

View file

@ -13,6 +13,11 @@ from ..utils import normurlpath
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
HTTPS_PORT = 443
@ -22,6 +27,15 @@ class Apache2Backend(ServiceController):
('webapps.WebApp', 'website_set'),
)
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):
context['port'] = self.HTTPS_PORT if ssl else self.HTTP_PORT
@ -362,12 +376,14 @@ class Apache2Backend(ServiceController):
class Apache2Traffic(ServiceMonitor):
"""
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'
resource = ServiceMonitor.TRAFFIC
verbose_name = _("Apache 2 Traffic")
doc_settings = (settings,
('WEBSITES_TRAFFIC_IGNORE_HOSTS',)
)
def prepare(self):
super(Apache2Traffic, self).prepare()
ignore_hosts = '\\|'.join(settings.WEBSITES_TRAFFIC_IGNORE_HOSTS)

View file

@ -15,6 +15,9 @@ class WebalizerBackend(ServiceController):
verbose_name = _("Webalizer Content")
model = 'websites.Content'
default_route_match = "content.webapp.type == 'webalizer'"
doc_settings = (settings,
('WEBSITES_WEBALIZER_PATH',)
)
def save(self, content):
context = self.get_context(content)