Refactoring: move WizardView from environments to catalog

And reorganize imports to conform hacking checks.

Change-Id: Ibcf202488c2260a66de09813e9607ecf6e17b871
This commit is contained in:
Timur Sufiev 2014-04-24 18:24:46 +04:00
parent c908f034ce
commit 47736f0727
4 changed files with 218 additions and 219 deletions

View File

@ -15,13 +15,11 @@
from django.conf.urls import patterns, url
from muranodashboard.catalog import views
from muranodashboard.catalog import image
from muranodashboard.environments import views as env_views
from muranodashboard.dynamic_ui import services
VIEW_MOD = 'muranodashboard.catalog.views'
wizard_view = env_views.Wizard.as_view(
wizard_view = views.Wizard.as_view(
services.get_app_forms, condition_dict=services.condition_getter)
urlpatterns = patterns(

View File

@ -11,20 +11,35 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import copy
import functools
import json
import logging
from django.views.generic import list
from horizon import tabs
from django import shortcuts
from django.conf import settings
from django.contrib.auth import REDIRECT_FIELD_NAME
from django.contrib.auth.decorators import login_required
from django.utils.http import is_safe_url
from muranodashboard.catalog import tabs as catalog_tabs
from muranodashboard.environments import api
from muranodashboard.environments import views
from muranodashboard.dynamic_ui import services
import re
from django.conf import settings
from django.contrib import auth
from django.contrib.auth import decorators as auth_dec
from django.contrib.formtools.wizard import views as wizard_views
from django.core import urlresolvers as url
from django import http
from django import shortcuts
from django.utils import decorators as django_dec
from django.utils import http as http_utils
from django.utils.translation import ugettext_lazy as _ # noqa
from django.views.generic import list as list_view
from horizon import messages
from horizon import tabs
from horizon.forms import views
from horizon import exceptions
from muranoclient.common import exceptions as exc
from muranodashboard.catalog import tabs as catalog_tabs
from muranodashboard.dynamic_ui import services
from muranodashboard.dynamic_ui import helpers
from muranodashboard.environments import api
from muranodashboard.environments import consts
from muranodashboard import utils
LOG = logging.getLogger(__name__)
@ -64,10 +79,11 @@ def get_environments_context(request):
return context
@login_required
def switch(request, environment_id, redirect_field_name=REDIRECT_FIELD_NAME):
@auth_dec.login_required
def switch(request, environment_id,
redirect_field_name=auth.REDIRECT_FIELD_NAME):
redirect_to = request.REQUEST.get(redirect_field_name, '')
if not is_safe_url(url=redirect_to, host=request.get_host()):
if not http_utils.is_safe_url(url=redirect_to, host=request.get_host()):
redirect_to = settings.LOGIN_REDIRECT_URL
for env in get_available_environments(request):
@ -95,12 +111,12 @@ def create_quick_environment(request):
return api.environment_create(request, params)
@login_required
@auth_dec.login_required
def quick_deploy(request, app_id):
env = create_quick_environment(request)
try:
view = views.Wizard.as_view(services.get_app_forms,
condition_dict=services.condition_getter)
view = Wizard.as_view(services.get_app_forms,
condition_dict=services.condition_getter)
return view(request, app_id=app_id, environment_id=env.id,
do_redirect=True, drop_wm_form=True)
except:
@ -108,7 +124,155 @@ def quick_deploy(request, app_id):
raise
class IndexView(list.ListView):
class LazyWizard(wizard_views.SessionWizardView):
"""The class which defers evaluation of form_list and condition_dict
until view method is called. So, each time we load a page with a dynamic
UI form, it will have markup/logic from the newest YAML-file definition.
"""
@django_dec.classonlymethod
def as_view(cls, initforms, *initargs, **initkwargs):
"""
Main entry point for a request-response process.
"""
# sanitize keyword arguments
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError(u"You tried to pass in the %s method name as a"
u" keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError(u"%s() received an invalid keyword %r" % (
cls.__name__, key))
def view(request, *args, **kwargs):
forms = initforms
if hasattr(initforms, '__call__'):
forms = initforms(request, kwargs)
_kwargs = copy.copy(initkwargs)
_kwargs = cls.get_initkwargs(forms, *initargs, **_kwargs)
cdict = _kwargs.get('condition_dict')
if cdict and hasattr(cdict, '__call__'):
_kwargs['condition_dict'] = cdict(request, kwargs)
self = cls(**_kwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
# take name and docstring from class
functools.update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
functools.update_wrapper(view, cls.dispatch, assigned=())
return view
class Wizard(views.ModalFormMixin, LazyWizard):
template_name = 'services/wizard_create.html'
do_redirect = False
def get_prefix(self, *args, **kwargs):
base = super(Wizard, self).get_prefix(*args, **kwargs)
fmt = utils.BlankFormatter()
return fmt.format('{0}_{environment_id}_{app_id}', base, **kwargs)
def done(self, form_list, **kwargs):
environment_id = kwargs.get('environment_id')
env_url = url.reverse('horizon:murano:environments:services',
args=(environment_id,))
app_name = services.get_service_name(self.request,
kwargs.get('app_id'))
service = form_list[0].service
attributes = service.extract_attributes()
attributes = helpers.insert_hidden_ids(attributes)
storage = attributes.setdefault('?', {}).setdefault(
consts.DASHBOARD_ATTRS_KEY, {})
storage['name'] = app_name
wm_form_data = service.cleaned_data.get('workflowManagement')
if wm_form_data:
do_redirect = not wm_form_data['StayAtCatalog']
else:
do_redirect = self.get_wizard_flag('do_redirect')
fail_url = url.reverse("horizon:murano:environments:index")
try:
srv = api.service_create(self.request, environment_id, attributes)
except exc.HTTPForbidden:
msg = _("Sorry, you can't add application right now. "
"The environment is deploying.")
exceptions.handle(self.request, msg, redirect=fail_url)
except Exception:
exceptions.handle(self.request,
_("Sorry, you can't add application right now."),
redirect=fail_url)
else:
message = "The '{0}' application successfully " \
"added to environment.".format(app_name)
messages.success(self.request, message)
if do_redirect:
return http.HttpResponseRedirect(env_url)
else:
srv_id = getattr(srv, '?')['id']
return self.create_hacked_response(srv_id, attributes['name'])
def create_hacked_response(self, obj_id, obj_name):
# copy-paste from horizon.forms.views.ModalFormView; should be done
# that way until we move here from django Wizard to horizon workflow
if views.ADD_TO_FIELD_HEADER in self.request.META:
field_id = self.request.META[views.ADD_TO_FIELD_HEADER]
response = http.HttpResponse(json.dumps([obj_id, obj_name]))
response["X-Horizon-Add-To-Field"] = field_id
return response
else:
return http.HttpResponse('Done')
def get_form_initial(self, step):
init_dict = {'request': self.request,
'environment_id': self.kwargs.get('environment_id')}
return self.initial_dict.get(step, init_dict)
def _get_wizard_param(self, key):
param = self.kwargs.get(key)
return param if param is not None else self.request.POST.get(key)
def get_wizard_flag(self, key):
value = self._get_wizard_param(key)
if isinstance(value, basestring):
return value.lower() == 'true'
else:
return value
def get_context_data(self, form, **kwargs):
context = super(Wizard, self).get_context_data(form=form, **kwargs)
app_id = self.kwargs.get('app_id')
app = api.muranoclient(self.request).packages.get(app_id)
context['field_descriptions'] = services.get_app_field_descriptions(
self.request, app_id, self.steps.index)
context.update({'type': app.fully_qualified_name,
'service_name': app.name,
'app_id': app_id,
'environment_id': self.kwargs.get('environment_id'),
'do_redirect': self.get_wizard_flag('do_redirect'),
'drop_wm_form': self.get_wizard_flag('drop_wm_form'),
'prefix': self.prefix,
})
return context
class IndexView(list_view.ListView):
paginate_by = 6
def get_queryset(self):

View File

@ -207,7 +207,7 @@ def get_service_name(request, app_id):
return app.name
def get_service_field_descriptions(request, app_id, index):
def get_app_field_descriptions(request, app_id, index):
app = import_app(request, app_id)
form_cls = app.forms[index]

View File

@ -12,213 +12,50 @@
# License for the specific language governing permissions and limitations
# under the License.
import json
import logging
import copy
from functools import update_wrapper
from django.core.urlresolvers import reverse, reverse_lazy
from django.utils.translation import ugettext_lazy as _
from django.contrib.formtools.wizard.views import SessionWizardView
from django.http import HttpResponseRedirect # noqa
from django.http import HttpResponse # noqa
from django.core import urlresolvers as url
from django.utils.translation import ugettext_lazy as _ # noqa
from django.http import HttpResponse
from django.views import generic
from django.utils.decorators import classonlymethod
from horizon import exceptions
from horizon import tabs
from horizon import tables
from horizon import workflows
from horizon import messages
from horizon.forms import views as hz_views
from tables import EnvironmentsTable
from tables import DeploymentsTable
from tables import EnvConfigTable
from workflows import CreateEnvironment, UpdateEnvironment
from tabs import ServicesTabs, DeploymentTabs, EnvironmentDetailsTabs
from . import api
from muranoclient.common.exceptions import HTTPUnauthorized, \
CommunicationError, HTTPInternalServerError, HTTPForbidden, HTTPNotFound
from muranodashboard.dynamic_ui.services import get_service_name
from muranodashboard.dynamic_ui.services import get_service_field_descriptions
from muranodashboard.dynamic_ui import helpers
from muranodashboard.environments import consts
from muranodashboard import utils
from muranoclient.common import exceptions as exc
from muranodashboard.environments import api
from muranodashboard.environments import tabs as env_tabs
from muranodashboard.environments import tables as env_tables
from muranodashboard.environments import workflows as env_workflows
LOG = logging.getLogger(__name__)
class LazyWizard(SessionWizardView):
"""The class which defers evaluation of form_list and condition_dict
until view method is called. So, each time we load a page with a dynamic
UI form, it will have markup/logic from the newest YAML-file definition.
"""
@classonlymethod
def as_view(cls, initforms, *initargs, **initkwargs):
"""
Main entry point for a request-response process.
"""
# sanitize keyword arguments
for key in initkwargs:
if key in cls.http_method_names:
raise TypeError(u"You tried to pass in the %s method name as a"
u" keyword argument to %s(). Don't do that."
% (key, cls.__name__))
if not hasattr(cls, key):
raise TypeError(u"%s() received an invalid keyword %r" % (
cls.__name__, key))
def view(request, *args, **kwargs):
forms = initforms
if hasattr(initforms, '__call__'):
forms = initforms(request, kwargs)
_kwargs = copy.copy(initkwargs)
_kwargs = cls.get_initkwargs(forms, *initargs, **_kwargs)
cdict = _kwargs.get('condition_dict')
if cdict and hasattr(cdict, '__call__'):
_kwargs['condition_dict'] = cdict(request, kwargs)
self = cls(**_kwargs)
if hasattr(self, 'get') and not hasattr(self, 'head'):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargs
return self.dispatch(request, *args, **kwargs)
# take name and docstring from class
update_wrapper(view, cls, updated=())
# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
class Wizard(hz_views.ModalFormMixin, LazyWizard):
template_name = 'services/wizard_create.html'
do_redirect = False
def get_prefix(self, *args, **kwargs):
base = super(Wizard, self).get_prefix(*args, **kwargs)
fmt = utils.BlankFormatter()
return fmt.format('{0}_{environment_id}_{app_id}', base, **kwargs)
def done(self, form_list, **kwargs):
environment_id = kwargs.get('environment_id')
url = reverse('horizon:murano:environments:services',
args=(environment_id,))
app_name = get_service_name(self.request, kwargs.get('app_id'))
service = form_list[0].service
attributes = service.extract_attributes()
attributes = helpers.insert_hidden_ids(attributes)
storage = attributes.setdefault('?', {}).setdefault(
consts.DASHBOARD_ATTRS_KEY, {})
storage['name'] = app_name
wm_form_data = service.cleaned_data.get('workflowManagement')
if wm_form_data:
do_redirect = not wm_form_data['StayAtCatalog']
else:
do_redirect = self.get_wizard_flag('do_redirect')
try:
srv = api.service_create(self.request, environment_id, attributes)
except HTTPForbidden:
msg = _("Sorry, you can\'t add application right now."
"The environment is deploying.")
redirect = reverse("horizon:murano:environments:index")
exceptions.handle(self.request, msg, redirect=redirect)
except Exception:
redirect = reverse("horizon:murano:environments:index")
exceptions.handle(self.request,
_("Sorry, you can't add application right now."),
redirect=redirect)
else:
message = "The '{0}' application successfully " \
"added to environment.".format(app_name)
messages.success(self.request, message)
if do_redirect:
return HttpResponseRedirect(url)
else:
srv_id = getattr(srv, '?')['id']
return self.create_hacked_response(srv_id, attributes['name'])
def create_hacked_response(self, obj_id, obj_name):
# copy-paste from horizon.forms.views.ModalFormView; should be done
# that way until we move here from django Wizard to horizon workflow
if hz_views.ADD_TO_FIELD_HEADER in self.request.META:
field_id = self.request.META[hz_views.ADD_TO_FIELD_HEADER]
response = HttpResponse(json.dumps([obj_id, obj_name]))
response["X-Horizon-Add-To-Field"] = field_id
return response
else:
return HttpResponse('Done')
def get_form_initial(self, step):
init_dict = {'request': self.request,
'environment_id': self.kwargs.get('environment_id')}
return self.initial_dict.get(step, init_dict)
def _get_wizard_param(self, key):
param = self.kwargs.get(key)
return param if param is not None else self.request.POST.get(key)
def get_wizard_flag(self, key):
value = self._get_wizard_param(key)
if isinstance(value, basestring):
return value.lower() == 'true'
else:
return value
def get_context_data(self, form, **kwargs):
context = super(Wizard, self).get_context_data(form=form, **kwargs)
app_id = self.kwargs.get('app_id')
app = api.muranoclient(self.request).packages.get(app_id)
context['field_descriptions'] = get_service_field_descriptions(
self.request, app_id, self.steps.index)
context.update({'type': app.fully_qualified_name,
'service_name': app.name,
'app_id': app_id,
'environment_id': self.kwargs.get('environment_id'),
'do_redirect': self.get_wizard_flag('do_redirect'),
'drop_wm_form': self.get_wizard_flag('drop_wm_form'),
'prefix': self.prefix,
})
return context
class IndexView(tables.DataTableView):
table_class = EnvironmentsTable
table_class = env_tables.EnvironmentsTable
template_name = 'environments/index.html'
def get_data(self):
environments = []
try:
environments = api.environments_list(self.request)
except CommunicationError:
except exc.CommunicationError:
exceptions.handle(self.request,
'Could not connect to Murano API \
Service, check connection details')
except HTTPInternalServerError:
except exc.HTTPInternalServerError:
exceptions.handle(self.request,
'Murano API Service is not responding. \
Try again later')
except HTTPUnauthorized:
except exc.HTTPUnauthorized:
exceptions.handle(self.request, ignore=True, escalate=True)
return environments
class EnvironmentDetails(tabs.TabbedTableView):
tab_group_class = EnvironmentDetailsTabs
tab_group_class = env_tabs.EnvironmentDetailsTabs
template_name = 'services/index.html'
def get_context_data(self, **kwargs):
@ -231,13 +68,13 @@ class EnvironmentDetails(tabs.TabbedTableView):
except:
msg = _("Sorry, this environment doesn't exist anymore")
redirect = reverse("horizon:murano:environments:index")
redirect = url.reverse("horizon:murano:environments:index")
exceptions.handle(self.request, msg, redirect=redirect)
return context
class DetailServiceView(tabs.TabView):
tab_group_class = ServicesTabs
tab_group_class = env_tabs.ServicesTabs
template_name = 'services/details.html'
def get_context_data(self, **kwargs):
@ -255,11 +92,11 @@ class DetailServiceView(tabs.TabView):
self.service = api.service_get(self.request,
self.environment_id,
service_id)
except HTTPUnauthorized:
except exc.HTTPUnauthorized:
exceptions.handle(self.request)
except HTTPForbidden:
redirect = reverse('horizon:murano:environments:index')
except exc.HTTPForbidden:
redirect = url.reverse('horizon:murano:environments:index')
exceptions.handle(self.request,
_('Unable to retrieve details for '
'service'),
@ -274,7 +111,7 @@ class DetailServiceView(tabs.TabView):
class CreateEnvironmentView(workflows.WorkflowView):
workflow_class = CreateEnvironment
workflow_class = env_workflows.CreateEnvironment
template_name = 'environments/create.html'
def get_initial(self):
@ -285,9 +122,9 @@ class CreateEnvironmentView(workflows.WorkflowView):
class EditEnvironmentView(workflows.WorkflowView):
workflow_class = UpdateEnvironment
workflow_class = env_workflows.UpdateEnvironment
template_name = 'environments/update.html'
success_url = reverse_lazy("horizon:murano:environments:index")
success_url = url.reverse_lazy("horizon:murano:environments:index")
def get_context_data(self, **kwargs):
context = super(EditEnvironmentView, self).get_context_data(**kwargs)
@ -301,7 +138,7 @@ class EditEnvironmentView(workflows.WorkflowView):
self._object = \
api.environment_get(self.request, environment_id)
except:
redirect = reverse("horizon:murano:environments:index")
redirect = url.reverse("horizon:murano:environments:index")
msg = _('Unable to retrieve environment details.')
exceptions.handle(self.request, msg, redirect=redirect)
return self._object
@ -314,7 +151,7 @@ class EditEnvironmentView(workflows.WorkflowView):
class DeploymentsView(tables.DataTableView):
table_class = DeploymentsTable
table_class = env_tables.DeploymentsTable
template_name = 'deployments/index.html'
def get_context_data(self, **kwargs):
@ -325,7 +162,7 @@ class DeploymentsView(tables.DataTableView):
context['environment_name'] = env.name
except:
msg = _("Sorry, this environment doesn't exist anymore")
redirect = reverse("horizon:murano:environments:index")
redirect = url.reverse("horizon:murano:environments:index")
exceptions.handle(self.request, msg, redirect=redirect)
return context
@ -337,20 +174,20 @@ class DeploymentsView(tables.DataTableView):
deployments = api.deployments_list(self.request,
self.environment_id)
except HTTPForbidden:
except exc.HTTPForbidden:
msg = _('Unable to retrieve list of deployments')
exceptions.handle(self.request, msg, redirect=reverse(ns_url))
exceptions.handle(self.request, msg, redirect=url.reverse(ns_url))
except HTTPInternalServerError:
except exc.HTTPInternalServerError:
msg = _("Environment with id %s doesn't exist anymore"
% self.environment_id)
exceptions.handle(self.request, msg, redirect=reverse(ns_url))
exceptions.handle(self.request, msg, redirect=url.reverse(ns_url))
return deployments
class DeploymentDetailsView(tabs.TabbedTableView):
tab_group_class = DeploymentTabs
table_class = EnvConfigTable
tab_group_class = env_tabs.DeploymentTabs
table_class = env_tables.EnvConfigTable
template_name = 'deployments/reports.html'
def get_context_data(self, **kwargs):
@ -370,10 +207,10 @@ class DeploymentDetailsView(tabs.TabbedTableView):
deployment = api.get_deployment_descr(self.request,
self.environment_id,
self.deployment_id)
except (HTTPInternalServerError, HTTPNotFound):
except (exc.HTTPInternalServerError, exc.HTTPNotFound):
msg = _("Deployment with id %s doesn't exist anymore"
% self.deployment_id)
redirect = reverse("horizon:murano:environments:deployments")
redirect = url.reverse("horizon:murano:environments:deployments")
exceptions.handle(self.request, msg, redirect=redirect)
return deployment
@ -383,10 +220,10 @@ class DeploymentDetailsView(tabs.TabbedTableView):
logs = api.deployment_reports(self.request,
self.environment_id,
self.deployment_id)
except (HTTPInternalServerError, HTTPNotFound):
except (exc.HTTPInternalServerError, exc.HTTPNotFound):
msg = _('Deployment with id %s doesn\'t exist anymore'
% self.deployment_id)
redirect = reverse("horizon:murano:environments:deployments")
redirect = url.reverse("horizon:murano:environments:deployments")
exceptions.handle(self.request, msg, redirect=redirect)
return logs