environment: coding style (#29240)

This commit is contained in:
Benjamin Dauvergne 2019-03-08 01:58:41 +01:00
parent ca5d0b18c3
commit 9bf094388a
5 changed files with 163 additions and 67 deletions

View File

@ -1,10 +1,25 @@
# hobo - portal to configure and deploy applications
# Copyright (C) 2015-2019 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django import forms
from django.conf import settings
from django.contrib import messages
from django.http import HttpResponseRedirect
from django.template.defaultfilters import slugify
from django.utils.translation import ugettext_lazy as _
from django.core.validators import validate_email
from .models import (Authentic, Wcs, Passerelle, Variable, Combo, Fargo, Welco,
@ -12,7 +27,8 @@ from .models import (Authentic, Wcs, Passerelle, Variable, Combo, Fargo, Welco,
from .utils import get_setting_variable
EXCLUDED_FIELDS = ('last_operational_check_timestamp',
'last_operational_success_timestamp', 'secret_key', 'secondary')
'last_operational_success_timestamp', 'secret_key',
'secondary')
class BaseForm(forms.ModelForm):
@ -29,8 +45,8 @@ class BaseForm(forms.ModelForm):
# choice that was selected as an additional, disabled, <select> widget.
if self.instance.id and len(choices) > 1:
self.fields['template_name_readonly'] = forms.fields.CharField(
label=_('Template'), required=False,
initial=self.instance.template_name)
label=_('Template'), required=False,
initial=self.instance.template_name)
self.fields['template_name_readonly'].widget = forms.Select(choices=choices)
self.fields['template_name_readonly'].widget.attrs['disabled'] = 'disabled'
@ -116,11 +132,13 @@ class MandayeJSForm(BaseForm):
model = MandayeJS
exclude = EXCLUDED_FIELDS
class ChronoForm(BaseForm):
class Meta:
model = Chrono
exclude = EXCLUDED_FIELDS
class CorboForm(BaseForm):
class Meta:
model = Corbo

View File

@ -1,3 +1,19 @@
# hobo - portal to configure and deploy applications
# Copyright (C) 2015-2019 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import re
import datetime
import json
@ -13,6 +29,7 @@ from django.utils.encoding import force_text
from django.utils.six.moves.urllib.parse import urlparse
from django.utils.timezone import now
from django.utils.translation import ugettext_lazy as _
from django.utils import six
from django.core.exceptions import ValidationError
from django.core.validators import URLValidator
@ -23,16 +40,16 @@ from .utils import Zone, get_installed_services
from .mandayejs_app_settings import APP_SETTINGS_CLASSES, DEFAULT_APP_SETTINGS
SECRET_CHARS = 'abcdefghijklmnopqrstuvwxyz0123456789!@#$%^&*(-_=+)'
FLOAT_RE = re.compile(r'^\s*[0-9]+\.[0-9]+\s*')
class Variable(models.Model):
name = models.CharField(max_length=100, verbose_name=_('name'))
label = models.CharField(max_length=100, blank=True, verbose_name=_('label'))
value = models.TextField(verbose_name=_('value'),
blank=True,
help_text=_('start with [ or { for a JSON document'))
value = models.TextField(
verbose_name=_('value'),
blank=True,
help_text=_('start with [ or { for a JSON document'))
auto = models.BooleanField(default=False)
service_type = models.ForeignKey(ContentType, null=True)
service_pk = models.PositiveIntegerField(null=True)
@ -81,16 +98,18 @@ class ServiceBase(models.Model):
last_operational_success_timestamp = models.DateTimeField(null=True)
last_update_timestamp = models.DateTimeField(auto_now=True, null=True)
variables = GenericRelation(Variable,
content_type_field='service_type', object_id_field='service_pk')
variables = GenericRelation(
Variable,
content_type_field='service_type',
object_id_field='service_pk')
@classmethod
def is_enabled(cls):
return True
def is_operational(self):
return (self.last_operational_success_timestamp is not None and
self.last_operational_success_timestamp == self.last_operational_check_timestamp)
return (self.last_operational_success_timestamp is not None
and self.last_operational_success_timestamp == self.last_operational_check_timestamp)
def check_operational(self):
once_now = now()
@ -100,7 +119,7 @@ class ServiceBase(models.Model):
response = requests.get(zone.href, timeout=10, allow_redirects=False)
response.raise_for_status()
self.last_operational_success_timestamp = once_now
except requests.RequestException as e:
except requests.RequestException:
pass
self.save(update_fields=('last_operational_check_timestamp', 'last_operational_success_timestamp'))
@ -120,7 +139,7 @@ class ServiceBase(models.Model):
def as_dict(self):
as_dict = dict([(x, y) for (x, y) in self.__dict__.items()
if type(y) in (int, str, unicode)])
if isinstance(y, six.integer_types + six.string_types)])
as_dict['base_url'] = self.get_base_url_path()
as_dict['service-id'] = self.Extra.service_id
as_dict['service-label'] = force_text(self.Extra.service_label)
@ -225,8 +244,8 @@ class ServiceBase(models.Model):
class Authentic(ServiceBase):
use_as_idp_for_self = models.BooleanField(
verbose_name=_('Use as IdP'),
default=False)
verbose_name=_('Use as IdP'),
default=False)
class Meta:
verbose_name = _('Authentic Identity Provider')
@ -240,9 +259,9 @@ class Authentic(ServiceBase):
def get_admin_zones(self):
return [
Zone(_('User Management'), 'users', self.get_base_url_path() + 'manage/users/'),
Zone(_('Role Management'), 'roles', self.get_base_url_path() + 'manage/roles/'),
]
Zone(_('User Management'), 'users', self.get_base_url_path() + 'manage/users/'),
Zone(_('Role Management'), 'roles', self.get_base_url_path() + 'manage/roles/'),
]
def get_saml_idp_metadata_url(self):
return self.get_base_url_path() + 'idp/saml2/metadata'
@ -267,8 +286,8 @@ class Wcs(ServiceBase):
def get_admin_zones(self):
return [
Zone(self.title, 'webforms', self.get_base_url_path() + 'admin/'),
]
Zone(self.title, 'webforms', self.get_base_url_path() + 'admin/'),
]
def get_saml_sp_metadata_url(self):
return self.get_base_url_path() + 'saml/metadata'
@ -287,8 +306,8 @@ class Passerelle(ServiceBase):
def get_admin_zones(self):
return [
Zone(self.title, 'webservices', self.get_base_url_path() + 'manage/')
]
Zone(self.title, 'webservices', self.get_base_url_path() + 'manage/')
]
def get_saml_sp_metadata_url(self):
return self.get_base_url_path() + 'accounts/mellon/metadata/'
@ -310,8 +329,8 @@ class Combo(ServiceBase):
def get_admin_zones(self):
return [
Zone(self.title, 'portal', self.get_base_url_path() + 'manage/')
]
Zone(self.title, 'portal', self.get_base_url_path() + 'manage/')
]
def get_saml_sp_metadata_url(self):
return self.get_base_url_path() + 'accounts/mellon/metadata/'
@ -333,8 +352,8 @@ class Fargo(ServiceBase):
def get_admin_zones(self):
return [
Zone(self.title, 'document-box', self.get_base_url_path() + 'admin/')
]
Zone(self.title, 'document-box', self.get_base_url_path() + 'admin/')
]
def get_saml_sp_metadata_url(self):
return self.get_base_url_path() + 'accounts/mellon/metadata/'
@ -352,8 +371,8 @@ class Welco(ServiceBase):
def get_admin_zones(self):
return [
Zone(self.title, 'multichannel-guichet', self.get_base_url_path() + 'admin/')
]
Zone(self.title, 'multichannel-guichet', self.get_base_url_path() + 'admin/')
]
def get_saml_sp_metadata_url(self):
return self.get_base_url_path() + 'accounts/mellon/metadata/'
@ -363,10 +382,12 @@ class Welco(ServiceBase):
class MandayeJS(ServiceBase):
site_app = models.CharField(_('Site Application'), max_length=128,
choices = APP_SETTINGS_CLASSES,
default = DEFAULT_APP_SETTINGS
)
site_app = models.CharField(
_('Site Application'),
max_length=128,
choices=APP_SETTINGS_CLASSES,
default=DEFAULT_APP_SETTINGS)
class Meta:
verbose_name = _('Authentication Reverse Proxy')
ordering = ['title']
@ -382,11 +403,11 @@ class MandayeJS(ServiceBase):
def get_admin_zones(self):
return [
Zone(self.title, 'mandayejs', self.get_base_url_path() + '_mandaye/admin/')
]
Zone(self.title, 'mandayejs', self.get_base_url_path() + '_mandaye/admin/')
]
def get_saml_sp_metadata_url(self):
return self.get_base_url_path()+ '_mandaye/accounts/mellon/metadata/'
return self.get_base_url_path() + '_mandaye/accounts/mellon/metadata/'
class Chrono(ServiceBase):
@ -402,8 +423,8 @@ class Chrono(ServiceBase):
def get_admin_zones(self):
return [
Zone(self.title, 'calendar', self.get_base_url_path() + 'manage/')
]
Zone(self.title, 'calendar', self.get_base_url_path() + 'manage/')
]
def get_saml_sp_metadata_url(self):
return self.get_base_url_path() + 'accounts/mellon/metadata/'
@ -425,8 +446,8 @@ class Hobo(ServiceBase):
def get_admin_zones(self):
return [
Zone(self.title, 'hobo', self.get_base_url_path())
]
Zone(self.title, 'hobo', self.get_base_url_path())
]
def get_saml_sp_metadata_url(self):
return self.get_base_url_path() + 'accounts/mellon/metadata/'
@ -452,11 +473,11 @@ class Corbo(ServiceBase):
def get_admin_zones(self):
return [
Zone(self.title, 'corbo', self.get_base_url_path() + 'admin/')
]
Zone(self.title, 'corbo', self.get_base_url_path() + 'admin/')
]
def get_saml_sp_metadata_url(self):
return self.get_base_url_path()+ 'accounts/mellon/metadata/'
return self.get_base_url_path() + 'accounts/mellon/metadata/'
def get_backoffice_menu_url(self):
return self.get_base_url_path() + 'manage/menu.json'

