OpenStack Dashboard (Horizon)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

tables.py 6.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. # vim: tabstop=4 shiftwidth=4 softtabstop=4
  2. # Copyright 2012 Nebula, Inc.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. import logging
  16. from cloudfiles.errors import ContainerNotEmpty
  17. from django import shortcuts
  18. from django.contrib import messages
  19. from django.core.urlresolvers import reverse
  20. from django.template.defaultfilters import filesizeformat
  21. from django.utils import http
  22. from django.utils.translation import ugettext as _
  23. from horizon import api
  24. from horizon import exceptions
  25. from horizon import tables
  26. LOG = logging.getLogger(__name__)
  27. class DeleteContainer(tables.Action):
  28. name = "delete"
  29. verbose_name = _("Delete")
  30. verbose_name_plural = _("Delete Containers")
  31. classes = ('btn-danger',)
  32. def handle(self, table, request, object_ids):
  33. deleted = []
  34. for obj_id in object_ids:
  35. obj = table.get_object_by_id(obj_id)
  36. try:
  37. api.swift_delete_container(request, obj_id)
  38. deleted.append(obj)
  39. except ContainerNotEmpty:
  40. LOG.exception('Unable to delete container "%s".' % obj.name)
  41. messages.error(request,
  42. _('Unable to delete non-empty container: %s') %
  43. obj.name)
  44. if deleted:
  45. messages.success(request,
  46. _('Successfully deleted containers: %s')
  47. % ", ".join([obj.name for obj in deleted]))
  48. return shortcuts.redirect('horizon:nova:containers:index')
  49. class CreateContainer(tables.LinkAction):
  50. name = "create"
  51. verbose_name = _("Create Container")
  52. url = "horizon:nova:containers:create"
  53. classes = ("ajax-modal",)
  54. class ListObjects(tables.LinkAction):
  55. name = "list_objects"
  56. verbose_name = _("List Objects")
  57. url = "horizon:nova:containers:object_index"
  58. class UploadObject(tables.LinkAction):
  59. name = "upload"
  60. verbose_name = _("Upload Object")
  61. url = "horizon:nova:containers:object_upload"
  62. classes = ("ajax-modal",)
  63. def get_link_url(self, datum=None):
  64. # Usable for both the container and object tables
  65. if getattr(datum, 'container', datum):
  66. # This is an Container
  67. container_name = http.urlquote(datum.name)
  68. else:
  69. # This is a table action and we already have the container name
  70. container_name = self.table.kwargs['container_name']
  71. return reverse(self.url, args=(container_name,))
  72. def update(self, request, obj):
  73. # This will only be called for the row, so we can remove the button
  74. # styles meant for the table action version.
  75. self.attrs = {'class': 'ajax-modal'}
  76. def get_size_used(container):
  77. return filesizeformat(container.size_used)
  78. class ContainersTable(tables.DataTable):
  79. name = tables.Column("name", link='horizon:nova:containers:object_index')
  80. objects = tables.Column("object_count",
  81. verbose_name=_('Objects'),
  82. empty_value="0")
  83. size = tables.Column(get_size_used, verbose_name=_('Size'))
  84. def get_object_id(self, container):
  85. return container.name
  86. class Meta:
  87. name = "containers"
  88. verbose_name = _("Containers")
  89. table_actions = (CreateContainer, DeleteContainer)
  90. row_actions = (ListObjects, UploadObject, DeleteContainer)
  91. class DeleteObject(tables.Action):
  92. name = "delete"
  93. verbose_name = _("Delete")
  94. verbose_name_plural = _("Delete Objects")
  95. classes = ('btn-danger',)
  96. def handle(self, table, request, object_ids):
  97. deleted = []
  98. for obj_id in object_ids:
  99. obj = table.get_object_by_id(obj_id)
  100. container_name = obj.container.name
  101. try:
  102. api.swift_delete_object(request, container_name, obj_id)
  103. deleted.append(obj)
  104. except:
  105. exceptions.handle(request, _('Unable to delete object.'))
  106. if deleted:
  107. messages.success(request,
  108. _('Successfully deleted objects: %s')
  109. % ", ".join([obj.name for obj in deleted]))
  110. return shortcuts.redirect('horizon:nova:containers:object_index',
  111. table.kwargs['container_name'])
  112. class CopyObject(tables.LinkAction):
  113. name = "copy"
  114. verbose_name = _("Copy")
  115. url = "horizon:nova:containers:object_copy"
  116. attrs = {"class": "ajax-modal"}
  117. def get_link_url(self, obj):
  118. return reverse(self.url, args=(http.urlquote(obj.container.name),
  119. http.urlquote(obj.name)))
  120. class DownloadObject(tables.LinkAction):
  121. name = "download"
  122. verbose_name = _("Download")
  123. url = "horizon:nova:containers:object_download"
  124. def get_link_url(self, obj):
  125. #assert False, obj.__dict__['_apiresource'].__dict__
  126. return reverse(self.url, args=(http.urlquote(obj.container.name),
  127. http.urlquote(obj.name)))
  128. class ObjectFilterAction(tables.FilterAction):
  129. def filter(self, table, users, filter_string):
  130. """ Really naive case-insensitive search. """
  131. # FIXME(gabriel): This should be smarter. Written for demo purposes.
  132. q = filter_string.lower()
  133. def comp(user):
  134. if q in user.name.lower() or q in user.email.lower():
  135. return True
  136. return False
  137. return filter(comp, users)
  138. def get_size(obj):
  139. return filesizeformat(obj.size)
  140. class ObjectsTable(tables.DataTable):
  141. name = tables.Column("name")
  142. size = tables.Column(get_size, verbose_name=_('Size'))
  143. def get_object_id(self, obj):
  144. return obj.name
  145. class Meta:
  146. name = "objects"
  147. verbose_name = _("Objects")
  148. table_actions = (ObjectFilterAction, UploadObject, DeleteObject)
  149. row_actions = (DownloadObject, CopyObject, DeleteObject)