Implement update segment
Added update segment functionality. Also added test cases that actually not covering the line of code but tested the update segment functionally. Partial-Implements: blueprint masakari-dashboard Change-Id: Ib0424ee076ff0e8cc8c3ea898d986d32cc195ed2
This commit is contained in:
parent
4996c377ad
commit
b18ad52f0e
|
@ -116,3 +116,10 @@ def get_segment(request, segment_id):
|
|||
def segment_delete(request, segment_id, ignore_missing=True):
|
||||
return openstack_connection(request).delete_segment(
|
||||
segment_id, ignore_missing)
|
||||
|
||||
|
||||
@handle_errors(_("Unable to update segment"), [])
|
||||
def segment_update(request, segment_id, fields_to_update):
|
||||
"""Update segment."""
|
||||
return openstack_connection(request).update_segment(
|
||||
segment_id, **fields_to_update)
|
||||
|
|
|
@ -67,3 +67,42 @@ class CreateSegmentForm(forms.SelfHandlingForm):
|
|||
redirect = reverse('horizon:masakaridashboard:segments:index')
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
return True
|
||||
|
||||
|
||||
class UpdateForm(forms.SelfHandlingForm):
|
||||
uuid = forms.CharField(widget=forms.HiddenInput())
|
||||
name = forms.CharField(
|
||||
label=_('Segment Name'),
|
||||
widget=forms.TextInput(attrs={'maxlength': 255}))
|
||||
recovery_method = forms.ChoiceField(
|
||||
label=_('Recovery Method'),
|
||||
choices=[('auto', 'auto'),
|
||||
('auto_priority', 'auto_priority'),
|
||||
('reserved_host', 'reserved_host'),
|
||||
('rh_priority', 'rh_priority')],
|
||||
widget=forms.Select(
|
||||
attrs={'class': 'switchable',
|
||||
'data-slug': 'recovery_method'}),
|
||||
required=False
|
||||
)
|
||||
description = forms.CharField(
|
||||
label=_('Description'),
|
||||
widget=forms.Textarea(
|
||||
attrs={'width': "100%", 'cols': "80", 'rows': "5", }),
|
||||
required=False
|
||||
)
|
||||
|
||||
def handle(self, request, data):
|
||||
try:
|
||||
fields_to_update = {'name': data['name'],
|
||||
'recovery_method': data['recovery_method'],
|
||||
'description': data['description']}
|
||||
api.segment_update(request, data['uuid'], fields_to_update)
|
||||
msg = _('Successfully updated segment.')
|
||||
messages.success(request, msg)
|
||||
except Exception:
|
||||
msg = _('Failed to update segment.')
|
||||
redirect = reverse('horizon:masakaridashboard:segments:index')
|
||||
exceptions.handle(request, msg, redirect=redirect)
|
||||
|
||||
return True
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import ungettext_lazy
|
||||
|
||||
|
@ -61,6 +62,18 @@ class DeleteSegment(tables.DeleteAction):
|
|||
api.segment_delete(request, segment_uuid, ignore_missing=True)
|
||||
|
||||
|
||||
class UpdateSegment(tables.LinkAction):
|
||||
name = "update"
|
||||
verbose_name = _("Update Segment")
|
||||
classes = ("ajax-modal",)
|
||||
|
||||
def get_link_url(self, datum):
|
||||
obj_id = datum.uuid
|
||||
url = "horizon:masakaridashboard:segments:update"
|
||||
|
||||
return reverse(url, args=[obj_id])
|
||||
|
||||
|
||||
class FailoverSegmentTable(tables.DataTable):
|
||||
|
||||
name = tables.WrappingColumn(
|
||||
|
@ -83,3 +96,4 @@ class FailoverSegmentTable(tables.DataTable):
|
|||
name = "failover_segment"
|
||||
verbose_name = _("FailoverSegment")
|
||||
table_actions = (DeleteSegment, CreateSegment, SegmentFilterAction)
|
||||
row_actions = (UpdateSegment,)
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
# Copyright (c) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import tabs
|
||||
|
||||
|
||||
class OverviewTab(tabs.Tab):
|
||||
name = _("Segments")
|
||||
slug = "segments"
|
||||
template_name = ("masakaridashboard/segments/_detail_overview.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
return {"segment": self.tab_group.kwargs['segment']}
|
||||
|
||||
|
||||
class SegmentDetailTabs(tabs.DetailTabsGroup):
|
||||
slug = "segment_details"
|
||||
tabs = (OverviewTab,)
|
||||
# Copyright (C) 2018 NTT DATA
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from horizon import tabs
|
||||
|
||||
|
||||
class OverviewTab(tabs.Tab):
|
||||
name = _("Segments")
|
||||
slug = "segments"
|
||||
template_name = ("masakaridashboard/segments/_detail_overview.html")
|
||||
|
||||
def get_context_data(self, request):
|
||||
return {"segment": self.tab_group.kwargs['segment']}
|
||||
|
||||
|
||||
class SegmentDetailTabs(tabs.DetailTabsGroup):
|
||||
slug = "segment_details"
|
||||
tabs = (OverviewTab,)
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
{% extends "horizon/common/_modal_form.html" %}
|
||||
{% load i18n %}
|
||||
{% block modal-body-right %}
|
||||
<h3>{% trans "Description:" %}</h3>
|
||||
<p>{% trans "Modify name, recovery_method and description of a failover segment." %}</p>
|
||||
{% endblock %}
|
|
@ -0,0 +1,7 @@
|
|||
{% extends 'base.html' %}
|
||||
{% load i18n %}
|
||||
{% block title %}{% trans "Update Segment" %}{% endblock %}
|
||||
|
||||
{% block main %}
|
||||
{% include 'masakaridashboard/segment/_update.html' %}
|
||||
{% endblock %}
|
|
@ -13,11 +13,13 @@
|
|||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import mock
|
||||
|
||||
from django.conf import settings
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.test.utils import override_settings
|
||||
from django.utils.http import urlunquote
|
||||
import mock
|
||||
from openstack_dashboard.test import helpers
|
||||
|
||||
from masakaridashboard.segments import tables as segment_table
|
||||
from masakaridashboard.test import helpers as test
|
||||
|
@ -38,7 +40,8 @@ class SegmentTest(test.TestCase):
|
|||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(res, 'masakaridashboard/segments/index.html')
|
||||
mock_get_segment_list.assert_called_once_with(
|
||||
filters={}, marker=None, paginate=True, request=mock.ANY)
|
||||
filters={}, marker=None, paginate=True,
|
||||
request=helpers.IsHttpRequest())
|
||||
segments = res.context['failover_segment_table'].data
|
||||
self.assertItemsEqual(segments, self.masakari_segment.list())
|
||||
|
||||
|
@ -62,7 +65,7 @@ class SegmentTest(test.TestCase):
|
|||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
|
||||
mocked_create.assert_called_once_with(
|
||||
mock.ANY,
|
||||
helpers.IsHttpRequest(),
|
||||
form_data
|
||||
)
|
||||
|
||||
|
@ -77,7 +80,8 @@ class SegmentTest(test.TestCase):
|
|||
self.assertEqual(res.status_code, 200)
|
||||
self.assertTemplateUsed(res, 'masakaridashboard/segments/index.html')
|
||||
mock_get_segment_list.assert_called_once_with(
|
||||
filters=filters, marker=marker, paginate=True, request=mock.ANY)
|
||||
filters=filters, marker=marker, paginate=True,
|
||||
request=helpers.IsHttpRequest())
|
||||
|
||||
return res
|
||||
|
||||
|
@ -167,7 +171,7 @@ class SegmentTest(test.TestCase):
|
|||
self.assertNoFormErrors(res)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
mocked_delete.assert_called_once_with(
|
||||
mock.ANY,
|
||||
helpers.IsHttpRequest(),
|
||||
segment.uuid,
|
||||
ignore_missing=True
|
||||
)
|
||||
|
@ -185,3 +189,34 @@ class SegmentTest(test.TestCase):
|
|||
self.assertTemplateUsed(res, 'horizon/common/_detail.html')
|
||||
self.assertTemplateUsed(
|
||||
res, 'masakaridashboard/segments/_detail_overview.html')
|
||||
|
||||
def test_update(self):
|
||||
segment_obj = self.masakari_segment.list()[0]
|
||||
update_url = reverse('horizon:masakaridashboard:segments:update',
|
||||
args=[segment_obj.uuid])
|
||||
segment_obj.name = 'fake'
|
||||
form_data = {
|
||||
'uuid': segment_obj.uuid,
|
||||
'name': segment_obj.name,
|
||||
'recovery_method': segment_obj.recovery_method,
|
||||
'description': segment_obj.description}
|
||||
|
||||
with mock.patch(
|
||||
'masakaridashboard.api.api.get_segment',
|
||||
return_value=self.masakari_segment.list()[0]), mock.patch(
|
||||
'masakaridashboard.api.api.segment_update',
|
||||
return_value=segment_obj) as mocked_update:
|
||||
res = self.client.post(update_url, form_data)
|
||||
self.assertNoFormErrors(res)
|
||||
self.assertEqual(res.status_code, 302)
|
||||
self.assertRedirectsNoFollow(res, INDEX_URL)
|
||||
data_to_update = {
|
||||
'name': segment_obj.name,
|
||||
'recovery_method': segment_obj.recovery_method,
|
||||
'description': segment_obj.description}
|
||||
|
||||
mocked_update.assert_called_once_with(
|
||||
helpers.IsHttpRequest(),
|
||||
segment_obj.uuid,
|
||||
data_to_update
|
||||
)
|
||||
|
|
|
@ -21,8 +21,8 @@ from masakaridashboard.segments import views
|
|||
SEGMENT = r'^(?P<segment_id>[^/]+)/%s$'
|
||||
urlpatterns = [
|
||||
url(r'^$', views.IndexView.as_view(), name='index'),
|
||||
url(r'^create_segment$',
|
||||
views.CreateSegmentView.as_view(),
|
||||
url(r'^create_segment$', views.CreateSegmentView.as_view(),
|
||||
name='create_segment'),
|
||||
url(SEGMENT % 'detail', views.DetailView.as_view(), name='detail'),
|
||||
url(SEGMENT % 'update', views.UpdateView.as_view(), name='update'),
|
||||
]
|
||||
|
|
|
@ -132,3 +132,41 @@ class DetailView(tabs.TabbedTableView):
|
|||
def get_tabs(self, request, *args, **kwargs):
|
||||
segment = self.get_data()
|
||||
return self.tab_group_class(request, segment=segment, **kwargs)
|
||||
|
||||
|
||||
class UpdateView(forms.ModalFormView):
|
||||
template_name = 'masakaridashboard/segments/update.html'
|
||||
modal_header = _("Update Segment")
|
||||
form_id = "update_segment"
|
||||
form_class = segment_forms.UpdateForm
|
||||
submit_label = _("Update")
|
||||
submit_url = "horizon:masakaridashboard:segments:update"
|
||||
success_url = reverse_lazy("horizon:masakaridashboard:segments:index")
|
||||
page_title = _("Update Segment")
|
||||
|
||||
@memoized.memoized_method
|
||||
def get_object(self):
|
||||
try:
|
||||
segment = api.get_segment(self.request, self.kwargs['segment_id'])
|
||||
return segment
|
||||
except Exception:
|
||||
msg = _('Unable to retrieve segment.')
|
||||
redirect = reverse('horizon:masakaridashboard:segments:index')
|
||||
exceptions.handle(self.request, msg, redirect=redirect)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(UpdateView, self).get_context_data(**kwargs)
|
||||
context['submit_url'] = reverse(
|
||||
self.submit_url,
|
||||
args=[self.kwargs["segment_id"]]
|
||||
)
|
||||
|
||||
return context
|
||||
|
||||
def get_initial(self, **kwargs):
|
||||
segment = self.get_object()
|
||||
|
||||
return {'uuid': self.kwargs['segment_id'],
|
||||
'name': segment.name,
|
||||
'recovery_method': segment.recovery_method,
|
||||
'description': segment.description}
|
||||
|
|
Loading…
Reference in New Issue