From 9f75312b07d27af8e3750a5f6a104d7b27f197cc Mon Sep 17 00:00:00 2001 From: David Lyle Date: Thu, 10 Nov 2016 15:57:10 -0700 Subject: [PATCH] Removing deprecated Swift UI code The move to the angularJS based UI for swift as the default occurred two releases ago in Mitaka. This patch removes the dead code. Change-Id: I0322808aeacab5406c0dd3f4b19bed50bc0ff089 --- .../dashboards/project/containers/browsers.py | 31 - .../dashboards/project/containers/forms.py | 244 -------- .../dashboards/project/containers/tables.py | 432 ------------- .../containers/_container_detail.html | 29 - .../containers/_container_loader.html | 5 - .../containers/_container_metadata.html | 12 - .../templates/containers/_copy.html | 24 - .../templates/containers/_create.html | 20 - .../containers/_create_pseudo_folder.html | 26 - .../templates/containers/_object_detail.html | 25 - .../templates/containers/_update.html | 28 - .../templates/containers/_upload.html | 29 - .../containers/container_detail.html | 11 - .../containers/templates/containers/copy.html | 7 - .../templates/containers/create.html | 7 - .../containers/create_pseudo_folder.html | 7 - .../templates/containers/index.html | 24 - .../templates/containers/object_detail.html | 11 - .../templates/containers/update.html | 7 - .../templates/containers/upload.html | 7 - .../dashboards/project/containers/tests.py | 565 ------------------ .../dashboards/project/containers/urls.py | 60 +- .../dashboards/project/containers/utils.py | 14 + .../dashboards/project/containers/views.py | 319 +--------- .../dashboards/project/stacks/tests.py | 2 +- .../project/volumes/backups/forms.py | 4 +- .../enabled/_1920_project_containers_panel.py | 7 - openstack_dashboard/test/settings.py | 4 - ...-deprecated-swift-ui-1165b60bab5771d6.yaml | 8 + 29 files changed, 33 insertions(+), 1936 deletions(-) delete mode 100644 openstack_dashboard/dashboards/project/containers/browsers.py delete mode 100644 openstack_dashboard/dashboards/project/containers/forms.py delete mode 100644 openstack_dashboard/dashboards/project/containers/tables.py delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/_container_detail.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/_container_loader.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/_container_metadata.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/_copy.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/_create.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/_create_pseudo_folder.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/_object_detail.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/_update.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/_upload.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/container_detail.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/copy.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/create.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/create_pseudo_folder.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/index.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/object_detail.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/update.html delete mode 100644 openstack_dashboard/dashboards/project/containers/templates/containers/upload.html delete mode 100644 openstack_dashboard/dashboards/project/containers/tests.py create mode 100644 releasenotes/notes/remove-deprecated-swift-ui-1165b60bab5771d6.yaml diff --git a/openstack_dashboard/dashboards/project/containers/browsers.py b/openstack_dashboard/dashboards/project/containers/browsers.py deleted file mode 100644 index 5b1c40c34..000000000 --- a/openstack_dashboard/dashboards/project/containers/browsers.py +++ /dev/null @@ -1,31 +0,0 @@ -# Copyright 2012 Nebula, Inc. -# -# 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 browsers - -from openstack_dashboard.dashboards.project.containers import tables - - -class ContainerBrowser(browsers.ResourceBrowser): - name = "swift" - verbose_name = _("Swift") - navigation_table_class = tables.ContainersTable - content_table_class = tables.ObjectsTable - navigable_item_name = _("Container") - navigation_kwarg_name = "container_name" - content_kwarg_name = "subfolder_path" - has_breadcrumb = True - breadcrumb_url = "horizon:project:containers:index" diff --git a/openstack_dashboard/dashboards/project/containers/forms.py b/openstack_dashboard/dashboards/project/containers/forms.py deleted file mode 100644 index 4e08f2b32..000000000 --- a/openstack_dashboard/dashboards/project/containers/forms.py +++ /dev/null @@ -1,244 +0,0 @@ -# Copyright 2012 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# Copyright 2012 Nebula, Inc. -# -# 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.core.urlresolvers import reverse -from django.core import validators -from django.utils.encoding import force_text -from django.utils.translation import pgettext_lazy -from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions -from horizon import forms -from horizon import messages - -from openstack_dashboard import api -from openstack_dashboard.dashboards.project.containers import utils - - -no_slash_validator = validators.RegexValidator(r'^(?u)[^/]+$', - _("Slash is not an allowed " - "character."), - code="noslash") -no_begin_or_end_slash = validators.RegexValidator(r'^[^\/](?u).+[^\/]$', - _("Slash is not allowed at " - "the beginning or end of " - "your string."), - code="nobeginorendslash") - - -class CreateContainer(forms.SelfHandlingForm): - ACCESS_CHOICES = ( - ("private", _("Private")), - ("public", _("Public")), - ) - - parent = forms.CharField(max_length=255, - required=False, - widget=forms.HiddenInput) - name = forms.CharField(max_length=255, - label=_("Container Name"), - validators=[no_slash_validator]) - access = forms.ThemableChoiceField(label=_("Container Access"), - choices=ACCESS_CHOICES) - - def handle(self, request, data): - try: - if not data['parent']: - is_public = data["access"] == "public" - metadata = ({'is_public': is_public}) - # Create a container - api.swift.swift_create_container(request, - data["name"], - metadata=metadata) - messages.success(request, _("Container created successfully.")) - else: - # Create a pseudo-folder - container, slash, remainder = data['parent'].partition("/") - remainder = remainder.rstrip("/") - subfolder_name = "/".join([bit for bit - in (remainder, data['name']) - if bit]) - api.swift.swift_create_subfolder(request, - container, - subfolder_name) - messages.success(request, _("Folder created successfully.")) - return True - except Exception: - exceptions.handle(request, _('Unable to create container.')) - - -class UploadObject(forms.SelfHandlingForm): - path = forms.CharField(max_length=255, - required=False, - widget=forms.HiddenInput) - object_file = forms.FileField(label=_("File"), - required=False, - allow_empty_file=True) - name = forms.CharField(max_length=255, - label=_("Object Name"), - help_text=_("Slashes are allowed, and are treated " - "as pseudo-folders by the Object " - "Store."), - widget=forms.TextInput( - attrs={"ng-model": "name", - "not-blank": ""} - )) - container_name = forms.CharField(widget=forms.HiddenInput()) - - def _set_object_path(self, data): - if data['path']: - object_path = "/".join([data['path'].rstrip("/"), data['name']]) - else: - object_path = data['name'] - return object_path - - def clean(self): - data = super(UploadObject, self).clean() - if 'object_file' not in self.files: - self.files['object_file'] = None - - return data - - def handle(self, request, data): - object_file = self.files['object_file'] - object_path = self._set_object_path(data) - try: - obj = api.swift.swift_upload_object(request, - data['container_name'], - object_path, - object_file) - msg = force_text(_("Object was successfully uploaded.")) - messages.success(request, msg) - return obj - except Exception: - exceptions.handle(request, _("Unable to upload object.")) - - -class UpdateObject(UploadObject): - def __init__(self, *args, **kwargs): - super(UpdateObject, self).__init__(*args, **kwargs) - self.fields['name'].widget = forms.TextInput( - attrs={"readonly": "readonly"}) - self.fields['name'].help_text = None - - def handle(self, request, data): - object_file = self.files.get('object_file') - if object_file: - object_path = self._set_object_path(data) - try: - obj = api.swift.swift_upload_object(request, - data['container_name'], - object_path, - object_file) - messages.success( - request, _("Object was successfully updated.")) - return obj - except Exception: - exceptions.handle(request, _("Unable to update object.")) - return False - else: - # If object file is not provided, then a POST method is needed - # to update ONLY metadata. This must be implemented when - # object metadata can be updated from this panel. - return True - - -class CreatePseudoFolder(forms.SelfHandlingForm): - path = forms.CharField(max_length=255, - required=False, - widget=forms.HiddenInput) - name = forms.CharField(max_length=255, - label=_("Pseudo-folder Name"), - validators=[no_begin_or_end_slash]) - container_name = forms.CharField(widget=forms.HiddenInput()) - - def _set_pseudo_folder_path(self, data): - if data['path']: - pseudo_folder_path = "/".join([data['path'].rstrip("/"), - data['name']]) + "/" - else: - pseudo_folder_path = data['name'] + "/" - return pseudo_folder_path - - def handle(self, request, data): - pseudo_folder_path = self._set_pseudo_folder_path(data) - try: - obj = api.swift.swift_create_pseudo_folder(request, - data['container_name'], - pseudo_folder_path) - messages.success(request, - _("Pseudo-folder was successfully created.")) - return obj - - except Exception: - exceptions.handle(request, _("Unable to create pseudo-folder.")) - - -class CopyObject(forms.SelfHandlingForm): - new_container_name = forms.ChoiceField(label=_("Destination container"), - validators=[no_slash_validator]) - path = forms.CharField( - label=pgettext_lazy("Swift pseudo folder path", u"Path"), - max_length=255, required=False) - new_object_name = forms.CharField(max_length=255, - label=_("Destination object name"), - validators=[no_slash_validator]) - orig_container_name = forms.CharField(widget=forms.HiddenInput()) - orig_object_name = forms.CharField(widget=forms.HiddenInput()) - - def __init__(self, *args, **kwargs): - containers = kwargs.pop('containers') - super(CopyObject, self).__init__(*args, **kwargs) - self.fields['new_container_name'].choices = containers - - def handle(self, request, data): - index = "horizon:project:containers:index" - orig_container = data['orig_container_name'] - orig_object = data['orig_object_name'] - new_container = data['new_container_name'] - new_object = data['new_object_name'] - path = data['path'] - if path and not path.endswith("/"): - path = path + "/" - new_path = "%s%s" % (path, new_object) - - # Now copy the object itself. - try: - api.swift.swift_copy_object(request, - orig_container, - orig_object, - new_container, - new_path) - dest = "%s/%s" % (new_container, path) - vals = {"dest": dest.rstrip("/"), - "orig": orig_object.split("/")[-1], - "new": new_object} - messages.success(request, - _('Copied "%(orig)s" to "%(dest)s" as "%(new)s".') - % vals) - return True - except exceptions.HorizonException as exc: - messages.error(request, exc) - raise exceptions.Http302( - reverse(index, args=[utils.wrap_delimiter(orig_container)])) - except Exception: - redirect = reverse(index, - args=[utils.wrap_delimiter(orig_container)]) - exceptions.handle(request, - _("Unable to copy object."), - redirect=redirect) diff --git a/openstack_dashboard/dashboards/project/containers/tables.py b/openstack_dashboard/dashboards/project/containers/tables.py deleted file mode 100644 index b283a72d8..000000000 --- a/openstack_dashboard/dashboards/project/containers/tables.py +++ /dev/null @@ -1,432 +0,0 @@ -# Copyright 2012 Nebula, Inc. -# -# 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. -import logging - -from django.core.urlresolvers import reverse -from django import shortcuts -from django import template -from django.template import defaultfilters as filters -from django.utils import http -from django.utils.translation import ugettext_lazy as _ -from django.utils.translation import ungettext_lazy - -from horizon import exceptions -from horizon import messages -from horizon import tables - -from openstack_dashboard import api -from openstack_dashboard.api import swift -from openstack_dashboard.dashboards.project.containers import utils - -LOG = logging.getLogger(__name__) - - -class ViewContainer(tables.LinkAction): - name = "view" - verbose_name = _("View Details") - url = "horizon:project:containers:container_detail" - classes = ("ajax-modal", "btn-view") - - def get_link_url(self, datum=None): - obj_id = self.table.get_object_id(datum) - return reverse(self.url, args=(obj_id,)) - - -class MakePublicContainer(tables.Action): - name = "make_public" - verbose_name = _("Make Public") - icon = "pencil" - - def allowed(self, request, container): - # Container metadata have not been loaded - if not hasattr(container, 'is_public'): - return False - return not container.is_public - - def single(self, table, request, obj_id): - try: - api.swift.swift_update_container(request, - obj_id, - metadata=({'is_public': True})) - LOG.info('Updating container "%s" access to public.' % obj_id) - messages.success(request, - _('Successfully updated container access to ' - 'public.')) - except Exception: - exceptions.handle(request, - _('Unable to update container access.')) - return shortcuts.redirect('horizon:project:containers:index') - - -class MakePrivateContainer(tables.Action): - name = "make_private" - verbose_name = _("Make Private") - icon = "pencil" - - def allowed(self, request, container): - # Container metadata have not been loaded - if not hasattr(container, 'is_public'): - return False - return container.is_public - - def single(self, table, request, obj_id): - try: - api.swift.swift_update_container(request, - obj_id, - metadata=({'is_public': False})) - LOG.info('Updating container "%s" access to private.' % obj_id) - messages.success(request, - _('Successfully updated container access to ' - 'private.')) - except Exception: - exceptions.handle(request, - _('Unable to update container access.')) - return shortcuts.redirect('horizon:project:containers:index') - - -class DeleteContainer(tables.DeleteAction): - @staticmethod - def action_present(count): - return ungettext_lazy( - u"Delete Container", - u"Delete Containers", - count - ) - - @staticmethod - def action_past(count): - return ungettext_lazy( - u"Deleted Container", - u"Deleted Containers", - count - ) - - success_url = "horizon:project:containers:index" - - def delete(self, request, obj_id): - try: - api.swift.swift_delete_container(request, obj_id) - except exceptions.Conflict as exc: - exceptions.handle(request, exc, redirect=self.success_url) - except Exception: - exceptions.handle(request, - _('Unable to delete container.'), - redirect=self.success_url) - - def get_success_url(self, request=None): - """Returns the URL to redirect to after a successful action. - """ - current_container = self.table.kwargs.get("container_name", None) - - # If the current_container is deleted, then redirect to the default - # completion url - if current_container in self.success_ids: - return self.success_url - return request.get_full_path() - - -class CreateContainer(tables.LinkAction): - name = "create" - verbose_name = _("Create Container") - url = "horizon:project:containers:create" - classes = ("ajax-modal",) - icon = "plus" - - -class ListObjects(tables.LinkAction): - name = "list_objects" - verbose_name = _("View Container") - url = "horizon:project:containers:index" - icon = "list" - - def get_link_url(self, datum=None): - container_name = http.urlquote(datum.name) - args = (utils.wrap_delimiter(container_name),) - return reverse(self.url, args=args) - - -class CreatePseudoFolder(tables.LinkAction): - name = "create_pseudo_folder" - verbose_name = _("Create Pseudo-folder") - url = "horizon:project:containers:create_pseudo_folder" - classes = ("ajax-modal",) - icon = "plus" - - def get_link_url(self, datum=None): - # Usable for both the container and object tables - if getattr(datum, 'container', datum): - container_name = http.urlquote(datum.name) - else: - container_name = self.table.kwargs['container_name'] - subfolders = self.table.kwargs.get('subfolder_path', '') - args = (bit for bit in (container_name, subfolders) if bit) - return reverse(self.url, args=args) - - def allowed(self, request, datum=None): - if self.table.kwargs.get('container_name', None): - return True - return False - - def update(self, request, obj): - # This will only be called for the row, so we can remove the button - # styles meant for the table action version. - self.attrs = {'class': 'ajax-modal'} - - -class UploadObject(tables.LinkAction): - name = "upload" - verbose_name = _("Upload Object") - url = "horizon:project:containers:object_upload" - classes = ("ajax-modal",) - icon = "upload" - - def get_link_url(self, datum=None): - # Usable for both the container and object tables - if getattr(datum, 'container', datum): - # This is a container - container_name = datum.name - else: - # This is a table action, and we already have the container name - container_name = self.table.kwargs['container_name'] - subfolders = self.table.kwargs.get('subfolder_path', '') - args = (bit for bit in (container_name, subfolders) if bit) - return reverse(self.url, args=args) - - def allowed(self, request, datum=None): - if self.table.kwargs.get('container_name', None): - return True - return False - - def update(self, request, obj): - # This will only be called for the row, so we can remove the button - # styles meant for the table action version. - self.attrs = {'class': 'ajax-modal'} - - -def get_size_used(container): - return filters.filesizeformat(container.bytes) - - -def get_container_link(container): - return reverse("horizon:project:containers:index", - args=(utils.wrap_delimiter(container.name),)) - - -class ContainerAjaxUpdateRow(tables.Row): - ajax = True - - def get_data(self, request, container_name): - container = api.swift.swift_get_container(request, - container_name, - with_data=False) - return container - - -def get_metadata(container): - # If the metadata has not been loading, display a loading image - if not hasattr(container, 'is_public'): - return template.loader.render_to_string( - 'project/containers/_container_loader.html' - ) - template_name = 'project/containers/_container_metadata.html' - context = {"container": container} - return template.loader.render_to_string(template_name, context) - - -def get_metadata_loaded(container): - # Determine if metadata has been loaded if the attribute is already set. - return hasattr(container, 'is_public') and container.is_public is not None - - -class ContainersTable(tables.DataTable): - METADATA_LOADED_CHOICES = ( - (False, None), - (True, True), - ) - name = tables.Column("name", - link=get_container_link, - verbose_name=_("Container Name")) - metadata = tables.Column(get_metadata, - verbose_name=_("Container Details"), - classes=('nowrap-col', ),) - metadata_loaded = tables.Column(get_metadata_loaded, - status=True, - status_choices=METADATA_LOADED_CHOICES, - hidden=True) - - class Meta(object): - name = "containers" - verbose_name = _("Containers") - row_class = ContainerAjaxUpdateRow - status_columns = ['metadata_loaded', ] - table_actions = (CreateContainer,) - row_actions = (ViewContainer, MakePublicContainer, - MakePrivateContainer, DeleteContainer,) - browser_table = "navigation" - footer = False - - def get_object_id(self, container): - return container.name - - -class ViewObject(tables.LinkAction): - name = "view" - verbose_name = _("View Details") - url = "horizon:project:containers:object_detail" - classes = ("ajax-modal", "btn-view") - allowed_data_types = ("objects",) - - def get_link_url(self, obj): - container_name = self.table.kwargs['container_name'] - return reverse(self.url, args=(container_name, obj.name)) - - -class UpdateObject(tables.LinkAction): - name = "update_object" - verbose_name = _("Edit") - url = "horizon:project:containers:object_update" - classes = ("ajax-modal",) - icon = "pencil" - allowed_data_types = ("objects",) - - def get_link_url(self, obj): - container_name = self.table.kwargs['container_name'] - return reverse(self.url, args=(container_name, obj.name)) - - -class DeleteObject(tables.DeleteAction): - @staticmethod - def action_present(count): - return ungettext_lazy( - u"Delete Object", - u"Delete Objects", - count - ) - - @staticmethod - def action_past(count): - return ungettext_lazy( - u"Deleted Object", - u"Deleted Objects", - count - ) - - name = "delete_object" - allowed_data_types = ("objects", "subfolders",) - - def delete(self, request, obj_id): - obj = self.table.get_object_by_id(obj_id) - container_name = obj.container_name - datum_type = getattr(obj, self.table._meta.data_type_name, None) - if datum_type == 'subfolders': - obj_id = obj_id[(len(container_name) + 1):] + "/" - api.swift.swift_delete_object(request, container_name, obj_id) - - -class DeleteMultipleObjects(DeleteObject): - name = "delete_multiple_objects" - - -class CopyObject(tables.LinkAction): - name = "copy" - verbose_name = _("Copy") - url = "horizon:project:containers:object_copy" - classes = ("ajax-modal",) - icon = "circle-arrow-right" - allowed_data_types = ("objects",) - - def get_link_url(self, obj): - container_name = self.table.kwargs['container_name'] - return reverse(self.url, args=(container_name, obj.name)) - - -class DownloadObject(tables.LinkAction): - name = "download" - verbose_name = _("Download") - url = "horizon:project:containers:object_download" - icon = "download" - allowed_data_types = ("objects",) - - def get_link_url(self, obj): - container_name = self.table.kwargs['container_name'] - return reverse(self.url, args=(container_name, obj.name)) - - def allowed(self, request, object): - return object.bytes and object.bytes > 0 - - -class ObjectFilterAction(tables.FilterAction): - def _filtered_data(self, table, filter_string): - request = table.request - container = self.table.kwargs['container_name'] - subfolder = self.table.kwargs['subfolder_path'] - prefix = utils.wrap_delimiter(subfolder) if subfolder else '' - self.filtered_data = api.swift.swift_filter_objects(request, - filter_string, - container, - prefix=prefix) - return self.filtered_data - - def filter_subfolders_data(self, table, objects, filter_string): - data = self._filtered_data(table, filter_string) - return [datum for datum in data if - datum.content_type == "application/pseudo-folder"] - - def filter_objects_data(self, table, objects, filter_string): - data = self._filtered_data(table, filter_string) - return [datum for datum in data if - datum.content_type != "application/pseudo-folder"] - - def allowed(self, request, datum=None): - if self.table.kwargs.get('container_name', None): - return True - return False - - -def sanitize_name(name): - return name.split(swift.FOLDER_DELIMITER)[-1] - - -def get_size(obj): - if obj.bytes is None: - return _("pseudo-folder") - return filters.filesizeformat(obj.bytes) - - -def get_link_subfolder(subfolder): - container_name = subfolder.container_name - return reverse("horizon:project:containers:index", - args=(utils.wrap_delimiter(container_name), - utils.wrap_delimiter(subfolder.name))) - - -class ObjectsTable(tables.DataTable): - name = tables.Column("name", - link=get_link_subfolder, - allowed_data_types=("subfolders",), - verbose_name=_("Object Name"), - filters=(sanitize_name,)) - - size = tables.Column(get_size, verbose_name=_('Size')) - - class Meta(object): - name = "objects" - verbose_name = _("Objects") - table_actions = (ObjectFilterAction, CreatePseudoFolder, UploadObject, - DeleteMultipleObjects) - row_actions = (DownloadObject, UpdateObject, CopyObject, - ViewObject, DeleteObject) - data_types = ("subfolders", "objects") - browser_table = "content" - footer = False diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/_container_detail.html b/openstack_dashboard/dashboards/project/containers/templates/containers/_container_detail.html deleted file mode 100644 index 659bdcee1..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/_container_detail.html +++ /dev/null @@ -1,29 +0,0 @@ -{% extends "horizon/common/_modal.html" %} -{% load i18n %} - -{% block modal-header %}{% trans "Container Details" %}{% endblock %} - -{% block modal-body %} -
-
-
{% trans "Container Name" %}
-
{{ container.name }}
-
{% trans "Container Access" %}
- {% if container.public_url %} -
{% trans "Public" %}
-
{% trans "Public URL" %}
-
{{ container.public_url }}
- {% else %} -
{% trans "Private" %}
- {% endif %} -
{% trans "Object Count" %}
-
{{ container.container_object_count }}
-
{% trans "Size" %}
-
{{ container.container_bytes_used|filesizeformat }}
-
-
-{% endblock %} - -{% block modal-footer %} - {% trans "Close" %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/_container_loader.html b/openstack_dashboard/dashboards/project/containers/templates/containers/_container_loader.html deleted file mode 100644 index 2d0d12b68..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/_container_loader.html +++ /dev/null @@ -1,5 +0,0 @@ -
-
-
-
-
diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/_container_metadata.html b/openstack_dashboard/dashboards/project/containers/templates/containers/_container_metadata.html deleted file mode 100644 index e268ff5e7..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/_container_metadata.html +++ /dev/null @@ -1,12 +0,0 @@ -{% load i18n %} - diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/_copy.html b/openstack_dashboard/dashboards/project/containers/templates/containers/_copy.html deleted file mode 100644 index 04fc6f2ec..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/_copy.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} - -{% block form_id %}copy_object_form{% endblock %} -{% block form_action %}{% url 'horizon:project:containers:object_copy' container_name object_name %}{% endblock %} - -{% block modal-header %}{% blocktrans %}Copy Object: {{ object_name }}{% endblocktrans %}{% endblock %} - -{% block modal-body %} -
-
- {% include "horizon/common/_form_fields.html" %} -
-
-
-

