From 837b730407b580ead2d241050f8690ab5cbb9617 Mon Sep 17 00:00:00 2001 From: Johan Lundberg Date: Wed, 22 Oct 2014 16:56:23 +0200 Subject: Added storage report views. --- meetingtools/apps/auth/utils.py | 14 ++++++++- meetingtools/apps/content/views.py | 44 +++++++++++++++++++++++++- meetingtools/multiresponse.py | 64 +++++++++++++++++++++++++++++++++++++- meetingtools/urls.py | 5 ++- 4 files changed, 123 insertions(+), 4 deletions(-) diff --git a/meetingtools/apps/auth/utils.py b/meetingtools/apps/auth/utils.py index 0651eba..c792b4a 100644 --- a/meetingtools/apps/auth/utils.py +++ b/meetingtools/apps/auth/utils.py @@ -5,6 +5,8 @@ Created on Jul 7, 2010 """ from uuid import uuid4 +from django.conf import settings as django_settings + def nonce(): return uuid4().hex @@ -19,4 +21,14 @@ def groups(request): if request.user.is_authenticated(): groups = request.user.groups - return groups \ No newline at end of file + return groups + + +def report_auth(request): + auth_data = request.META.get('HTTP_X_REPORT_AUTH', None) + if auth_data and ':' in auth_data: + report_users = getattr(django_settings, 'REPORT_USERS') + requester, key = auth_data.split(':') + if report_users[requester]['key'] == key: + return report_users[requester] + return False \ No newline at end of file diff --git a/meetingtools/apps/content/views.py b/meetingtools/apps/content/views.py index bc8abb3..ceec589 100644 --- a/meetingtools/apps/content/views.py +++ b/meetingtools/apps/content/views.py @@ -5,12 +5,14 @@ from django.contrib.auth.decorators import login_required from django.db.models import Sum from django.http import HttpResponseForbidden from django.core.cache import cache -from meetingtools.multiresponse import respond_to +from django.template.defaultfilters import filesizeformat from django.shortcuts import get_object_or_404 from tagging.models import Tag +from meetingtools.multiresponse import respond_to, dicts_to_csv_response from meetingtools.apps.content.models import Content from meetingtools.apps.cluster.models import ACCluster from meetingtools.apps.content import tasks +from meetingtools.apps.auth.utils import report_auth @login_required @@ -66,3 +68,43 @@ def domain(request, domain_name): return respond_to(request, {'text/html': 'apps/content/domain.html'}, {'domain': domain_name, 'total_bytecount': total_bytecount, 'total_files': total_files, 'users': users}) + + +def cluster_report(request, cluster_name): + requester = report_auth(request) + if requester and cluster_name in requester['clusters']: + data = [] + acc = get_object_or_404(ACCluster, name=cluster_name) + domains, total_bytecount = tasks.get_cluster_content(acc) + for item in domains: + value = float(item['domain_bytes']) + max_value = float(total_bytecount) + percent = (value / max_value) * 100 + data.append({ + 'domain': item['domain'], + 'number_of_files': item['number_of_files'], + 'storage_used': filesizeformat(item['domain_bytes']), + 'percent': '{:0.2g}%'.format(percent) + }) + return dicts_to_csv_response(data, header=['domain', 'number_of_files', 'storage_used', 'percent']) + return HttpResponseForbidden() + + +def domain_report(request, domain_name): + requester = report_auth(request) + if requester and (domain_name in requester['domains'] or '*' in requester['domains']): + data = [] + domain_tag = get_object_or_404(Tag, name='domain:%s' % domain_name) + users, total_files, total_bytecount = tasks.get_domain_content(domain_tag) + for item in users: + value = float(item['bytecount']) + max_value = float(total_bytecount) + percent = (value / max_value) * 100 + data.append({ + 'username': item['username'], + 'number_of_files': item['number_of_files'], + 'storage_used': filesizeformat(item['bytecount']), + 'percent': '{:0.2g}%'.format(percent) + }) + return dicts_to_csv_response(data, header=['username', 'number_of_files', 'storage_used', 'percent']) + return HttpResponseForbidden() \ No newline at end of file diff --git a/meetingtools/multiresponse.py b/meetingtools/multiresponse.py index 1510760..f4784ba 100644 --- a/meetingtools/multiresponse.py +++ b/meetingtools/multiresponse.py @@ -1,6 +1,9 @@ from meetingtools import context_processors import meetingtools.mimeparse as mimeparse import re +import csv +import codecs +import cStringIO import rfc822 from django.conf import settings from django.shortcuts import render_to_response @@ -15,6 +18,37 @@ default_suffix_mapping = {"\.htm(l?)$": "text/html", "\.atom$": "application/atom+xml", "\.torrent$": "application/x-bittorrent"} + +class UnicodeCSVWriter: + """ + A CSV writer which will write rows to CSV file "f", + which is encoded in the given encoding. + """ + + def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds): + # Redirect output to a queue + self.queue = cStringIO.StringIO() + self.writer = csv.writer(self.queue, dialect=dialect, **kwds) + self.stream = f + self.encoder = codecs.getincrementalencoder(encoding)() + + def writerow(self, row): + self.writer.writerow([s.encode("utf-8") for s in row]) + # Fetch UTF-8 output from the queue ... + data = self.queue.getvalue() + data = data.decode("utf-8") + # ... and reencode it into the target encoding + data = self.encoder.encode(data) + # write to the target stream + self.stream.write(data) + # empty queue + self.queue.truncate(0) + + def writerows(self, rows): + for row in rows: + self.writerow(row) + + def _accept_types(request, suffix): for r in suffix.keys(): p = re.compile(r) @@ -45,9 +79,37 @@ def json_response(data,request=None): r = HttpResponse(response_data,content_type='application/json') r['Cache-Control'] = 'no-cache, must-revalidate' r['Pragma'] = 'no-cache' - return r + +def dicts_to_csv_response(dict_list, header=None): + """ + Takes a list of dicts and returns a comma separated file with all dict keys + and their values. + """ + # Create the HttpResponse object with the appropriate CSV header. + response = HttpResponse(mimetype='text/csv') + response['Content-Disposition'] = 'attachment; filename=result.csv; charset=utf-8;' + writer = UnicodeCSVWriter(response, delimiter=',', quoting=csv.QUOTE_NONNUMERIC) + if not header: + key_set = set() + for item in dict_list: + key_set.update(item.keys()) + key_set = sorted(key_set) + else: + key_set = header + writer.writerow(key_set) # Line collection with header + for item in dict_list: + line = [] + for key in key_set: + try: + line.append('%s' % item[key]) + except KeyError: + line.append('') # Node did not have that key, add a blank item. + writer.writerow(line) + return response + + def render500(request): return render_to_response("500.html",RequestContext(request,{},[context_processors.misc_urls])) diff --git a/meetingtools/urls.py b/meetingtools/urls.py index 925783e..d84f68f 100644 --- a/meetingtools/urls.py +++ b/meetingtools/urls.py @@ -63,6 +63,9 @@ urlpatterns = patterns('', (r'^stats/room/(\d+)$','meetingtools.apps.stats.views.room'), (r'^content$', 'meetingtools.apps.content.views.user'), (r'^content/cluster/$', 'meetingtools.apps.content.views.cluster'), + (r'^content/cluster/(?P[\w ]+)/report$', 'meetingtools.apps.content.views.cluster_report'), + (r'^content/domain/(?P[\w\.;]+)/report$', 'meetingtools.apps.content.views.domain_report'), (r'^content/cluster/(?P[\w ]+)$', 'meetingtools.apps.content.views.cluster'), - (r'^content/domain/(?P[\w\.;]+)$', 'meetingtools.apps.content.views.domain') + (r'^content/domain/(?P[\w\.;]+)$', 'meetingtools.apps.content.views.domain'), + ) -- cgit v1.1