Random fixes
This commit is contained in:
parent
d5cc1b7d7c
commit
786b9a7657
5
TODO.md
5
TODO.md
|
@ -160,9 +160,6 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
||||||
|
|
||||||
* service.name / verbose_name instead of .description ?
|
* service.name / verbose_name instead of .description ?
|
||||||
* miscellaneous.name / verbose_name
|
* miscellaneous.name / verbose_name
|
||||||
* service.invoice_name
|
|
||||||
|
|
||||||
* Bills can have sublines?
|
|
||||||
|
|
||||||
* proforma without billing contact?
|
* proforma without billing contact?
|
||||||
|
|
||||||
|
@ -177,3 +174,5 @@ Remember that, as always with QuerySets, any subsequent chained methods which im
|
||||||
* ManyToManyField.symmetrical = False (user group)
|
* ManyToManyField.symmetrical = False (user group)
|
||||||
|
|
||||||
* REST PERMISSIONS
|
* REST PERMISSIONS
|
||||||
|
|
||||||
|
* caching based on def text2int(textnum, numwords={}):
|
||||||
|
|
|
@ -42,7 +42,7 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
|
||||||
)
|
)
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(_("User"), {
|
(_("User"), {
|
||||||
'fields': ('username', 'password',)
|
'fields': ('username', 'password', 'main_systemuser_link')
|
||||||
}),
|
}),
|
||||||
(_("Personal info"), {
|
(_("Personal info"), {
|
||||||
'fields': ('first_name', 'last_name', 'email', ('type', 'language'), 'comments'),
|
'fields': ('first_name', 'last_name', 'email', ('type', 'language'), 'comments'),
|
||||||
|
@ -59,12 +59,14 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
|
||||||
add_form = AccountCreationForm
|
add_form = AccountCreationForm
|
||||||
form = UserChangeForm
|
form = UserChangeForm
|
||||||
filter_horizontal = ()
|
filter_horizontal = ()
|
||||||
change_readonly_fields = ('username',)
|
change_readonly_fields = ('username', 'main_systemuser_link')
|
||||||
change_form_template = 'admin/accounts/account/change_form.html'
|
change_form_template = 'admin/accounts/account/change_form.html'
|
||||||
actions = [disable]
|
actions = [disable]
|
||||||
change_view_actions = actions
|
change_view_actions = actions
|
||||||
list_select_related = ('billcontact',)
|
list_select_related = ('billcontact',)
|
||||||
|
|
||||||
|
main_systemuser_link = admin_link('main_systemuser')
|
||||||
|
|
||||||
def formfield_for_dbfield(self, db_field, **kwargs):
|
def formfield_for_dbfield(self, db_field, **kwargs):
|
||||||
""" Make value input widget bigger """
|
""" Make value input widget bigger """
|
||||||
if db_field.name == 'comments':
|
if db_field.name == 'comments':
|
||||||
|
@ -101,9 +103,11 @@ class AccountAdmin(ChangePasswordAdminMixin, auth.UserAdmin, ExtendedModelAdmin)
|
||||||
return fieldsets
|
return fieldsets
|
||||||
|
|
||||||
def save_model(self, request, obj, form, change):
|
def save_model(self, request, obj, form, change):
|
||||||
super(AccountAdmin, self).save_model(request, obj, form, change)
|
|
||||||
if not change:
|
if not change:
|
||||||
|
form.save_model(obj)
|
||||||
form.save_related(obj)
|
form.save_related(obj)
|
||||||
|
else:
|
||||||
|
super(AccountAdmin, self).save_model(request, obj, form, change)
|
||||||
|
|
||||||
|
|
||||||
admin.site.register(Account, AccountAdmin)
|
admin.site.register(Account, AccountAdmin)
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.db.models.loading import get_model
|
from django.db.models.loading import get_model
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
@ -9,12 +11,12 @@ from .models import Account
|
||||||
|
|
||||||
|
|
||||||
def create_account_creation_form():
|
def create_account_creation_form():
|
||||||
fields = {
|
fields = OrderedDict(**{
|
||||||
'create_systemuser': forms.BooleanField(initial=True, required=False,
|
'enable_systemuser': forms.BooleanField(initial=True, required=False,
|
||||||
label=_("Create systemuser"), widget=forms.CheckboxInput(attrs={'disabled': True}),
|
label=_("Enable systemuser"),
|
||||||
help_text=_("Designates whether to creates a related system user with the same "
|
help_text=_("Designates whether to creates an enabled or disabled related system user. "
|
||||||
"username and password or not."))
|
"Notice that a related system user will be always created."))
|
||||||
}
|
})
|
||||||
for model, key, kwargs, help_text in settings.ACCOUNTS_CREATE_RELATED:
|
for model, key, kwargs, help_text in settings.ACCOUNTS_CREATE_RELATED:
|
||||||
model = get_model(model)
|
model = get_model(model)
|
||||||
field_name = 'create_%s' % model._meta.model_name
|
field_name = 'create_%s' % model._meta.model_name
|
||||||
|
@ -46,6 +48,8 @@ def create_account_creation_form():
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
_("A %s with this name already exists") % verbose_name
|
_("A %s with this name already exists") % verbose_name
|
||||||
)
|
)
|
||||||
|
def save_model(self, account):
|
||||||
|
account.save(active_systemuser=self.cleaned_data['enable_systemuser'])
|
||||||
|
|
||||||
def save_related(self, account):
|
def save_related(self, account):
|
||||||
for model, key, related_kwargs, __ in settings.ACCOUNTS_CREATE_RELATED:
|
for model, key, related_kwargs, __ in settings.ACCOUNTS_CREATE_RELATED:
|
||||||
|
@ -60,6 +64,7 @@ def create_account_creation_form():
|
||||||
fields.update({
|
fields.update({
|
||||||
'create_related_fields': fields.keys(),
|
'create_related_fields': fields.keys(),
|
||||||
'clean': clean,
|
'clean': clean,
|
||||||
|
'save_model': save_model,
|
||||||
'save_related': save_related,
|
'save_related': save_related,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -60,12 +60,12 @@ class Account(auth.AbstractBaseUser):
|
||||||
def get_main(cls):
|
def get_main(cls):
|
||||||
return cls.objects.get(pk=settings.ACCOUNTS_MAIN_PK)
|
return cls.objects.get(pk=settings.ACCOUNTS_MAIN_PK)
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, active_systemuser=False, *args, **kwargs):
|
||||||
created = not self.pk
|
created = not self.pk
|
||||||
super(Account, self).save(*args, **kwargs)
|
super(Account, self).save(*args, **kwargs)
|
||||||
if created:
|
if created:
|
||||||
self.main_systemuser = self.systemusers.create(account=self, username=self.username,
|
self.main_systemuser = self.systemusers.create(account=self, username=self.username,
|
||||||
password=self.password)
|
password=self.password, is_active=active_systemuser)
|
||||||
self.save(update_fields=['main_systemuser'])
|
self.save(update_fields=['main_systemuser'])
|
||||||
|
|
||||||
def clean(self):
|
def clean(self):
|
||||||
|
|
|
@ -146,10 +146,7 @@ class Order(models.Model):
|
||||||
if account_id is None:
|
if account_id is None:
|
||||||
# New account workaround -> user.account_id == None
|
# New account workaround -> user.account_id == None
|
||||||
continue
|
continue
|
||||||
ignore = False
|
ignore = service.handler.get_ignore(instance)
|
||||||
account = getattr(instance, 'account', instance)
|
|
||||||
if account.is_superuser:
|
|
||||||
ignore = service.ignore_superusers
|
|
||||||
order = cls(content_object=instance, service=service,
|
order = cls(content_object=instance, service=service,
|
||||||
account_id=account_id, ignore=ignore)
|
account_id=account_id, ignore=ignore)
|
||||||
if commit:
|
if commit:
|
||||||
|
@ -163,8 +160,7 @@ class Order(models.Model):
|
||||||
order.update()
|
order.update()
|
||||||
elif orders:
|
elif orders:
|
||||||
order = orders.get()
|
order = orders.get()
|
||||||
if commit:
|
order.cancel(commit=commit)
|
||||||
order.cancel()
|
|
||||||
updates.append((order, 'cancelled'))
|
updates.append((order, 'cancelled'))
|
||||||
return updates
|
return updates
|
||||||
|
|
||||||
|
@ -188,10 +184,12 @@ class Order(models.Model):
|
||||||
self.description = description
|
self.description = description
|
||||||
self.save(update_fields=['description'])
|
self.save(update_fields=['description'])
|
||||||
|
|
||||||
def cancel(self):
|
def cancel(self, commit=True):
|
||||||
self.cancelled_on = timezone.now()
|
self.cancelled_on = timezone.now()
|
||||||
self.save(update_fields=['cancelled_on'])
|
self.ignore = self.service.handler.get_order_ignore(self)
|
||||||
logger.info("CANCELLED order id: {id}".format(id=self.id))
|
if commit:
|
||||||
|
self.save(update_fields=['cancelled_on', 'ignore'])
|
||||||
|
logger.info("CANCELLED order id: {id}".format(id=self.id))
|
||||||
|
|
||||||
def mark_as_ignored(self):
|
def mark_as_ignored(self):
|
||||||
self.ignore = True
|
self.ignore = True
|
||||||
|
|
|
@ -10,3 +10,23 @@ SAAS_ENABLED_SERVICES = getattr(settings, 'SAAS_ENABLED_SERVICES', (
|
||||||
'orchestra.apps.saas.services.gitlab.GitLabService',
|
'orchestra.apps.saas.services.gitlab.GitLabService',
|
||||||
'orchestra.apps.saas.services.phplist.PHPListService',
|
'orchestra.apps.saas.services.phplist.PHPListService',
|
||||||
))
|
))
|
||||||
|
|
||||||
|
|
||||||
|
SAAS_WORDPRESSMU_BASE_URL = getattr(settings, 'SAAS_WORDPRESSMU_BASE_URL',
|
||||||
|
'http://%(site_name)s.example.com')
|
||||||
|
|
||||||
|
|
||||||
|
SAAS_WORDPRESSMU_ADMIN_PASSWORD = getattr(settings, 'SAAS_WORDPRESSMU_ADMIN_PASSWORD',
|
||||||
|
'secret')
|
||||||
|
|
||||||
|
|
||||||
|
SAAS_DOKUWIKIMU_TEMPLATE_PATH = setattr(settings, 'SAAS_DOKUWIKIMU_TEMPLATE_PATH',
|
||||||
|
'/home/httpd/htdocs/wikifarm/template.tar.gz')
|
||||||
|
|
||||||
|
|
||||||
|
SAAS_DOKUWIKIMU_FARM_PATH = getattr(settings, 'SAAS_DOKUWIKIMU_FARM_PATH',
|
||||||
|
'/home/httpd/htdocs/wikifarm/farm')
|
||||||
|
|
||||||
|
|
||||||
|
SAAS_DRUPAL_SITES_PATH = getattr(settings, 'SAAS_DRUPAL_SITES_PATH',
|
||||||
|
'/home/httpd/htdocs/drupal-mu/sites/%(site_name)s')
|
||||||
|
|
|
@ -42,7 +42,8 @@ class ServiceAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
}),
|
}),
|
||||||
(_("Billing options"), {
|
(_("Billing options"), {
|
||||||
'classes': ('wide',),
|
'classes': ('wide',),
|
||||||
'fields': ('billing_period', 'billing_point', 'is_fee', 'order_description')
|
'fields': ('billing_period', 'billing_point', 'is_fee', 'order_description',
|
||||||
|
'ignore_period')
|
||||||
}),
|
}),
|
||||||
(_("Pricing options"), {
|
(_("Pricing options"), {
|
||||||
'classes': ('wide',),
|
'classes': ('wide',),
|
||||||
|
|
|
@ -55,6 +55,32 @@ class ServiceHandler(plugins.Plugin):
|
||||||
}
|
}
|
||||||
return eval(self.match, safe_locals)
|
return eval(self.match, safe_locals)
|
||||||
|
|
||||||
|
def get_ignore_delta(self):
|
||||||
|
if self.ignore_period == self.NEVER:
|
||||||
|
return None
|
||||||
|
value, unit = self.ignore_period.split('_')
|
||||||
|
value = text2int(value)
|
||||||
|
if unit.lowe().startswith('day'):
|
||||||
|
return timedelta(days=value)
|
||||||
|
if unit.lowe().startswith('month'):
|
||||||
|
return timedelta(months=value)
|
||||||
|
else:
|
||||||
|
raise ValueError("Unknown unit %s" % unit)
|
||||||
|
|
||||||
|
def get_order_ignore(self, order):
|
||||||
|
""" service trial delta """
|
||||||
|
ignore_delta = self.get_ignore_delta()
|
||||||
|
if ignore_delta and (order.cancelled_on-ignore_delta).date() <= order.registered_on:
|
||||||
|
return True
|
||||||
|
return order.ignore
|
||||||
|
|
||||||
|
def get_ignore(self, instance):
|
||||||
|
ignore = False
|
||||||
|
account = getattr(instance, 'account', instance)
|
||||||
|
if account.is_superuser:
|
||||||
|
ignore = self.ignore_superusers
|
||||||
|
return ignore
|
||||||
|
|
||||||
def get_metric(self, instance):
|
def get_metric(self, instance):
|
||||||
if self.metric:
|
if self.metric:
|
||||||
safe_locals = {
|
safe_locals = {
|
||||||
|
|
|
@ -89,6 +89,8 @@ class Service(models.Model):
|
||||||
# DAILY = 'DAILY'
|
# DAILY = 'DAILY'
|
||||||
MONTHLY = 'MONTHLY'
|
MONTHLY = 'MONTHLY'
|
||||||
ANUAL = 'ANUAL'
|
ANUAL = 'ANUAL'
|
||||||
|
ONE_DAY = 'ONE_DAY'
|
||||||
|
TWO_DAYS = 'TWO_DAYS'
|
||||||
TEN_DAYS = 'TEN_DAYS'
|
TEN_DAYS = 'TEN_DAYS'
|
||||||
ONE_MONTH = 'ONE_MONTH'
|
ONE_MONTH = 'ONE_MONTH'
|
||||||
ALWAYS = 'ALWAYS'
|
ALWAYS = 'ALWAYS'
|
||||||
|
@ -158,6 +160,17 @@ class Service(models.Model):
|
||||||
"used for generating the description for the bill lines of this services.<br>"
|
"used for generating the description for the bill lines of this services.<br>"
|
||||||
"Defaults to <tt>'%s: %s' % (handler.description, instance)</tt>"
|
"Defaults to <tt>'%s: %s' % (handler.description, instance)</tt>"
|
||||||
))
|
))
|
||||||
|
ignore_period = models.CharField(_("ignore period"), max_length=16, blank=True,
|
||||||
|
help_text=_("Period in which orders will be ignored if cancelled. "
|
||||||
|
"Useful for designating <i>trial periods</i>"),
|
||||||
|
choices=(
|
||||||
|
(NEVER, _("No ignore")),
|
||||||
|
(ONE_DAY, _("One day")),
|
||||||
|
(TWO_DAYS, _("Two days")),
|
||||||
|
(TEN_DAYS, _("Ten days")),
|
||||||
|
(ONE_MONTH, _("One month")),
|
||||||
|
),
|
||||||
|
default=settings.SERVICES_DEFAULT_IGNORE_PERIOD)
|
||||||
# Pricing
|
# Pricing
|
||||||
metric = models.CharField(_("metric"), max_length=256, blank=True,
|
metric = models.CharField(_("metric"), max_length=256, blank=True,
|
||||||
help_text=_(
|
help_text=_(
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
@ -14,3 +16,6 @@ SERVICES_SERVICE_ANUAL_BILLING_MONTH = getattr(settings, 'SERVICES_SERVICE_ANUAL
|
||||||
|
|
||||||
|
|
||||||
SERVICES_ORDER_MODEL = getattr(settings, 'SERVICES_ORDER_MODEL', 'orders.Order')
|
SERVICES_ORDER_MODEL = getattr(settings, 'SERVICES_ORDER_MODEL', 'orders.Order')
|
||||||
|
|
||||||
|
|
||||||
|
SERVICES_DEFAULT_IGNORE_PERIOD = getattr(settings, 'SERVICES_DEFAULT_IGNORE_PERIOD', 'TWO_DAYS')
|
||||||
|
|
|
@ -55,7 +55,6 @@ class WebAppServiceMixin(object):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
for __, module_name, __ in pkgutil.walk_packages(__path__):
|
for __, module_name, __ in pkgutil.walk_packages(__path__):
|
||||||
# sorry for the exec(), but Import module function fails :(
|
# sorry for the exec(), but Import module function fails :(
|
||||||
exec('from . import %s' % module_name)
|
exec('from . import %s' % module_name)
|
||||||
|
|
|
@ -5,23 +5,17 @@ from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.core import validators, services
|
from orchestra.core import validators, services
|
||||||
|
from orchestra.utils import tuple_setting_to_choices, dict_setting_to_choices
|
||||||
from orchestra.utils.functional import cached
|
from orchestra.utils.functional import cached
|
||||||
|
|
||||||
from . import settings
|
from . import settings
|
||||||
|
|
||||||
|
|
||||||
def settings_to_choices(choices):
|
|
||||||
return sorted(
|
|
||||||
[ (name, opt[0]) for name,opt in choices.iteritems() ],
|
|
||||||
key=lambda e: e[0]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class WebApp(models.Model):
|
class WebApp(models.Model):
|
||||||
""" Represents a web application """
|
""" Represents a web application """
|
||||||
name = models.CharField(_("name"), max_length=128, validators=[validators.validate_name])
|
name = models.CharField(_("name"), max_length=128, validators=[validators.validate_name])
|
||||||
type = models.CharField(_("type"), max_length=32,
|
type = models.CharField(_("type"), max_length=32,
|
||||||
choices=settings_to_choices(settings.WEBAPPS_TYPES),
|
choices=dict_setting_to_choices(settings.WEBAPPS_TYPES),
|
||||||
default=settings.WEBAPPS_DEFAULT_TYPE)
|
default=settings.WEBAPPS_DEFAULT_TYPE)
|
||||||
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
account = models.ForeignKey('accounts.Account', verbose_name=_("Account"),
|
||||||
related_name='webapps')
|
related_name='webapps')
|
||||||
|
@ -41,20 +35,23 @@ class WebApp(models.Model):
|
||||||
def get_fpm_port(self):
|
def get_fpm_port(self):
|
||||||
return settings.WEBAPPS_FPM_START_PORT + self.account.pk
|
return settings.WEBAPPS_FPM_START_PORT + self.account.pk
|
||||||
|
|
||||||
def get_method(self):
|
def get_directive(self):
|
||||||
method = settings.WEBAPPS_TYPES[self.type]
|
directive = settings.WEBAPPS_TYPES[self.type]['directive']
|
||||||
args = method[2] if len(method) == 4 else ()
|
args = directive[1:] if len(directive) > 1 else ()
|
||||||
return method[1], args
|
return directive[0], args
|
||||||
|
|
||||||
def get_path(self):
|
def get_path(self):
|
||||||
context = {
|
context = {
|
||||||
'user': self.account.username,
|
'home': webapp.get_user().get_home(),
|
||||||
'app_name': self.name,
|
'app_name': self.name,
|
||||||
}
|
}
|
||||||
return settings.WEBAPPS_BASE_ROOT % context
|
return settings.WEBAPPS_BASE_ROOT % context
|
||||||
|
|
||||||
|
def get_user(self):
|
||||||
|
return self.account.main_systemuser
|
||||||
|
|
||||||
def get_username(self):
|
def get_username(self):
|
||||||
return self.account.username
|
return self.get_user().username
|
||||||
|
|
||||||
def get_groupname(self):
|
def get_groupname(self):
|
||||||
return self.get_username()
|
return self.get_username()
|
||||||
|
@ -64,7 +61,7 @@ class WebAppOption(models.Model):
|
||||||
webapp = models.ForeignKey(WebApp, verbose_name=_("Web application"),
|
webapp = models.ForeignKey(WebApp, verbose_name=_("Web application"),
|
||||||
related_name='options')
|
related_name='options')
|
||||||
name = models.CharField(_("name"), max_length=128,
|
name = models.CharField(_("name"), max_length=128,
|
||||||
choices=settings_to_choices(settings.WEBAPPS_OPTIONS))
|
choices=tuple_setting_to_choices(settings.WEBAPPS_OPTIONS))
|
||||||
value = models.CharField(_("value"), max_length=256)
|
value = models.CharField(_("value"), max_length=256)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -2,8 +2,7 @@ from django.conf import settings
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
|
||||||
# TODO make '%(mainuser_home)s/webapps...
|
WEBAPPS_BASE_ROOT = getattr(settings, 'WEBAPPS_BASE_ROOT', '%(home)s/webapps/%(app_name)s/')
|
||||||
WEBAPPS_BASE_ROOT = getattr(settings, 'WEBAPPS_BASE_ROOT', '/home/%(user)s/webapps/%(app_name)s/')
|
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_FPM_LISTEN = getattr(settings, 'WEBAPPS_FPM_LISTEN',
|
WEBAPPS_FPM_LISTEN = getattr(settings, 'WEBAPPS_FPM_LISTEN',
|
||||||
|
@ -23,57 +22,36 @@ WEBAPPS_FCGID_PATH = getattr(settings, 'WEBAPPS_FCGID_PATH',
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', {
|
WEBAPPS_TYPES = getattr(settings, 'WEBAPPS_TYPES', {
|
||||||
# { name: ( verbose_name, method_name, method_args, description) }
|
'php5.5': {
|
||||||
'php5.5': (
|
'verbose_name': "PHP 5.5",
|
||||||
_("PHP 5.5"),
|
|
||||||
# 'fpm', ('unix:/var/run/%(user)s-%(app_name)s.sock|fcgi://127.0.0.1%(app_path)s',),
|
# 'fpm', ('unix:/var/run/%(user)s-%(app_name)s.sock|fcgi://127.0.0.1%(app_path)s',),
|
||||||
'fpm', ('fcgi://127.0.0.1:%(fpm_port)s%(app_path)s',),
|
'directive': ('fpm', 'fcgi://{}%(app_path)s'.format(WEBAPPS_FPM_LISTEN)),
|
||||||
_("This creates a PHP5.5 application under ~/webapps/<app_name>\n"
|
'help_text': _("This creates a PHP5.5 application under ~/webapps/<app_name><br>"
|
||||||
"PHP-FPM will be used to execute PHP files.")
|
"PHP-FPM will be used to execute PHP files.")
|
||||||
),
|
},
|
||||||
'php5.2': (
|
'php5.2': {
|
||||||
_("PHP 5.2"),
|
'verbose_name': "PHP 5.2",
|
||||||
'fcgid', (WEBAPPS_FCGID_PATH,),
|
'directive': ('fcgi', WEBAPPS_FCGID_PATH),
|
||||||
_("This creates a PHP5.2 application under ~/webapps/<app_name>\n"
|
'help_text': _("This creates a PHP5.2 application under ~/webapps/<app_name><br>"
|
||||||
"Apache-mod-fcgid will be used to execute PHP files.")
|
"Apache-mod-fcgid will be used to execute PHP files.")
|
||||||
),
|
},
|
||||||
'php4': (
|
'php4': {
|
||||||
_("PHP 4"),
|
'verbose_name': "PHP 4",
|
||||||
'fcgid', (WEBAPPS_FCGID_PATH,),
|
'directive': ('fcgi', WEBAPPS_FCGID_PATH,),
|
||||||
_("This creates a PHP4 application under ~/webapps/<app_name>\n"
|
'help_text': _("This creates a PHP4 application under ~/webapps/<app_name><br>"
|
||||||
"Apache-mod-fcgid will be used to execute PHP files.")
|
"Apache-mod-fcgid will be used to execute PHP files.")
|
||||||
),
|
},
|
||||||
'static': (
|
'static': {
|
||||||
_("Static"),
|
'verbose_name': _("Static"),
|
||||||
'alias', (),
|
'directive': ('static',),
|
||||||
_("This creates a Static application under ~/webapps/<app_name>\n"
|
'help_text': _("This creates a Static application under ~/webapps/<app_name><br>"
|
||||||
"Apache2 will be used to serve static content and execute CGI files.")
|
"Apache2 will be used to serve static content and execute CGI files.")
|
||||||
),
|
},
|
||||||
# 'wordpress': (
|
'webalizer': {
|
||||||
# _("Wordpress"),
|
'verbose_name': "Webalizer",
|
||||||
# 'fpm', ('fcgi://127.0.0.1:8990/home/httpd/wordpress-mu/',),
|
'directive': ('static', '%(app_path)s%(site_name)s'),
|
||||||
# _("This creates a Wordpress site into a shared Wordpress server\n"
|
'help_text': _("This creates a Webalizer application under ~/webapps/<app_name>-<site_name>")
|
||||||
# "By default this blog will be accessible via http://<app_name>.blogs.example.com")
|
},
|
||||||
#
|
|
||||||
# ),
|
|
||||||
# 'dokuwiki': (
|
|
||||||
# _("DokuWiki"),
|
|
||||||
# 'alias', ('/home/httpd/wikifarm/farm/',),
|
|
||||||
# _("This create a Dokuwiki wiki into a shared Dokuwiki server\n")
|
|
||||||
# ),
|
|
||||||
# 'drupal': (
|
|
||||||
# _("Drupdal"),
|
|
||||||
# 'fpm', ('fcgi://127.0.0.1:8991/home/httpd/drupal-mu/',),
|
|
||||||
# _("This creates a Drupal site into a shared Drupal server\n"
|
|
||||||
# "The installation will be completed after visiting "
|
|
||||||
# "http://<app_name>.drupal.example.com/install.php?profile=standard&locale=ca\n"
|
|
||||||
# "By default this site will be accessible via http://<app_name>.drupal.example.com")
|
|
||||||
# ),
|
|
||||||
'webalizer': (
|
|
||||||
_("Webalizer"),
|
|
||||||
'alias', ('%(app_path)s%(site_name)s',),
|
|
||||||
_("This creates a Webalizer application under ~/webapps/<app_name>-<site_name>\n")
|
|
||||||
),
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -194,25 +172,3 @@ WEBAPPS_PHP_DISABLED_FUNCTIONS = getattr(settings, 'WEBAPPS_PHP_DISABLED_FUNCTIO
|
||||||
'escapeshellarg',
|
'escapeshellarg',
|
||||||
'dl'
|
'dl'
|
||||||
])
|
])
|
||||||
|
|
||||||
|
|
||||||
# TODO
|
|
||||||
WEBAPPS_WORDPRESSMU_BASE_URL = getattr(settings, 'WEBAPPS_WORDPRESSMU_BASE_URL',
|
|
||||||
'http://blogs.example.com')
|
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_WORDPRESSMU_ADMIN_PASSWORD = getattr(settings, 'WEBAPPS_WORDPRESSMU_ADMIN_PASSWORD',
|
|
||||||
'secret')
|
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_DOKUWIKIMU_TEMPLATE_PATH = setattr(settings, 'WEBAPPS_DOKUWIKIMU_TEMPLATE_PATH',
|
|
||||||
'/home/httpd/htdocs/wikifarm/template.tar.gz')
|
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_DOKUWIKIMU_FARM_PATH = getattr(settings, 'WEBAPPS_DOKUWIKIMU_FARM_PATH',
|
|
||||||
'/home/httpd/htdocs/wikifarm/farm')
|
|
||||||
|
|
||||||
|
|
||||||
WEBAPPS_DRUPAL_SITES_PATH = getattr(settings, 'WEBAPPS_DRUPAL_SITES_PATH',
|
|
||||||
'/home/httpd/htdocs/drupal-mu/sites/%(app_name)s')
|
|
||||||
|
|
||||||
|
|
|
@ -65,12 +65,12 @@ class Apache2Backend(ServiceController):
|
||||||
def get_content_directives(self, site):
|
def get_content_directives(self, site):
|
||||||
directives = ''
|
directives = ''
|
||||||
for content in site.content_set.all().order_by('-path'):
|
for content in site.content_set.all().order_by('-path'):
|
||||||
method, args = content.webapp.get_method()
|
method, args = content.webapp.get_directive()
|
||||||
method = getattr(self, 'get_%s_directives' % method)
|
method = getattr(self, 'get_%s_directives' % method)
|
||||||
directives += method(content, *args)
|
directives += method(content, *args)
|
||||||
return directives
|
return directives
|
||||||
|
|
||||||
def get_alias_directives(self, content, *args):
|
def get_static_directives(self, content, *args):
|
||||||
context = self.get_content_context(content)
|
context = self.get_content_context(content)
|
||||||
context['path'] = args[0] % context if args else content.webapp.get_path()
|
context['path'] = args[0] % context if args else content.webapp.get_path()
|
||||||
return "Alias %(location)s %(path)s\n" % context
|
return "Alias %(location)s %(path)s\n" % context
|
||||||
|
@ -81,10 +81,10 @@ class Apache2Backend(ServiceController):
|
||||||
directive = "ProxyPassMatch ^%(location)s(.*\.php(/.*)?)$ %(fcgi_path)s$1\n"
|
directive = "ProxyPassMatch ^%(location)s(.*\.php(/.*)?)$ %(fcgi_path)s$1\n"
|
||||||
return directive % context
|
return directive % context
|
||||||
|
|
||||||
def get_fcgid_directives(self, content, fcgid_path):
|
def get_fcgi_directives(self, content, fcgid_path):
|
||||||
context = self.get_content_context(content)
|
context = self.get_content_context(content)
|
||||||
context['fcgid_path'] = fcgid_path % context
|
context['fcgid_path'] = fcgid_path % context
|
||||||
fcgid = self.get_alias_directives(content)
|
fcgid = self.get_static_directives(content)
|
||||||
fcgid += textwrap.dedent("""\
|
fcgid += textwrap.dedent("""\
|
||||||
ProxyPass %(location)s !
|
ProxyPass %(location)s !
|
||||||
<Directory %(app_path)s>
|
<Directory %(app_path)s>
|
||||||
|
|
|
@ -5,18 +5,12 @@ from django.db import models
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.core import validators, services
|
from orchestra.core import validators, services
|
||||||
|
from orchestra.utils import tuple_setting_to_choices
|
||||||
from orchestra.utils.functional import cached
|
from orchestra.utils.functional import cached
|
||||||
|
|
||||||
from . import settings
|
from . import settings
|
||||||
|
|
||||||
|
|
||||||
def settings_to_choices(choices):
|
|
||||||
return sorted(
|
|
||||||
[ (name, opt[0]) for name,opt in choices.iteritems() ],
|
|
||||||
key=lambda e: e[0]
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Website(models.Model):
|
class Website(models.Model):
|
||||||
name = models.CharField(_("name"), max_length=128, unique=True,
|
name = models.CharField(_("name"), max_length=128, unique=True,
|
||||||
validators=[validators.validate_name])
|
validators=[validators.validate_name])
|
||||||
|
@ -67,7 +61,7 @@ class WebsiteOption(models.Model):
|
||||||
website = models.ForeignKey(Website, verbose_name=_("web site"),
|
website = models.ForeignKey(Website, verbose_name=_("web site"),
|
||||||
related_name='options')
|
related_name='options')
|
||||||
name = models.CharField(_("name"), max_length=128,
|
name = models.CharField(_("name"), max_length=128,
|
||||||
choices=settings_to_choices(settings.WEBSITES_OPTIONS))
|
choices=tuple_setting_to_choices(settings.WEBSITES_OPTIONS))
|
||||||
value = models.CharField(_("value"), max_length=256)
|
value = models.CharField(_("value"), max_length=256)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django import forms
|
||||||
from django.contrib.auth import forms as auth_forms
|
from django.contrib.auth import forms as auth_forms
|
||||||
from django.utils.translation import ugettext, ugettext_lazy as _
|
from django.utils.translation import ugettext, ugettext_lazy as _
|
||||||
|
|
||||||
|
from .. import settings
|
||||||
from ..core.validators import validate_password
|
from ..core.validators import validate_password
|
||||||
|
|
||||||
|
|
||||||
|
@ -51,8 +52,8 @@ class UserCreationForm(forms.ModelForm):
|
||||||
# self.fields['password1'].validators.append(validate_password)
|
# self.fields['password1'].validators.append(validate_password)
|
||||||
|
|
||||||
def clean_password2(self):
|
def clean_password2(self):
|
||||||
password1 = self.cleaned_data.get("password1")
|
password1 = self.cleaned_data.get('password1')
|
||||||
password2 = self.cleaned_data.get("password2")
|
password2 = self.cleaned_data.get('password2')
|
||||||
if password1 and password2 and password1 != password2:
|
if password1 and password2 and password1 != password2:
|
||||||
raise forms.ValidationError(
|
raise forms.ValidationError(
|
||||||
self.error_messages['password_mismatch'],
|
self.error_messages['password_mismatch'],
|
||||||
|
@ -72,7 +73,10 @@ class UserCreationForm(forms.ModelForm):
|
||||||
|
|
||||||
def save(self, commit=True):
|
def save(self, commit=True):
|
||||||
user = super(UserCreationForm, self).save(commit=False)
|
user = super(UserCreationForm, self).save(commit=False)
|
||||||
user.set_password(self.cleaned_data["password1"])
|
if settings.ORCHESTRA_MIGRATION_MODE:
|
||||||
|
user.password = self.cleaned_data['password1']
|
||||||
|
else:
|
||||||
|
user.set_password(self.cleaned_data['password1'])
|
||||||
if commit:
|
if commit:
|
||||||
user.save()
|
user.save()
|
||||||
return user
|
return user
|
||||||
|
|
|
@ -28,3 +28,6 @@ STOP_SERVICES = getattr(settings, 'STOP_SERVICES',
|
||||||
|
|
||||||
|
|
||||||
API_ROOT_VIEW = getattr(settings, 'API_ROOT_VIEW', 'orchestra.api.root.APIRoot')
|
API_ROOT_VIEW = getattr(settings, 'API_ROOT_VIEW', 'orchestra.api.root.APIRoot')
|
||||||
|
|
||||||
|
|
||||||
|
ORCHESTRA_MIGRATION_MODE = getattr(settings, 'ORCHESTRA_MIGRATION_MODE', False)
|
||||||
|
|
|
@ -128,3 +128,39 @@ def naturaldate(date):
|
||||||
count = abs(count)
|
count = abs(count)
|
||||||
fmt = pluralizefun(count)
|
fmt = pluralizefun(count)
|
||||||
return fmt.format(num=count, ago=ago)
|
return fmt.format(num=count, ago=ago)
|
||||||
|
|
||||||
|
|
||||||
|
def text2int(textnum, numwords={}):
|
||||||
|
if not numwords:
|
||||||
|
units = (
|
||||||
|
'zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight',
|
||||||
|
'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen',
|
||||||
|
'sixteen', 'seventeen', 'eighteen', 'nineteen',
|
||||||
|
)
|
||||||
|
|
||||||
|
tens = ('', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety')
|
||||||
|
|
||||||
|
scales = ['hundred', 'thousand', 'million', 'billion', 'trillion']
|
||||||
|
|
||||||
|
numwords['and'] = (1, 0)
|
||||||
|
for idx, word in enumerate(units):
|
||||||
|
numwords[word] = (1, idx)
|
||||||
|
for idx, word in enumerate(tens):
|
||||||
|
numwords[word] = (1, idx * 10)
|
||||||
|
for idx, word in enumerate(scales):
|
||||||
|
numwords[word] = (10 ** (idx * 3 or 2), 0)
|
||||||
|
|
||||||
|
current = result = 0
|
||||||
|
for word in textnum.split():
|
||||||
|
word = word.lower()
|
||||||
|
if word not in numwords:
|
||||||
|
raise Exception("Illegal word: " + word)
|
||||||
|
|
||||||
|
scale, increment = numwords[word]
|
||||||
|
current = current * scale + increment
|
||||||
|
if scale > 100:
|
||||||
|
result += current
|
||||||
|
current = 0
|
||||||
|
|
||||||
|
return result + current
|
||||||
|
|
||||||
|
|
|
@ -45,3 +45,17 @@ def running_syncdb():
|
||||||
|
|
||||||
def database_ready():
|
def database_ready():
|
||||||
return not running_syncdb() and 'setuppostgres' not in sys.argv and 'test' not in sys.argv
|
return not running_syncdb() and 'setuppostgres' not in sys.argv and 'test' not in sys.argv
|
||||||
|
|
||||||
|
|
||||||
|
def dict_setting_to_choices(choices):
|
||||||
|
return sorted(
|
||||||
|
[ (name, opt.get('verbose_name', 'name')) for name, opt in choices.iteritems() ],
|
||||||
|
key=lambda e: e[0]
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def tuple_setting_to_choices(choices):
|
||||||
|
return sorted(
|
||||||
|
[ (name, opt[0]) for name,opt in choices.iteritems() ],
|
||||||
|
key=lambda e: e[0]
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue