# 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 # noqa
from django import shortcuts
from django import template
from django.template import defaultfilters as filters
from django.utils import http
from django.utils import safestring
from django.utils.translation import ugettext_lazy as _ # noqa
from horizon import exceptions
from horizon import messages
from horizon import tables
from openstack_dashboard import api
from openstack_dashboard.api import swift
LOG = logging.getLogger(__name__)
LOADING_IMAGE = '<img src="/static/dashboard/img/loading.gif" />'
def wrap_delimiter(name):
if name and not name.endswith(swift.FOLDER_DELIMITER):
[docs] return name + swift.FOLDER_DELIMITER
return name
class ViewContainer(tables.LinkAction):
name = "view"
[docs] 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)
[docs] args = (http.urlquote(obj_id),)
return reverse(self.url, args=args)
class MakePublicContainer(tables.Action):
name = "make_public"
[docs] verbose_name = _("Make Public")
classes = ("btn-edit", )
def allowed(self, request, container):
# Container metadata have not been loaded
[docs] if not hasattr(container, 'is_public'):
return False
return not container.is_public
def single(self, table, request, obj_id):
try:
[docs] 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"
[docs] verbose_name = _("Make Private")
classes = ("btn-edit", )
def allowed(self, request, container):
# Container metadata have not been loaded
[docs] if not hasattr(container, 'is_public'):
return False
return container.is_public
def single(self, table, request, obj_id):
try:
[docs] 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):
data_type_singular = _("Container")
[docs] data_type_plural = _("Containers")
success_url = "horizon:project:containers:index"
def delete(self, request, obj_id):
api.swift.swift_delete_container(request, obj_id)
[docs]
def get_success_url(self, request=None):
"""Returns the URL to redirect to after a successful action.
[docs] """
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"
[docs] verbose_name = _("Create Container")
url = "horizon:project:containers:create"
classes = ("ajax-modal", "btn-create")
class ListObjects(tables.LinkAction):
name = "list_objects"
[docs] verbose_name = _("View Container")
url = "horizon:project:containers:index"
classes = ("btn-list",)
def get_link_url(self, datum=None):
container_name = http.urlquote(datum.name)
[docs] args = (wrap_delimiter(container_name),)
return reverse(self.url, args=args)
class CreatePseudoFolder(tables.LinkAction):
name = "create_pseudo_folder"
[docs] 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
[docs] 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):
[docs] return True
return False
def update(self, request, obj):
# This will only be called for the row, so we can remove the button
[docs] # styles meant for the table action version.
self.attrs = {'class': 'ajax-modal'}
class UploadObject(tables.LinkAction):
name = "upload"
[docs] verbose_name = _("Upload Object")
url = "horizon:project:containers:object_upload"
classes = ("ajax-modal", "btn-upload")
def get_link_url(self, datum=None):
# Usable for both the container and object tables
[docs] if getattr(datum, 'container', datum):
# This is a container
container_name = http.urlquote(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 = (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):
[docs] return True
return False
def update(self, request, obj):
# This will only be called for the row, so we can remove the button
[docs] # styles meant for the table action version.
self.attrs = {'class': 'ajax-modal'}
def get_size_used(container):
return filters.filesizeformat(container.bytes)
[docs]
def get_container_link(container):
return reverse("horizon:project:containers:index",
[docs] args=(http.urlquote(wrap_delimiter(container.name)),))
class ContainerAjaxUpdateRow(tables.Row):
ajax = True
[docs]
def get_data(self, request, container_name):
container = api.swift.swift_get_container(request, container_name)
[docs] return container
def get_metadata(container):
# If the metadata has not been loading, display a loading image
[docs] (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,
verbose_name=_("Metadata Loaded"),
status=True,
status_choices=METADATA_LOADED_CHOICES,
hidden=True)
class Meta:
name = "containers"
[docs]
def get_absolute_url(self):
url = super(ContainersTable, self).get_absolute_url()
[docs] return http.urlquote(url)
class ViewObject(tables.LinkAction):
name = "view"
[docs] 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']
[docs] return reverse(self.url, args=(http.urlquote(container_name),
http.urlquote(obj.name)))
class DeleteObject(tables.DeleteAction):
name = "delete_object"
[docs] data_type_singular = _("Object")
data_type_plural = _("Objects")
allowed_data_types = ("objects",)
def delete(self, request, obj_id):
obj = self.table.get_object_by_id(obj_id)
[docs] container_name = obj.container_name
api.swift.swift_delete_object(request, container_name, obj_id)
def get_success_url(self, request):
url = super(DeleteObject, self).get_success_url(request)
[docs] return http.urlquote(url)
class DeleteMultipleObjects(DeleteObject):
name = "delete_multiple_objects"
[docs] data_type_singular = _("Object")
data_type_plural = _("Objects")
allowed_data_types = ("objects",)
class CopyObject(tables.LinkAction):
name = "copy"
[docs] verbose_name = _("Copy")
url = "horizon:project:containers:object_copy"
classes = ("ajax-modal", "btn-copy")
allowed_data_types = ("objects",)
def get_link_url(self, obj):
container_name = self.table.kwargs['container_name']
[docs] return reverse(self.url, args=(http.urlquote(container_name),
http.urlquote(obj.name)))
class DownloadObject(tables.LinkAction):
name = "download"
[docs] verbose_name = _("Download")
url = "horizon:project:containers:object_download"
classes = ("btn-download",)
allowed_data_types = ("objects",)
def get_link_url(self, obj):
container_name = self.table.kwargs['container_name']
[docs] return reverse(self.url, args=(http.urlquote(container_name),
http.urlquote(obj.name)))
class ObjectFilterAction(tables.FilterAction):
def _filtered_data(self, table, filter_string):
[docs] request = table.request
container = self.table.kwargs['container_name']
subfolder = self.table.kwargs['subfolder_path']
prefix = 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)
[docs] 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)
[docs] 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):
[docs] return True
return False
def sanitize_name(name):
return name.split(swift.FOLDER_DELIMITER)[-1]
[docs]
def get_size(obj):
if obj.bytes:
[docs] return filters.filesizeformat(obj.bytes)
def get_link_subfolder(subfolder):
container_name = subfolder.container_name
[docs] return reverse("horizon:project:containers:index",
args=(http.urlquote(wrap_delimiter(container_name)),
http.urlquote(wrap_delimiter(subfolder.name))))
class ObjectsTable(tables.DataTable):
name = tables.Column("name",
[docs] 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:
name = "objects"
[docs] return http.urlquote(url)