{% trans "Description:" %}

-

{% trans "Make a new copy of an existing object to store in this or another container. You may additionally specify the path within the selected container where the new copy should be stored." %}

-
-{% endblock %} - -{% block modal-footer %} - - {% trans "Cancel" %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/_create.html b/openstack_dashboard/dashboards/project/containers/templates/containers/_create.html deleted file mode 100644 index 8367ab25a..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/_create.html +++ /dev/null @@ -1,20 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} - -{% block form_id %}create_container_form{% endblock %} -{% block form_action %}{% url 'horizon:project:containers:create' %}{% endblock %} - -{% block modal-header %}{% trans "Create Container" %}{% endblock %} - -{% block modal-body %} -
-
- {% include "horizon/common/_form_fields.html" %} -
-
-
-

{% trans "Description:" %}

-

{% trans "A container is a storage compartment for your data and provides a way for you to organize your data. You can think of a container as a folder in Windows ® or a directory in UNIX ®. The primary difference between a container and these other file system concepts is that containers cannot be nested. You can, however, create an unlimited number of containers within your account. Data must be stored in a container so you must have at least one container defined in your account prior to uploading data." %}

-

{% trans "Note: A Public Container will allow anyone with the Public URL to gain access to your objects in the container." %}

-
-{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/_create_pseudo_folder.html b/openstack_dashboard/dashboards/project/containers/templates/containers/_create_pseudo_folder.html deleted file mode 100644 index bef492cb1..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/_create_pseudo_folder.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} - -{% block form_id %}create_directory_form{% endblock %} -{% block form_action %}{% url 'horizon:project:containers:create_pseudo_folder' container_name %}{% endblock %} - -{% block modal-header %} - {% blocktrans %}Create pseudo-folder in container {{ container_name }}{% endblocktrans %} -{% endblock %} - -{% block modal-body %} -
-
- {% include "horizon/common/_form_fields.html" %} -
-
-
-