View File

@ -1,22 +1,38 @@
# hobo - portal to configure and deploy applications
# Copyright (C) 2015-2019 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.conf.urls import url
from .views import *
from . import views
urlpatterns = [
url(r'^$', HomeView.as_view(), name='environment-home'),
url(r'^variables$', VariablesView.as_view(), name='environment-variables'),
url(r'^new-variable$', VariableCreateView.as_view(), name='new-variable',),
url(r'^update-variable/(?P<pk>\w+)$', VariableUpdateView.as_view(),
url(r'^$', views.HomeView.as_view(), name='environment-home'),
url(r'^variables$', views.VariablesView.as_view(), name='environment-variables'),
url(r'^new-variable$', views.VariableCreateView.as_view(), name='new-variable',),
url(r'^update-variable/(?P<pk>\w+)$', views.VariableUpdateView.as_view(),
name='update-variable'),
url(r'^delete-variable/(?P<pk>\w+)$', VariableDeleteView.as_view(),
url(r'^delete-variable/(?P<pk>\w+)$', views.VariableDeleteView.as_view(),
name='delete-variable'),
url(r'^check_operational/(?P<service>\w+)/(?P<slug>[\w-]+)$',
operational_check_view, name='operational-check'),
url(r'^new-(?P<service>\w+)$', ServiceCreateView.as_view(), name='create-service'),
url(r'^save-(?P<service>\w+)/(?P<slug>[\w-]+)$', ServiceUpdateView.as_view(), name='save-service'),
url(r'^delete-(?P<service>\w+)/(?P<slug>[\w-]+)$', ServiceDeleteView.as_view(), name='delete-service'),
views.operational_check_view, name='operational-check'),
url(r'^new-(?P<service>\w+)$', views.ServiceCreateView.as_view(), name='create-service'),
url(r'^save-(?P<service>\w+)/(?P<slug>[\w-]+)$', views.ServiceUpdateView.as_view(), name='save-service'),
url(r'^delete-(?P<service>\w+)/(?P<slug>[\w-]+)$', views.ServiceDeleteView.as_view(), name='delete-service'),
url(r'^new-variable-(?P<service>\w+)/(?P<slug>[\w-]+)$',
VariableCreateView.as_view(), name='new-variable-service',),
url(r'^debug.json$', debug_json, name='debug-json'),
views.VariableCreateView.as_view(), name='new-variable-service',),
url(r'^debug.json$', views.debug_json, name='debug-json'),
]

