From 33b70476b3deb660d6808ed45eea327688a7e87a Mon Sep 17 00:00:00 2001 From: Lucas Lavandeira <19612265+lucaslavandeira@users.noreply.github.com> Date: Fri, 16 Feb 2018 12:23:49 -0300 Subject: [PATCH 1/8] =?UTF-8?q?Renombro=20m=C3=B3dulo=20de=20tasks=20async?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- series_tiempo_ar_api/apps/analytics/{analytics.py => tasks.py} | 0 series_tiempo_ar_api/apps/analytics/tests.py | 2 +- series_tiempo_ar_api/apps/analytics/views.py | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename series_tiempo_ar_api/apps/analytics/{analytics.py => tasks.py} (100%) diff --git a/series_tiempo_ar_api/apps/analytics/analytics.py b/series_tiempo_ar_api/apps/analytics/tasks.py similarity index 100% rename from series_tiempo_ar_api/apps/analytics/analytics.py rename to series_tiempo_ar_api/apps/analytics/tasks.py diff --git a/series_tiempo_ar_api/apps/analytics/tests.py b/series_tiempo_ar_api/apps/analytics/tests.py index e780bcd8..dfcd3e5f 100644 --- a/series_tiempo_ar_api/apps/analytics/tests.py +++ b/series_tiempo_ar_api/apps/analytics/tests.py @@ -4,7 +4,7 @@ from django.test import TestCase from django.urls import reverse -from .analytics import analytics +from .tasks import analytics from .models import Query from .utils import kong_milliseconds_to_tzdatetime diff --git a/series_tiempo_ar_api/apps/analytics/views.py b/series_tiempo_ar_api/apps/analytics/views.py index 6abcc74a..9734097b 100644 --- a/series_tiempo_ar_api/apps/analytics/views.py +++ b/series_tiempo_ar_api/apps/analytics/views.py @@ -6,7 +6,7 @@ from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt -from .analytics import analytics +from .tasks import analytics @csrf_exempt From b8ac08e2de883c4d09ae14e3c20605b18b9637bd Mon Sep 17 00:00:00 2001 From: Lucas Lavandeira <19612265+lucaslavandeira@users.noreply.github.com> Date: Fri, 16 Feb 2018 14:25:31 -0300 Subject: [PATCH 2/8] =?UTF-8?q?Agrego=20acci=C3=B3n=20para=20exportar=20an?= =?UTF-8?q?alytics=20a=20CSV?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 + protected/.gitkeep | 0 series_tiempo_ar_api/apps/analytics/admin.py | 6 ++++++ series_tiempo_ar_api/apps/analytics/tasks.py | 14 ++++++++++++++ 4 files changed, 21 insertions(+) create mode 100644 protected/.gitkeep diff --git a/.gitignore b/.gitignore index e6ba32ca..05828577 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ coverage.xml #Media media/* +protected/* #Autoenv files .autoenv.zsh diff --git a/protected/.gitkeep b/protected/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/series_tiempo_ar_api/apps/analytics/admin.py b/series_tiempo_ar_api/apps/analytics/admin.py index 3581b3db..a8c568b2 100644 --- a/series_tiempo_ar_api/apps/analytics/admin.py +++ b/series_tiempo_ar_api/apps/analytics/admin.py @@ -6,6 +6,7 @@ from import_export.admin import ImportExportModelAdmin from series_tiempo_ar_api.apps.analytics.models import Query +from .tasks import export class QueryResource(resources.ModelResource): @@ -25,6 +26,11 @@ class QueryAdmin(ImportExportModelAdmin): search_fields = ('timestamp', 'params', 'ip_address', 'args', 'ids') resource_class = QueryResource + actions = ('export_analytics', ) + + def export_analytics(self, *_): + export.delay() + export_analytics.short_description = "Export analytics" admin.site.register(Query, QueryAdmin) diff --git a/series_tiempo_ar_api/apps/analytics/tasks.py b/series_tiempo_ar_api/apps/analytics/tasks.py index d9ddee02..2e9901ab 100644 --- a/series_tiempo_ar_api/apps/analytics/tasks.py +++ b/series_tiempo_ar_api/apps/analytics/tasks.py @@ -1,6 +1,7 @@ #! coding: utf-8 import json +import unicodecsv from django_rq import job from .models import Query @@ -13,3 +14,16 @@ def analytics(ids, args_string, ip_address, params, timestamp_milliseconds): timestamp = kong_milliseconds_to_tzdatetime(timestamp_milliseconds) query = Query(ids=ids, args=args_string, ip_address=ip_address, params=params_json, timestamp=timestamp) query.save() + + +@job("default") +def export(): + queryset = Query.objects.all() + with open('protected/analytics.csv', 'wb') as f: + writer = unicodecsv.writer(f) + + # header + writer.writerow(['timestamp', 'ip_address', 'ids', 'params']) + for query in queryset.iterator(): + + writer.writerow([query.timestamp, query.ip_address, query.ids, query.params]) From 3a8868a2ea59b49f5ee880b4d5e6aa7177912518 Mon Sep 17 00:00:00 2001 From: Lucas Lavandeira <19612265+lucaslavandeira@users.noreply.github.com> Date: Fri, 16 Feb 2018 15:03:54 -0300 Subject: [PATCH 3/8] Agrego django-sendfile y un endpoint para descargar el dump de analytics --- conf/settings/base.py | 7 +++++-- conf/settings/local_example.py | 2 ++ requirements/base.txt | 2 +- series_tiempo_ar_api/apps/analytics/admin.py | 16 +--------------- series_tiempo_ar_api/apps/analytics/tasks.py | 18 ++++++++++++++---- series_tiempo_ar_api/apps/analytics/urls.py | 6 +++--- series_tiempo_ar_api/apps/analytics/views.py | 12 +++++++++++- 7 files changed, 37 insertions(+), 26 deletions(-) diff --git a/conf/settings/base.py b/conf/settings/base.py index 0df23535..79fb972e 100644 --- a/conf/settings/base.py +++ b/conf/settings/base.py @@ -151,7 +151,7 @@ VENDOR_APPS = ( "django_rq", - 'import_export', + 'sendfile', 'des' ) @@ -290,4 +290,7 @@ ENV_TYPE = env('ENV_TYPE', default='') # Tarea a ser croneada para indexación -READ_DATAJSON_SHELL_CMD = env('READ_DATAJSON_BIN_PATH', default='') \ No newline at end of file +READ_DATAJSON_SHELL_CMD = env('READ_DATAJSON_BIN_PATH', default='') + +PROTECTED_MEDIA_DIR = ROOT_DIR('protected') +ANALYTICS_CSV_FILENAME = 'analytics.csv' diff --git a/conf/settings/local_example.py b/conf/settings/local_example.py index 431e6558..684f9a21 100644 --- a/conf/settings/local_example.py +++ b/conf/settings/local_example.py @@ -17,3 +17,5 @@ 'PASSWORD': env('DATABASE_PASSWORD'), } } + +SENDFILE_BACKEND = 'sendfile.backends.development' diff --git a/requirements/base.txt b/requirements/base.txt index 26c819c1..1e97cf6a 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -12,6 +12,6 @@ numpy django-rq==1.0.0 pyyaml django-ipware==1.1.6 -django-import-export==0.5.1 +django-sendfile==0.3.11 python-crontab==2.2.8 django-des==2.2.0 diff --git a/series_tiempo_ar_api/apps/analytics/admin.py b/series_tiempo_ar_api/apps/analytics/admin.py index a8c568b2..0fb4c838 100644 --- a/series_tiempo_ar_api/apps/analytics/admin.py +++ b/series_tiempo_ar_api/apps/analytics/admin.py @@ -1,31 +1,17 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals -from import_export import resources from django.contrib import admin -from import_export.admin import ImportExportModelAdmin from series_tiempo_ar_api.apps.analytics.models import Query from .tasks import export -class QueryResource(resources.ModelResource): - class Meta: - model = Query - fields = export_order = ( - 'timestamp', - 'ip_address', - 'ids', - 'params', - ) - - -class QueryAdmin(ImportExportModelAdmin): +class QueryAdmin(admin.ModelAdmin): list_display = ('timestamp', 'params',) readonly_fields = ('timestamp', 'params', 'ip_address', 'args', 'ids') search_fields = ('timestamp', 'params', 'ip_address', 'args', 'ids') - resource_class = QueryResource actions = ('export_analytics', ) def export_analytics(self, *_): diff --git a/series_tiempo_ar_api/apps/analytics/tasks.py b/series_tiempo_ar_api/apps/analytics/tasks.py index 2e9901ab..8da51166 100644 --- a/series_tiempo_ar_api/apps/analytics/tasks.py +++ b/series_tiempo_ar_api/apps/analytics/tasks.py @@ -1,7 +1,9 @@ #! coding: utf-8 +import os import json import unicodecsv +from django.conf import settings from django_rq import job from .models import Query @@ -19,11 +21,19 @@ def analytics(ids, args_string, ip_address, params, timestamp_milliseconds): @job("default") def export(): queryset = Query.objects.all() - with open('protected/analytics.csv', 'wb') as f: - writer = unicodecsv.writer(f) + filepath = os.path.join(settings.PROTECTED_MEDIA_DIR, settings.ANALYTICS_CSV_FILENAME) + + fields = [ + Query.timestamp, + Query.ip_address, + Query.ids, + Query.params + ] + with open(filepath, 'wb') as f: + writer = unicodecsv.writer(f) # header - writer.writerow(['timestamp', 'ip_address', 'ids', 'params']) + writer.writerow([field.field_name for field in fields]) for query in queryset.iterator(): - writer.writerow([query.timestamp, query.ip_address, query.ids, query.params]) + writer.writerow([getattr(query, field.field_name) for field in fields]) diff --git a/series_tiempo_ar_api/apps/analytics/urls.py b/series_tiempo_ar_api/apps/analytics/urls.py index ff53df4f..3b239927 100644 --- a/series_tiempo_ar_api/apps/analytics/urls.py +++ b/series_tiempo_ar_api/apps/analytics/urls.py @@ -1,7 +1,7 @@ from django.conf.urls import url - -from .views import save +from .views import save, read_analytics urlpatterns = [ - url('^save/$', save, name='save') + url('^save/$', save, name='save'), + url('^analytics.csv', read_analytics, name='read_analytics'), ] diff --git a/series_tiempo_ar_api/apps/analytics/views.py b/series_tiempo_ar_api/apps/analytics/views.py index 9734097b..f5446e67 100644 --- a/series_tiempo_ar_api/apps/analytics/views.py +++ b/series_tiempo_ar_api/apps/analytics/views.py @@ -1,9 +1,12 @@ # -*- coding: utf-8 -*- from __future__ import unicode_literals +import os import json -from django.http import HttpResponse +import sendfile +from django.http import HttpResponse, Http404 +from django.conf import settings from django.views.decorators.csrf import csrf_exempt from .tasks import analytics @@ -33,3 +36,10 @@ def save(request): args = args[params_start:] analytics.delay(ids, args, ip_address, params, timestamp) return HttpResponse() + + +def read_analytics(request): + if not request.user.is_staff: + raise Http404 + + return sendfile.sendfile(request, os.path.join(settings.PROTECTED_MEDIA_DIR, 'analytics.csv')) From 58fe940beb2938789964e42117f42af43706aa06 Mon Sep 17 00:00:00 2001 From: Lucas Lavandeira <19612265+lucaslavandeira@users.noreply.github.com> Date: Mon, 19 Feb 2018 10:08:11 -0300 Subject: [PATCH 4/8] =?UTF-8?q?Muevo=20la=20acci=C3=B3n=20de=20exportar=20?= =?UTF-8?q?a=20un=20bot=C3=B3n=20fuera=20de=20las=20acciones?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- series_tiempo_ar_api/apps/analytics/admin.py | 8 +------ .../admin/analytics/change_list.html | 7 +++++++ .../apps/analytics/templates/export.html | 21 +++++++++++++++++++ series_tiempo_ar_api/apps/analytics/urls.py | 3 ++- series_tiempo_ar_api/apps/analytics/views.py | 11 +++++++++- 5 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 series_tiempo_ar_api/apps/analytics/templates/admin/analytics/change_list.html create mode 100644 series_tiempo_ar_api/apps/analytics/templates/export.html diff --git a/series_tiempo_ar_api/apps/analytics/admin.py b/series_tiempo_ar_api/apps/analytics/admin.py index 0fb4c838..e5238c1a 100644 --- a/series_tiempo_ar_api/apps/analytics/admin.py +++ b/series_tiempo_ar_api/apps/analytics/admin.py @@ -4,19 +4,13 @@ from django.contrib import admin from series_tiempo_ar_api.apps.analytics.models import Query -from .tasks import export class QueryAdmin(admin.ModelAdmin): - list_display = ('timestamp', 'params',) + list_display = ('timestamp', 'ip_address', 'params',) readonly_fields = ('timestamp', 'params', 'ip_address', 'args', 'ids') search_fields = ('timestamp', 'params', 'ip_address', 'args', 'ids') - actions = ('export_analytics', ) - - def export_analytics(self, *_): - export.delay() - export_analytics.short_description = "Export analytics" admin.site.register(Query, QueryAdmin) diff --git a/series_tiempo_ar_api/apps/analytics/templates/admin/analytics/change_list.html b/series_tiempo_ar_api/apps/analytics/templates/admin/analytics/change_list.html new file mode 100644 index 00000000..0e1762f5 --- /dev/null +++ b/series_tiempo_ar_api/apps/analytics/templates/admin/analytics/change_list.html @@ -0,0 +1,7 @@ +{% extends "admin/change_list.html" %} + +{% block object-tools-items %} +
  • EXPORT TO CSV
  • + {{ block.super }} + +{% endblock %} diff --git a/series_tiempo_ar_api/apps/analytics/templates/export.html b/series_tiempo_ar_api/apps/analytics/templates/export.html new file mode 100644 index 00000000..7f62b56e --- /dev/null +++ b/series_tiempo_ar_api/apps/analytics/templates/export.html @@ -0,0 +1,21 @@ + + + + + Export + + + +

    OK! En unos segundos el link de descarga ({% url 'analytics:read_analytics' %}) estará actualizado.

    +

    Redirecting in 5 seconds...

    + + + \ No newline at end of file diff --git a/series_tiempo_ar_api/apps/analytics/urls.py b/series_tiempo_ar_api/apps/analytics/urls.py index 3b239927..b08434e9 100644 --- a/series_tiempo_ar_api/apps/analytics/urls.py +++ b/series_tiempo_ar_api/apps/analytics/urls.py @@ -1,7 +1,8 @@ from django.conf.urls import url -from .views import save, read_analytics +from .views import save, read_analytics, export_analytics urlpatterns = [ url('^save/$', save, name='save'), url('^analytics.csv', read_analytics, name='read_analytics'), + url('^export', export_analytics, name='export_analytics'), ] diff --git a/series_tiempo_ar_api/apps/analytics/views.py b/series_tiempo_ar_api/apps/analytics/views.py index f5446e67..5dcbb8f3 100644 --- a/series_tiempo_ar_api/apps/analytics/views.py +++ b/series_tiempo_ar_api/apps/analytics/views.py @@ -8,8 +8,9 @@ from django.http import HttpResponse, Http404 from django.conf import settings from django.views.decorators.csrf import csrf_exempt +from django.shortcuts import render -from .tasks import analytics +from .tasks import analytics, export @csrf_exempt @@ -43,3 +44,11 @@ def read_analytics(request): raise Http404 return sendfile.sendfile(request, os.path.join(settings.PROTECTED_MEDIA_DIR, 'analytics.csv')) + + +def export_analytics(request): + if not request.user.is_staff: + raise Http404 + + export.delay() + return HttpResponse(render(request, 'export.html')) From 09d26bc228b1be1dc9411dac494380778c998f8a Mon Sep 17 00:00:00 2001 From: Lucas Lavandeira <19612265+lucaslavandeira@users.noreply.github.com> Date: Mon, 19 Feb 2018 11:11:55 -0300 Subject: [PATCH 5/8] =?UTF-8?q?Agrego=20casos=20de=20prueba=20a=20la=20exp?= =?UTF-8?q?ortaci=C3=B3n=20de=20analytics?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- series_tiempo_ar_api/apps/analytics/tasks.py | 4 +- .../apps/analytics/tests/__init__.py | 1 + .../apps/analytics/tests/export_tests.py | 32 ++++++++++++ .../tests/samples/sample_analytics_dump.csv | 2 + .../apps/analytics/{ => tests}/tests.py | 6 +-- .../apps/analytics/tests/view_tests.py | 50 +++++++++++++++++++ 6 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 series_tiempo_ar_api/apps/analytics/tests/__init__.py create mode 100644 series_tiempo_ar_api/apps/analytics/tests/export_tests.py create mode 100644 series_tiempo_ar_api/apps/analytics/tests/samples/sample_analytics_dump.csv rename series_tiempo_ar_api/apps/analytics/{ => tests}/tests.py (90%) create mode 100644 series_tiempo_ar_api/apps/analytics/tests/view_tests.py diff --git a/series_tiempo_ar_api/apps/analytics/tasks.py b/series_tiempo_ar_api/apps/analytics/tasks.py index 8da51166..51020d4c 100644 --- a/series_tiempo_ar_api/apps/analytics/tasks.py +++ b/series_tiempo_ar_api/apps/analytics/tasks.py @@ -19,9 +19,9 @@ def analytics(ids, args_string, ip_address, params, timestamp_milliseconds): @job("default") -def export(): +def export(path=None): queryset = Query.objects.all() - filepath = os.path.join(settings.PROTECTED_MEDIA_DIR, settings.ANALYTICS_CSV_FILENAME) + filepath = path or os.path.join(settings.PROTECTED_MEDIA_DIR, settings.ANALYTICS_CSV_FILENAME) fields = [ Query.timestamp, diff --git a/series_tiempo_ar_api/apps/analytics/tests/__init__.py b/series_tiempo_ar_api/apps/analytics/tests/__init__.py new file mode 100644 index 00000000..f7c9f9dc --- /dev/null +++ b/series_tiempo_ar_api/apps/analytics/tests/__init__.py @@ -0,0 +1 @@ +#!coding=utf8 diff --git a/series_tiempo_ar_api/apps/analytics/tests/export_tests.py b/series_tiempo_ar_api/apps/analytics/tests/export_tests.py new file mode 100644 index 00000000..aa42f100 --- /dev/null +++ b/series_tiempo_ar_api/apps/analytics/tests/export_tests.py @@ -0,0 +1,32 @@ +#!coding=utf8 +import os + +from django.test import TestCase +from django.utils import timezone + +from series_tiempo_ar_api.apps.analytics.models import Query +from series_tiempo_ar_api.apps.analytics.tasks import export + + +class ExportTests(TestCase): + + filepath = 'test' + + def test_export(self): + Query(args='test', params='test', ip_address='ip_addr', timestamp=timezone.now(), ids='').save() + + export(path=self.filepath) + + with open(self.filepath) as f: + self.assertEqual(len(f.readlines()), 2) + + def test_export_empty(self): + export(path=self.filepath) + + with open(self.filepath) as f: + # Esperado solo una línea de header + self.assertEqual(len(f.readlines()), 1) + + def tearDown(self): + if os.path.exists(self.filepath): + os.remove(self.filepath) diff --git a/series_tiempo_ar_api/apps/analytics/tests/samples/sample_analytics_dump.csv b/series_tiempo_ar_api/apps/analytics/tests/samples/sample_analytics_dump.csv new file mode 100644 index 00000000..7b371c17 --- /dev/null +++ b/series_tiempo_ar_api/apps/analytics/tests/samples/sample_analytics_dump.csv @@ -0,0 +1,2 @@ +timestamp,ip_address,ids,params +2018-02-16 16:59:04.275899+00:00,huh,test,params diff --git a/series_tiempo_ar_api/apps/analytics/tests.py b/series_tiempo_ar_api/apps/analytics/tests/tests.py similarity index 90% rename from series_tiempo_ar_api/apps/analytics/tests.py rename to series_tiempo_ar_api/apps/analytics/tests/tests.py index dfcd3e5f..42f80f0a 100644 --- a/series_tiempo_ar_api/apps/analytics/tests.py +++ b/series_tiempo_ar_api/apps/analytics/tests/tests.py @@ -4,9 +4,9 @@ from django.test import TestCase from django.urls import reverse -from .tasks import analytics -from .models import Query -from .utils import kong_milliseconds_to_tzdatetime +from series_tiempo_ar_api.apps.analytics.tasks import analytics +from series_tiempo_ar_api.apps.analytics.models import Query +from series_tiempo_ar_api.apps.analytics.utils import kong_milliseconds_to_tzdatetime class AnalyticsTests(TestCase): diff --git a/series_tiempo_ar_api/apps/analytics/tests/view_tests.py b/series_tiempo_ar_api/apps/analytics/tests/view_tests.py new file mode 100644 index 00000000..54691314 --- /dev/null +++ b/series_tiempo_ar_api/apps/analytics/tests/view_tests.py @@ -0,0 +1,50 @@ +#!coding=utf8 +import os +import mock + +import sendfile +from django.http import FileResponse +from django.test import TestCase +from django.urls import reverse +from django.contrib.auth.models import User + +samples_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'samples') + + +class ExportViewTests(TestCase): + + def test_export_when_not_staff(self): + response = self.client.get(reverse('analytics:export_analytics')) + + self.assertEqual(response.status_code, 404) + + def test_export_as_staff(self): + user = User(username='user', password='pass', email='mail@test.com', is_staff=True) + user.save() + self.client.force_login(user) + response = self.client.get(reverse('analytics:export_analytics')) + + self.assertEqual(response.status_code, 200) + + +class AnalyticsDownloadTests(TestCase): + + def test_download_when_not_staff(self): + response = self.client.get(reverse('analytics:read_analytics')) + + self.assertEqual(response.status_code, 404) + + def test_download_as_staff(self): + user = User(username='user', password='pass', email='mail@test.com', is_staff=True) + user.save() + self.client.force_login(user) + + response_file = open(os.path.join(samples_dir, 'sample_analytics_dump.csv')) + sendfile.sendfile = mock.Mock(return_value=FileResponse(response_file)) + response = self.client.get(reverse('analytics:read_analytics')) + + self.assertEqual(response.status_code, 200) + + with open(os.path.join(samples_dir, 'sample_analytics_dump.csv')) as response_file: + response_content = list(response.streaming_content)[0] # Unwrap iterable + self.assertEqual(response_content, response_file.read()) From 33dd562e06d33a094737c9d5b9d8ab581f28c526 Mon Sep 17 00:00:00 2001 From: Lucas Lavandeira <19612265+lucaslavandeira@users.noreply.github.com> Date: Mon, 19 Feb 2018 11:48:33 -0300 Subject: [PATCH 6/8] Agrego config de staging/prod para sendfile --- conf/settings/production.py | 4 ++++ conf/settings/staging.py | 3 +++ 2 files changed, 7 insertions(+) diff --git a/conf/settings/production.py b/conf/settings/production.py index 5de7c48b..b771293c 100644 --- a/conf/settings/production.py +++ b/conf/settings/production.py @@ -40,3 +40,7 @@ } INSTALLED_APPS += 'raven.contrib.django.raven_compat', + +SENDFILE_BACKEND = 'sendfile.backends.nginx' +SENDFILE_ROOT = PROTECTED_MEDIA_DIR +SENDFILE_URL = env('PROTECTED_INTERNAL_URL', default='/protected') diff --git a/conf/settings/staging.py b/conf/settings/staging.py index c05f6c34..c9f2ef21 100644 --- a/conf/settings/staging.py +++ b/conf/settings/staging.py @@ -37,3 +37,6 @@ } INSTALLED_APPS = INSTALLED_APPS + ('raven.contrib.django.raven_compat',) +SENDFILE_BACKEND = 'sendfile.backends.nginx' +SENDFILE_ROOT = PROTECTED_MEDIA_DIR +SENDFILE_URL = env('PROTECTED_INTERNAL_URL', default='/protected') From e4209ca619f504a98461234a6d86bc1d080cc1f4 Mon Sep 17 00:00:00 2001 From: Lucas Lavandeira <19612265+lucaslavandeira@users.noreply.github.com> Date: Mon, 19 Feb 2018 14:24:38 -0300 Subject: [PATCH 7/8] Uso decorators de django para authentication --- series_tiempo_ar_api/apps/analytics/tests/view_tests.py | 6 ++++-- series_tiempo_ar_api/apps/analytics/views.py | 9 +++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/series_tiempo_ar_api/apps/analytics/tests/view_tests.py b/series_tiempo_ar_api/apps/analytics/tests/view_tests.py index 54691314..0515c359 100644 --- a/series_tiempo_ar_api/apps/analytics/tests/view_tests.py +++ b/series_tiempo_ar_api/apps/analytics/tests/view_tests.py @@ -16,7 +16,8 @@ class ExportViewTests(TestCase): def test_export_when_not_staff(self): response = self.client.get(reverse('analytics:export_analytics')) - self.assertEqual(response.status_code, 404) + # Expected: admin login redirect + self.assertEqual(response.status_code, 302) def test_export_as_staff(self): user = User(username='user', password='pass', email='mail@test.com', is_staff=True) @@ -32,7 +33,8 @@ class AnalyticsDownloadTests(TestCase): def test_download_when_not_staff(self): response = self.client.get(reverse('analytics:read_analytics')) - self.assertEqual(response.status_code, 404) + # Expected: admin login redirect + self.assertEqual(response.status_code, 302) def test_download_as_staff(self): user = User(username='user', password='pass', email='mail@test.com', is_staff=True) diff --git a/series_tiempo_ar_api/apps/analytics/views.py b/series_tiempo_ar_api/apps/analytics/views.py index 176149d3..e51ed966 100644 --- a/series_tiempo_ar_api/apps/analytics/views.py +++ b/series_tiempo_ar_api/apps/analytics/views.py @@ -8,6 +8,7 @@ from django.http import HttpResponse, Http404 from django.conf import settings from django.views.decorators.csrf import csrf_exempt +from django.contrib.admin.views.decorators import staff_member_required from django.shortcuts import render from .tasks import analytics, export @@ -40,16 +41,12 @@ def save(request): return HttpResponse() +@staff_member_required def read_analytics(request): - if not request.user.is_staff: - raise Http404 - return sendfile.sendfile(request, os.path.join(settings.PROTECTED_MEDIA_DIR, 'analytics.csv')) +@staff_member_required def export_analytics(request): - if not request.user.is_staff: - raise Http404 - export.delay() return HttpResponse(render(request, 'export.html')) From 811f0cb523e726f3fe0c8a1d200520530b0d87ea Mon Sep 17 00:00:00 2001 From: Lucas Lavandeira <19612265+lucaslavandeira@users.noreply.github.com> Date: Mon, 19 Feb 2018 14:25:29 -0300 Subject: [PATCH 8/8] Borro import no usado --- series_tiempo_ar_api/apps/analytics/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/series_tiempo_ar_api/apps/analytics/views.py b/series_tiempo_ar_api/apps/analytics/views.py index e51ed966..2e329dd0 100644 --- a/series_tiempo_ar_api/apps/analytics/views.py +++ b/series_tiempo_ar_api/apps/analytics/views.py @@ -5,7 +5,7 @@ import json import sendfile -from django.http import HttpResponse, Http404 +from django.http import HttpResponse from django.conf import settings from django.views.decorators.csrf import csrf_exempt from django.contrib.admin.views.decorators import staff_member_required