{% trans "Description:" %}

-

{% trans "Pseudo-folder:" %} {% trans "Within a container you can group your objects into pseudo-folders, which behave similarly to folders in your desktop operating system, with the exception that they are virtual collections defined by a common prefix on the object's name. A slash (/) character is used as the delimiter for pseudo-folders in the Object Store." %}

-
-{% endblock %} - -{% block modal-footer %} - {% trans "Cancel" %} - -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/_object_detail.html b/openstack_dashboard/dashboards/project/containers/templates/containers/_object_detail.html deleted file mode 100644 index cd6d5b181..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/_object_detail.html +++ /dev/null @@ -1,25 +0,0 @@ -{% extends "horizon/common/_modal.html" %} -{% load i18n %} - -{% block modal-header %}{% trans "Object Details" %}{% endblock %} - -{% block modal-body %} -
-
-
{% trans "Name" %}
-
{{ object.name }}
-
{% trans "Hash" %}
-
{{ object.etag }}
-
{% trans "Content Type" %}
-
{{ object.content_type }}
-
{% trans "Last Modified" %}
-
{{ object.timestamp|parse_isotime }}
-
{% trans "Size" %}
-
{{ object.bytes|filesizeformat }}
-
-
-{% endblock %} - -{% block modal-footer %} - {% trans "Close" %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/_update.html b/openstack_dashboard/dashboards/project/containers/templates/containers/_update.html deleted file mode 100644 index 6bb75c65d..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/_update.html +++ /dev/null @@ -1,28 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} - -{% block form_id %}update_object_form{% endblock %} -{% block ng_controller %}DummyController{% endblock %} -{% block form_name %}updateForm{% endblock %} -{% block form_action %}{% url 'horizon:project:containers:object_update' container_name subfolder_path object_path %}{% endblock %} -{% block form_attrs %}enctype="multipart/form-data"{% endblock %} - -{% block modal-header %}{% trans "Edit Object" %}{% endblock %} - -{% block modal-body %} -
-
- {% include "horizon/common/_form_fields.html" %} -
-
-
-

