diff --git a/TODO.md b/TODO.md
index 47f1fca1..2d72feaf 100644
--- a/TODO.md
+++ b/TODO.md
@@ -210,18 +210,10 @@ https://code.djangoproject.com/ticket/24576
* move all tests to django-orchestra/tests
* *natural keys: those fields that uniquely identify a service, list.name, website.name, webapp.name+account, make sure rest api can not edit thos things
-
* MultiCHoiceField proper serialization
-* 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?
* replace unique_name by natural_key?
* do not require contact or create default
-* send signals for backend triggers
-* force ignore slack billing period overridig when billing
-* fpm reload starts new pools?
-* 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
@@ -380,8 +372,6 @@ Case
# round decimals on every billing operation
-# PHPlist cron, bounces and traffic (maybe specific mail script with sitename)
-
# use "su $user --shell /bin/bash" on backends for security : MKDIR -p...
# model.field.flatchoices
@@ -396,3 +386,7 @@ Case
# Implement wordpressmu change password or remove password from the form
+
+# Deprecate orchestra start/stop/restart services management commands?
+
+# Enable/disable ignore period orders list filter
diff --git a/orchestra/contrib/saas/backends/__init__.py b/orchestra/contrib/saas/backends/__init__.py
index 83d99b13..45a66f6c 100644
--- a/orchestra/contrib/saas/backends/__init__.py
+++ b/orchestra/contrib/saas/backends/__init__.py
@@ -89,7 +89,7 @@ class ApacheTrafficByHost(ServiceMonitor):
sys.stderr.write(str(e)+'\\n')
for opts in sites.values():
ini_date, object_id, size = opts
- print object_id, size
+ sys.stdout.write('%s %s\n' % (object_id, size))
""").format(**context)
)
diff --git a/orchestra/contrib/saas/forms.py b/orchestra/contrib/saas/forms.py
new file mode 100644
index 00000000..3d317683
--- /dev/null
+++ b/orchestra/contrib/saas/forms.py
@@ -0,0 +1,76 @@
+from django import forms
+from django.core.validators import RegexValidator
+from django.utils.translation import ugettext_lazy as _
+
+from orchestra.core import validators
+from orchestra.forms.widgets import SpanWidget
+from orchestra.plugins.forms import PluginDataForm
+from orchestra.utils.python import random_ascii
+
+
+class SaaSBaseForm(PluginDataForm):
+ site_url = forms.CharField(label=_("Site URL"), widget=SpanWidget(), required=False)
+
+ class Meta:
+ exclude = ('database',)
+ readonly_fields = ('site_url',)
+
+ def __init__(self, *args, **kwargs):
+ super(SaaSBaseForm, self).__init__(*args, **kwargs)
+ self.is_change = bool(self.instance and self.instance.pk)
+ if self.is_change:
+ site_domain = self.instance.get_site_domain()
+ else:
+ site_domain = self.plugin.site_domain
+ if site_domain:
+ site_link = '%s' % (site_domain, site_domain)
+ else:
+ site_link = '<site_name>.%s' % self.plugin.site_base_domain
+ self.fields['site_url'].widget.display = site_link
+ self.fields['name'].label = _("Site name") if self.plugin.site_base_domain else _("Username")
+
+
+class SaaSPasswordForm(SaaSBaseForm):
+ password = forms.CharField(label=_("Password"), required=False,
+ widget=SpanWidget(display='Unknown password'),
+ validators=[
+ validators.validate_password,
+ RegexValidator(r'^[^"\'\\]+$',
+ _('Enter a valid password. '
+ 'This value may contain any ascii character except for '
+ ' \'/"/\\/ characters.'), 'invalid'),
+ ],
+ help_text=_("Passwords are not stored, so there is no way to see this "
+ "service's password, but you can change the password using "
+ "this form."))
+ password1 = forms.CharField(label=_("Password"), validators=[validators.validate_password],
+ widget=forms.PasswordInput)
+ password2 = forms.CharField(label=_("Password confirmation"),
+ widget=forms.PasswordInput,
+ help_text=_("Enter the same password as above, for verification."))
+
+ def __init__(self, *args, **kwargs):
+ super(SaaSPasswordForm, self).__init__(*args, **kwargs)
+ if self.is_change:
+ self.fields['password1'].required = False
+ self.fields['password1'].widget = forms.HiddenInput()
+ self.fields['password2'].required = False
+ self.fields['password2'].widget = forms.HiddenInput()
+ else:
+ self.fields['password'].widget = forms.HiddenInput()
+ self.fields['password1'].help_text = _("Suggestion: %s") % random_ascii(10)
+
+ def clean_password2(self):
+ if not self.is_change:
+ password1 = self.cleaned_data.get("password1")
+ password2 = self.cleaned_data.get("password2")
+ if password1 and password2 and password1 != password2:
+ msg = _("The two password fields didn't match.")
+ raise forms.ValidationError(msg)
+ return password2
+
+ def save(self, commit=True):
+ obj = super(SoftwareServiceForm, self).save(commit=commit)
+ if not self.is_change:
+ obj.set_password(self.cleaned_data["password1"])
+ return obj
diff --git a/orchestra/contrib/saas/services/bscw.py b/orchestra/contrib/saas/services/bscw.py
index 2bbc29be..06f1892f 100644
--- a/orchestra/contrib/saas/services/bscw.py
+++ b/orchestra/contrib/saas/services/bscw.py
@@ -3,10 +3,11 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from .. import settings
-from .options import SoftwareService, SoftwareServiceForm
+from ..forms import SaaSPasswordForm
+from .options import SoftwareService
-class BSCWForm(SoftwareServiceForm):
+class BSCWForm(SaaSPasswordForm):
email = forms.EmailField(label=_("Email"), widget=forms.TextInput(attrs={'size':'40'}))
diff --git a/orchestra/contrib/saas/services/gitlab.py b/orchestra/contrib/saas/services/gitlab.py
index 1e470a83..7fc73770 100644
--- a/orchestra/contrib/saas/services/gitlab.py
+++ b/orchestra/contrib/saas/services/gitlab.py
@@ -4,12 +4,12 @@ from rest_framework import serializers
from orchestra.forms import widgets
-from .options import SoftwareService, SoftwareServiceForm
-
from .. import settings
+from ..forms import SaaSPasswordForm
+from .options import SoftwareService
-class GitLabForm(SoftwareServiceForm):
+class GitLabForm(SaaSPasswordForm):
email = forms.EmailField(label=_("Email"),
help_text=_("Initial email address, changes on the GitLab server are not reflected here."))
diff --git a/orchestra/contrib/saas/services/moodle.py b/orchestra/contrib/saas/services/moodle.py
index 72e39bdc..88f5e623 100644
--- a/orchestra/contrib/saas/services/moodle.py
+++ b/orchestra/contrib/saas/services/moodle.py
@@ -1,10 +1,11 @@
from django import forms
from django.utils.translation import ugettext_lazy as _
-from .options import SoftwareService, SoftwareServiceForm
+from ..forms import SaaSPasswordForm
+from .options import SoftwareService
-class MoodleForm(SoftwareServiceForm):
+class MoodleForm(SaaSPasswordForm):
email = forms.EmailField(label=_("Email"))
diff --git a/orchestra/contrib/saas/services/options.py b/orchestra/contrib/saas/services/options.py
index 3024905f..cdc40a62 100644
--- a/orchestra/contrib/saas/services/options.py
+++ b/orchestra/contrib/saas/services/options.py
@@ -1,81 +1,17 @@
-from django import forms
from django.core.exceptions import ValidationError
-from django.core.validators import RegexValidator
from django.utils.translation import ugettext_lazy as _
from orchestra import plugins
from orchestra.contrib.orchestration import Operation
-from orchestra.core import validators
-from orchestra.forms.widgets import SpanWidget
-from orchestra.plugins.forms import PluginDataForm
from orchestra.utils.functional import cached
-from orchestra.utils.python import import_class, random_ascii
+from orchestra.utils.python import import_class
from .. import settings
-
-
-class SoftwareServiceForm(PluginDataForm):
- site_url = forms.CharField(label=_("Site URL"), widget=SpanWidget(), required=False)
- password = forms.CharField(label=_("Password"), required=False,
- widget=SpanWidget(display='Unknown password'),
- validators=[
- validators.validate_password,
- RegexValidator(r'^[^"\'\\]+$',
- _('Enter a valid password. '
- 'This value may contain any ascii character except for '
- ' \'/"/\\/ characters.'), 'invalid'),
- ],
- help_text=_("Passwords are not stored, so there is no way to see this "
- "service's password, but you can change the password using "
- "this form."))
- password1 = forms.CharField(label=_("Password"), validators=[validators.validate_password],
- widget=forms.PasswordInput)
- password2 = forms.CharField(label=_("Password confirmation"),
- widget=forms.PasswordInput,
- help_text=_("Enter the same password as above, for verification."))
-
- class Meta:
- exclude = ('database',)
- readonly_fields = ('site_url',)
-
- def __init__(self, *args, **kwargs):
- super(SoftwareServiceForm, self).__init__(*args, **kwargs)
- self.is_change = bool(self.instance and self.instance.pk)
- if self.is_change:
- site_domain = self.instance.get_site_domain()
- self.fields['password1'].required = False
- self.fields['password1'].widget = forms.HiddenInput()
- self.fields['password2'].required = False
- self.fields['password2'].widget = forms.HiddenInput()
- else:
- self.fields['password'].widget = forms.HiddenInput()
- self.fields['password1'].help_text = _("Suggestion: %s") % random_ascii(10)
- site_domain = self.plugin.site_domain
- if site_domain:
- site_link = '%s' % (site_domain, site_domain)
- else:
- site_link = '<site_name>.%s' % self.plugin.site_base_domain
- self.fields['site_url'].widget.display = site_link
- self.fields['name'].label = _("Site name") if self.plugin.site_base_domain else _("Username")
-
- def clean_password2(self):
- if not self.is_change:
- password1 = self.cleaned_data.get("password1")
- password2 = self.cleaned_data.get("password2")
- if password1 and password2 and password1 != password2:
- msg = _("The two password fields didn't match.")
- raise forms.ValidationError(msg)
- return password2
-
- def save(self, commit=True):
- obj = super(SoftwareServiceForm, self).save(commit=commit)
- if not self.is_change:
- obj.set_password(self.cleaned_data["password1"])
- return obj
+from ..forms import SaaSPasswordForm
class SoftwareService(plugins.Plugin):
- form = SoftwareServiceForm
+ form = SaaSPasswordForm
site_domain = None
site_base_domain = None
has_custom_domain = False
diff --git a/orchestra/contrib/saas/services/phplist.py b/orchestra/contrib/saas/services/phplist.py
index 0bcd4d4a..555ec816 100644
--- a/orchestra/contrib/saas/services/phplist.py
+++ b/orchestra/contrib/saas/services/phplist.py
@@ -8,10 +8,11 @@ from orchestra.contrib.databases.models import Database, DatabaseUser
from orchestra.forms.widgets import SpanWidget
from .. import settings
-from .options import SoftwareService, SoftwareServiceForm
+from ..forms import SaaSPasswordForm
+from .options import SoftwareService
-class PHPListForm(SoftwareServiceForm):
+class PHPListForm(SaaSPasswordForm):
admin_username = forms.CharField(label=_("Admin username"), required=False,
widget=SpanWidget(display='admin'))
diff --git a/orchestra/contrib/saas/services/seafile.py b/orchestra/contrib/saas/services/seafile.py
index 3484e2c6..da736142 100644
--- a/orchestra/contrib/saas/services/seafile.py
+++ b/orchestra/contrib/saas/services/seafile.py
@@ -3,12 +3,13 @@ from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
from .. import settings
-from .options import SoftwareService, SoftwareServiceForm
+from ..forms import SaaSPasswordForm
+from .options import SoftwareService
# TODO monitor quota since out of sync?
-class SeaFileForm(SoftwareServiceForm):
+class SeaFileForm(SaaSPasswordForm):
email = forms.EmailField(label=_("Email"), widget=forms.TextInput(attrs={'size':'40'}))
quota = forms.IntegerField(label=_("Quota"), initial=settings.SAAS_SEAFILE_DEFAULT_QUOTA,
help_text=_("Disk quota in MB."))
diff --git a/orchestra/contrib/saas/services/wordpress.py b/orchestra/contrib/saas/services/wordpress.py
index afca5222..021ec464 100644
--- a/orchestra/contrib/saas/services/wordpress.py
+++ b/orchestra/contrib/saas/services/wordpress.py
@@ -1,13 +1,23 @@
from django import forms
+from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from rest_framework import serializers
-from .options import SoftwareService, SoftwareServiceForm
+from .options import SoftwareService
+from ..forms import SaaSBaseForm
-class WordPressForm(SoftwareServiceForm):
- email = forms.EmailField(label=_("Email"), widget=forms.TextInput(attrs={'size':'40'}))
-
+class WordPressForm(SaaSBaseForm):
+ email = forms.EmailField(label=_("Email"), widget=forms.TextInput(attrs={'size':'40'}),
+ help_text=_("A new user will be created if the above email address is not in the database.
"
+ "The username and password will be mailed to this email address."))
+
+ def __init__(self, *args, **kwargs):
+ super(WordPressForm, self).__init__(*args, **kwargs)
+ if self.is_change:
+ admin_url = 'http://%s/wp-admin/' % self.instance.get_site_domain()
+ help_text = 'Admin URL: {0}'.format(admin_url)
+ self.fields['site_url'].help_text = mark_safe(help_text)
class WordPressDataSerializer(serializers.Serializer):
email = serializers.EmailField(label=_("Email"))