View File

@ -1,3 +1,19 @@
# hobo - portal to configure and deploy applications
# Copyright (C) 2015-2019 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from django.conf import settings
from django.core.urlresolvers import reverse
from django.db import connection
@ -13,11 +29,13 @@ def get_installed_services():
installed_services.extend(available_service.objects.all())
return installed_services
def get_operational_services():
return [x for x in get_installed_services() if x.is_operational()]
def get_installed_services_dict():
from .models import AVAILABLE_SERVICES, Variable
from .models import Variable
hobo_service = []
build_absolute_uri = None
if hasattr(connection, 'get_tenant') and hasattr(connection.get_tenant(), 'build_absolute_uri'):
@ -38,9 +56,8 @@ def get_installed_services_dict():
}]
return {
'services': hobo_service + [x.as_dict() for x in get_installed_services()],
'variables': dict(((v.name, v.json)
for v in Variable.objects.filter(service_pk__isnull=True))),
}
'variables': {v.name: v.json for v in Variable.objects.filter(service_pk__isnull=True)}
}
class Zone:
@ -56,8 +73,12 @@ class Zone:
def get_setting_variable(name):
from .models import Variable
variable, created = Variable.objects.get_or_create(name=name,
defaults={'auto': True, 'value': settings.VARIABLE_SETTINGS_DEFAULTS.get(name) or ''})
variable, created = Variable.objects.get_or_create(
name=name,
defaults={
'auto': True,
'value': settings.VARIABLE_SETTINGS_DEFAULTS.get(name) or ''
})
return variable
def create_base_url(hostname, service):

