summaryrefslogtreecommitdiff
path: root/openstack_dashboard/dashboards/project/containers
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2013-11-26 20:30:04 +0000
committerGerrit Code Review <review@openstack.org>2013-11-26 20:30:04 +0000
commit2d06e1b23f1da266c818d15712b3c12b76acef6a (patch)
tree88849881eab332402102ecfff51a4999d276937f /openstack_dashboard/dashboards/project/containers
parent0fac884aa3c1513b42e4d2e43e4c56fa73289b7a (diff)
parent56ae1e84e4276531c08406a88b596a45e6f9d6e7 (diff)
downloadhorizon-2d06e1b23f1da266c818d15712b3c12b76acef6a.tar.gz
Merge "Adds pseudo-folder creation"
Diffstat (limited to 'openstack_dashboard/dashboards/project/containers')
-rw-r--r--openstack_dashboard/dashboards/project/containers/forms.py38
-rw-r--r--openstack_dashboard/dashboards/project/containers/tables.py30
-rw-r--r--openstack_dashboard/dashboards/project/containers/templates/containers/_create_pseudo_folder.html25
-rw-r--r--openstack_dashboard/dashboards/project/containers/templates/containers/create_pseudo_folder.html11
-rw-r--r--openstack_dashboard/dashboards/project/containers/tests.py28
-rw-r--r--openstack_dashboard/dashboards/project/containers/urls.py5
-rw-r--r--openstack_dashboard/dashboards/project/containers/views.py29
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'