diff --git a/TODO.md b/TODO.md index 216a5e82..2557c795 100644 --- a/TODO.md +++ b/TODO.md @@ -138,3 +138,5 @@ Remember that, as always with QuerySets, any subsequent chained methods which im * Move MU webapps to SaaS? * DN: Transaction atomicity and backend failure + +* SaaS Icons diff --git a/orchestra/apps/orchestration/admin.py b/orchestra/apps/orchestration/admin.py index ae932b0d..fdbbffb6 100644 --- a/orchestra/apps/orchestration/admin.py +++ b/orchestra/apps/orchestration/admin.py @@ -46,8 +46,8 @@ class RouteAdmin(admin.ModelAdmin): class BackendOperationInline(admin.TabularInline): model = BackendOperation - fields = ('action', 'content_object_link') - readonly_fields = ('action', 'content_object_link') + fields = ('action', 'instance_link') + readonly_fields = ('action', 'instance_link') extra = 0 can_delete = False @@ -56,22 +56,22 @@ class BackendOperationInline(admin.TabularInline): 'all': ('orchestra/css/hide-inline-id.css',) } - def content_object_link(self, operation): + def instance_link(self, operation): try: - return admin_link('content_object')(self, operation) + return admin_link('instance')(self, operation) except: return _("deleted {0} {1}").format( escape(operation.content_type), escape(operation.object_id) ) - content_object_link.allow_tags = True - content_object_link.short_description = _("Content_object") + instance_link.allow_tags = True + instance_link.short_description = _("Instance") def has_add_permission(self, *args, **kwargs): return False def get_queryset(self, request): queryset = super(BackendOperationInline, self).get_queryset(request) - return queryset.prefetch_related('content_object') + return queryset.prefetch_related('instance') def display_mono(field): diff --git a/orchestra/apps/orchestration/models.py b/orchestra/apps/orchestration/models.py index 8ef143a9..826b795f 100644 --- a/orchestra/apps/orchestration/models.py +++ b/orchestra/apps/orchestration/models.py @@ -102,23 +102,19 @@ class BackendOperation(models.Model): content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() - content_object = generic.GenericForeignKey('content_type', 'object_id') + instance = generic.GenericForeignKey('content_type', 'object_id') class Meta: verbose_name = _("Operation") verbose_name_plural = _("Operations") - def __init__(self, *args, **kwargs): - self.instance = kwargs.pop('instance', None) - super(BackendOperation, self).__init__(*args, **kwargs) - def __unicode__(self): - return '%s.%s(%s)' % (self.backend, self.action, self.instance or self.content_object) + return '%s.%s(%s)' % (self.backend, self.action, self.instance) def __hash__(self): """ set() """ backend = getattr(self, 'backend', self.backend) - return hash(backend) + hash(self.instance or self.content_object) + hash(self.action) + return hash(backend) + hash(self.instance) + hash(self.action) def __eq__(self, operation): """ set() """ @@ -126,7 +122,7 @@ class BackendOperation(models.Model): @classmethod def create(cls, backend, instance, action): - op = cls(backend=backend.get_name(), instance=instance, content_object=instance, action=action) + op = cls(backend=backend.get_name(), instance=instance, action=action) op.backend = backend return op diff --git a/orchestra/apps/orchestration/settings.py b/orchestra/apps/orchestration/settings.py index 1a2d0b45..86b17ac1 100644 --- a/orchestra/apps/orchestration/settings.py +++ b/orchestra/apps/orchestration/settings.py @@ -7,15 +7,19 @@ ORCHESTRATION_OS_CHOICES = getattr(settings, 'ORCHESTRATION_OS_CHOICES', ( ('LINUX', "Linux"), )) + ORCHESTRATION_DEFAULT_OS = getattr(settings, 'ORCHESTRATION_DEFAULT_OS', 'LINUX') + ORCHESTRATION_SSH_KEY_PATH = getattr(settings, 'ORCHESTRATION_SSH_KEY_PATH', path.join(path.expanduser('~'), '.ssh/id_rsa')) + ORCHESTRATION_ROUTER = getattr(settings, 'ORCHESTRATION_ROUTER', 'orchestra.apps.orchestration.models.Route' ) + ORCHESTRATION_TEMP_SCRIPT_PATH = getattr(settings, 'ORCHESTRATION_TEMP_SCRIPT_PATH', '/dev/shm' ) diff --git a/orchestra/apps/saas/services/dokuwiki.py b/orchestra/apps/saas/services/dokuwiki.py new file mode 100644 index 00000000..93690fd4 --- /dev/null +++ b/orchestra/apps/saas/services/dokuwiki.py @@ -0,0 +1,19 @@ +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from orchestra.forms import PluginDataForm + +from .options import SoftwareService + + +class DowkuwikiForm(PluginDataForm): + username = forms.CharField(label=_("Username"), max_length=64) + password = forms.CharField(label=_("Password"), max_length=64) + site_name = forms.CharField(label=_("Site name"), max_length=64) + email = forms.EmailField(label=_("Email")) + + +class DokuwikiService(SoftwareService): + verbose_name = "Dowkuwiki" + form = DowkuwikiForm + description_field = 'site_name' diff --git a/orchestra/apps/saas/services/drupal.py b/orchestra/apps/saas/services/drupal.py new file mode 100644 index 00000000..05318e21 --- /dev/null +++ b/orchestra/apps/saas/services/drupal.py @@ -0,0 +1,19 @@ +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from orchestra.forms import PluginDataForm + +from .options import SoftwareService + + +class DrupalForm(PluginDataForm): + username = forms.CharField(label=_("Username"), max_length=64) + password = forms.CharField(label=_("Password"), max_length=64) + site_name = forms.CharField(label=_("Site name"), max_length=64) + email = forms.EmailField(label=_("Email")) + + +class DrupalService(SoftwareService): + verbose_name = "Drupal" + form = DrupalForm + description_field = 'site_name' diff --git a/orchestra/apps/saas/services/moodle.py b/orchestra/apps/saas/services/moodle.py new file mode 100644 index 00000000..17e6da0c --- /dev/null +++ b/orchestra/apps/saas/services/moodle.py @@ -0,0 +1,19 @@ +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from orchestra.forms import PluginDataForm + +from .options import SoftwareService + + +class MoodleForm(PluginDataForm): + username = forms.CharField(label=_("Username"), max_length=64) + password = forms.CharField(label=_("Password"), max_length=64) + site_name = forms.CharField(label=_("Site name"), max_length=64) + email = forms.EmailField(label=_("Email")) + + +class MoodleService(SoftwareService): + verbose_name = "Moodle" + form = MoodleForm + description_field = 'site_name' diff --git a/orchestra/apps/saas/services/wordpress.py b/orchestra/apps/saas/services/wordpress.py new file mode 100644 index 00000000..677b86bd --- /dev/null +++ b/orchestra/apps/saas/services/wordpress.py @@ -0,0 +1,20 @@ +from django import forms +from django.utils.translation import ugettext_lazy as _ + +from orchestra.forms import PluginDataForm + +from .options import SoftwareService + + +class WordpressForm(PluginDataForm): + username = forms.CharField(label=_("Username"), max_length=64) + password = forms.CharField(label=_("Password"), max_length=64) + site_name = forms.CharField(label=_("Site name"), max_length=64, + help_text=_("URL will be <site_name>.blogs.orchestra.lan")) + email = forms.EmailField(label=_("Email")) + + +class WordpressService(SoftwareService): + verbose_name = "Wordpress" + form = WordpressForm + description_field = 'site_name' diff --git a/orchestra/apps/saas/settings.py b/orchestra/apps/saas/settings.py index 2ba71ec9..c143b2f7 100644 --- a/orchestra/apps/saas/settings.py +++ b/orchestra/apps/saas/settings.py @@ -2,6 +2,10 @@ from django.conf import settings SAAS_ENABLED_SERVICES = getattr(settings, 'SAAS_ENABLED_SERVICES', ( + 'orchestra.apps.saas.services.wordpress.WordpressService', + 'orchestra.apps.saas.services.drupal.DrupalService', + 'orchestra.apps.saas.services.dokuwiki.DokuwikiService', + 'orchestra.apps.saas.services.moodle.MoodleService', 'orchestra.apps.saas.services.bscw.BSCWService', 'orchestra.apps.saas.services.gitlab.GitLabService', 'orchestra.apps.saas.services.phplist.PHPListService', diff --git a/orchestra/apps/saas/static/saas/icons/Dokuwiki.svg b/orchestra/apps/saas/static/saas/icons/Dokuwiki.svg new file mode 100644 index 00000000..cbee241e --- /dev/null +++ b/orchestra/apps/saas/static/saas/icons/Dokuwiki.svg @@ -0,0 +1,553 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orchestra/apps/saas/static/saas/icons/Drupal.svg b/orchestra/apps/saas/static/saas/icons/Drupal.svg new file mode 100644 index 00000000..7da67bde --- /dev/null +++ b/orchestra/apps/saas/static/saas/icons/Drupal.svg @@ -0,0 +1 @@ +]>Druplicon \ No newline at end of file diff --git a/orchestra/apps/saas/static/saas/icons/Moodle.svg b/orchestra/apps/saas/static/saas/icons/Moodle.svg new file mode 100644 index 00000000..3ea6155d --- /dev/null +++ b/orchestra/apps/saas/static/saas/icons/Moodle.svg @@ -0,0 +1,233 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/orchestra/apps/saas/static/saas/icons/WordPress.svg b/orchestra/apps/saas/static/saas/icons/WordPress.svg new file mode 100644 index 00000000..8628e3ad --- /dev/null +++ b/orchestra/apps/saas/static/saas/icons/WordPress.svg @@ -0,0 +1,68 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/orchestra/apps/saas/static/saas/icons/gitlab.png b/orchestra/apps/saas/static/saas/icons/gitlab.png new file mode 100644 index 00000000..09b1689c Binary files /dev/null and b/orchestra/apps/saas/static/saas/icons/gitlab.png differ diff --git a/orchestra/apps/webapps/tests/functional_tests/tests.py b/orchestra/apps/webapps/tests/functional_tests/tests.py index 7349a29e..e9d08fcd 100644 --- a/orchestra/apps/webapps/tests/functional_tests/tests.py +++ b/orchestra/apps/webapps/tests/functional_tests/tests.py @@ -93,15 +93,9 @@ class PHPFcidWebAppMixin(StaticWebAppMixin): ) -class PHPFPMWebAppMixin(StaticWebAppMixin): +class PHPFPMWebAppMixin(PHPFcidWebAppMixin): backend = backends.phpfpm.PHPFPMBackend type_value = 'php5.5' - token = random_ascii(100) - page = ( - 'index.php', - '\n' % token, - 'Hello World! %s' % token, - ) class RESTWebAppMixin(object): @@ -170,10 +164,18 @@ class AdminWebAppMixin(WebAppMixin): self.assertNotEqual(url, self.selenium.current_url) +class RESTWebAppTest(StaticWebAppMixin, RESTWebAppMixin, WebAppMixin, BaseLiveServerTestCase): + pass + + class RESTWebAppTest(PHPFcidWebAppMixin, RESTWebAppMixin, WebAppMixin, BaseLiveServerTestCase): pass +class RESTWebAppTest(PHPFPMWebAppMixin, RESTWebAppMixin, WebAppMixin, BaseLiveServerTestCase): + pass + + #class AdminWebAppTest(AdminWebAppMixin, BaseLiveServerTestCase): # pass diff --git a/orchestra/apps/websites/tests/functional_tests/tests.py b/orchestra/apps/websites/tests/functional_tests/tests.py index 7840a4a9..2095acd2 100644 --- a/orchestra/apps/websites/tests/functional_tests/tests.py +++ b/orchestra/apps/websites/tests/functional_tests/tests.py @@ -71,14 +71,12 @@ class RESTWebsiteMixin(RESTWebAppMixin): self.rest.websites.create(name=name, domains=[domain.url], contents=[{'webapp': webapp.url}]) - -#class RESTWebsiteTest(RESTWebsiteMixin, StaticWebAppMixin, WebsiteMixin, BaseLiveServerTestCase): -# pass +class RESTWebsiteTest(RESTWebsiteMixin, StaticWebAppMixin, WebsiteMixin, BaseLiveServerTestCase): + pass -PHPFPMWebAppMixin -#class RESTWebsiteTest(RESTWebsiteMixin, PHPFcidWebAppMixin, WebsiteMixin, BaseLiveServerTestCase): -# pass +class RESTWebsiteTest(RESTWebsiteMixin, PHPFcidWebAppMixin, WebsiteMixin, BaseLiveServerTestCase): + pass class RESTWebsiteTest(RESTWebsiteMixin, PHPFPMWebAppMixin, WebsiteMixin, BaseLiveServerTestCase):