View File

@ -1,3 +1,19 @@
# hobo - portal to configure and deploy applications
# Copyright (C) 2015-2019 Entr'ouvert
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import json
import string
@ -25,7 +41,8 @@ class HomeView(TemplateView):
def get_context_data(self, **kwargs):
context = super(HomeView, self).get_context_data(**kwargs)
context['available_services'] = [
AvailableService(x) for x in AVAILABLE_SERVICES if x.is_enabled()]
AvailableService(x) for x in AVAILABLE_SERVICES if x.is_enabled()
]
context['installed_services'] = [x for x in utils.get_installed_services() if not x.secondary]
return context
@ -35,8 +52,7 @@ class VariablesView(TemplateView):
def get_context_data(self, **kwargs):
context = super(VariablesView, self).get_context_data(**kwargs)
context['variables'] = Variable.objects.filter(auto=False,
service_pk__isnull=True).order_by('label')
context['variables'] = Variable.objects.filter(auto=False, service_pk__isnull=True).order_by('label')
return context
@ -67,8 +83,8 @@ class VariableCreateView(CreateView):
}
try:
self.object = Variable.objects.get(
name=form.instance.name,
**service_kwargs)
name=form.instance.name,
**service_kwargs)
except Variable.DoesNotExist:
self.object = form.save()
else:
@ -113,7 +129,9 @@ class ServiceCreateView(CreateView):
def get_initial(self):
initial = super(ServiceCreateView, self).get_initial()
initial['base_url'] = utils.create_base_url(self.request.build_absolute_uri(), self.model.Extra.service_default_slug)
initial['base_url'] = utils.create_base_url(
self.request.build_absolute_uri(),
self.model.Extra.service_default_slug)
initial['slug'] = self.model.Extra.service_default_slug
return initial
@ -166,6 +184,7 @@ class ServiceUpdateView(UpdateView):
return form_class
return None
class ServiceDeleteView(DeleteView):
success_url = reverse_lazy('environment-home')
template_name = 'environment/generic_confirm_delete.html'
@ -179,6 +198,7 @@ class ServiceDeleteView(DeleteView):
return service.objects.get(slug=service_slug)
return None
def operational_check_view(request, service, slug, **kwargs):
for klass in AVAILABLE_SERVICES: