From 829498aacc20b87d81ec9eae1f3b2ff8f777ab19 Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Fri, 16 Oct 2020 13:41:17 -0300 Subject: [PATCH 01/12] Cria estrutura para redirects --- brasilio/settings.py | 1 + traffic_control/handlers.py | 7 ++++++- traffic_control/middlewares.py | 9 +++++++++ traffic_control/tests/test_middlewares.py | 11 +++++++++++ 4 files changed, 27 insertions(+), 1 deletion(-) diff --git a/brasilio/settings.py b/brasilio/settings.py index 36fc5732..5b27d637 100644 --- a/brasilio/settings.py +++ b/brasilio/settings.py @@ -58,6 +58,7 @@ "traffic_control.middlewares.block_suspicious_requests", "whitenoise.middleware.WhiteNoiseMiddleware", "corsheaders.middleware.CorsMiddleware", + "traffic_control.middlewares.redirect_requests_from_expired_routes", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.cache.UpdateCacheMiddleware", "django.middleware.common.CommonMiddleware", diff --git a/traffic_control/handlers.py b/traffic_control/handlers.py index e407043d..9a601435 100644 --- a/traffic_control/handlers.py +++ b/traffic_control/handlers.py @@ -4,7 +4,7 @@ from functools import lru_cache from django.conf import settings -from django.shortcuts import render +from django.shortcuts import redirect, render from django.urls import reverse from ratelimit.exceptions import Ratelimited from rest_framework.exceptions import Throttled @@ -69,3 +69,8 @@ def api_exception_handler(exc, context): response.data = {"message": msg} return response + + +def handler_redirects(request): + if request.path in ["/datasets/gastos_diretos/"]: + return redirect("/datasets/govbr/") diff --git a/traffic_control/middlewares.py b/traffic_control/middlewares.py index fe3a0e86..22628a3a 100644 --- a/traffic_control/middlewares.py +++ b/traffic_control/middlewares.py @@ -5,6 +5,7 @@ from ratelimit.exceptions import Ratelimited from traffic_control.constants import RATELIMITED_VIEW_ATTR +from traffic_control.handlers import handler_redirects from traffic_control.util import ratelimit_key @@ -39,3 +40,11 @@ def middleware(request): return get_response(request) return middleware + + +def redirect_requests_from_expired_routes(get_response): + def middleware(request): + redirect = handler_redirects(request) + return get_response(request) if not redirect else redirect + + return middleware diff --git a/traffic_control/tests/test_middlewares.py b/traffic_control/tests/test_middlewares.py index 9edfa806..46e897d7 100644 --- a/traffic_control/tests/test_middlewares.py +++ b/traffic_control/tests/test_middlewares.py @@ -1,6 +1,8 @@ from django.conf import settings from django.test import TestCase, override_settings +from traffic_control.tests.util import TrafficControlClient + class BlockSuspiciousRequestsMiddlewareTests(TestCase): def assert429(self, response): @@ -36,3 +38,12 @@ def test_middleware_respects_append_slash_setings(self): with override_settings(APPEND_SLASH=False): response = self.client.get(url, HTTP_USER_AGENT="other_agent") assert 404 == response.status_code + + +class HandlerRedirectsTests(TestCase): + client_class = TrafficControlClient + + def test_redirect_dataset_urls(self): + response = self.client.get("/datasets/gastos_diretos/") + + self.assertRedirects(response, "/datasets/govbr/", fetch_redirect_response=False) From 15cfebc113abd5e12a5185de15531886b4a79c2f Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Fri, 16 Oct 2020 14:06:07 -0300 Subject: [PATCH 02/12] Modelo para armazenar redirects --- .../migrations/0008_dataurlredirect.py | 25 +++++++++++++++++++ traffic_control/models.py | 11 ++++++++ 2 files changed, 36 insertions(+) create mode 100644 traffic_control/migrations/0008_dataurlredirect.py diff --git a/traffic_control/migrations/0008_dataurlredirect.py b/traffic_control/migrations/0008_dataurlredirect.py new file mode 100644 index 00000000..6a8422b2 --- /dev/null +++ b/traffic_control/migrations/0008_dataurlredirect.py @@ -0,0 +1,25 @@ +# Generated by Django 3.1.1 on 2020-10-16 17:05 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("traffic_control", "0007_auto_20200918_0253"), + ] + + operations = [ + migrations.CreateModel( + name="DataUrlRedirect", + fields=[ + ("id", models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("dataset_prev", models.SlugField(default="")), + ("dataset_dest", models.SlugField(default="")), + ("tablename_prev", models.SlugField(default="")), + ("tablename_dest", models.SlugField(default="")), + ("field_prev", models.SlugField(default="")), + ("field_dest", models.SlugField(default="")), + ], + ), + ] diff --git a/traffic_control/models.py b/traffic_control/models.py index 9e9c473e..a8d0cd1d 100644 --- a/traffic_control/models.py +++ b/traffic_control/models.py @@ -77,3 +77,14 @@ def blocked_ips(cls, hourly_max=30, daily_max=1200, hours_ago=None): class Meta: ordering = ["-created_at"] + + +class DataUrlRedirect(models.Model): + dataset_prev = models.SlugField(default="") + dataset_dest = models.SlugField(default="") + + tablename_prev = models.SlugField(default="") + tablename_dest = models.SlugField(default="") + + field_prev = models.SlugField(default="") + field_dest = models.SlugField(default="") From 0971a488dcac36f870645b302103b96231cfe1e2 Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Fri, 16 Oct 2020 14:27:40 -0300 Subject: [PATCH 03/12] =?UTF-8?q?Redireciona=20baseando-se=20em=20informa?= =?UTF-8?q?=C3=A7=C3=A3o=20no=20banco?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- traffic_control/handlers.py | 8 +++--- traffic_control/models.py | 21 +++++++++++++++ traffic_control/tests/test_middlewares.py | 32 +++++++++++++++++++++-- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/traffic_control/handlers.py b/traffic_control/handlers.py index 9a601435..d5437662 100644 --- a/traffic_control/handlers.py +++ b/traffic_control/handlers.py @@ -12,6 +12,7 @@ from api.versioning import redirect_from_older_version from traffic_control.logging import log_blocked_request +from traffic_control.models import DataUrlRedirect rate_limit_msg = """

Você atingiu o limite de requisições e, por isso, essa requisição foi bloqueada. Caso você precise acessar várias páginas de um dataset, por favor, baixe o dataset completo em vez de percorrer várias páginas na interface (o link para baixar o arquivo completo encontra-se na página do dataset).

@@ -71,6 +72,7 @@ def api_exception_handler(exc, context): return response -def handler_redirects(request): - if request.path in ["/datasets/gastos_diretos/"]: - return redirect("/datasets/govbr/") +def handler_redirects(request, permanent=False): + redirect_url = DataUrlRedirect.redirect_from(request.path) + if redirect_url: + return redirect(redirect_url, permanent=permanent) diff --git a/traffic_control/models.py b/traffic_control/models.py index a8d0cd1d..8143b257 100644 --- a/traffic_control/models.py +++ b/traffic_control/models.py @@ -3,6 +3,7 @@ from itertools import chain from django.db import models +from django.urls import reverse from django.utils import timezone @@ -88,3 +89,23 @@ class DataUrlRedirect(models.Model): field_prev = models.SlugField(default="") field_dest = models.SlugField(default="") + + @property + def redirect_map(self): + return { + reverse("core:dataset-detail", args=[self.dataset_prev]): reverse( + "core:dataset-detail", args=[self.dataset_dest] + ), + reverse("core:dataset-files-detail", args=[self.dataset_prev]): reverse( + "core:dataset-files-detail", args=[self.dataset_dest] + ), + } + + @classmethod + def redirect_from(cls, path): + redirects = {} + + for data_url_redirect in cls.objects.all().iterator(): + redirects.update(**data_url_redirect.redirect_map) + + return redirects.get(path, "") diff --git a/traffic_control/tests/test_middlewares.py b/traffic_control/tests/test_middlewares.py index 46e897d7..dd81be99 100644 --- a/traffic_control/tests/test_middlewares.py +++ b/traffic_control/tests/test_middlewares.py @@ -1,6 +1,10 @@ +from model_bakery import baker + from django.conf import settings from django.test import TestCase, override_settings +from django.urls import reverse +from traffic_control.models import DataUrlRedirect from traffic_control.tests.util import TrafficControlClient @@ -43,7 +47,31 @@ def test_middleware_respects_append_slash_setings(self): class HandlerRedirectsTests(TestCase): client_class = TrafficControlClient + def setUp(self): + self.dataset_redirects = [ + baker.make(DataUrlRedirect, dataset_prev="gastos_diretos", dataset_dest="govbr"), + baker.make(DataUrlRedirect, dataset_prev="bens_candidatos", dataset_dest="bem_declarado"), + ] + def test_redirect_dataset_urls(self): - response = self.client.get("/datasets/gastos_diretos/") + response = self.client.get("/dataset/gastos_diretos/") + + self.assertRedirects(response, "/dataset/govbr/", fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db(self): + for ds_redirect in self.dataset_redirects: + url = reverse("core:dataset-detail", args=[ds_redirect.dataset_prev]) + redirect_url = reverse("core:dataset-detail", args=[ds_redirect.dataset_dest]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db_for_files(self): + for ds_redirect in self.dataset_redirects: + url = reverse("core:dataset-files-detail", args=[ds_redirect.dataset_prev]) + redirect_url = reverse("core:dataset-files-detail", args=[ds_redirect.dataset_dest]) + + response = self.client.get(url) - self.assertRedirects(response, "/datasets/govbr/", fetch_redirect_response=False) + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) From 2c05ff7ab9ea20b4b89099f8139e13e43c0a1287 Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Fri, 16 Oct 2020 14:32:25 -0300 Subject: [PATCH 04/12] Redireciona rotas da API para datasets --- traffic_control/models.py | 3 +++ traffic_control/tests/test_middlewares.py | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/traffic_control/models.py b/traffic_control/models.py index 8143b257..8a296bcc 100644 --- a/traffic_control/models.py +++ b/traffic_control/models.py @@ -99,6 +99,9 @@ def redirect_map(self): reverse("core:dataset-files-detail", args=[self.dataset_prev]): reverse( "core:dataset-files-detail", args=[self.dataset_dest] ), + reverse("api-v1:dataset-detail", args=[self.dataset_prev]): reverse( + "api-v1:dataset-detail", args=[self.dataset_dest] + ), } @classmethod diff --git a/traffic_control/tests/test_middlewares.py b/traffic_control/tests/test_middlewares.py index dd81be99..81b80ed3 100644 --- a/traffic_control/tests/test_middlewares.py +++ b/traffic_control/tests/test_middlewares.py @@ -1,8 +1,7 @@ -from model_bakery import baker - from django.conf import settings from django.test import TestCase, override_settings from django.urls import reverse +from model_bakery import baker from traffic_control.models import DataUrlRedirect from traffic_control.tests.util import TrafficControlClient @@ -67,7 +66,7 @@ def test_dataset_redirect_fetch_data_from_db(self): self.assertRedirects(response, redirect_url, fetch_redirect_response=False) - def test_dataset_redirect_fetch_data_from_db_for_files(self): + def test_dataset_redirect_fetch_data_from_db_for_files_urls(self): for ds_redirect in self.dataset_redirects: url = reverse("core:dataset-files-detail", args=[ds_redirect.dataset_prev]) redirect_url = reverse("core:dataset-files-detail", args=[ds_redirect.dataset_dest]) @@ -75,3 +74,12 @@ def test_dataset_redirect_fetch_data_from_db_for_files(self): response = self.client.get(url) self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db_for_api_urls(self): + for ds_redirect in self.dataset_redirects: + url = reverse("api-v1:dataset-detail", args=[ds_redirect.dataset_prev]) + redirect_url = reverse("api-v1:dataset-detail", args=[ds_redirect.dataset_dest]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) From 479175cfd07ea0e1408a67e82dd405ad35cd8c49 Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Fri, 16 Oct 2020 14:35:50 -0300 Subject: [PATCH 05/12] =?UTF-8?q?Refatora=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- traffic_control/models.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/traffic_control/models.py b/traffic_control/models.py index 8a296bcc..e5487be8 100644 --- a/traffic_control/models.py +++ b/traffic_control/models.py @@ -92,17 +92,13 @@ class DataUrlRedirect(models.Model): @property def redirect_map(self): - return { - reverse("core:dataset-detail", args=[self.dataset_prev]): reverse( - "core:dataset-detail", args=[self.dataset_dest] - ), - reverse("core:dataset-files-detail", args=[self.dataset_prev]): reverse( - "core:dataset-files-detail", args=[self.dataset_dest] - ), - reverse("api-v1:dataset-detail", args=[self.dataset_prev]): reverse( - "api-v1:dataset-detail", args=[self.dataset_dest] - ), - } + dataset_url_names = [ + "core:dataset-detail", + "core:dataset-files-detail", + "api-v1:dataset-detail", + ] + + return {reverse(n, args=[self.dataset_prev]): reverse(n, args=[self.dataset_dest]) for n in dataset_url_names} @classmethod def redirect_from(cls, path): From 9b98c81508acaebfd10cff4ce79b1b6f67104787 Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Fri, 16 Oct 2020 14:46:46 -0300 Subject: [PATCH 06/12] Garante redirecionamento das tabelas --- traffic_control/models.py | 6 +++++- traffic_control/tests/test_middlewares.py | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/traffic_control/models.py b/traffic_control/models.py index e5487be8..09701751 100644 --- a/traffic_control/models.py +++ b/traffic_control/models.py @@ -107,4 +107,8 @@ def redirect_from(cls, path): for data_url_redirect in cls.objects.all().iterator(): redirects.update(**data_url_redirect.redirect_map) - return redirects.get(path, "") + # Order prefixes begining by the most complex ones + for url_prefix in sorted(redirects, reverse=True): + if path.startswith(url_prefix): + redirect_url_prefix = redirects[url_prefix] + return path.replace(url_prefix, redirect_url_prefix) diff --git a/traffic_control/tests/test_middlewares.py b/traffic_control/tests/test_middlewares.py index 81b80ed3..b244ee36 100644 --- a/traffic_control/tests/test_middlewares.py +++ b/traffic_control/tests/test_middlewares.py @@ -83,3 +83,21 @@ def test_dataset_redirect_fetch_data_from_db_for_api_urls(self): response = self.client.get(url) self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db_for_tabledata(self): + for ds_redirect in self.dataset_redirects: + url = reverse("core:dataset-table-detail", args=[ds_redirect.dataset_prev, "caso"]) + redirect_url = reverse("core:dataset-table-detail", args=[ds_redirect.dataset_dest, "caso"]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db_for_api_tabledata(self): + for ds_redirect in self.dataset_redirects: + url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_prev, "caso"]) + redirect_url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_dest, "caso"]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) From 55b04787340149a32aa432eceb3a605b474084bf Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Fri, 16 Oct 2020 15:26:10 -0300 Subject: [PATCH 07/12] Move modelo e testes para app core --- .../migrations/0028_auto_20201016_1519.py | 4 +- core/models.py | 34 ++++++++++ core/tests/test_views.py | 64 +++++++++++++++++- traffic_control/handlers.py | 2 +- traffic_control/models.py | 35 ---------- traffic_control/tests/test_middlewares.py | 65 ------------------- 6 files changed, 99 insertions(+), 105 deletions(-) rename traffic_control/migrations/0008_dataurlredirect.py => core/migrations/0028_auto_20201016_1519.py (87%) diff --git a/traffic_control/migrations/0008_dataurlredirect.py b/core/migrations/0028_auto_20201016_1519.py similarity index 87% rename from traffic_control/migrations/0008_dataurlredirect.py rename to core/migrations/0028_auto_20201016_1519.py index 6a8422b2..5ce1c68c 100644 --- a/traffic_control/migrations/0008_dataurlredirect.py +++ b/core/migrations/0028_auto_20201016_1519.py @@ -1,4 +1,4 @@ -# Generated by Django 3.1.1 on 2020-10-16 17:05 +# Generated by Django 3.1.1 on 2020-10-16 18:19 from django.db import migrations, models @@ -6,7 +6,7 @@ class Migration(migrations.Migration): dependencies = [ - ("traffic_control", "0007_auto_20200918_0253"), + ("core", "0027_auto_20201007_1707"), ] operations = [ diff --git a/core/models.py b/core/models.py index adcd4cea..bbdad08b 100644 --- a/core/models.py +++ b/core/models.py @@ -675,3 +675,37 @@ def readable_size(self): @property def admin_url(self): return reverse("admin:core_tablefile_change", args=[self.id]) + + +class DataUrlRedirect(models.Model): + dataset_prev = models.SlugField(default="") + dataset_dest = models.SlugField(default="") + + tablename_prev = models.SlugField(default="") + tablename_dest = models.SlugField(default="") + + field_prev = models.SlugField(default="") + field_dest = models.SlugField(default="") + + @property + def redirect_map(self): + dataset_url_names = [ + "core:dataset-detail", + "core:dataset-files-detail", + "api-v1:dataset-detail", + ] + + return {reverse(n, args=[self.dataset_prev]): reverse(n, args=[self.dataset_dest]) for n in dataset_url_names} + + @classmethod + def redirect_from(cls, path): + redirects = {} + + for data_url_redirect in cls.objects.all().iterator(): + redirects.update(**data_url_redirect.redirect_map) + + # Order prefixes begining by the most complex ones + for url_prefix in sorted(redirects, reverse=True): + if path.startswith(url_prefix): + redirect_url_prefix = redirects[url_prefix] + return path.replace(url_prefix, redirect_url_prefix) diff --git a/core/tests/test_views.py b/core/tests/test_views.py index 0c0d7440..7da5e9ed 100644 --- a/core/tests/test_views.py +++ b/core/tests/test_views.py @@ -1,11 +1,11 @@ from unittest.mock import patch from django.core.management import call_command -from django.test import override_settings +from django.test import TestCase, override_settings from django.urls import reverse from model_bakery import baker -from core.models import TableFile +from core.models import DataUrlRedirect, TableFile from core.tests.utils import BaseTestCaseWithSampleDataset from traffic_control.tests.util import TrafficControlClient from utils.tests import DjangoAssertionsMixin @@ -123,3 +123,63 @@ def test_return_empty_list_if_no_visible_table(self): assert 200 == response.status_code self.assertTemplateUsed(response, "404.html") assert response.context["message"] + + +class DataRedirectsTests(TestCase): + client_class = TrafficControlClient + + def setUp(self): + self.dataset_redirects = [ + baker.make(DataUrlRedirect, dataset_prev="gastos_diretos", dataset_dest="govbr"), + baker.make(DataUrlRedirect, dataset_prev="bens_candidatos", dataset_dest="bem_declarado"), + ] + + def test_redirect_dataset_urls(self): + response = self.client.get("/dataset/gastos_diretos/") + + self.assertRedirects(response, "/dataset/govbr/", fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db(self): + for ds_redirect in self.dataset_redirects: + url = reverse("core:dataset-detail", args=[ds_redirect.dataset_prev]) + redirect_url = reverse("core:dataset-detail", args=[ds_redirect.dataset_dest]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db_for_files_urls(self): + for ds_redirect in self.dataset_redirects: + url = reverse("core:dataset-files-detail", args=[ds_redirect.dataset_prev]) + redirect_url = reverse("core:dataset-files-detail", args=[ds_redirect.dataset_dest]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db_for_api_urls(self): + for ds_redirect in self.dataset_redirects: + url = reverse("api-v1:dataset-detail", args=[ds_redirect.dataset_prev]) + redirect_url = reverse("api-v1:dataset-detail", args=[ds_redirect.dataset_dest]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db_for_tabledata(self): + for ds_redirect in self.dataset_redirects: + url = reverse("core:dataset-table-detail", args=[ds_redirect.dataset_prev, "caso"]) + redirect_url = reverse("core:dataset-table-detail", args=[ds_redirect.dataset_dest, "caso"]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db_for_api_tabledata(self): + for ds_redirect in self.dataset_redirects: + url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_prev, "caso"]) + redirect_url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_dest, "caso"]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) diff --git a/traffic_control/handlers.py b/traffic_control/handlers.py index d5437662..4a54b859 100644 --- a/traffic_control/handlers.py +++ b/traffic_control/handlers.py @@ -11,8 +11,8 @@ from rest_framework.views import exception_handler from api.versioning import redirect_from_older_version +from core.models import DataUrlRedirect from traffic_control.logging import log_blocked_request -from traffic_control.models import DataUrlRedirect rate_limit_msg = """

