diff options
Diffstat (limited to 'openstack_dashboard/dashboards/project/containers')
7 files changed, 162 insertions, 4 deletions
diff --git a/openstack_dashboard/dashboards/project/containers/forms.py b/openstack_dashboard/dashboards/project/containers/forms.py index c9d4de740..99f293e45 100644 --- a/openstack_dashboard/dashboards/project/containers/forms.py +++ b/openstack_dashboard/dashboards/project/containers/forms.py @@ -78,12 +78,16 @@ class UploadObject(forms.SelfHandlingForm): object_file = forms.FileField(label=_("File"), allow_empty_file=True) container_name = forms.CharField(widget=forms.HiddenInput()) - def handle(self, request, data): - object_file = self.files['object_file'] + 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 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'], @@ -95,6 +99,36 @@ class UploadObject(forms.SelfHandlingForm): exceptions.handle(request, _("Unable to upload object.")) +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")) + 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]) diff --git a/openstack_dashboard/dashboards/project/containers/tables.py b/openstack_dashboard/dashboards/project/containers/tables.py index f641832da..92b18ddee 100644 --- a/openstack_dashboard/dashboards/project/containers/tables.py +++ b/openstack_dashboard/dashboards/project/containers/tables.py @@ -77,6 +77,34 @@ class ListObjects(tables.LinkAction): 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", "btn-create") + + 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 = (http.urlquote(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") @@ -247,7 +275,7 @@ class ObjectsTable(tables.DataTable): class Meta: name = "objects" verbose_name = _("Objects") - table_actions = (ObjectFilterAction, UploadObject, + table_actions = (ObjectFilterAction, CreatePseudoFolder, UploadObject, DeleteMultipleObjects) row_actions = (DownloadObject, CopyObject, ViewObject, DeleteObject) data_types = ("subfolders", "objects") 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 new file mode 100644 index 000000000..d8ee31e50 --- /dev/null +++ b/openstack_dashboard/dashboards/project/containers/templates/containers/_create_pseudo_folder.html @@ -0,0 +1,25 @@ +{% extends "horizon/common/_modal_form.html" %} +{% load i18n %} +{% load url from future %} + +{% block form_id %}create_directory_form{% endblock %} +{% block form_action %}{% url 'horizon:project:containers:create_pseudo_folder' container_name %}{% endblock %} + +{% block modal-header %}{% trans "Create pseudo-folder in container" %} {{ container_name }}{% endblock %} + +{% block modal-body %} +<div class="left"> + <fieldset> + {% include "horizon/common/_form_fields.html" %} + </fieldset> +</div> +<div class="right"> + <h3>{% trans "Description" %}:</h3> + <p><strong>{% trans "Pseudo-folder" %}</strong>: {% 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." %}</p> +</div> +{% endblock %} + +{% block modal-footer %} + <input class="btn btn-primary pull-right" type="submit" value="{% trans "Create" %}" /> + <a href="{% url 'horizon:project:containers:index' container_name|add:'/' %}" class="btn secondary cancel close">{% trans "Cancel" %}</a> +{% 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 new file mode 100644 index 000000000..f163a1476 --- /dev/null +++ b/openstack_dashboard/dashboards/project/containers/templates/containers/create_pseudo_folder.html @@ -0,0 +1,11 @@ +{% extends 'base.html' %} +{% load i18n %} +{% block title %}{% trans "Create Pseudo-folder" %}{% endblock %} + +{% block page_header %} + {% include "horizon/common/_page_header.html" with title=_("Create Pseudo-folder") %} +{% endblock page_header %} + +{% block main %} + {% include 'project/containers/_create_pseudo_folder.html' %} +{% endblock %}
\ No newline at end of file diff --git a/openstack_dashboard/dashboards/project/containers/tests.py b/openstack_dashboard/dashboards/project/containers/tests.py index 58eea80e8..cd4b01dbb 100644 --- a/openstack_dashboard/dashboards/project/containers/tests.py +++ b/openstack_dashboard/dashboards/project/containers/tests.py @@ -157,6 +157,34 @@ class SwiftTests(test.TestCase): args=[tables.wrap_delimiter(container.name)]) 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') + + 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=[tables.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() diff --git a/openstack_dashboard/dashboards/project/containers/urls.py b/openstack_dashboard/dashboards/project/containers/urls.py index c54914c2f..49d43a5c7 100644 --- a/openstack_dashboard/dashboards/project/containers/urls.py +++ b/openstack_dashboard/dashboards/project/containers/urls.py @@ -48,6 +48,11 @@ urlpatterns = patterns(VIEW_MOD, views.UploadView.as_view(), name='object_upload'), + url(r'^(?P<container_name>.+?)/(?P<subfolder_path>(.+/)+)' + '?create_pseudo_folder', + views.CreatePseudoFolderView.as_view(), + name='create_pseudo_folder'), + url(r'^(?P<container_name>[^/]+)/' r'(?P<subfolder_path>(.+/)+)?' r'(?P<object_name>.+)/copy$', diff --git a/openstack_dashboard/dashboards/project/containers/views.py b/openstack_dashboard/dashboards/project/containers/views.py index f69637759..c2818464b 100644 --- a/openstack_dashboard/dashboards/project/containers/views.py +++ b/openstack_dashboard/dashboards/project/containers/views.py @@ -92,10 +92,15 @@ class ContainerView(browsers.ResourceBrowserView): 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)] + if (not self.is_subdir(item) and + not self.is_placeholder(item))] return filtered_objects def get_subfolders_data(self): @@ -142,6 +147,28 @@ class CreateView(forms.ModalFormView): 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" + + def get_success_url(self): + container_name = self.request.POST['container_name'] + return reverse(self.success_url, + args=(tables.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' |