{% trans "Description:" %}

-

{% trans "Object:" %} {% trans "An object is the basic storage entity that represents a file you store in the OpenStack Object Storage system. When you upload data to OpenStack Object Storage, the data is stored as-is (no compression or encryption) and consists of a location (container), the object's name, and any metadata consisting of key/value pairs." %}

-

{% trans "File:" %} {% trans "A new uploaded file will replace the content of the current object" %}

-
-{% endblock %} - -{% block modal-footer %} - {% trans "Cancel" %} - -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/_upload.html b/openstack_dashboard/dashboards/project/containers/templates/containers/_upload.html deleted file mode 100644 index e7996a888..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/_upload.html +++ /dev/null @@ -1,29 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} - -{% block form_id %}upload_object_form{% endblock %} -{% block form_name %}uploadForm{% endblock %} -{% block form_action %}{% url 'horizon:project:containers:object_upload' container_name %}{% endblock %} -{% block form_attrs %}enctype="multipart/form-data"{% endblock %} - -{% block modal-header %} - {% blocktrans %}Upload Object To Container: {{ container_name }}{% endblocktrans %} -{% endblock %} - -{% block modal-body %} -
-
- {% include "horizon/common/_form_fields.html" %} -
-
-
-

{% trans "Description:" %}

-

{% trans "Object:" %} {% trans "An object is the basic storage entity that represents a file you store in the OpenStack Object Storage system. When you upload data to OpenStack Object Storage, the data is stored as-is (no compression or encryption) and consists of a location (container), the object's name, and any metadata consisting of key/value pairs." %}

-

{% trans "Pseudo-folder:" %} {% trans "Within a container you can group your objects into pseudo-folders, which behave similarly to folders in your desktop operating system, with the exception that they are virtual collections defined by a common prefix on the object's name. A slash (/) character is used as the delimiter for pseudo-folders in the Object Store." %}