Você atingiu o limite de requisições e, por isso, essa requisição foi bloqueada. Caso você precise acessar várias páginas de um dataset, por favor, baixe o dataset completo em vez de percorrer várias páginas na interface (o link para baixar o arquivo completo encontra-se na página do dataset).

diff --git a/traffic_control/models.py b/traffic_control/models.py index 09701751..9e9c473e 100644 --- a/traffic_control/models.py +++ b/traffic_control/models.py @@ -3,7 +3,6 @@ from itertools import chain from django.db import models -from django.urls import reverse from django.utils import timezone @@ -78,37 +77,3 @@ def blocked_ips(cls, hourly_max=30, daily_max=1200, hours_ago=None): class Meta: ordering = ["-created_at"] - - -class DataUrlRedirect(models.Model): - dataset_prev = models.SlugField(default="") - dataset_dest = models.SlugField(default="") - - tablename_prev = models.SlugField(default="") - tablename_dest = models.SlugField(default="") - - field_prev = models.SlugField(default="") - field_dest = models.SlugField(default="") - - @property - def redirect_map(self): - dataset_url_names = [ - "core:dataset-detail", - "core:dataset-files-detail", - "api-v1:dataset-detail", - ] - - return {reverse(n, args=[self.dataset_prev]): reverse(n, args=[self.dataset_dest]) for n in dataset_url_names} - - @classmethod - def redirect_from(cls, path): - redirects = {} - - for data_url_redirect in cls.objects.all().iterator(): - redirects.update(**data_url_redirect.redirect_map) - - # Order prefixes begining by the most complex ones - for url_prefix in sorted(redirects, reverse=True): - if path.startswith(url_prefix): - redirect_url_prefix = redirects[url_prefix] - return path.replace(url_prefix, redirect_url_prefix) diff --git a/traffic_control/tests/test_middlewares.py b/traffic_control/tests/test_middlewares.py index b244ee36..9edfa806 100644 --- a/traffic_control/tests/test_middlewares.py +++ b/traffic_control/tests/test_middlewares.py @@ -1,10 +1,5 @@ from django.conf import settings from django.test import TestCase, override_settings -from django.urls import reverse -from model_bakery import baker - -from traffic_control.models import DataUrlRedirect -from traffic_control.tests.util import TrafficControlClient class BlockSuspiciousRequestsMiddlewareTests(TestCase): @@ -41,63 +36,3 @@ def test_middleware_respects_append_slash_setings(self): with override_settings(APPEND_SLASH=False): response = self.client.get(url, HTTP_USER_AGENT="other_agent") assert 404 == response.status_code - - -class HandlerRedirectsTests(TestCase): - client_class = TrafficControlClient - - def setUp(self): - self.dataset_redirects = [ - baker.make(DataUrlRedirect, dataset_prev="gastos_diretos", dataset_dest="govbr"), - baker.make(DataUrlRedirect, dataset_prev="bens_candidatos", dataset_dest="bem_declarado"), - ] - - def test_redirect_dataset_urls(self): - response = self.client.get("/dataset/gastos_diretos/") - - self.assertRedirects(response, "/dataset/govbr/", fetch_redirect_response=False) - - def test_dataset_redirect_fetch_data_from_db(self): - for ds_redirect in self.dataset_redirects: - url = reverse("core:dataset-detail", args=[ds_redirect.dataset_prev]) - redirect_url = reverse("core:dataset-detail", args=[ds_redirect.dataset_dest]) - - response = self.client.get(url) - - self.assertRedirects(response, redirect_url, fetch_redirect_response=False) - - def test_dataset_redirect_fetch_data_from_db_for_files_urls(self): - for ds_redirect in self.dataset_redirects: - url = reverse("core:dataset-files-detail", args=[ds_redirect.dataset_prev]) - redirect_url = reverse("core:dataset-files-detail", args=[ds_redirect.dataset_dest]) - - response = self.client.get(url) - - self.assertRedirects(response, redirect_url, fetch_redirect_response=False) - - def test_dataset_redirect_fetch_data_from_db_for_api_urls(self): - for ds_redirect in self.dataset_redirects: - url = reverse("api-v1:dataset-detail", args=[ds_redirect.dataset_prev]) - redirect_url = reverse("api-v1:dataset-detail", args=[ds_redirect.dataset_dest]) - - response = self.client.get(url) - - self.assertRedirects(response, redirect_url, fetch_redirect_response=False) - - def test_dataset_redirect_fetch_data_from_db_for_tabledata(self): - for ds_redirect in self.dataset_redirects: - url = reverse("core:dataset-table-detail", args=[ds_redirect.dataset_prev, "caso"]) - redirect_url = reverse("core:dataset-table-detail", args=[ds_redirect.dataset_dest, "caso"]) - - response = self.client.get(url) - - self.assertRedirects(response, redirect_url, fetch_redirect_response=False) - - def test_dataset_redirect_fetch_data_from_db_for_api_tabledata(self): - for ds_redirect in self.dataset_redirects: - url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_prev, "caso"]) - redirect_url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_dest, "caso"]) - - response = self.client.get(url) - - self.assertRedirects(response, redirect_url, fetch_redirect_response=False) From 15e39cfbbd284094be0626b257f339a362c6e4b0 Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Fri, 16 Oct 2020 15:29:29 -0300 Subject: [PATCH 08/12] =?UTF-8?q?Remove=20implementa=C3=A7=C3=A3o=20via=20?= =?UTF-8?q?middleware?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- brasilio/settings.py | 1 - traffic_control/handlers.py | 9 +-------- traffic_control/middlewares.py | 9 --------- 3 files changed, 1 insertion(+), 18 deletions(-) diff --git a/brasilio/settings.py b/brasilio/settings.py index 5b27d637..36fc5732 100644 --- a/brasilio/settings.py +++ b/brasilio/settings.py @@ -58,7 +58,6 @@ "traffic_control.middlewares.block_suspicious_requests", "whitenoise.middleware.WhiteNoiseMiddleware", "corsheaders.middleware.CorsMiddleware", - "traffic_control.middlewares.redirect_requests_from_expired_routes", "django.contrib.sessions.middleware.SessionMiddleware", "django.middleware.cache.UpdateCacheMiddleware", "django.middleware.common.CommonMiddleware", diff --git a/traffic_control/handlers.py b/traffic_control/handlers.py index 4a54b859..e407043d 100644 --- a/traffic_control/handlers.py +++ b/traffic_control/handlers.py @@ -4,14 +4,13 @@ from functools import lru_cache from django.conf import settings -from django.shortcuts import redirect, render +from django.shortcuts import render from django.urls import reverse from ratelimit.exceptions import Ratelimited from rest_framework.exceptions import Throttled from rest_framework.views import exception_handler from api.versioning import redirect_from_older_version -from core.models import DataUrlRedirect from traffic_control.logging import log_blocked_request rate_limit_msg = """ @@ -70,9 +69,3 @@ def api_exception_handler(exc, context): response.data = {"message": msg} return response - - -def handler_redirects(request, permanent=False): - redirect_url = DataUrlRedirect.redirect_from(request.path) - if redirect_url: - return redirect(redirect_url, permanent=permanent) diff --git a/traffic_control/middlewares.py b/traffic_control/middlewares.py index 22628a3a..fe3a0e86 100644 --- a/traffic_control/middlewares.py +++ b/traffic_control/middlewares.py @@ -5,7 +5,6 @@ from ratelimit.exceptions import Ratelimited from traffic_control.constants import RATELIMITED_VIEW_ATTR -from traffic_control.handlers import handler_redirects from traffic_control.util import ratelimit_key @@ -40,11 +39,3 @@ def middleware(request): return get_response(request) return middleware - - -def redirect_requests_from_expired_routes(get_response): - def middleware(request): - redirect = handler_redirects(request) - return get_response(request) if not redirect else redirect - - return middleware From 3d5c5eaa4512bdab7e887a07bbfd67033a21b214 Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Fri, 16 Oct 2020 15:52:44 -0300 Subject: [PATCH 09/12] Implementa redirects nas views --- api/views.py | 18 +++++++++++++++--- core/models.py | 3 ++- core/tests/test_views.py | 2 ++ core/views.py | 19 ++++++++++++++++--- 4 files changed, 35 insertions(+), 7 deletions(-) diff --git a/api/views.py b/api/views.py index 00b16bbc..1f4cbffc 100644 --- a/api/views.py +++ b/api/views.py @@ -1,6 +1,7 @@ from collections import Sequence -from django.shortcuts import get_object_or_404 +from django.http import Http404 +from django.shortcuts import get_object_or_404, redirect from rest_framework import viewsets from rest_framework.generics import ListAPIView from rest_framework.response import Response @@ -9,7 +10,7 @@ from api.versioning import check_api_version_redirect from core.filters import parse_querystring from core.forms import get_table_dynamic_form -from core.models import Dataset, Table +from core.models import Dataset, DataUrlRedirect, Table from core.templatetags.utils import obfuscate from . import paginators @@ -21,7 +22,14 @@ class DatasetViewSet(viewsets.ModelViewSet): @check_api_version_redirect def retrieve(self, request, slug): - obj = get_object_or_404(self.get_queryset(), slug=slug) + try: + obj = self.get_queryset().get(slug=slug) + except Dataset.DoesNotExist: + redirect_url = DataUrlRedirect.redirect_from(request) + if redirect_url: + return redirect(redirect_url) + raise Http404 + serializer = DatasetDetailSerializer(obj, context=self.get_serializer_context(),) return Response(serializer.data) @@ -92,6 +100,10 @@ def handle_exception(self, exc): if isinstance(exc, InvalidFiltersException): return Response(exc.errors_list, status=400) else: + if isinstance(exc, Http404): + redirect_url = DataUrlRedirect.redirect_from(self.request) + if redirect_url: + return redirect(redirect_url) return super().handle_exception(exc) @check_api_version_redirect diff --git a/core/models.py b/core/models.py index bbdad08b..88afd6bc 100644 --- a/core/models.py +++ b/core/models.py @@ -698,7 +698,8 @@ def redirect_map(self): return {reverse(n, args=[self.dataset_prev]): reverse(n, args=[self.dataset_dest]) for n in dataset_url_names} @classmethod - def redirect_from(cls, path): + def redirect_from(cls, request): + path = request.path redirects = {} for data_url_redirect in cls.objects.all().iterator(): diff --git a/core/tests/test_views.py b/core/tests/test_views.py index 7da5e9ed..5b5a131c 100644 --- a/core/tests/test_views.py +++ b/core/tests/test_views.py @@ -1,5 +1,6 @@ from unittest.mock import patch +from django.conf import settings from django.core.management import call_command from django.test import TestCase, override_settings from django.urls import reverse @@ -129,6 +130,7 @@ class DataRedirectsTests(TestCase): client_class = TrafficControlClient def setUp(self): + self.client.force_login(baker.make(settings.AUTH_USER_MODEL)) self.dataset_redirects = [ baker.make(DataUrlRedirect, dataset_prev="gastos_diretos", dataset_dest="govbr"), baker.make(DataUrlRedirect, dataset_prev="bens_candidatos", dataset_dest="bem_declarado"), diff --git a/core/views.py b/core/views.py index 400e13e2..c792443b 100644 --- a/core/views.py +++ b/core/views.py @@ -7,13 +7,13 @@ from django.core.paginator import Paginator from django.db.models import Q from django.http import StreamingHttpResponse -from django.shortcuts import get_object_or_404, redirect, render +from django.shortcuts import redirect, render from django.urls import reverse from core.filters import parse_querystring from core.forms import ContactForm, DatasetSearchForm, get_table_dynamic_form from core.middlewares import disable_non_logged_user_cache -from core.models import Dataset, Table +from core.models import Dataset, DataUrlRedirect, Table from core.templatetags.utils import obfuscate from core.util import cached_http_get_json from data_activities_log.activites import recent_activities @@ -109,6 +109,10 @@ def dataset_detail(request, slug, tablename=""): try: dataset = Dataset.objects.get(slug=slug) except Dataset.DoesNotExist: + redirect_url = DataUrlRedirect.redirect_from(request) + if redirect_url: + return redirect(redirect_url) + context = {"message": "Dataset does not exist"} return render(request, "404.html", context, status=404) @@ -233,7 +237,16 @@ def contributors(request): def dataset_files_detail(request, slug): - dataset = get_object_or_404(Dataset, slug=slug) + try: + dataset = Dataset.objects.get(slug=slug) + except Dataset.DoesNotExist: + redirect_url = DataUrlRedirect.redirect_from(request) + if redirect_url: + return redirect(redirect_url) + + context = {"message": "Dataset does not exist"} + return render(request, "404.html", context, status=404) + try: all_files = dataset.all_files except ObjectDoesNotExist: From c800f070722f396d4c55609afe6218da6e8691c9 Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Fri, 16 Oct 2020 16:18:34 -0300 Subject: [PATCH 10/12] Garante redirects de datasets e tabelas --- core/models.py | 25 +++++++++++++- core/tests/test_views.py | 72 +++++++++++++++++++++++++++++++++++++++- core/views.py | 3 ++ 3 files changed, 98 insertions(+), 2 deletions(-) diff --git a/core/models.py b/core/models.py index 88afd6bc..54e311ea 100644 --- a/core/models.py +++ b/core/models.py @@ -689,13 +689,36 @@ class DataUrlRedirect(models.Model): @property def redirect_map(self): + map = {} dataset_url_names = [ "core:dataset-detail", "core:dataset-files-detail", "api-v1:dataset-detail", ] - return {reverse(n, args=[self.dataset_prev]): reverse(n, args=[self.dataset_dest]) for n in dataset_url_names} + if self.dataset_prev != self.dataset_dest: + map.update( + **{ + reverse(n, args=[self.dataset_prev]): reverse(n, args=[self.dataset_dest]) + for n in dataset_url_names + } + ) + + if self.tablename_dest != self.tablename_prev: + table_url_names = [ + "core:dataset-table-detail", + "api-v1:dataset-table-data", + ] + map.update( + **{ + reverse(n, args=[self.dataset_prev, self.tablename_prev]): reverse( + n, args=[self.dataset_dest, self.tablename_dest] + ) + for n in table_url_names + } + ) + + return map @classmethod def redirect_from(cls, request): diff --git a/core/tests/test_views.py b/core/tests/test_views.py index 5b5a131c..0df2a59c 100644 --- a/core/tests/test_views.py +++ b/core/tests/test_views.py @@ -6,7 +6,7 @@ from django.urls import reverse from model_bakery import baker -from core.models import DataUrlRedirect, TableFile +from core.models import Dataset, DataUrlRedirect, TableFile from core.tests.utils import BaseTestCaseWithSampleDataset from traffic_control.tests.util import TrafficControlClient from utils.tests import DjangoAssertionsMixin @@ -185,3 +185,73 @@ def test_dataset_redirect_fetch_data_from_db_for_api_tabledata(self): response = self.client.get(url) self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db_for_tabledata_with_table_redirect(self): + ds_redirect = self.dataset_redirects[0] + ds_redirect.tablename_prev = "caso2019" + ds_redirect.tablename_dest = "caso2020" + ds_redirect.save() + + url = reverse("core:dataset-table-detail", args=[ds_redirect.dataset_prev, "caso2019"]) + redirect_url = reverse("core:dataset-table-detail", args=[ds_redirect.dataset_dest, "caso2020"]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_dataset_redirect_fetch_data_from_db_for_api_tabledata_with_table_redirect(self): + ds_redirect = self.dataset_redirects[0] + ds_redirect.tablename_prev = "caso2019" + ds_redirect.tablename_dest = "caso2020" + ds_redirect.save() + + url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_prev, "caso2019"]) + redirect_url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_dest, "caso2020"]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_table_only_redirect(self): + baker.make(Dataset, slug="covid19") + ds_redirect = self.dataset_redirects[0] + ds_redirect.dataset_prev = "covid19" + ds_redirect.dataset_dest = "covid19" + ds_redirect.tablename_prev = "caso2020" + ds_redirect.tablename_dest = "caso2021" + ds_redirect.save() + + url = reverse("core:dataset-table-detail", args=["covid19", "caso2020"]) + redirect_url = reverse("core:dataset-table-detail", args=["covid19", "caso2021"]) + + response = self.client.get(url) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + # API as well + url = reverse("api-v1:dataset-table-data", args=["covid19", "caso2020"]) + redirect_url = reverse("api-v1:dataset-table-data", args=["covid19", "caso2021"]) + + def test_avoid_infinite_redirect_if_same_dataset_config(self): + ds_redirect = self.dataset_redirects[0] + ds_redirect.dataset_prev = "foo" + ds_redirect.dataset_dest = "foo" + ds_redirect.save() + + url = reverse("core:dataset-detail", args=[ds_redirect.dataset_prev]) + response = self.client.get(url) + + assert 404 == response.status_code + + def test_avoid_infinite_redirect_if_same_dataset_config_in_table(self): + ds_redirect = self.dataset_redirects[0] + ds_redirect.dataset_prev = "foo" + ds_redirect.dataset_dest = "foo" + ds_redirect.tablename_prev = "bar" + ds_redirect.tablename_dest = "bar" + ds_redirect.save() + + url = reverse("api-v1:dataset-table-data", args=["foo", "bar"]) + response = self.client.get(url) + + assert 404 == response.status_code diff --git a/core/views.py b/core/views.py index c792443b..55a9c636 100644 --- a/core/views.py +++ b/core/views.py @@ -126,6 +126,9 @@ def dataset_detail(request, slug, tablename=""): except Table.DoesNotExist: context = {"message": "Table does not exist"} try: + redirect_url = DataUrlRedirect.redirect_from(request) + if redirect_url: + return redirect(redirect_url) # log 404 request only if hidden table exist hidden_table = dataset.get_table(tablename, allow_hidden=True) if hidden_table: From 2a94620974aeb076fb29e2ffe6103b454e5d187e Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Fri, 16 Oct 2020 17:12:05 -0300 Subject: [PATCH 11/12] Redireciona por conta de querystring de campos --- api/views.py | 7 ++-- core/models.py | 39 +++++++++++++++++--- core/tests/test_views.py | 77 ++++++++++++++++++++++++++++++++++++++++ core/views.py | 5 +++ 4 files changed, 120 insertions(+), 8 deletions(-) diff --git a/api/views.py b/api/views.py index 1f4cbffc..b1541345 100644 --- a/api/views.py +++ b/api/views.py @@ -100,14 +100,13 @@ def handle_exception(self, exc): if isinstance(exc, InvalidFiltersException): return Response(exc.errors_list, status=400) else: - if isinstance(exc, Http404): - redirect_url = DataUrlRedirect.redirect_from(self.request) - if redirect_url: - return redirect(redirect_url) return super().handle_exception(exc) @check_api_version_redirect def get(self, *args, **kwargs): + redirect_url = DataUrlRedirect.redirect_from(self.request) + if redirect_url: + return redirect(redirect_url) return super().get(*args, **kwargs) diff --git a/core/models.py b/core/models.py index 54e311ea..38b7ed3f 100644 --- a/core/models.py +++ b/core/models.py @@ -2,8 +2,9 @@ import random import string from collections import OrderedDict, namedtuple +from copy import deepcopy from textwrap import dedent -from urllib.parse import urlparse +from urllib.parse import urlencode, urlparse import django.contrib.postgres.indexes as pg_indexes import django.db.models.indexes as django_indexes @@ -724,12 +725,42 @@ def redirect_map(self): def redirect_from(cls, request): path = request.path redirects = {} + fields_map = {} - for data_url_redirect in cls.objects.all().iterator(): - redirects.update(**data_url_redirect.redirect_map) + for r in cls.objects.all().iterator(): + redirects.update(**r.redirect_map) + + if r.field_prev != r.field_dest: + key = (r.dataset_dest, r.tablename_dest, r.field_prev) + fields_map[key] = r.field_dest # Order prefixes begining by the most complex ones + redirect_url = "" for url_prefix in sorted(redirects, reverse=True): if path.startswith(url_prefix): redirect_url_prefix = redirects[url_prefix] - return path.replace(url_prefix, redirect_url_prefix) + redirect_url = path.replace(url_prefix, redirect_url_prefix) + break + + qs = "" + query_params = getattr(request, "GET", {}) + redirect_qs = deepcopy(query_params) + if query_params: + url = redirect_url or path + for key in fields_map: + dataset, tablename, field_prev = key + has_field_update = all([f"/{dataset}/" in url, f"/{tablename}/" in url, field_prev in redirect_qs]) + if has_field_update: + value = redirect_qs[field_prev] + redirect_qs.pop(field_prev) + redirect_qs[fields_map[key]] = value + + qs = urlencode(redirect_qs) + + if not redirect_url and qs and set(query_params.keys()) != set(redirect_qs.keys()): + redirect_url = path + + if not redirect_url: + return "" + + return redirect_url + (f"?{qs}" if qs else "") diff --git a/core/tests/test_views.py b/core/tests/test_views.py index 0df2a59c..0c681589 100644 --- a/core/tests/test_views.py +++ b/core/tests/test_views.py @@ -255,3 +255,80 @@ def test_avoid_infinite_redirect_if_same_dataset_config_in_table(self): response = self.client.get(url) assert 404 == response.status_code + + def test_redirect_dataset_plus_field_name_redirect(self): + ds_redirect = self.dataset_redirects[0] + ds_redirect.tablename_prev = "caso2020" + ds_redirect.tablename_dest = "caso2020" + ds_redirect.field_prev = "query1" + ds_redirect.field_dest = "newquery" + ds_redirect.save() + + url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_prev, "caso2020"]) + redirect_url = ( + reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_dest, "caso2020"]) + + "?newquery=foo&query2=bar" + ) + response = self.client.get(url, data={"query1": "foo", "query2": "bar"}) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_redirect_dataset_plus_table_pluse_field_name_redirect(self): + ds_redirect = self.dataset_redirects[0] + ds_redirect.tablename_prev = "caso2019" + ds_redirect.tablename_dest = "caso2020" + ds_redirect.field_prev = "query1" + ds_redirect.field_dest = "newquery" + ds_redirect.save() + + url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_prev, "caso2019"]) + redirect_url = ( + reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_dest, "caso2020"]) + + "?newquery=foo&query2=bar" + ) + response = self.client.get(url, data={"query1": "foo", "query2": "bar"}) + + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_redirect_only_querystring_using_new_fieldname(self): + ds_redirect = self.dataset_redirects[0] + ds_redirect.dataset_dest = "dataset" + ds_redirect.dataset_prev = "dataset" + ds_redirect.tablename_prev = "caso2020" + ds_redirect.tablename_dest = "caso2020" + ds_redirect.field_prev = "query1" + ds_redirect.field_dest = "newquery" + ds_redirect.save() + baker.make("core.Table", dataset__slug="dataset", name="caso2020", dataset__show=True) + + # API endpoint + url = reverse("api-v1:dataset-table-data", args=["dataset", "caso2020"]) + redirect_url = reverse("api-v1:dataset-table-data", args=["dataset", "caso2020"]) + "?newquery=foo&query2=bar" + response = self.client.get(url, data={"query1": "foo", "query2": "bar"}) + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + # Dataset table route + url = reverse("core:dataset-table-detail", args=["dataset", "caso2020"]) + redirect_url = reverse("core:dataset-table-detail", args=["dataset", "caso2020"]) + "?newquery=foo&query2=bar" + response = self.client.get(url, data={"query1": "foo", "query2": "bar"}) + self.assertRedirects(response, redirect_url, fetch_redirect_response=False) + + def test_avoid_infinite_redirect_if_same_fieldname_config(self): + ds_redirect = self.dataset_redirects[0] + ds_redirect.dataset_dest = "dataset" + ds_redirect.dataset_prev = "dataset" + ds_redirect.tablename_prev = "caso2020" + ds_redirect.tablename_dest = "caso2020" + ds_redirect.field_prev = "query1" + ds_redirect.field_dest = "query1" + ds_redirect.save() + + # API url + url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_prev, ds_redirect.tablename_prev]) + response = self.client.get(url, data={"query1": "foo", "query2": "bar"}) + self.assertEqual(404, response.status_code) + + # Dataset table route + url = reverse("core:dataset-table-detail", args=[ds_redirect.dataset_prev, ds_redirect.tablename_prev]) + response = self.client.get(url, data={"query1": "foo", "query2": "bar"}) + self.assertEqual(404, response.status_code) diff --git a/core/views.py b/core/views.py index 55a9c636..cd085334 100644 --- a/core/views.py +++ b/core/views.py @@ -137,6 +137,11 @@ def dataset_detail(request, slug, tablename=""): pass return render(request, "404.html", context, status=404) + # check for querystring fields that should be redirected + redirect_url = DataUrlRedirect.redirect_from(request) + if redirect_url: + return redirect(redirect_url) + querystring = request.GET.copy() page_number = querystring.pop("page", ["1"])[0].strip() or "1" items_per_page = querystring.pop("items", [str(settings.ROWS_PER_PAGE)])[0].strip() or str(settings.ROWS_PER_PAGE) From 2d42448cc1795a563c67d978f224bb24a09d01ee Mon Sep 17 00:00:00 2001 From: Bernardo Fontes Date: Mon, 19 Oct 2020 15:59:56 -0300 Subject: [PATCH 12/12] Adiciona django admin --- core/admin.py | 13 +++++++++++++ core/models.py | 14 ++++++-------- core/tests/test_views.py | 4 ++-- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/core/admin.py b/core/admin.py index 0932aaf2..c0df00c4 100644 --- a/core/admin.py +++ b/core/admin.py @@ -190,4 +190,17 @@ def has_delete_permission(self, request, *args, **kwargs): return request.user.is_superuser +class DataUrlRedirectAdmin(admin.ModelAdmin): + list_display = [ + "id", + "dataset_prev", + "dataset_dest", + "tablename_prev", + "tablename_dest", + "field_prev", + "field_dest", + ] + + admin.site.register(models.TableFile, TableFileAdmin) +admin.site.register(models.DataUrlRedirect, DataUrlRedirectAdmin) diff --git a/core/models.py b/core/models.py index 38b7ed3f..ffbbdd8e 100644 --- a/core/models.py +++ b/core/models.py @@ -679,14 +679,12 @@ def admin_url(self): class DataUrlRedirect(models.Model): - dataset_prev = models.SlugField(default="") - dataset_dest = models.SlugField(default="") - - tablename_prev = models.SlugField(default="") - tablename_dest = models.SlugField(default="") - - field_prev = models.SlugField(default="") - field_dest = models.SlugField(default="") + dataset_prev = models.SlugField(default="", blank=True) + dataset_dest = models.SlugField(default="", blank=True) + tablename_prev = models.SlugField(default="", blank=True) + tablename_dest = models.SlugField(default="", blank=True) + field_prev = models.SlugField(default="", blank=True) + field_dest = models.SlugField(default="", blank=True) @property def redirect_map(self): diff --git a/core/tests/test_views.py b/core/tests/test_views.py index 0c681589..38c54aa6 100644 --- a/core/tests/test_views.py +++ b/core/tests/test_views.py @@ -267,7 +267,7 @@ def test_redirect_dataset_plus_field_name_redirect(self): url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_prev, "caso2020"]) redirect_url = ( reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_dest, "caso2020"]) - + "?newquery=foo&query2=bar" + + "?newquery=foo&query2=bar" # noqa ) response = self.client.get(url, data={"query1": "foo", "query2": "bar"}) @@ -284,7 +284,7 @@ def test_redirect_dataset_plus_table_pluse_field_name_redirect(self): url = reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_prev, "caso2019"]) redirect_url = ( reverse("api-v1:dataset-table-data", args=[ds_redirect.dataset_dest, "caso2020"]) - + "?newquery=foo&query2=bar" + + "?newquery=foo&query2=bar" # noqa ) response = self.client.get(url, data={"query1": "foo", "query2": "bar"})