Added support for moodle SaaS and disable form autocomplition
This commit is contained in:
parent
835a4ab872
commit
be8f830ebb
3
TODO.md
3
TODO.md
|
@ -379,7 +379,7 @@ Case
|
||||||
# Don't enforce one contact per account? remove account.email in favour of contacts?
|
# Don't enforce one contact per account? remove account.email in favour of contacts?
|
||||||
|
|
||||||
# Mailer: mark as sent
|
# Mailer: mark as sent
|
||||||
|
# Mailer: download attachments
|
||||||
|
|
||||||
# Deprecate orchestra start/stop/restart services management commands?
|
# Deprecate orchestra start/stop/restart services management commands?
|
||||||
|
|
||||||
|
@ -387,3 +387,4 @@ Case
|
||||||
|
|
||||||
|
|
||||||
# Modsecurity rules template by cms (wordpress, joomla, dokuwiki (973337 973338 973347 958057), ...
|
# Modsecurity rules template by cms (wordpress, joomla, dokuwiki (973337 973338 973347 958057), ...
|
||||||
|
|
||||||
|
|
|
@ -90,9 +90,11 @@ def action_to_view(action, modeladmin):
|
||||||
|
|
||||||
|
|
||||||
def change_url(obj):
|
def change_url(obj):
|
||||||
opts = obj._meta
|
if obj is not None:
|
||||||
view_name = 'admin:%s_%s_change' % (opts.app_label, opts.model_name)
|
opts = obj._meta
|
||||||
return reverse(view_name, args=(obj.pk,))
|
view_name = 'admin:%s_%s_change' % (opts.app_label, opts.model_name)
|
||||||
|
return reverse(view_name, args=(obj.pk,))
|
||||||
|
raise NoReverseMatch
|
||||||
|
|
||||||
|
|
||||||
@admin_field
|
@admin_field
|
||||||
|
|
|
@ -85,7 +85,7 @@ class MySQLUserBackend(ServiceController):
|
||||||
context = self.get_context(user)
|
context = self.get_context(user)
|
||||||
self.append(textwrap.dedent("""\
|
self.append(textwrap.dedent("""\
|
||||||
# Create user %(username)s
|
# Create user %(username)s
|
||||||
mysql -e 'CREATE USER "%(username)s"@"%(host)s";' || true
|
mysql -e 'CREATE USER "%(username)s"@"%(host)s";' || true # User already exists
|
||||||
mysql -e 'UPDATE mysql.user SET Password="%(password)s" WHERE User="%(username)s";'\
|
mysql -e 'UPDATE mysql.user SET Password="%(password)s" WHERE User="%(username)s";'\
|
||||||
""") % context
|
""") % context
|
||||||
)
|
)
|
||||||
|
|
|
@ -12,7 +12,8 @@ from .models import DatabaseUser, Database
|
||||||
|
|
||||||
class DatabaseUserCreationForm(forms.ModelForm):
|
class DatabaseUserCreationForm(forms.ModelForm):
|
||||||
password1 = forms.CharField(label=_("Password"), required=False,
|
password1 = forms.CharField(label=_("Password"), required=False,
|
||||||
widget=forms.PasswordInput, validators=[validate_password])
|
widget=forms.PasswordInput(attrs={'autocomplete': 'off'}),
|
||||||
|
validators=[validate_password])
|
||||||
password2 = forms.CharField(label=_("Password confirmation"), required=False,
|
password2 = forms.CharField(label=_("Password confirmation"), required=False,
|
||||||
widget=forms.PasswordInput,
|
widget=forms.PasswordInput,
|
||||||
help_text=_("Enter the same password as above, for verification."))
|
help_text=_("Enter the same password as above, for verification."))
|
||||||
|
@ -57,6 +58,7 @@ class DatabaseCreationForm(DatabaseUserCreationForm):
|
||||||
username = self.cleaned_data.get('username')
|
username = self.cleaned_data.get('username')
|
||||||
if DatabaseUser.objects.filter(username=username).exists():
|
if DatabaseUser.objects.filter(username=username).exists():
|
||||||
raise ValidationError("Provided username already exists.")
|
raise ValidationError("Provided username already exists.")
|
||||||
|
return username
|
||||||
|
|
||||||
def clean_password2(self):
|
def clean_password2(self):
|
||||||
username = self.cleaned_data.get('username')
|
username = self.cleaned_data.get('username')
|
||||||
|
@ -79,7 +81,7 @@ class DatabaseCreationForm(DatabaseUserCreationForm):
|
||||||
def clean(self):
|
def clean(self):
|
||||||
cleaned_data = super(DatabaseCreationForm, self).clean()
|
cleaned_data = super(DatabaseCreationForm, self).clean()
|
||||||
if 'user' in cleaned_data and 'username' in cleaned_data:
|
if 'user' in cleaned_data and 'username' in cleaned_data:
|
||||||
msg = _("Use existing user or create a new one?")
|
msg = _("Use existing user or create a new one? you have provided both.")
|
||||||
if cleaned_data['user'] and self.cleaned_data['username']:
|
if cleaned_data['user'] and self.cleaned_data['username']:
|
||||||
raise ValidationError(msg)
|
raise ValidationError(msg)
|
||||||
elif not (cleaned_data['username'] or cleaned_data['user']):
|
elif not (cleaned_data['username'] or cleaned_data['user']):
|
||||||
|
|
|
@ -49,7 +49,7 @@ class MetricStorageInline(admin.TabularInline):
|
||||||
|
|
||||||
class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
list_display = (
|
list_display = (
|
||||||
'id', 'service_link', 'account_link', 'content_object_link',
|
'display_description', 'service_link', 'account_link', 'content_object_link',
|
||||||
'display_registered_on', 'display_billed_until', 'display_cancelled_on',
|
'display_registered_on', 'display_billed_until', 'display_cancelled_on',
|
||||||
'display_metric'
|
'display_metric'
|
||||||
)
|
)
|
||||||
|
@ -78,6 +78,12 @@ class OrderAdmin(AccountAdminMixin, ExtendedModelAdmin):
|
||||||
display_registered_on = admin_date('registered_on')
|
display_registered_on = admin_date('registered_on')
|
||||||
display_cancelled_on = admin_date('cancelled_on')
|
display_cancelled_on = admin_date('cancelled_on')
|
||||||
|
|
||||||
|
def display_description(self, order):
|
||||||
|
return order.description[:64]
|
||||||
|
display_description.short_description = _("Description")
|
||||||
|
display_description.allow_tags = True
|
||||||
|
display_description.admin_order_field = 'description'
|
||||||
|
|
||||||
def content_object_link(self, order):
|
def content_object_link(self, order):
|
||||||
if order.content_object:
|
if order.content_object:
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -151,9 +151,10 @@ class TransactionProcessAdmin(ChangeViewActionsMixin, admin.ModelAdmin):
|
||||||
lines = []
|
lines = []
|
||||||
counter = 0
|
counter = 0
|
||||||
# Because of values_list this query doesn't benefit from prefetch_related
|
# Because of values_list this query doesn't benefit from prefetch_related
|
||||||
tx_ids = process.transactions.values_list('id', flat=True)
|
for trans in process.transactions.only('id', 'state'):
|
||||||
for tx_id in tx_ids:
|
color = STATE_COLORS.get(trans.state, 'black')
|
||||||
ids.append(str(tx_id))
|
state = trans.get_state_display()
|
||||||
|
ids.append('<span style="color:%s" title="%s">%i</span>' % (color, state, trans.id))
|
||||||
counter += 1
|
counter += 1
|
||||||
if counter > 10:
|
if counter > 10:
|
||||||
counter = 0
|
counter = 0
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
import os
|
||||||
|
import textwrap
|
||||||
|
|
||||||
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from orchestra.contrib.orchestration import ServiceController, replace
|
||||||
|
|
||||||
|
from .. import settings
|
||||||
|
|
||||||
|
|
||||||
|
class MoodleMuBackend(ServiceController):
|
||||||
|
"""
|
||||||
|
Creates a Moodle site on a Moodle multisite installation
|
||||||
|
|
||||||
|
// config.php
|
||||||
|
$site_map = array(
|
||||||
|
// "<HTTP_HOST>" => ["<SITE_NAME>", "<WWWROOT>"],
|
||||||
|
);
|
||||||
|
|
||||||
|
wwwroot = "https://{$site}-courses.pangea.org";
|
||||||
|
$site = getenv("SITE");
|
||||||
|
if ( $site == '' ) {
|
||||||
|
http_host = $_SERVER['HTTP_HOST'];
|
||||||
|
if (array_key_exists($http_host, $site_map)) {
|
||||||
|
$site = $site_map[$http_host][0];
|
||||||
|
$wwwroot = $site_map[$http_host][1];
|
||||||
|
} elseif (strpos($http_host, '-courses.') !== false) {
|
||||||
|
$site = array_shift((explode("-courses.", $http_host)));
|
||||||
|
} else {
|
||||||
|
$site = array_shift((explode(".", $http_host)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$CFG->prefix = "${site}_";
|
||||||
|
$CFG->wwwroot = $wwwroot;
|
||||||
|
$CFG->dataroot = "/home/pangea/moodledata/{$site}/";
|
||||||
|
"""
|
||||||
|
verbose_name = _("Moodle multisite")
|
||||||
|
model = 'saas.SaaS'
|
||||||
|
default_route_match = "saas.service == 'moodle'"
|
||||||
|
|
||||||
|
def save(self, webapp):
|
||||||
|
context = self.get_context(webapp)
|
||||||
|
self.append(textwrap.dedent("""\
|
||||||
|
mkdir -p %(moodledata_path)s
|
||||||
|
chown %(user)s:%(user)s %(moodledata_path)s
|
||||||
|
export SITE=%(site_name)s
|
||||||
|
CHANGE_PASSWORD=0
|
||||||
|
php %(moodle_path)s/admin/cli/install_database.php \\
|
||||||
|
--fullname="%(site_name)s" \\
|
||||||
|
--shortname="%(site_name)s" \\
|
||||||
|
--adminpass="%(password)s" \\
|
||||||
|
--adminemail="%(email)s" \\
|
||||||
|
--non-interactive \\
|
||||||
|
--agree-license \\
|
||||||
|
--allow-unstable || CHANGE_PASSWORD=1
|
||||||
|
""") % context
|
||||||
|
)
|
||||||
|
if context['password']:
|
||||||
|
self.append(textwrap.dedent("""\
|
||||||
|
mysql \\
|
||||||
|
--host="%(db_host)s" \\
|
||||||
|
--user="%(db_user)s" \\
|
||||||
|
--password="%(db_pass)s" \\
|
||||||
|
--execute='UPDATE %(site_name)s_user
|
||||||
|
SET password=MD5("%(password)s")
|
||||||
|
WHERE username="admin"' \\
|
||||||
|
%(db_name)s
|
||||||
|
""") % context
|
||||||
|
)
|
||||||
|
if context['crontab']:
|
||||||
|
context['escaped_crontab'] = context['crontab'].replace('$', '\\$')
|
||||||
|
self.append(textwrap.dedent("""\
|
||||||
|
# Configuring Moodle crontabs
|
||||||
|
if ! crontab -u %(user)s -l | grep 'Moodle:"%(site_name)s"' > /dev/null; then
|
||||||
|
cat << EOF | su %(user)s --shell /bin/bash -c 'crontab'
|
||||||
|
$(crontab -u %(user)s -l)
|
||||||
|
|
||||||
|
# %(banner)s - Moodle:"%(site_name)s"
|
||||||
|
%(escaped_crontab)s
|
||||||
|
EOF
|
||||||
|
fi""") % context
|
||||||
|
)
|
||||||
|
|
||||||
|
def delete(self, saas):
|
||||||
|
context = self.get_context(saas)
|
||||||
|
self.append(textwrap.dedent("""
|
||||||
|
rm -rf %(moodledata_path)s
|
||||||
|
# Delete tables with prefix %(site_name)s
|
||||||
|
mysql -Nrs \\
|
||||||
|
--host="%(db_host)s" \\
|
||||||
|
--user="%(db_user)s" \\
|
||||||
|
--password="%(db_pass)s" \\
|
||||||
|
--execute='SET GROUP_CONCAT_MAX_LEN=10000;
|
||||||
|
SET @tbls = (SELECT GROUP_CONCAT(TABLE_NAME)
|
||||||
|
FROM information_schema.TABLES
|
||||||
|
WHERE TABLE_SCHEMA = "%(db_name)s"
|
||||||
|
AND TABLE_NAME LIKE "%(site_name)s_%%");
|
||||||
|
SET @delStmt = CONCAT("DROP TABLE ", @tbls);
|
||||||
|
-- SELECT @delStmt;
|
||||||
|
PREPARE stmt FROM @delStmt;
|
||||||
|
EXECUTE stmt;
|
||||||
|
DEALLOCATE PREPARE stmt;' \\
|
||||||
|
%(db_name)s
|
||||||
|
""") % context
|
||||||
|
)
|
||||||
|
if context['crontab']:
|
||||||
|
context['crontab_regex'] = '\\|'.join(context['crontab'].splitlines())
|
||||||
|
context['crontab_regex'] = context['crontab_regex'].replace('*', '\\*')
|
||||||
|
self.append(textwrap.dedent("""\
|
||||||
|
crontab -u %(user)s -l \\
|
||||||
|
| grep -v 'Moodle:"%(site_name)s"\\|%(crontab_regex)s' \\
|
||||||
|
| su %(user)s --shell /bin/bash -c 'crontab'
|
||||||
|
""") % context
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_context(self, saas):
|
||||||
|
context = {
|
||||||
|
'banner': self.get_banner(),
|
||||||
|
'name': saas.name,
|
||||||
|
'site_name': saas.name,
|
||||||
|
'full_name': "%s course" % saas.name.capitalize(),
|
||||||
|
'moodle_path': settings.SAAS_MOODLE_PATH,
|
||||||
|
'user': settings.SAAS_MOODLE_SYSTEMUSER,
|
||||||
|
'db_user': settings.SAAS_MOODLE_DB_USER,
|
||||||
|
'db_pass': settings.SAAS_MOODLE_DB_PASS,
|
||||||
|
'db_name': settings.SAAS_MOODLE_DB_NAME,
|
||||||
|
'db_host': settings.SAAS_MOODLE_DB_HOST,
|
||||||
|
'email': saas.account.email,
|
||||||
|
'password': getattr(saas, 'password', None),
|
||||||
|
}
|
||||||
|
context.update({
|
||||||
|
'crontab': settings.SAAS_MOODLE_CRONTAB % context,
|
||||||
|
'db_name': context['db_name'] % context,
|
||||||
|
'moodledata_path': settings.SAAS_MOODLE_DATA_PATH % context,
|
||||||
|
})
|
||||||
|
return context
|
|
@ -19,6 +19,9 @@ class PhpListSaaSBackend(ServiceController):
|
||||||
The site is created by means of creating a new database per phpList site,
|
The site is created by means of creating a new database per phpList site,
|
||||||
but all sites share the same code.
|
but all sites share the same code.
|
||||||
|
|
||||||
|
Different databases are used instead of prefixes because php-list reacts by launching
|
||||||
|
the installation process.
|
||||||
|
|
||||||
<tt>// config/config.php
|
<tt>// config/config.php
|
||||||
$site = getenv("SITE");
|
$site = getenv("SITE");
|
||||||
if ( $site == '' ) {
|
if ( $site == '' ) {
|
||||||
|
|
|
@ -49,7 +49,7 @@ class SaaSPasswordForm(SaaSBaseForm):
|
||||||
"service's password, but you can change the password using "
|
"service's password, but you can change the password using "
|
||||||
"<a href=\"password/\">this form</a>."))
|
"<a href=\"password/\">this form</a>."))
|
||||||
password1 = forms.CharField(label=_("Password"), validators=[validators.validate_password],
|
password1 = forms.CharField(label=_("Password"), validators=[validators.validate_password],
|
||||||
widget=forms.PasswordInput)
|
widget=forms.PasswordInput(attrs={'autocomplete': 'off'}))
|
||||||
password2 = forms.CharField(label=_("Password confirmation"),
|
password2 = forms.CharField(label=_("Password confirmation"),
|
||||||
widget=forms.PasswordInput,
|
widget=forms.PasswordInput,
|
||||||
help_text=_("Enter the same password as above, for verification."))
|
help_text=_("Enter the same password as above, for verification."))
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
from django import forms
|
from django import forms
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
|
from orchestra.forms.widgets import SpanWidget
|
||||||
|
|
||||||
|
from .. import settings
|
||||||
from ..forms import SaaSPasswordForm
|
from ..forms import SaaSPasswordForm
|
||||||
from .options import SoftwareService
|
from .options import SoftwareService
|
||||||
|
|
||||||
|
|
||||||
class MoodleForm(SaaSPasswordForm):
|
class MoodleForm(SaaSPasswordForm):
|
||||||
email = forms.EmailField(label=_("Email"))
|
admin_username = forms.CharField(label=_("Admin username"), required=False,
|
||||||
|
widget=SpanWidget(display='admin'))
|
||||||
|
|
||||||
|
|
||||||
class MoodleService(SoftwareService):
|
class MoodleService(SoftwareService):
|
||||||
|
name = 'moodle'
|
||||||
verbose_name = "Moodle"
|
verbose_name = "Moodle"
|
||||||
form = MoodleForm
|
form = MoodleForm
|
||||||
description_field = 'site_name'
|
description_field = 'site_name'
|
||||||
icon = 'orchestra/icons/apps/Moodle.png'
|
icon = 'orchestra/icons/apps/Moodle.png'
|
||||||
|
site_domain = settings.SAAS_MOODLE_DOMAIN
|
||||||
|
db_name = settings.SAAS_MOODLE_DB_NAME
|
||||||
|
db_user = settings.SAAS_MOODLE_DB_USER
|
||||||
|
|
|
@ -2,6 +2,7 @@ from django.core.exceptions import ValidationError
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra import plugins
|
from orchestra import plugins
|
||||||
|
from orchestra.contrib.databases.models import Database, DatabaseUser
|
||||||
from orchestra.contrib.orchestration import Operation
|
from orchestra.contrib.orchestration import Operation
|
||||||
from orchestra.utils.functional import cached
|
from orchestra.utils.functional import cached
|
||||||
from orchestra.utils.python import import_class
|
from orchestra.utils.python import import_class
|
||||||
|
@ -64,3 +65,58 @@ class SoftwareService(plugins.Plugin):
|
||||||
|
|
||||||
def get_related(self):
|
def get_related(self):
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
class DBSoftwareService(SoftwareService):
|
||||||
|
db_name = None
|
||||||
|
db_user = None
|
||||||
|
|
||||||
|
def get_db_name(self):
|
||||||
|
context = {
|
||||||
|
'name': self.instance.name,
|
||||||
|
'site_name': self.instance.name,
|
||||||
|
}
|
||||||
|
db_name = self.db_name % context
|
||||||
|
# Limit for mysql database names
|
||||||
|
return db_name[:65]
|
||||||
|
|
||||||
|
def get_db_user(self):
|
||||||
|
return self.db_user
|
||||||
|
|
||||||
|
@cached
|
||||||
|
def get_account(self):
|
||||||
|
account_model = self.instance._meta.get_field_by_name('account')[0]
|
||||||
|
return account_model.rel.to.objects.get_main()
|
||||||
|
|
||||||
|
def validate(self):
|
||||||
|
super(DBSoftwareService, self).validate()
|
||||||
|
create = not self.instance.pk
|
||||||
|
if create:
|
||||||
|
account = self.get_account()
|
||||||
|
# Validated Database
|
||||||
|
db_user = self.get_db_user()
|
||||||
|
try:
|
||||||
|
DatabaseUser.objects.get(username=db_user)
|
||||||
|
except DatabaseUser.DoesNotExist:
|
||||||
|
raise ValidationError(
|
||||||
|
_("Global database user for PHPList '%(db_user)s' does not exists.") % {
|
||||||
|
'db_user': db_user
|
||||||
|
}
|
||||||
|
)
|
||||||
|
db = Database(name=self.get_db_name(), account=account)
|
||||||
|
try:
|
||||||
|
db.full_clean()
|
||||||
|
except ValidationError as e:
|
||||||
|
raise ValidationError({
|
||||||
|
'name': e.messages,
|
||||||
|
})
|
||||||
|
|
||||||
|
def save(self):
|
||||||
|
account = self.get_account()
|
||||||
|
# Database
|
||||||
|
db_name = self.get_db_name()
|
||||||
|
db_user = self.get_db_user()
|
||||||
|
db, db_created = account.databases.get_or_create(name=db_name, type=Database.MYSQL)
|
||||||
|
user = DatabaseUser.objects.get(username=db_user)
|
||||||
|
db.users.add(user)
|
||||||
|
self.instance.database_id = db.pk
|
||||||
|
|
|
@ -5,13 +5,12 @@ from django.db.models import Q
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from orchestra.contrib.databases.models import Database, DatabaseUser
|
|
||||||
from orchestra.contrib.mailboxes.models import Mailbox
|
from orchestra.contrib.mailboxes.models import Mailbox
|
||||||
from orchestra.forms.widgets import SpanWidget
|
from orchestra.forms.widgets import SpanWidget
|
||||||
|
|
||||||
from .. import settings
|
from .. import settings
|
||||||
from ..forms import SaaSPasswordForm
|
from ..forms import SaaSPasswordForm
|
||||||
from .options import SoftwareService
|
from .options import DBSoftwareService
|
||||||
|
|
||||||
|
|
||||||
class PHPListForm(SaaSPasswordForm):
|
class PHPListForm(SaaSPasswordForm):
|
||||||
|
@ -64,26 +63,15 @@ class PHPListChangeForm(PHPListForm):
|
||||||
original=mailbox.name, display=mailbox_link)
|
original=mailbox.name, display=mailbox_link)
|
||||||
|
|
||||||
|
|
||||||
class PHPListService(SoftwareService):
|
class PHPListService(DBSoftwareService):
|
||||||
name = 'phplist'
|
name = 'phplist'
|
||||||
verbose_name = "phpList"
|
verbose_name = "phpList"
|
||||||
form = PHPListForm
|
form = PHPListForm
|
||||||
change_form = PHPListChangeForm
|
change_form = PHPListChangeForm
|
||||||
icon = 'orchestra/icons/apps/Phplist.png'
|
icon = 'orchestra/icons/apps/Phplist.png'
|
||||||
site_domain = settings.SAAS_PHPLIST_DOMAIN
|
site_domain = settings.SAAS_PHPLIST_DOMAIN
|
||||||
|
db_name = settings.SAAS_PHPLIST_DB_NAME
|
||||||
def get_db_name(self):
|
db_user = settings.SAAS_PHPLIST_DB_USER
|
||||||
context = {
|
|
||||||
'name': self.instance.name,
|
|
||||||
'site_name': self.instance.name,
|
|
||||||
}
|
|
||||||
return settings.SAAS_PHPLIST_DB_NAME % context
|
|
||||||
db_name = 'phplist_mu_%s' % self.instance.name
|
|
||||||
# Limit for mysql database names
|
|
||||||
return db_name[:65]
|
|
||||||
|
|
||||||
def get_db_user(self):
|
|
||||||
return settings.SAAS_PHPLIST_DB_USER
|
|
||||||
|
|
||||||
def get_mailbox_name(self):
|
def get_mailbox_name(self):
|
||||||
context = {
|
context = {
|
||||||
|
@ -92,32 +80,11 @@ class PHPListService(SoftwareService):
|
||||||
}
|
}
|
||||||
return settings.SAAS_PHPLIST_BOUNCES_MAILBOX_NAME % context
|
return settings.SAAS_PHPLIST_BOUNCES_MAILBOX_NAME % context
|
||||||
|
|
||||||
def get_account(self):
|
|
||||||
account_model = self.instance._meta.get_field_by_name('account')[0]
|
|
||||||
return account_model.rel.to.objects.get_main()
|
|
||||||
|
|
||||||
def validate(self):
|
def validate(self):
|
||||||
super(PHPListService, self).validate()
|
super(PHPListService, self).validate()
|
||||||
create = not self.instance.pk
|
create = not self.instance.pk
|
||||||
if create:
|
if create:
|
||||||
account = self.get_account()
|
account = self.get_account()
|
||||||
# Validated Database
|
|
||||||
db_user = self.get_db_user()
|
|
||||||
try:
|
|
||||||
DatabaseUser.objects.get(username=db_user)
|
|
||||||
except DatabaseUser.DoesNotExist:
|
|
||||||
raise ValidationError(
|
|
||||||
_("Global database user for PHPList '%(db_user)s' does not exists.") % {
|
|
||||||
'db_user': db_user
|
|
||||||
}
|
|
||||||
)
|
|
||||||
db = Database(name=self.get_db_name(), account=account)
|
|
||||||
try:
|
|
||||||
db.full_clean()
|
|
||||||
except ValidationError as e:
|
|
||||||
raise ValidationError({
|
|
||||||
'name': e.messages,
|
|
||||||
})
|
|
||||||
# Validate mailbox
|
# Validate mailbox
|
||||||
mailbox = Mailbox(name=self.get_mailbox_name(), account=account)
|
mailbox = Mailbox(name=self.get_mailbox_name(), account=account)
|
||||||
try:
|
try:
|
||||||
|
@ -129,13 +96,6 @@ class PHPListService(SoftwareService):
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
account = self.get_account()
|
account = self.get_account()
|
||||||
# Database
|
|
||||||
db_name = self.get_db_name()
|
|
||||||
db_user = self.get_db_user()
|
|
||||||
db, db_created = account.databases.get_or_create(name=db_name, type=Database.MYSQL)
|
|
||||||
user = DatabaseUser.objects.get(username=db_user)
|
|
||||||
db.users.add(user)
|
|
||||||
self.instance.database_id = db.pk
|
|
||||||
# Mailbox
|
# Mailbox
|
||||||
mailbox_name = self.get_mailbox_name()
|
mailbox_name = self.get_mailbox_name()
|
||||||
mailbox, mb_created = account.mailboxes.get_or_create(name=mailbox_name)
|
mailbox, mb_created = account.mailboxes.get_or_create(name=mailbox_name)
|
||||||
|
|
|
@ -197,3 +197,54 @@ SAAS_GITLAB_DOMAIN = Setting('SAAS_GITLAB_DOMAIN',
|
||||||
'gitlab.{}'.format(ORCHESTRA_BASE_DOMAIN),
|
'gitlab.{}'.format(ORCHESTRA_BASE_DOMAIN),
|
||||||
help_text="Uses <tt>ORCHESTRA_BASE_DOMAIN</tt> by default.",
|
help_text="Uses <tt>ORCHESTRA_BASE_DOMAIN</tt> by default.",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
# Moodle
|
||||||
|
|
||||||
|
SAAS_MOODLE_DB_USER = Setting('SAAS_MOODLE_DB_USER',
|
||||||
|
'moodle_mu',
|
||||||
|
help_text=_("Needed for password changing support."),
|
||||||
|
)
|
||||||
|
|
||||||
|
SAAS_MOODLE_DB_PASS = Setting('SAAS_MOODLE_DB_PASS',
|
||||||
|
'secret',
|
||||||
|
help_text=_("Needed for password changing support."),
|
||||||
|
)
|
||||||
|
|
||||||
|
SAAS_MOODLE_DB_NAME = Setting('SAAS_MOODLE_DB_NAME',
|
||||||
|
'moodle_mu',
|
||||||
|
help_text=_("Needed for password changing support."),
|
||||||
|
)
|
||||||
|
|
||||||
|
SAAS_MOODLE_DB_HOST = Setting('SAAS_MOODLE_DB_HOST',
|
||||||
|
'loclahost',
|
||||||
|
help_text=_("Needed for password changing support."),
|
||||||
|
)
|
||||||
|
|
||||||
|
SAAS_MOODLE_DOMAIN = Setting('SAAS_MOODLE_DOMAIN',
|
||||||
|
'%(site_name)s.courses.{}'.format(ORCHESTRA_BASE_DOMAIN),
|
||||||
|
help_text="Uses <tt>ORCHESTRA_BASE_DOMAIN</tt> by default.",
|
||||||
|
)
|
||||||
|
|
||||||
|
SAAS_MOODLE_PATH = Setting('SAAS_MOODLE_PATH',
|
||||||
|
'/var/www/moodle-mu',
|
||||||
|
help_text=_("Filesystem path to the Moodle source code installed on the server. "
|
||||||
|
"Used by <tt>SAAS_MOODLE_CRONTAB</tt>.")
|
||||||
|
)
|
||||||
|
|
||||||
|
SAAS_MOODLE_DATA_PATH = Setting('SAAS_MOODLE_DATA_PATH',
|
||||||
|
'/var/moodledata/%(site_name)s',
|
||||||
|
help_text=_("Filesystem path to the Moodle source code installed on the server. "
|
||||||
|
"Used by <tt>SAAS_MOODLE_CRONTAB</tt>.")
|
||||||
|
)
|
||||||
|
|
||||||
|
SAAS_MOODLE_SYSTEMUSER = Setting('SAAS_MOODLE_SYSTEMUSER',
|
||||||
|
'root',
|
||||||
|
help_text=_("System user running Moodle on the server."
|
||||||
|
"Used by <tt>SAAS_MOODLE_CRONTAB</tt>.")
|
||||||
|
)
|
||||||
|
|
||||||
|
SAAS_MOODLE_CRONTAB = Setting('SAAS_MOODLE_CRONTAB',
|
||||||
|
'*/15 * * * * export SITE="%(site_name)s"; php %(moodle_path)s/admin/cli/cron.php >/dev/null',
|
||||||
|
help_text=_("Left blank if you don't want crontab to be configured")
|
||||||
|
)
|
||||||
|
|
|
@ -20,7 +20,8 @@ class UserCreationForm(forms.ModelForm):
|
||||||
'duplicate_username': _("A user with that username already exists."),
|
'duplicate_username': _("A user with that username already exists."),
|
||||||
}
|
}
|
||||||
password1 = forms.CharField(label=_("Password"),
|
password1 = forms.CharField(label=_("Password"),
|
||||||
widget=forms.PasswordInput, validators=[validate_password])
|
widget=forms.PasswordInput(attrs={'autocomplete': 'off'}),
|
||||||
|
validators=[validate_password])
|
||||||
password2 = forms.CharField(label=_("Password confirmation"),
|
password2 = forms.CharField(label=_("Password confirmation"),
|
||||||
widget=forms.PasswordInput,
|
widget=forms.PasswordInput,
|
||||||
help_text=_("Enter the same password as above, for verification."))
|
help_text=_("Enter the same password as above, for verification."))
|
||||||
|
|
Loading…
Reference in New Issue