-
-{% endblock %} - -{% block modal-footer %} - {% trans "Cancel" %} - -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/container_detail.html b/openstack_dashboard/dashboards/project/containers/templates/containers/container_detail.html deleted file mode 100644 index 5c15d25a1..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/container_detail.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Container Details" %}{% endblock %} - -{% block main %} -
-
- {% include 'project/containers/_container_detail.html' %} -
-
-{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/copy.html b/openstack_dashboard/dashboards/project/containers/templates/containers/copy.html deleted file mode 100644 index 9d22bb9ee..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/copy.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Copy Object" %}{% endblock %} - -{% block main %} - {% include 'project/containers/_copy.html' %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/create.html b/openstack_dashboard/dashboards/project/containers/templates/containers/create.html deleted file mode 100644 index 9278ba545..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/create.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Create Container" %}{% endblock %} - -{% block main %} - {% include "project/containers/_create.html" %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/create_pseudo_folder.html b/openstack_dashboard/dashboards/project/containers/templates/containers/create_pseudo_folder.html deleted file mode 100644 index 7cc8b099c..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/create_pseudo_folder.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Create Pseudo-folder" %}{% endblock %} - -{% block main %} - {% include 'project/containers/_create_pseudo_folder.html' %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/index.html b/openstack_dashboard/dashboards/project/containers/templates/containers/index.html deleted file mode 100644 index cbc6dac32..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/index.html +++ /dev/null @@ -1,24 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} - -{% block title %}{% trans "Containers" %}{% endblock %} - -{% block main %} - {% if subfolders %} -
-
-

- {{ container_name }} : / - {% for folder in subfolders %} - {% if forloop.last %} - {{ folder.0 }} - {% else %} - {{ folder.0 }} / - {% endif %} - {% endfor %} -

-
-
- {% endif %} - {{ swift_browser.render }} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/object_detail.html b/openstack_dashboard/dashboards/project/containers/templates/containers/object_detail.html deleted file mode 100644 index be652e525..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/object_detail.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Object Details" %}{% endblock %} - -{% block main %} -
-
- {% include 'project/containers/_object_detail.html' %} -
-
-{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/update.html b/openstack_dashboard/dashboards/project/containers/templates/containers/update.html deleted file mode 100644 index 96c1577a1..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/update.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Update Object" %}{% endblock %} - -{% block main %} - {% include 'project/containers/_update.html' %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/templates/containers/upload.html b/openstack_dashboard/dashboards/project/containers/templates/containers/upload.html deleted file mode 100644 index cdf115b17..000000000 --- a/openstack_dashboard/dashboards/project/containers/templates/containers/upload.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Upload Object" %}{% endblock %} - -{% block main %} - {% include 'project/containers/_upload.html' %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/project/containers/tests.py b/openstack_dashboard/dashboards/project/containers/tests.py deleted file mode 100644 index 1fd672973..000000000 --- a/openstack_dashboard/dashboards/project/containers/tests.py +++ /dev/null @@ -1,565 +0,0 @@ -# Copyright 2012 United States Government as represented by the -# Administrator of the National Aeronautics and Space Administration. -# All Rights Reserved. -# -# Copyright 2012 Nebula, Inc. -# -# 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. - -import copy -import email.header -import tempfile - -import django -from django.core.files.uploadedfile import InMemoryUploadedFile # noqa -from django.core.urlresolvers import reverse -from django import http -from django.utils import http as utils_http - -from mox3.mox import IsA # noqa -import six - -from openstack_dashboard import api -from openstack_dashboard.dashboards.project.containers import forms -from openstack_dashboard.dashboards.project.containers import tables -from openstack_dashboard.dashboards.project.containers import utils -from openstack_dashboard.dashboards.project.containers import views -from openstack_dashboard.test import helpers as test - -CONTAINER_NAME_1 = u"container one%\u6346" -CONTAINER_NAME_2 = u"container_two\u6346" -CONTAINER_NAME_1_QUOTED = utils_http.urlquote(CONTAINER_NAME_1) -CONTAINER_NAME_2_QUOTED = utils_http.urlquote(CONTAINER_NAME_2) -INVALID_CONTAINER_NAME_1 = utils_http.urlquote(CONTAINER_NAME_1_QUOTED) -INVALID_CONTAINER_NAME_2 = utils_http.urlquote(CONTAINER_NAME_2_QUOTED) -CONTAINER_INDEX_URL = reverse('horizon:project:containers:index') - -INVALID_PATHS = [] - - -def invalid_paths(): - if not INVALID_PATHS: - for x in (CONTAINER_NAME_1_QUOTED, CONTAINER_NAME_2_QUOTED): - y = reverse('horizon:project:containers:index', - args=(utils.wrap_delimiter(x), )) - INVALID_PATHS.append(y) - for x in (CONTAINER_NAME_1, CONTAINER_NAME_2): - INVALID_PATHS.append(CONTAINER_INDEX_URL + x) - return INVALID_PATHS - - -class SwiftTests(test.TestCase): - - def _test_invalid_paths(self, response): - for x in invalid_paths(): - self.assertNotContains(response, x) - - @test.create_stubs({api.swift: ('swift_get_containers',)}) - def test_index_no_container_selected(self): - containers = self.containers.list() - api.swift.swift_get_containers(IsA(http.HttpRequest), marker=None) \ - .AndReturn((containers, False)) - self.mox.ReplayAll() - - res = self.client.get(CONTAINER_INDEX_URL) - - self.assertTemplateUsed(res, 'project/containers/index.html') - self.assertIn('table', res.context) - resp_containers = res.context['table'].data - self.assertEqual(len(resp_containers), len(containers)) - - @test.create_stubs({api.swift: ('swift_delete_container', )}) - def test_delete_container(self): - for container in self.containers.list(): - self.mox.ResetAll() # mandatory in a for loop - api.swift.swift_delete_container(IsA(http.HttpRequest), - container.name) - self.mox.ReplayAll() - - action_string = u"containers__delete__%s" % container.name - form_data = {"action": action_string} - req = self.factory.post(CONTAINER_INDEX_URL, form_data) - table = tables.ContainersTable(req, self.containers.list()) - handled = table.maybe_handle() - self.assertEqual(handled['location'], CONTAINER_INDEX_URL) - - @test.create_stubs({api.swift: ('swift_get_objects', )}) - def test_delete_container_nonempty(self): - container = self.containers.first() - objects = self.objects.list() - api.swift.swift_get_objects(IsA(http.HttpRequest), - container.name).AndReturn([objects, False]) - self.mox.ReplayAll() - - action_string = u"containers__delete__%s" % container.name - form_data = {"action": action_string} - req = self.factory.post(CONTAINER_INDEX_URL, form_data) - req.META['HTTP_REFERER'] = '%s/%s' % (CONTAINER_INDEX_URL, - container.name) - table = tables.ContainersTable(req, self.containers.list()) - handled = table.maybe_handle() - - self.assertEqual(handled.status_code, 302) - self.assertEqual(six.text_type(list(req._messages)[0].message), - u"The container cannot be deleted " - u"since it is not empty.") - - def test_create_container_get(self): - res = self.client.get(reverse('horizon:project:containers:create')) - self.assertTemplateUsed(res, 'project/containers/create.html') - - @test.create_stubs({api.swift: ('swift_create_container',)}) - def test_create_container_post(self): - for container in self.containers.list(): - self.mox.ResetAll() # mandatory in a for loop - api.swift.swift_create_container(IsA(http.HttpRequest), - container.name, - metadata=({'is_public': False})) - self.mox.ReplayAll() - - formData = {'name': container.name, - 'access': "private", - 'method': forms.CreateContainer.__name__} - res = self.client.post( - reverse('horizon:project:containers:create'), formData) - args = (utils.wrap_delimiter(container.name),) - url = reverse('horizon:project:containers:index', args=args) - self.assertRedirectsNoFollow(res, url) - - @test.create_stubs({api.swift: ('swift_update_container', )}) - def test_update_container_to_public(self): - container = self.containers.get(name=u"container one%\u6346") - api.swift.swift_update_container(IsA(http.HttpRequest), - container.name, - metadata=({'is_public': True})) - self.mox.ReplayAll() - - action_string = u"containers__make_public__%s" % container.name - form_data = {"action": action_string} - req = self.factory.post(CONTAINER_INDEX_URL, form_data) - table = tables.ContainersTable(req, self.containers.list()) - handled = table.maybe_handle() - self.assertEqual(handled['location'], CONTAINER_INDEX_URL) - - @test.create_stubs({api.swift: ('swift_update_container', )}) - def test_update_container_to_private(self): - container = self.containers.get(name=u"container_two\u6346") - api.swift.swift_update_container(IsA(http.HttpRequest), - container.name, - metadata=({'is_public': False})) - self.mox.ReplayAll() - - action_string = u"containers__make_private__%s" % container.name - form_data = {"action": action_string} - req = self.factory.post(CONTAINER_INDEX_URL, form_data) - table = tables.ContainersTable(req, self.containers.list()) - handled = table.maybe_handle() - self.assertEqual(handled['location'], CONTAINER_INDEX_URL) - - @test.create_stubs({api.swift: ('swift_get_containers', - 'swift_get_objects')}) - def test_index_container_selected(self): - containers = (self.containers.list(), False) - ret = (self.objects.list(), False) - api.swift.swift_get_containers(IsA(http.HttpRequest), - marker=None).AndReturn(containers) - api.swift.swift_get_objects(IsA(http.HttpRequest), - self.containers.first().name, - marker=None, - prefix=None).AndReturn(ret) - self.mox.ReplayAll() - - container_name = self.containers.first().name - res = self.client.get( - reverse('horizon:project:containers:index', - args=[utils.wrap_delimiter(container_name)])) - self.assertTemplateUsed(res, 'project/containers/index.html') - # UTF8 encoding here to ensure there aren't problems with Nose output. - expected = [obj.name.encode('utf8') for obj in self.objects.list()] - self.assertQuerysetEqual(res.context['objects_table'].data, - expected, - lambda obj: obj.name.encode('utf8')) - # Check if the two forms' URL are properly 'urlquote()d'. - form_action = ' action="%s%s/" ' % (CONTAINER_INDEX_URL, - CONTAINER_NAME_1_QUOTED) - self.assertContains(res, form_action, count=2) - self._test_invalid_paths(res) - - @test.create_stubs({api.swift: ('swift_upload_object',)}) - def test_upload(self): - container = self.containers.first() - obj = self.objects.first() - OBJECT_DATA = b'objectData' - - temp_file = tempfile.NamedTemporaryFile() - temp_file.write(OBJECT_DATA) - temp_file.flush() - temp_file.seek(0) - - api.swift.swift_upload_object(IsA(http.HttpRequest), - container.name, - obj.name, - IsA(InMemoryUploadedFile)).AndReturn(obj) - self.mox.ReplayAll() - - upload_url = reverse('horizon:project:containers:object_upload', - args=[container.name]) - - res = self.client.get(upload_url) - self.assertTemplateUsed(res, 'project/containers/upload.html') - self.assertContains(res, 'enctype="multipart/form-data"') - self._test_invalid_paths(res) - - formData = {'method': forms.UploadObject.__name__, - 'container_name': container.name, - 'name': obj.name, - 'object_file': temp_file} - res = self.client.post(upload_url, formData) - - args = (utils.wrap_delimiter(container.name),) - index_url = reverse('horizon:project:containers:index', args=args) - self.assertRedirectsNoFollow(res, index_url) - - @test.create_stubs({api.swift: ('swift_upload_object',)}) - def test_upload_without_file(self): - container = self.containers.first() - obj = self.objects.first() - - api.swift.swift_upload_object(IsA(http.HttpRequest), - container.name, - obj.name, - None).AndReturn(obj) - self.mox.ReplayAll() - - upload_url = reverse('horizon:project:containers:object_upload', - args=[container.name]) - - res = self.client.get(upload_url) - self.assertTemplateUsed(res, 'project/containers/upload.html') - - res = self.client.get(upload_url) - self.assertContains(res, 'enctype="multipart/form-data"') - self.assertNotContains(res, INVALID_CONTAINER_NAME_1) - self.assertNotContains(res, INVALID_CONTAINER_NAME_2) - - formData = {'method': forms.UploadObject.__name__, - 'container_name': container.name, - 'name': obj.name, - 'object_file': None} - res = self.client.post(upload_url, formData) - - args = (utils.wrap_delimiter(container.name),) - index_url = reverse('horizon:project:containers:index', args=args) - self.assertRedirectsNoFollow(res, index_url) - - @test.create_stubs({api.swift: ('swift_create_pseudo_folder',)}) - def test_create_pseudo_folder(self): - container = self.containers.first() - obj = self.objects.first() - - api.swift.swift_create_pseudo_folder(IsA(http.HttpRequest), - container.name, - obj.name + "/").AndReturn(obj) - self.mox.ReplayAll() - - create_pseudo_folder_url = reverse('horizon:project:containers:' - 'create_pseudo_folder', - args=[container.name]) - - res = self.client.get(create_pseudo_folder_url) - self.assertTemplateUsed(res, - 'project/containers/create_pseudo_folder.html') - self._test_invalid_paths(res) - - formData = {'method': forms.CreatePseudoFolder.__name__, - 'container_name': container.name, - 'name': obj.name} - res = self.client.post(create_pseudo_folder_url, formData) - - index_url = reverse('horizon:project:containers:index', - args=[utils.wrap_delimiter(container.name)]) - - self.assertRedirectsNoFollow(res, index_url) - - @test.create_stubs({api.swift: ('swift_delete_object',)}) - def test_delete(self): - container = self.containers.first() - obj = self.objects.first() - args = (utils.wrap_delimiter(container.name),) - index_url = reverse('horizon:project:containers:index', args=args) - api.swift.swift_delete_object(IsA(http.HttpRequest), - container.name, - obj.name) - self.mox.ReplayAll() - - action_string = "objects__delete_object__%s" % obj.name - form_data = {"action": action_string} - req = self.factory.post(index_url, form_data) - kwargs = {"container_name": container.name} - table = tables.ObjectsTable(req, self.objects.list(), **kwargs) - handled = table.maybe_handle() - self.assertEqual(handled['location'], index_url) - - @test.create_stubs({api.swift: ('swift_delete_object',)}) - def test_delete_pseudo_folder(self): - container = self.containers.first() - folder = self.folder.first() - args = (utils.wrap_delimiter(container.name),) - index_url = reverse('horizon:project:containers:index', args=args) - api.swift.swift_delete_object(IsA(http.HttpRequest), - container.name, - folder.name + '/') - self.mox.ReplayAll() - - action_string = "objects__delete_object__%s/%s" % (container.name, - folder.name) - form_data = {"action": action_string} - req = self.factory.post(index_url, form_data) - kwargs = {"container_name": container.name} - table = tables.ObjectsTable(req, self.folder.list(), **kwargs) - handled = table.maybe_handle() - self.assertEqual(handled['location'], index_url) - - @test.create_stubs({api.swift: ('swift_get_object',)}) - def test_download(self): - for container in self.containers.list(): - for obj in self.objects.list(): - self.mox.ResetAll() # mandatory in a for loop - obj = copy.copy(obj) - _data = obj.data - - def make_iter(): - yield _data - - obj.data = make_iter() - api.swift.swift_get_object( - IsA(http.HttpRequest), - container.name, - obj.name, - resp_chunk_size=api.swift.CHUNK_SIZE).AndReturn(obj) - self.mox.ReplayAll() - - download_url = reverse( - 'horizon:project:containers:object_download', - args=[container.name, obj.name]) - res = self.client.get(download_url) - - self.assertTrue(res.has_header('Content-Disposition')) - self.assertEqual(b''.join(res.streaming_content), _data) - self.assertNotContains(res, INVALID_CONTAINER_NAME_1) - self.assertNotContains(res, INVALID_CONTAINER_NAME_2) - - # Check that the returned Content-Disposition filename is - # correct - some have commas which must be removed - expected_name = obj.name.replace(',', '') - - # some have a path which must be removed - if '/' in expected_name: - expected_name = expected_name.split('/')[-1] - - # There will also be surrounding double quotes - expected_name = '"' + expected_name + '"' - - expected = 'attachment; filename=%s' % expected_name - content = res.get('Content-Disposition') - - if six.PY3: - header = email.header.decode_header(content) - content = header[0][0] - if isinstance(content, str): - content = content.encode('utf-8') - expected = expected.encode('utf-8') - - self.assertEqual(content, expected) - - @test.create_stubs({api.swift: ('swift_get_containers',)}) - def test_copy_index(self): - ret = (self.containers.list(), False) - api.swift.swift_get_containers(IsA(http.HttpRequest)).AndReturn(ret) - self.mox.ReplayAll() - - res = self.client.get(reverse('horizon:project:containers:object_copy', - args=[self.containers.first().name, - self.objects.first().name])) - self.assertTemplateUsed(res, 'project/containers/copy.html') - self.assertNotContains(res, INVALID_CONTAINER_NAME_1) - self.assertNotContains(res, INVALID_CONTAINER_NAME_2) - - @test.create_stubs({api.swift: ('swift_get_containers', - 'swift_copy_object')}) - def test_copy(self): - container_1 = self.containers.get(name=CONTAINER_NAME_1) - container_2 = self.containers.get(name=CONTAINER_NAME_2) - obj = self.objects.first() - - ret = (self.containers.list(), False) - api.swift.swift_get_containers(IsA(http.HttpRequest)).AndReturn(ret) - api.swift.swift_copy_object(IsA(http.HttpRequest), - container_1.name, - obj.name, - container_2.name, - obj.name) - self.mox.ReplayAll() - - formData = {'method': forms.CopyObject.__name__, - 'new_container_name': container_2.name, - 'new_object_name': obj.name, - 'orig_container_name': container_1.name, - 'orig_object_name': obj.name} - copy_url = reverse('horizon:project:containers:object_copy', - args=[container_1.name, obj.name]) - res = self.client.post(copy_url, formData) - args = (utils.wrap_delimiter(container_2.name),) - index_url = reverse('horizon:project:containers:index', args=args) - self.assertRedirectsNoFollow(res, index_url) - - @test.create_stubs({api.swift: ('swift_get_containers', - 'swift_copy_object')}) - def test_copy_get(self): - original_name = u"test folder%\u6346/test.txt" - copy_name = u"test.copy.txt" - container = self.containers.first() - obj = self.objects.get(name=original_name) - ret = (self.containers.list(), False) - api.swift.swift_get_containers(IsA(http.HttpRequest)).AndReturn(ret) - self.mox.ReplayAll() - copy_url = reverse('horizon:project:containers:object_copy', - args=[container.name, obj.name]) - res = self.client.get(copy_url) - # The copy's name must appear in initial data - if django.VERSION >= (1, 10): - pattern = ('' % copy_name) - else: - pattern = ('' % copy_name) - self.assertContains(res, pattern, html=True) - - def test_get_copy_name(self): - self.assertEqual(views.CopyView.get_copy_name('test.txt'), - 'test.copy.txt') - self.assertEqual(views.CopyView.get_copy_name('test'), - 'test.copy') - - @test.create_stubs({api.swift: ('swift_upload_object',)}) - def test_update_with_file(self): - container = self.containers.first() - obj = self.objects.first() - OBJECT_DATA = b'objectData' - - temp_file = tempfile.NamedTemporaryFile() - temp_file.write(OBJECT_DATA) - temp_file.flush() - temp_file.seek(0) - - api.swift.swift_upload_object(IsA(http.HttpRequest), - container.name, - obj.name, - IsA(InMemoryUploadedFile)).AndReturn(obj) - self.mox.ReplayAll() - - update_url = reverse('horizon:project:containers:object_update', - args=[container.name, obj.name]) - - res = self.client.get(update_url) - self.assertTemplateUsed(res, 'project/containers/update.html') - self.assertContains(res, 'enctype="multipart/form-data"') - self._test_invalid_paths(res) - - formData = {'method': forms.UpdateObject.__name__, - 'container_name': container.name, - 'name': obj.name, - 'object_file': temp_file} - res = self.client.post(update_url, formData) - - args = (utils.wrap_delimiter(container.name),) - index_url = reverse('horizon:project:containers:index', args=args) - self.assertRedirectsNoFollow(res, index_url) - - @test.create_stubs({api.swift: ('swift_upload_object',)}) - def test_update_without_file(self): - container = self.containers.first() - obj = self.objects.first() - - self.mox.ReplayAll() - - update_url = reverse('horizon:project:containers:object_update', - args=[container.name, obj.name]) - - res = self.client.get(update_url) - self.assertTemplateUsed(res, 'project/containers/update.html') - self.assertContains(res, 'enctype="multipart/form-data"') - self._test_invalid_paths(res) - - formData = {'method': forms.UpdateObject.__name__, - 'container_name': container.name, - 'name': obj.name} - res = self.client.post(update_url, formData) - - args = (utils.wrap_delimiter(container.name),) - index_url = reverse('horizon:project:containers:index', args=args) - self.assertRedirectsNoFollow(res, index_url) - - @test.create_stubs({api.swift: ('swift_get_container', )}) - def test_view_container(self): - for container in self.containers.list(): - self.mox.ResetAll() # mandatory in a for loop - api.swift.swift_get_container(IsA(http.HttpRequest), - container.name, - with_data=False) \ - .AndReturn(container) - self.mox.ReplayAll() - - view_url = reverse('horizon:project:containers:container_detail', - args=[container.name]) - res = self.client.get(view_url) - - self.assertTemplateUsed(res, - 'project/containers/container_detail.html') - self.assertContains(res, container.name, 1, 200) - self.assertNotContains(res, INVALID_CONTAINER_NAME_1) - self.assertNotContains(res, INVALID_CONTAINER_NAME_2) - - @test.create_stubs({api.swift: ('swift_get_object', )}) - def test_view_object(self): - for container in self.containers.list(): - for obj in self.objects.list(): - self.mox.ResetAll() # mandatory in a for loop - api.swift.swift_get_object(IsA(http.HttpRequest), - container.name, - obj.name, - with_data=False) \ - .AndReturn(obj) - self.mox.ReplayAll() - view_url = reverse('horizon:project:containers:object_detail', - args=[container.name, obj.name]) - res = self.client.get(view_url) - - self.assertTemplateUsed( - res, 'project/containers/object_detail.html') - self.assertContains(res, obj.name, 1, 200) - self._test_invalid_paths(res) - - def test_wrap_delimiter(self): - expected = { - 'containerA': 'containerA/', - 'containerB%': 'containerB%/', # no urlquote() should occur - 'containerC/': 'containerC/', # already wrapped name - 'containerD/objectA': 'containerD/objectA/' - } - for name, expected_name in expected.items(): - self.assertEqual(utils.wrap_delimiter(name), expected_name) diff --git a/openstack_dashboard/dashboards/project/containers/urls.py b/openstack_dashboard/dashboards/project/containers/urls.py index e3224d0f3..ca3a50452 100644 --- a/openstack_dashboard/dashboards/project/containers/urls.py +++ b/openstack_dashboard/dashboards/project/containers/urls.py @@ -16,60 +16,14 @@ # License for the specific language governing permissions and limitations # under the License. -from django.conf import settings from django.conf.urls import url from openstack_dashboard.dashboards.project.containers import views -if settings.HORIZON_CONFIG['swift_panel'] == 'angular': - # New angular containers and objects - urlpatterns = [ - url(r'^container/((?P.+?)/)?' - '(?P.+)?$', - views.NgIndexView.as_view(), name='index'), - url(r'^$', - views.NgIndexView.as_view(), name='index') - ] -else: - # Legacy swift containers and objects - urlpatterns = [ - url(r'^((?P.+?)/)?(?P(.+/)+)?$', - views.ContainerView.as_view(), name='index'), - - url(r'^(?P(.+/)+)?create$', - views.CreateView.as_view(), - name='create'), - - url(r'^(?P.+?)/(?P(.+/)+)' - '?container_detail$', - views.ContainerDetailView.as_view(), - name='container_detail'), - - url(r'^(?P[^/]+)/(?P.+)/object_detail$', - views.ObjectDetailView.as_view(), - name='object_detail'), - - url(r'^(?P[^/]+)/(?P(.+/)+)?' - '(?P.+)/update$', - views.UpdateObjectView.as_view(), - name='object_update'), - - url(r'^(?P.+?)/(?P(.+/)+)?upload$', - views.UploadView.as_view(), - name='object_upload'), - - url(r'^(?P.+?)/(?P(.+/)+)' - '?create_pseudo_folder', - views.CreatePseudoFolderView.as_view(), - name='create_pseudo_folder'), - - url(r'^(?P[^/]+)/' - r'(?P(.+/)+)?' - r'(?P.+)/copy$', - views.CopyView.as_view(), - name='object_copy'), - - url(r'^(?P[^/]+)/(?P.+)/download$', - views.object_download, - name='object_download'), - ] +urlpatterns = [ + url(r'^container/((?P.+?)/)?' + '(?P.+)?$', + views.NgIndexView.as_view(), name='index'), + url(r'^$', + views.NgIndexView.as_view(), name='index') +] diff --git a/openstack_dashboard/dashboards/project/containers/utils.py b/openstack_dashboard/dashboards/project/containers/utils.py index a7e8e05f8..97dfa2e7f 100644 --- a/openstack_dashboard/dashboards/project/containers/utils.py +++ b/openstack_dashboard/dashboards/project/containers/utils.py @@ -10,9 +10,23 @@ # License for the specific language governing permissions and limitations # under the License. +from django.core import validators +from django.utils.translation import ugettext_lazy as _ + from openstack_dashboard.api import swift +no_slash_validator = validators.RegexValidator(r'^(?u)[^/]+$', + _("Slash is not an allowed " + "character."), + code="noslash") +no_begin_or_end_slash = validators.RegexValidator(r'^[^\/](?u).+[^\/]$', + _("Slash is not allowed at " + "the beginning or end of " + "your string."), + code="nobeginorendslash") + + def wrap_delimiter(name): if name and not name.endswith(swift.FOLDER_DELIMITER): return name + swift.FOLDER_DELIMITER diff --git a/openstack_dashboard/dashboards/project/containers/views.py b/openstack_dashboard/dashboards/project/containers/views.py index 0b82701bf..2f0dbbfc0 100644 --- a/openstack_dashboard/dashboards/project/containers/views.py +++ b/openstack_dashboard/dashboards/project/containers/views.py @@ -16,327 +16,10 @@ # License for the specific language governing permissions and limitations # under the License. -""" -Views for managing Swift containers. -""" -import os - -from django.core.urlresolvers import reverse -from django import http -from django.utils.functional import cached_property # noqa -from django.utils.translation import ugettext_lazy as _ from django.views import generic -import six - -from horizon import browsers -from horizon import exceptions -from horizon import forms -from horizon.utils import memoized - -from openstack_dashboard import api -from openstack_dashboard.api import swift -from openstack_dashboard.dashboards.project.containers \ - import browsers as project_browsers -from openstack_dashboard.dashboards.project.containers \ - import forms as project_forms -from openstack_dashboard.dashboards.project.containers import utils class NgIndexView(generic.TemplateView): + """View for managing Swift containers.""" template_name = 'project/containers/ngindex.html' - - -class ContainerView(browsers.ResourceBrowserView): - browser_class = project_browsers.ContainerBrowser - template_name = "project/containers/index.html" - page_title = _("Containers") - - def get_containers_data(self): - containers = [] - self._more = None - marker = self.request.GET.get('marker', None) - try: - containers, self._more = api.swift.swift_get_containers( - self.request, marker=marker) - except Exception: - msg = _('Unable to retrieve container list.') - exceptions.handle(self.request, msg) - return containers - - @cached_property - def objects(self): - """Returns a list of objects given the subfolder's path. - - The path is from the kwargs of the request. - """ - objects = [] - self._more = None - marker = self.request.GET.get('marker', None) - container_name = self.kwargs['container_name'] - subfolder = self.kwargs['subfolder_path'] - prefix = None - if container_name: - self.navigation_selection = True - if subfolder: - prefix = subfolder - try: - objects, self._more = api.swift.swift_get_objects( - self.request, - container_name, - marker=marker, - prefix=prefix) - except Exception: - self._more = None - objects = [] - msg = _('Unable to retrieve object list.') - exceptions.handle(self.request, msg) - return objects - - def is_subdir(self, item): - content_type = "application/pseudo-folder" - return getattr(item, "content_type", None) == content_type - - def is_placeholder(self, item): - object_name = getattr(item, "name", "") - return object_name.endswith(api.swift.FOLDER_DELIMITER) - - def get_objects_data(self): - """Returns a list of objects within the current folder.""" - filtered_objects = [item for item in self.objects - if (not self.is_subdir(item) and - not self.is_placeholder(item))] - return filtered_objects - - def get_subfolders_data(self): - """Returns a list of subfolders within the current folder.""" - filtered_objects = [item for item in self.objects - if self.is_subdir(item)] - return filtered_objects - - def get_context_data(self, **kwargs): - context = super(ContainerView, self).get_context_data(**kwargs) - context['container_name'] = self.kwargs["container_name"] - context['subfolders'] = [] - if self.kwargs["subfolder_path"]: - (parent, slash, folder) = self.kwargs["subfolder_path"] \ - .strip('/').rpartition('/') - while folder: - path = "%s%s%s/" % (parent, slash, folder) - context['subfolders'].insert(0, (folder, path)) - (parent, slash, folder) = parent.rpartition('/') - return context - - -class CreateView(forms.ModalFormView): - form_class = project_forms.CreateContainer - template_name = 'project/containers/create.html' - success_url = "horizon:project:containers:index" - page_title = _("Create Container") - - def get_success_url(self): - parent = self.request.POST.get('parent', None) - if parent: - container, slash, remainder = parent.partition( - swift.FOLDER_DELIMITER) - args = (utils.wrap_delimiter(container), - utils.wrap_delimiter(remainder)) - return reverse(self.success_url, args=args) - else: - container = utils.wrap_delimiter(self.request.POST['name']) - return reverse(self.success_url, args=[container]) - - def get_initial(self): - initial = super(CreateView, self).get_initial() - initial['parent'] = self.kwargs['container_name'] - return initial - - -class CreatePseudoFolderView(forms.ModalFormView): - form_class = project_forms.CreatePseudoFolder - template_name = 'project/containers/create_pseudo_folder.html' - success_url = "horizon:project:containers:index" - page_title = _("Create Pseudo-folder") - - def get_success_url(self): - container_name = self.request.POST['container_name'] - return reverse(self.success_url, - args=(utils.wrap_delimiter(container_name), - self.request.POST.get('path', ''))) - - def get_initial(self): - return {"container_name": self.kwargs["container_name"], - "path": self.kwargs['subfolder_path']} - - def get_context_data(self, **kwargs): - context = super(CreatePseudoFolderView, self). \ - get_context_data(**kwargs) - context['container_name'] = self.kwargs["container_name"] - return context - - -class UploadView(forms.ModalFormView): - form_class = project_forms.UploadObject - template_name = 'project/containers/upload.html' - success_url = "horizon:project:containers:index" - page_title = _("Upload Objects") - - def get_success_url(self): - container = utils.wrap_delimiter(self.request.POST['container_name']) - path = utils.wrap_delimiter(self.request.POST.get('path', '')) - args = (container, path) - return reverse(self.success_url, args=args) - - def get_initial(self): - return {"container_name": self.kwargs["container_name"], - "path": self.kwargs['subfolder_path']} - - def get_context_data(self, **kwargs): - context = super(UploadView, self).get_context_data(**kwargs) - context['container_name'] = self.kwargs["container_name"] - return context - - -def object_download(request, container_name, object_path): - try: - obj = api.swift.swift_get_object(request, container_name, object_path, - resp_chunk_size=swift.CHUNK_SIZE) - except Exception: - redirect = reverse("horizon:project:containers:index") - exceptions.handle(request, - _("Unable to retrieve object."), - redirect=redirect) - # Add the original file extension back on if it wasn't preserved in the - # name given to the object. - filename = object_path.rsplit(swift.FOLDER_DELIMITER)[-1] - if not os.path.splitext(obj.name)[1] and obj.orig_name: - name, ext = os.path.splitext(obj.orig_name) - filename = "%s%s" % (filename, ext) - response = http.StreamingHttpResponse(obj.data) - safe_name = filename.replace(",", "") - if six.PY2: - safe_name = safe_name.encode('utf-8') - response['Content-Disposition'] = 'attachment; filename="%s"' % safe_name - response['Content-Type'] = 'application/octet-stream' - response['Content-Length'] = obj.bytes - return response - - -class CopyView(forms.ModalFormView): - form_class = project_forms.CopyObject - template_name = 'project/containers/copy.html' - success_url = "horizon:project:containers:index" - page_title = _("Copy Object") - - def get_success_url(self): - container = utils.wrap_delimiter( - self.request.POST['new_container_name']) - path = utils.wrap_delimiter(self.request.POST.get('path', '')) - args = (container, path) - return reverse(self.success_url, args=args) - - def get_form_kwargs(self): - kwargs = super(CopyView, self).get_form_kwargs() - try: - containers = api.swift.swift_get_containers(self.request) - except Exception: - redirect = reverse("horizon:project:containers:index") - exceptions.handle(self.request, - _('Unable to list containers.'), - redirect=redirect) - kwargs['containers'] = [(c.name, c.name) for c in containers[0]] - return kwargs - - @staticmethod - def get_copy_name(object_name): - filename, ext = os.path.splitext(object_name) - return "%s.copy%s" % (filename, ext) - - def get_initial(self): - path = self.kwargs["subfolder_path"] - object_name = self.kwargs["object_name"] - orig = "%s%s" % (path or '', object_name) - - return {"new_container_name": self.kwargs["container_name"], - "orig_container_name": self.kwargs["container_name"], - "orig_object_name": orig, - "path": path, - "new_object_name": self.get_copy_name(object_name)} - - def get_context_data(self, **kwargs): - context = super(CopyView, self).get_context_data(**kwargs) - context['container_name'] = self.kwargs["container_name"] - context['object_name'] = self.kwargs["object_name"] - return context - - -class ContainerDetailView(forms.ModalFormMixin, generic.TemplateView): - template_name = 'project/containers/container_detail.html' - page_title = _("Container Details") - - @memoized.memoized_method - def get_object(self): - try: - return api.swift.swift_get_container( - self.request, - self.kwargs["container_name"], - with_data=False) - except Exception: - redirect = reverse("horizon:project:containers:index") - exceptions.handle(self.request, - _('Unable to retrieve details.'), - redirect=redirect) - - def get_context_data(self, **kwargs): - context = super(ContainerDetailView, self).get_context_data(**kwargs) - context['container'] = self.get_object() - return context - - -class ObjectDetailView(forms.ModalFormMixin, generic.TemplateView): - template_name = 'project/containers/object_detail.html' - page_title = _("Object Details") - - @memoized.memoized_method - def get_object(self): - try: - return api.swift.swift_get_object( - self.request, - self.kwargs["container_name"], - self.kwargs["object_path"], - with_data=False) - except Exception: - redirect = reverse("horizon:project:containers:index") - exceptions.handle(self.request, - _('Unable to retrieve details.'), - redirect=redirect) - - def get_context_data(self, **kwargs): - context = super(ObjectDetailView, self).get_context_data(**kwargs) - context['object'] = self.get_object() - return context - - -class UpdateObjectView(forms.ModalFormView): - form_class = project_forms.UpdateObject - template_name = 'project/containers/update.html' - success_url = "horizon:project:containers:index" - page_title = _("Update Object") - - def get_success_url(self): - container = utils.wrap_delimiter(self.request.POST['container_name']) - path = utils.wrap_delimiter(self.request.POST.get('path', '')) - args = (container, path) - return reverse(self.success_url, args=args) - - def get_initial(self): - return {"container_name": self.kwargs["container_name"], - "path": self.kwargs["subfolder_path"], - "name": self.kwargs["object_name"]} - - def get_context_data(self, **kwargs): - context = super(UpdateObjectView, self).get_context_data(**kwargs) - context['container_name'] = self.kwargs["container_name"] - context['subfolder_path'] = self.kwargs["subfolder_path"] - context['object_name'] = self.kwargs["object_name"] - return context diff --git a/openstack_dashboard/dashboards/project/stacks/tests.py b/openstack_dashboard/dashboards/project/stacks/tests.py index 71e972e0c..cb8e68703 100644 --- a/openstack_dashboard/dashboards/project/stacks/tests.py +++ b/openstack_dashboard/dashboards/project/stacks/tests.py @@ -74,7 +74,7 @@ class MappingsTests(test.TestCase): 'AWS::EC2::Instance', 'aaa') assertMappingUrl( - '/project/containers/aaa/', + '/project/containers/container/aaa/', 'OS::Swift::Container', 'aaa') assertMappingUrl( diff --git a/openstack_dashboard/dashboards/project/volumes/backups/forms.py b/openstack_dashboard/dashboards/project/volumes/backups/forms.py index ae0d7ae8f..31a4fff3b 100644 --- a/openstack_dashboard/dashboards/project/volumes/backups/forms.py +++ b/openstack_dashboard/dashboards/project/volumes/backups/forms.py @@ -26,7 +26,7 @@ from horizon import messages from openstack_dashboard import api from openstack_dashboard.dashboards.project.containers \ - import forms as containers_forms + import utils as containers_utils class CreateBackupForm(forms.SelfHandlingForm): @@ -37,7 +37,7 @@ class CreateBackupForm(forms.SelfHandlingForm): container_name = forms.CharField( max_length=255, label=_("Container Name"), - validators=[containers_forms.no_slash_validator], + validators=[containers_utils.no_slash_validator], required=False) volume_id = forms.CharField(widget=forms.HiddenInput()) diff --git a/openstack_dashboard/enabled/_1920_project_containers_panel.py b/openstack_dashboard/enabled/_1920_project_containers_panel.py index 305bdf3c6..9bbfee66b 100644 --- a/openstack_dashboard/enabled/_1920_project_containers_panel.py +++ b/openstack_dashboard/enabled/_1920_project_containers_panel.py @@ -25,13 +25,6 @@ ADD_PANEL = ('openstack_dashboard.dashboards.project.' DISABLED = False -# Which implementation of the panel should we use? Valid options -# here are 'angular' (new implementation) and 'legacy' (old -# implementation.) -UPDATE_HORIZON_CONFIG = { - 'swift_panel': 'angular' -} - ADD_SCSS_FILES = [ 'dashboard/project/containers/_containers.scss', ] diff --git a/openstack_dashboard/test/settings.py b/openstack_dashboard/test/settings.py index 24d073c2f..42cd7c45e 100644 --- a/openstack_dashboard/test/settings.py +++ b/openstack_dashboard/test/settings.py @@ -121,10 +121,6 @@ settings_utils.update_dashboards( INSTALLED_APPS, ) -# Remove this when the legacy panel is removed, along with its tests and -# the stacks MappingsTests are updated with the new URL path. -HORIZON_CONFIG['swift_panel'] = 'legacy' - settings_utils.find_static_files(HORIZON_CONFIG, AVAILABLE_THEMES, THEME_COLLECTION_DIR, ROOT_PATH) diff --git a/releasenotes/notes/remove-deprecated-swift-ui-1165b60bab5771d6.yaml b/releasenotes/notes/remove-deprecated-swift-ui-1165b60bab5771d6.yaml new file mode 100644 index 000000000..499b82bc1 --- /dev/null +++ b/releasenotes/notes/remove-deprecated-swift-ui-1165b60bab5771d6.yaml @@ -0,0 +1,8 @@ +--- +upgrade: + - Any past use of the Django based Swift UI is no longer + supported and the code is being removed. The new + angularJS based version should be used instead. +deprecations: + - Removing formerly deprecated Swift UI code that was + replaced with an improved Angular version in Mitaka.