From 5dd95f15641e6a0e413352b3d164922e797ff9a3 Mon Sep 17 00:00:00 2001 From: Marcel Marques Date: Mon, 5 Apr 2021 09:10:10 -0300 Subject: [PATCH 01/13] Subindo app clipping para gerenciamento de links e referencias a datasets do brasilio --- clipping/__init__.py | 0 clipping/admin.py | 53 +++++++++++++++++++ clipping/apps.py | 5 ++ clipping/migrations/0001_initial.py | 45 ++++++++++++++++ clipping/migrations/__init__.py | 0 clipping/models.py | 35 ++++++++++++ .../templates/admin/clipping/change_form.html | 43 +++++++++++++++ clipping/tests.py | 3 ++ clipping/urls.py | 8 +++ clipping/views.py | 17 ++++++ 10 files changed, 209 insertions(+) create mode 100644 clipping/__init__.py create mode 100644 clipping/admin.py create mode 100644 clipping/apps.py create mode 100644 clipping/migrations/0001_initial.py create mode 100644 clipping/migrations/__init__.py create mode 100644 clipping/models.py create mode 100644 clipping/templates/admin/clipping/change_form.html create mode 100644 clipping/tests.py create mode 100644 clipping/urls.py create mode 100644 clipping/views.py diff --git a/clipping/__init__.py b/clipping/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/clipping/admin.py b/clipping/admin.py new file mode 100644 index 00000000..f8cb5aaa --- /dev/null +++ b/clipping/admin.py @@ -0,0 +1,53 @@ +from django import forms +from django.contrib import admin +from django.forms.models import ModelChoiceField + +from .models import ClippingRelation, Clipping +from django.contrib.contenttypes.models import ContentType + +from django.conf import settings + + +class ClippingRelationAdminForm(forms.ModelForm): + contents = [] + for app_name in settings.CONTENTS: + for model_name in settings.CONTENTS[app_name]: + contents.append(model_name) + + content_type = ModelChoiceField(ContentType.objects.filter(app_label__in=settings.CONTENTS, model__in=contents), + empty_label="--------", label='Content') + object_id = forms.CharField(widget=forms.Select(choices=[('','---------')]), label='Element') + + class Meta: + model = ClippingRelation + fields = ['content_type', 'object_id', 'clipping'] + + +@admin.register(ClippingRelation) +class ClippingRelationAdmin(admin.ModelAdmin): + form = ClippingRelationAdminForm + list_display = ('get_clipping_relation', 'clipping', 'content_type') + + def get_clipping_relation(self, obj): + return obj.content_object.name + get_clipping_relation.short_description = 'Relation' + + +class ClippingAdminForm(forms.ModelForm): + category = forms.CharField(widget=forms.Select(choices=settings.CATEGORY_CHOICES), label='Category') + + class Meta: + model = Clipping + exclude = ['added_by'] + + +@admin.register(Clipping) +class ClippingAdmin(admin.ModelAdmin): + form = ClippingAdminForm + list_display = ('date','title', 'author', 'vehicle', 'category', 'url', 'added_by', 'published') + + # Sets the current user as the adder + def save_model(self, request, obj, form, change): + if getattr(obj, 'added_by', None) is None: + obj.added_by = request.user + obj.save() diff --git a/clipping/apps.py b/clipping/apps.py new file mode 100644 index 00000000..6b35d3be --- /dev/null +++ b/clipping/apps.py @@ -0,0 +1,5 @@ +from django.apps import AppConfig + + +class ClippingConfig(AppConfig): + name = 'clipping' diff --git a/clipping/migrations/0001_initial.py b/clipping/migrations/0001_initial.py new file mode 100644 index 00000000..e9faac43 --- /dev/null +++ b/clipping/migrations/0001_initial.py @@ -0,0 +1,45 @@ +# Generated by Django 3.1.6 on 2021-04-09 13:04 + +import datetime +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('contenttypes', '0002_remove_content_type_name'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='Clipping', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField(default=datetime.date.today)), + ('vehicle', models.CharField(blank=True, max_length=100, null=True)), + ('author', models.CharField(blank=True, max_length=100, null=True)), + ('title', models.CharField(blank=True, max_length=200, null=True)), + ('category', models.CharField(max_length=100, null=True)), + ('url', models.URLField(unique=True)), + ('published', models.BooleanField(blank=True, default=False)), + ('added_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to=settings.AUTH_USER_MODEL)), + ], + ), + migrations.CreateModel( + name='ClippingRelation', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('object_id', models.PositiveIntegerField(db_index=True)), + ('clipping', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='clipping.clipping')), + ('content_type', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype')), + ], + options={ + 'unique_together': {('content_type', 'object_id', 'clipping')}, + }, + ), + ] diff --git a/clipping/migrations/__init__.py b/clipping/migrations/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/clipping/models.py b/clipping/models.py new file mode 100644 index 00000000..7fe241f1 --- /dev/null +++ b/clipping/models.py @@ -0,0 +1,35 @@ +import datetime +from django.contrib.auth import get_user_model +from django.db import models +from django.contrib.contenttypes.fields import GenericForeignKey +from django.contrib.contenttypes.models import ContentType + + +class Clipping(models.Model): + date = models.DateField(null=False, blank=False, default=datetime.date.today) + vehicle = models.CharField(max_length=100, null=True, blank=True) + author = models.CharField(max_length=100, null=True, blank=True) + title = models.CharField(max_length=200, null=True, blank=True) + category = models.CharField(max_length=100, null=True) + url = models.URLField(null=False, blank=False, unique=True) + published = models.BooleanField(default=False, blank=True) + + added_by = models.ForeignKey(get_user_model(), null=True, blank=True, + on_delete=models.SET_NULL) + + def __str__(self): + return self.title + + +class ClippingRelation(models.Model): + content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE) + object_id = models.PositiveIntegerField(db_index=True) + content_object = GenericForeignKey() + + clipping = models.ForeignKey(Clipping, on_delete=models.CASCADE) + + def __str__(self): + return "Content: {} | Clipping: {}".format(self.content_object.name, self.clipping.title) + + class Meta: + unique_together = ['content_type', 'object_id', 'clipping'] diff --git a/clipping/templates/admin/clipping/change_form.html b/clipping/templates/admin/clipping/change_form.html new file mode 100644 index 00000000..6861fd20 --- /dev/null +++ b/clipping/templates/admin/clipping/change_form.html @@ -0,0 +1,43 @@ +{% extends "admin/change_form.html" %} {% block extrahead %} {{ block.super }} + + +{% endblock %} diff --git a/clipping/tests.py b/clipping/tests.py new file mode 100644 index 00000000..7ce503c2 --- /dev/null +++ b/clipping/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/clipping/urls.py b/clipping/urls.py new file mode 100644 index 00000000..ebaf58e8 --- /dev/null +++ b/clipping/urls.py @@ -0,0 +1,8 @@ +from django.urls import path + +from . import views + +urlpatterns = [ + path('get/contentype_instances/', views.get_contenttype_instances), + path('get/selected_instance/', views.get_current_selected_instance), +] diff --git a/clipping/views.py b/clipping/views.py new file mode 100644 index 00000000..e8ec5e8e --- /dev/null +++ b/clipping/views.py @@ -0,0 +1,17 @@ +import json +from django.http import HttpResponse +from django.shortcuts import render # get_object_or_404, redirect +from django.contrib.contenttypes.models import ContentType +from .models import Clipping, ClippingRelation + + +def get_contenttype_instances(request): + pk = request.GET.get('id') + result = list(ContentType.objects.get(id=pk).model_class().objects.filter().values('id', 'name')) + return HttpResponse(json.dumps(result), content_type="application/json") + + +def get_current_selected_instance(request): + pk = request.GET.get('id') + result = ClippingRelation.objects.get(id=pk).object_id + return HttpResponse(json.dumps(result), content_type="application/json") From 069eaa3da0cb0c67b4b47af718c673bc10918f4a Mon Sep 17 00:00:00 2001 From: Marcel Marques Date: Mon, 5 Apr 2021 09:22:34 -0300 Subject: [PATCH 02/13] Adicionando o app na settings e setando content para as relacoes que deseja disponibilizar e choices para as ecolhas de categoria na criacao de clipping, urls setadas para funcioamento de selects do django admin --- project/settings.py | 9 +++++++++ project/urls.py | 1 + 2 files changed, 10 insertions(+) diff --git a/project/settings.py b/project/settings.py index 08bd8648..e57e3008 100644 --- a/project/settings.py +++ b/project/settings.py @@ -73,6 +73,7 @@ "covid19.apps.Covid19Config", "dashboard", "traffic_control", + "clipping", ] MIDDLEWARE = [ @@ -356,3 +357,11 @@ LOGGING = DEFAULT_LOGGING.copy() LOGGING["handlers"]["null"] = {"class": "logging.NullHandler"} LOGGING["loggers"]["django.security.DisallowedHost"] = {"handlers": ["null"], "propagate": False} + +# Clipping app +CONTENTS = {"core": ["dataset", "table"]} +CATEGORY_CHOICES = [ + ("noticias_e_entrevistas", "Notícias e Entrevistas"), + ("analises", "Análises"), + ("podcasts_e_radio", "Podcasts e Rádio"), +] diff --git a/project/urls.py b/project/urls.py index c922500f..a4e1e749 100644 --- a/project/urls.py +++ b/project/urls.py @@ -8,6 +8,7 @@ path("api/", include("project.api_urls")), path("auth/", include("brasilio_auth.urls", namespace="brasilio_auth")), path("covid19/", include("covid19.urls", namespace="covid19")), + path("clipping/", include("clipping.urls")), path("django-rq/", include("django_rq.urls")), path("markdownx/", include("markdownx.urls")), path("", include("core.urls", namespace="core")), From 7301c7e1915454dc064b1a503ac090f953fb69fa Mon Sep 17 00:00:00 2001 From: Marcel Marques Date: Fri, 9 Apr 2021 09:42:28 -0300 Subject: [PATCH 03/13] Exibindo clippings nas templates de table junto com formulario para sugestao de novos links por usuarios --- clipping/forms.py | 16 ++++ core/templates/core/dataset-detail.html | 106 ++++++++++++++++++++++++ core/views.py | 30 +++++++ 3 files changed, 152 insertions(+) create mode 100644 clipping/forms.py diff --git a/clipping/forms.py b/clipping/forms.py new file mode 100644 index 00000000..8ae0a70f --- /dev/null +++ b/clipping/forms.py @@ -0,0 +1,16 @@ +from django.forms import ModelForm +from .models import Clipping +from django import forms +from django.conf import settings + + +class ClippingForm(ModelForm): + category = forms.CharField(widget=forms.Select(choices=settings.CATEGORY_CHOICES), label='Categoria') + date = forms.CharField(widget=forms.TextInput(attrs={'class':'datepicker'}),label='Data') + author = forms.CharField(label='Autor') + title = forms.CharField(label='Título') + + class Meta: + model = Clipping + fields = '__all__' + exclude = ['added_by', 'published'] diff --git a/core/templates/core/dataset-detail.html b/core/templates/core/dataset-detail.html index d9a0ee14..2c6b33e6 100644 --- a/core/templates/core/dataset-detail.html +++ b/core/templates/core/dataset-detail.html @@ -77,6 +77,7 @@

{{ dataset.name }}

@@ -197,9 +198,91 @@
Filtros
+ +
+ +
+
+
+
+
+ + Referências desta base de dados na mídia + +
+ +
+ + + + + + + + + + + + {% if clipping|length > 0 %} + {% for link in clipping %} + {% if link.clipping.published %} + + + + + + + {% endif %} + {% endfor %} + {% else %} + + + + + + + {% endif %} + + +
TítuloAutorCategoriaLink
{{ link.clipping.title }} {{ link.clipping.author }} {{ link.clipping.category }} {{ link.clipping.url|truncatechars:30}}
--- --- Nenhum link publicado ---
+ {% if user.is_authenticated %} +
+ + Sugerir novo link + +
+
+ {% csrf_token %} + {% for field in form %} +
+ {{field}} + + {% if field.errors %} + {{field.errors}} + {% endif %} +
+ {% endfor %} +
+ +
+
+
+
+ {% endif %} +
+
+
+
+
+ +
+{% if message %} + +{% endif %} + {% endlocalize %}{% endblock %} {% block script %} @@ -216,6 +299,29 @@
Filtros
"ordering": false, "bInfo": false, }); + $('.datepicker').datepicker({ + i18n: { + months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'], + monthsShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'], + weekdays: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sabádo'], + weekdaysShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab'], + weekdaysAbbrev: ['D', 'S', 'T', 'Q', 'Q', 'S', 'S'], + today: 'Hoje', + clear: 'Limpar', + cancel: 'Sair', + done: 'Confirmar', + labelMonthNext: 'Próximo mês', + labelMonthPrev: 'Mês anterior', + labelMonthSelect: 'Selecione um mês', + labelYearSelect: 'Selecione um ano', + selectMonths: true, + selectYears: true, + }, + yearRange: [2010,new Date().getFullYear()], + format: 'yyyy-mm-dd', + container: 'body', + maxDate: new Date(), + }); }); {% endblock %} diff --git a/core/views.py b/core/views.py index 61022be5..3dbdba36 100644 --- a/core/views.py +++ b/core/views.py @@ -18,6 +18,9 @@ from core.util import cached_http_get_json from data_activities_log.activites import recent_activities from traffic_control.logging import log_blocked_request +from clipping.models import ClippingRelation +from clipping.forms import ClippingForm +from django.contrib.contenttypes.models import ContentType class Echo: @@ -204,7 +207,32 @@ def dataset_detail(request, slug, tablename=""): if not value: del querystring[key] + clipping = [] + clipping_type_dataset = ContentType.objects.get(app_label='core', model='dataset') + clipping_dataset = list(ClippingRelation.objects.filter(content_type=clipping_type_dataset.id, object_id=dataset.pk)) + clipping.extend(clipping_dataset) + clipping_type_table = ContentType.objects.get(app_label='core', model='table') + clipping_table = list(ClippingRelation.objects.filter(content_type=clipping_type_table.id, object_id=table.pk)) + clipping.extend(clipping_table) + + message = None + if request.method == 'POST': + clipping_form = ClippingForm(request.POST) + if clipping_form.is_valid(): + clipping = clipping_form.save(commit=False) + clipping.added_by = request.user + clipping.save() + clipping_form.added_by = request.user + + clipping_form = ClippingForm() + message = "Sugestão enviada com sucesso" + else: + message = "Erro: Verifique o formulário novamente" + else: + clipping_form = ClippingForm() + context = { + "clipping": clipping, "data": data, "dataset": dataset, "filter_form": filter_form, @@ -215,6 +243,8 @@ def dataset_detail(request, slug, tablename=""): "table": table, "total_count": all_data.count(), "version": version, + "form": clipping_form, + "message": message } status = 200 From dcdac32872349ef335687e790a5186ccbaa13412 Mon Sep 17 00:00:00 2001 From: Marcel Marques Date: Fri, 9 Apr 2021 10:12:40 -0300 Subject: [PATCH 04/13] Adicionando comando management para importar dados de csv com links/clippings para o banco de dados --- .../management/commands/import_clippings.py | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 clipping/management/commands/import_clippings.py diff --git a/clipping/management/commands/import_clippings.py b/clipping/management/commands/import_clippings.py new file mode 100644 index 00000000..9c1f49b9 --- /dev/null +++ b/clipping/management/commands/import_clippings.py @@ -0,0 +1,32 @@ +import os +import csv +import rows + +from django.core.management.base import BaseCommand +from pathlib import Path + +from django.contrib.auth import get_user_model +from clipping.models import Clipping + + +class Command(BaseCommand): + def add_arguments(self, parser): + parser.add_argument("csv", type=Path, help="CSV file to update the clippings JSON field") + + def clean_args(self, **kwargs): + csv_file = kwargs["csv"] + if csv_file and not csv_file.exists(): + raise Exception(f"The CSV {csv_file} does not exists") + return csv_file + + def handle(self, *args, **kwargs): + csv_file = self.clean_args(**kwargs) + username = "turicas" + user = get_user_model().objects.get(username=username) + with open(csv_file, encoding='utf-8') as csvfile: + reader = csv.DictReader(csvfile) + for row in reader: + p = Clipping(date=row['data'], vehicle=row['veiculo'], author=row['autor'], title=row['titulo'], + category=row['categoria'], url=row['link'], published=True, added_by=user) + p.save() + self.stdout.write(self.style.SUCCESS('Successfully imported')) From 56fa90da1efd7d1fec2c8cdbeeb9855687d14927 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Justen=20=28=40turicas=29?= Date: Fri, 10 May 2024 18:36:50 -0300 Subject: [PATCH 05/13] make lint --- clipping/admin.py | 31 ++++++++++--------- clipping/apps.py | 2 +- clipping/forms.py | 17 +++++----- .../management/commands/import_clippings.py | 22 ++++++++----- clipping/models.py | 8 ++--- clipping/tests.py | 2 -- clipping/urls.py | 4 +-- clipping/views.py | 13 ++++---- core/views.py | 18 ++++++----- 9 files changed, 64 insertions(+), 53 deletions(-) diff --git a/clipping/admin.py b/clipping/admin.py index f8cb5aaa..fafc9362 100644 --- a/clipping/admin.py +++ b/clipping/admin.py @@ -1,11 +1,10 @@ from django import forms +from django.conf import settings from django.contrib import admin -from django.forms.models import ModelChoiceField - -from .models import ClippingRelation, Clipping from django.contrib.contenttypes.models import ContentType +from django.forms.models import ModelChoiceField -from django.conf import settings +from .models import Clipping, ClippingRelation class ClippingRelationAdminForm(forms.ModelForm): @@ -14,40 +13,44 @@ class ClippingRelationAdminForm(forms.ModelForm): for model_name in settings.CONTENTS[app_name]: contents.append(model_name) - content_type = ModelChoiceField(ContentType.objects.filter(app_label__in=settings.CONTENTS, model__in=contents), - empty_label="--------", label='Content') - object_id = forms.CharField(widget=forms.Select(choices=[('','---------')]), label='Element') + content_type = ModelChoiceField( + ContentType.objects.filter(app_label__in=settings.CONTENTS, model__in=contents), + empty_label="--------", + label="Content", + ) + object_id = forms.CharField(widget=forms.Select(choices=[("", "---------")]), label="Element") class Meta: model = ClippingRelation - fields = ['content_type', 'object_id', 'clipping'] + fields = ["content_type", "object_id", "clipping"] @admin.register(ClippingRelation) class ClippingRelationAdmin(admin.ModelAdmin): form = ClippingRelationAdminForm - list_display = ('get_clipping_relation', 'clipping', 'content_type') + list_display = ("get_clipping_relation", "clipping", "content_type") def get_clipping_relation(self, obj): return obj.content_object.name - get_clipping_relation.short_description = 'Relation' + + get_clipping_relation.short_description = "Relation" class ClippingAdminForm(forms.ModelForm): - category = forms.CharField(widget=forms.Select(choices=settings.CATEGORY_CHOICES), label='Category') + category = forms.CharField(widget=forms.Select(choices=settings.CATEGORY_CHOICES), label="Category") class Meta: model = Clipping - exclude = ['added_by'] + exclude = ["added_by"] @admin.register(Clipping) class ClippingAdmin(admin.ModelAdmin): form = ClippingAdminForm - list_display = ('date','title', 'author', 'vehicle', 'category', 'url', 'added_by', 'published') + list_display = ("date", "title", "author", "vehicle", "category", "url", "added_by", "published") # Sets the current user as the adder def save_model(self, request, obj, form, change): - if getattr(obj, 'added_by', None) is None: + if getattr(obj, "added_by", None) is None: obj.added_by = request.user obj.save() diff --git a/clipping/apps.py b/clipping/apps.py index 6b35d3be..67270305 100644 --- a/clipping/apps.py +++ b/clipping/apps.py @@ -2,4 +2,4 @@ class ClippingConfig(AppConfig): - name = 'clipping' + name = "clipping" diff --git a/clipping/forms.py b/clipping/forms.py index 8ae0a70f..f87ea691 100644 --- a/clipping/forms.py +++ b/clipping/forms.py @@ -1,16 +1,17 @@ -from django.forms import ModelForm -from .models import Clipping from django import forms from django.conf import settings +from django.forms import ModelForm + +from .models import Clipping class ClippingForm(ModelForm): - category = forms.CharField(widget=forms.Select(choices=settings.CATEGORY_CHOICES), label='Categoria') - date = forms.CharField(widget=forms.TextInput(attrs={'class':'datepicker'}),label='Data') - author = forms.CharField(label='Autor') - title = forms.CharField(label='Título') + category = forms.CharField(widget=forms.Select(choices=settings.CATEGORY_CHOICES), label="Categoria") + date = forms.CharField(widget=forms.TextInput(attrs={"class": "datepicker"}), label="Data") + author = forms.CharField(label="Autor") + title = forms.CharField(label="Título") class Meta: model = Clipping - fields = '__all__' - exclude = ['added_by', 'published'] + fields = "__all__" + exclude = ["added_by", "published"] diff --git a/clipping/management/commands/import_clippings.py b/clipping/management/commands/import_clippings.py index 9c1f49b9..b651f63a 100644 --- a/clipping/management/commands/import_clippings.py +++ b/clipping/management/commands/import_clippings.py @@ -1,11 +1,9 @@ -import os import csv -import rows - -from django.core.management.base import BaseCommand from pathlib import Path from django.contrib.auth import get_user_model +from django.core.management.base import BaseCommand + from clipping.models import Clipping @@ -23,10 +21,18 @@ def handle(self, *args, **kwargs): csv_file = self.clean_args(**kwargs) username = "turicas" user = get_user_model().objects.get(username=username) - with open(csv_file, encoding='utf-8') as csvfile: + with open(csv_file, encoding="utf-8") as csvfile: reader = csv.DictReader(csvfile) for row in reader: - p = Clipping(date=row['data'], vehicle=row['veiculo'], author=row['autor'], title=row['titulo'], - category=row['categoria'], url=row['link'], published=True, added_by=user) + p = Clipping( + date=row["data"], + vehicle=row["veiculo"], + author=row["autor"], + title=row["titulo"], + category=row["categoria"], + url=row["link"], + published=True, + added_by=user, + ) p.save() - self.stdout.write(self.style.SUCCESS('Successfully imported')) + self.stdout.write(self.style.SUCCESS("Successfully imported")) diff --git a/clipping/models.py b/clipping/models.py index 7fe241f1..f248f9b3 100644 --- a/clipping/models.py +++ b/clipping/models.py @@ -1,8 +1,9 @@ import datetime + from django.contrib.auth import get_user_model -from django.db import models from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType +from django.db import models class Clipping(models.Model): @@ -14,8 +15,7 @@ class Clipping(models.Model): url = models.URLField(null=False, blank=False, unique=True) published = models.BooleanField(default=False, blank=True) - added_by = models.ForeignKey(get_user_model(), null=True, blank=True, - on_delete=models.SET_NULL) + added_by = models.ForeignKey(get_user_model(), null=True, blank=True, on_delete=models.SET_NULL) def __str__(self): return self.title @@ -32,4 +32,4 @@ def __str__(self): return "Content: {} | Clipping: {}".format(self.content_object.name, self.clipping.title) class Meta: - unique_together = ['content_type', 'object_id', 'clipping'] + unique_together = ["content_type", "object_id", "clipping"] diff --git a/clipping/tests.py b/clipping/tests.py index 7ce503c2..a39b155a 100644 --- a/clipping/tests.py +++ b/clipping/tests.py @@ -1,3 +1 @@ -from django.test import TestCase - # Create your tests here. diff --git a/clipping/urls.py b/clipping/urls.py index ebaf58e8..19e5dc82 100644 --- a/clipping/urls.py +++ b/clipping/urls.py @@ -3,6 +3,6 @@ from . import views urlpatterns = [ - path('get/contentype_instances/', views.get_contenttype_instances), - path('get/selected_instance/', views.get_current_selected_instance), + path("get/contentype_instances/", views.get_contenttype_instances), + path("get/selected_instance/", views.get_current_selected_instance), ] diff --git a/clipping/views.py b/clipping/views.py index e8ec5e8e..d7f1ddaa 100644 --- a/clipping/views.py +++ b/clipping/views.py @@ -1,17 +1,18 @@ import json -from django.http import HttpResponse -from django.shortcuts import render # get_object_or_404, redirect + from django.contrib.contenttypes.models import ContentType -from .models import Clipping, ClippingRelation +from django.http import HttpResponse + +from .models import ClippingRelation def get_contenttype_instances(request): - pk = request.GET.get('id') - result = list(ContentType.objects.get(id=pk).model_class().objects.filter().values('id', 'name')) + pk = request.GET.get("id") + result = list(ContentType.objects.get(id=pk).model_class().objects.filter().values("id", "name")) return HttpResponse(json.dumps(result), content_type="application/json") def get_current_selected_instance(request): - pk = request.GET.get('id') + pk = request.GET.get("id") result = ClippingRelation.objects.get(id=pk).object_id return HttpResponse(json.dumps(result), content_type="application/json") diff --git a/core/views.py b/core/views.py index 3dbdba36..5a139684 100644 --- a/core/views.py +++ b/core/views.py @@ -2,6 +2,7 @@ import uuid from django.conf import settings +from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist from django.core.mail import EmailMessage from django.core.paginator import Paginator @@ -10,6 +11,8 @@ from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse +from clipping.forms import ClippingForm +from clipping.models import ClippingRelation 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 @@ -18,9 +21,6 @@ from core.util import cached_http_get_json from data_activities_log.activites import recent_activities from traffic_control.logging import log_blocked_request -from clipping.models import ClippingRelation -from clipping.forms import ClippingForm -from django.contrib.contenttypes.models import ContentType class Echo: @@ -208,15 +208,17 @@ def dataset_detail(request, slug, tablename=""): del querystring[key] clipping = [] - clipping_type_dataset = ContentType.objects.get(app_label='core', model='dataset') - clipping_dataset = list(ClippingRelation.objects.filter(content_type=clipping_type_dataset.id, object_id=dataset.pk)) + clipping_type_dataset = ContentType.objects.get(app_label="core", model="dataset") + clipping_dataset = list( + ClippingRelation.objects.filter(content_type=clipping_type_dataset.id, object_id=dataset.pk) + ) clipping.extend(clipping_dataset) - clipping_type_table = ContentType.objects.get(app_label='core', model='table') + clipping_type_table = ContentType.objects.get(app_label="core", model="table") clipping_table = list(ClippingRelation.objects.filter(content_type=clipping_type_table.id, object_id=table.pk)) clipping.extend(clipping_table) message = None - if request.method == 'POST': + if request.method == "POST": clipping_form = ClippingForm(request.POST) if clipping_form.is_valid(): clipping = clipping_form.save(commit=False) @@ -244,7 +246,7 @@ def dataset_detail(request, slug, tablename=""): "total_count": all_data.count(), "version": version, "form": clipping_form, - "message": message + "message": message, } status = 200 From 0f5431db5a49ae0e35edec1c3210117c46ee36cb Mon Sep 17 00:00:00 2001 From: Marcel Marques Date: Mon, 13 Sep 2021 16:41:16 -0300 Subject: [PATCH 06/13] New datasets views and urls --- core/urls.py | 3 ++- core/views.py | 36 ++++++++++++++++++++++++++++++++++-- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/core/urls.py b/core/urls.py index 8dabada4..615d1906 100644 --- a/core/urls.py +++ b/core/urls.py @@ -16,7 +16,8 @@ path("home/", views.home, name="home"), path("dataset//", views.dataset_detail, name="dataset-detail"), path("dataset//files/", views.dataset_files_detail, name="dataset-files-detail"), - path("dataset///", enable_ratelimit(views.dataset_detail), name="dataset-table-detail"), + path("dataset///", enable_ratelimit(views.dataset_table_detail), name="dataset-table-detail"), + path("dataset//list_all//", views.dataset_list_detail, name="dataset-list-detail"), path("datasets/sugira/", views.dataset_suggestion, name="dataset-suggestion"), path("manifesto/", views.manifesto, name="manifesto"), path("colabore/", views.collaborate, name="collaborate"), diff --git a/core/views.py b/core/views.py index 5a139684..3a908a50 100644 --- a/core/views.py +++ b/core/views.py @@ -107,8 +107,40 @@ def dataset_list(request): context = {"datasets": Dataset.objects.filter(q).order_by("name"), "form": form} return render(request, "core/dataset-list.html", context) +def dataset_list_detail(request, slug, listname): + if len(request.GET) > 0 and not request.user.is_authenticated: + return redirect(f"{settings.LOGIN_URL}?next={request.get_full_path()}") + + try: + dataset = Dataset.objects.get(slug=slug) + except Dataset.DoesNotExist: + context = {"message": "Dataset does not exist"} + return render(request, "404.html", context, status=404) + + context = { + "listname": listname.replace('_', ' '), + "dataset": dataset, + } + + return render(request, "core/dataset-list-detail.html", context, status=200) + +def dataset_detail(request, slug): + if len(request.GET) > 0 and not request.user.is_authenticated: + return redirect(f"{settings.LOGIN_URL}?next={request.get_full_path()}") + + try: + dataset = Dataset.objects.get(slug=slug) + except Dataset.DoesNotExist: + context = {"message": "Dataset does not exist"} + return render(request, "404.html", context, status=404) + + context = { + "dataset": dataset, + } + + return render(request, "core/dataset-detail.html", context, status=200) -def dataset_detail(request, slug, tablename=""): +def dataset_table_detail(request, slug, tablename=""): if len(request.GET) > 0 and not request.user.is_authenticated: return redirect(f"{settings.LOGIN_URL}?next={request.get_full_path()}") @@ -252,7 +284,7 @@ def dataset_detail(request, slug, tablename=""): status = 200 if filter_form.errors: status = 400 - return render(request, "core/dataset-detail.html", context, status=status) + return render(request, "core/dataset-table-detail.html", context, status=status) def dataset_suggestion(request): From d4384a42bdb21c378da0b91aed0fd16d19f6e31f Mon Sep 17 00:00:00 2001 From: Marcel Marques Date: Mon, 13 Sep 2021 16:42:43 -0300 Subject: [PATCH 07/13] New templates and updates in dataset-detail template --- core/static/core/css/dataset-detail.css | 128 +++++++ core/templates/core/dataset-detail.html | 332 +++++------------- core/templates/core/dataset-list-detail.html | 53 +++ core/templates/core/dataset-table-detail.html | 275 +++++++++++++++ core/urls.py | 1 + core/views.py | 65 ++-- 6 files changed, 589 insertions(+), 265 deletions(-) create mode 100644 core/static/core/css/dataset-detail.css create mode 100644 core/templates/core/dataset-list-detail.html create mode 100644 core/templates/core/dataset-table-detail.html diff --git a/core/static/core/css/dataset-detail.css b/core/static/core/css/dataset-detail.css new file mode 100644 index 00000000..02d76f43 --- /dev/null +++ b/core/static/core/css/dataset-detail.css @@ -0,0 +1,128 @@ +.breadcrumb { + letter-spacing: 3px; + margin-left: 21px; + padding-bottom: 12px; +} + +h1 { + font-size: 25px; + margin-bottom: 25px; + margin-left: 7px; +} + +.nav-content a:hover { + text-decoration: underline; +} + +.main-card { + height: 291px; + overflow-y: auto; +} + +.main-card-title { + font-size: x-large; + margin: 0 0 12px 0; +} + +.main-card-util { + margin: 12px 0 9px 0; + font-size: medium; +} + +#dataset-icon { + padding: 0 0 14px; +} + +.side-card-title { + font-size: large; + font-weight: 500; + margin: 14px 0 10px 0; +} + +.side-card-data { + font-weight: 500; + padding: 14px 0 2px 0; +} + +.side-card-data a { + font-weight: 500; +} + +.side-card-data-text { + font-weight: 400; +} + +.side-card p { + max-width: 450px; +} + +.main-card p { + max-width: 650px; +} + +.secondary-card-title { + font-size: medium; + font-weight: 500; + margin: 4px 0 12px 0; +} + +.secondary-card-content { + max-width: 900px; + margin: auto; +} + +.metadata { + margin: 4px 0; +} + +.metadata li { + padding: 5px 0; + font-weight: 600; +} + +.collection-item { + font-weight: 500; + letter-spacing: 1px; + color:#007db6 !important; +} + +.card-flex { + display: flex; +} + +.card-flex-item { + flex-grow: 1; +} + +/* Container style of BRiO */ +.container { + margin: 0 auto; + width: 90%; + max-width: 100%; +} + +/* Table detail */ + +.tab a.active { + background-color: rgba(203, 203, 255, 0.2) !important; +} + +.tabs .tab a { + background-color: rgba(225, 225, 255, 0.1) +} + +.tabs .indicator { + background-color: blue !important; +} + +@media only screen and (min-width: 301px) { + .table-detail p { + max-width: 600px; + } +} + +@media only screen and (min-width: 993px) { + .table-detail p { + max-width: 900px; + } +} \ No newline at end of file diff --git a/core/templates/core/dataset-detail.html b/core/templates/core/dataset-detail.html index 2c6b33e6..feb0845a 100644 --- a/core/templates/core/dataset-detail.html +++ b/core/templates/core/dataset-detail.html @@ -2,216 +2,93 @@ {% load cache %} {% load humanize %} {% load l10n %} +{% load static %} {% load markdown %} {% load utils %} {% block title %}{{ dataset.name }} - Datasets - Brasil.IO{% endblock %} + +{% block head %} +{{ block.super }} + +{% endblock %} + +{% block nav %} + +{% endblock %} {% block content %}{% localize off %}
-
-

{{ dataset.name }}

-

- {{ dataset.description }} -

- -
-
-
- Tabelas: - {% for dataset_table in dataset.tables %} - {% spaceless %} - {% if dataset_table == table %} - {{ dataset_table.name }} - {% else %} - {{ dataset_table.name }} - {% endif %} - {% endspaceless %}{% if not forloop.last %}, {% else %}.{% endif %} - {% endfor %} - - {% cache 3600 table_description table.description %} - {% if table.description %} -
-
-
-
- Informações úteis - {{ table.description | markdownify | safe }} -
-
-
-
- {% endif %} - {% endcache %} - -

- Quer baixar os dados completos ou precisa acessá-los de - maneira automatizada? Antes de mais nada, leia - a documentação e depois baixe - o dataset completo ou - utilize - nossa API. -

- - -
-
-
-
-
Filtros
- -
-
- -
- - - -
- - {% for field in filter_form %} -
- - {{ field }} - {% if field.errors %} - {{ field.errors.as_text }} - {% endif %} -
- {% endfor %} - -
-
- -
- -
-
-
- -
-

- Dados capturados em {{ version.collected_at }}. - {% if table.import_date %} - Importação dos dados feita em {{ table.import_date }}. +

+
+
+ {{ dataset.icon }} +

{{ dataset.name|capfirst }}

+

{{ dataset.description }}

+ {% if dataset.long_description != None %} +

{{ dataset.long_description }}

{% endif %} -

- -
- {% if total_count > 0 and total_count <= max_export_rows and querystring %} - - Baixar resultado em CSV* - -
- * No máximo {{ max_export_rows|localize }} registros serão - exportados. Caso você necessite de mais dados, considere - baixar o dataset completo. - {% else %} - - Baixar dados completos em CSV - + {% if dataset.info != None %} +

Informações úteis

{% endif %}
- -
-
    -
  • {{ data.start_index|localize }}-{{ data.end_index|localize }} de um total de {{ total_count|localize }}
  • - {% if data.has_previous %} -
  • chevron_left
  • - {% endif %} - - {% if data.has_next %} -
  • chevron_right
  • - {% endif %} -
-
-
- -
- {% with table_id=dataset.slug fields=table.fields %} - {% include 'core/data-table.html' %} - {% endwith %} +
+
+
+
+

Tabelas

+
+ +
+ {% if dataset.tables|length > 4 %} + + {% endif %} +
-
-
- -
-
-
-
- - Dicionário de Dados - Tabela {{ table.name }} - - - - - - - - - - - - - - {% for field in table.fields %} - - - - - - +
+
+
+

{{dataset.name}}

+

{{ dataset.description }}

+
- -
ColunaTipoTítuloDescrição
{{ field.name }} {{ field.type }}{% if field.options_text %} ({{ field.options_text }}){% endif %} {{ field.title }} {{ field.description }}
- -
+ +
-
-
- -
- -
-
-
-
+
+
+
+

Referências desta base de dados na mídia

- - Referências desta base de dados na mídia - -
- -
@@ -221,21 +98,20 @@
Filtros
- + {% if clipping|length > 0 %} - {% for link in clipping %} - {% if link.clipping.published %} - - - - - - - {% endif %} - {% endfor %} + {% for link in clipping %} + + + + + + + {% endfor %} {% else %} - + @@ -243,40 +119,17 @@
Filtros
{% endif %} - +
Link
{{ link.clipping.title }} {{ link.clipping.author }} {{ link.clipping.category }} {{ link.clipping.url|truncatechars:30}}
{{ link.clipping.title }} {% if link.clipping.author %}{{ link.clipping.author }}{% else %} --- {% endif %} {{ link.clipping.category }} {{ link.clipping.url|truncatechars:30}}
--- --- Nenhum link publicado
{% if user.is_authenticated %} -
- - Sugerir novo link - -
-
- {% csrf_token %} - {% for field in form %} -
- {{field}} - - {% if field.errors %} - {{field.errors}} - {% endif %} -
- {% endfor %} -
- -
-
-
-
+ {% endif %}
-
-
-
-
{% if message %} @@ -287,17 +140,18 @@
Filtros
{% block script %} {{ block.super }} - + -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/dataset-list-detail.html b/core/templates/core/dataset-list-detail.html new file mode 100644 index 00000000..9edbc710 --- /dev/null +++ b/core/templates/core/dataset-list-detail.html @@ -0,0 +1,53 @@ +{% extends 'base.html' %} +{% load cache %} +{% load humanize %} +{% load l10n %} +{% load static %} +{% block title %}{{ dataset.name }} - Datasets {{ listname|capfirst }} - Brasil.IO{% endblock %} +{% block head %} +{{ block.super }} + +{% endblock %} +{% block nav %} + +{% endblock %} +{% block content %}{% localize off %} +
+
+
+
+
+

+ {{ listname|capfirst }} +

+
+
+ +
+
+
+
+
+
+
+{% endlocalize %}{% endblock %} \ No newline at end of file diff --git a/core/templates/core/dataset-table-detail.html b/core/templates/core/dataset-table-detail.html new file mode 100644 index 00000000..ce204b96 --- /dev/null +++ b/core/templates/core/dataset-table-detail.html @@ -0,0 +1,275 @@ +{% extends 'base.html' %} +{% load cache %} +{% load humanize %} +{% load l10n %} +{% load static %} +{% load markdown %} +{% block title %}{{ dataset.name }} - Datasets Table {{ table.name|capfirst }} - Brasil.IO{% endblock %} +{% block head %} +{{ block.super }} + +{% endblock %} +{% block nav %} + + + +{% endblock %} +{% block content %}{% localize off %} +
+
+
+
+
+

{{ table.name|capfirst }}

+ {% if table.short_description != None %} +

{{ table.short_description }}

+ {% endif %} + {% if table.description != None %} +

{{ table.description }}

+ {% endif %} +

+ Quer baixar os dados completos ou precisa acessá-los de + maneira automatizada? + + leia a documentação + + e depois + + baixe o dataset completo + + ou + utilize + nossa API + . +

+
+
+
+
+
+ +
+
+
+
+
+
+
+ + +
+ {% for field in filter_form %} +
+ + {{ field }} + {% if field.errors %} + {{ field.errors.as_text }} + {% endif %} +
+ {% endfor %} +
+
+ +
+
+
+
+
+
+
+
+ + Dicionário de Dados - Tabela {{ table.name }} + + + + + + + + + + + + + + {% for field in table.fields %} + + + + + + + {% endfor %} + + +
ColunaTipoTítuloDescrição
{{ field.name }} {{ field.type }}{% if field.options_text %} ({{ field.options_text }}){% endif %} {{ field.title }} {{ field.description }}
+
+
+
+
+
+
+ + Referências desta base de dados na mídia + +
+ +
+ + + + + + + + + + + + {% if clipping|length > 0 %} + {% for link in clipping %} + {% if link.clipping.published %} + + + + + + + {% endif %} + {% endfor %} + {% else %} + + + + + + + {% endif %} + + +
TítuloAutorCategoriaLink
{{ link.clipping.title }} {% if link.clipping.author %}{{ link.clipping.author }}{% else %} --- {% endif %} {{ link.clipping.category }} {{ link.clipping.url|truncatechars:30}}
--- --- Nenhum link publicado ---
+ {% if user.is_authenticated %} + + {% endif %} +
+
+
+
+
+
+
+
+
+

Dados

+
+
+ Dados capturados em {{ version.collected_at }}.
+ {% if table.import_date %} + Importação dos dados feita em {{ table.import_date }}. + {% endif %} +
+
+
+ {% if total_count > 0 and total_count <= max_export_rows and querystring %} +
+ +
+ {% else %} + + {% endif %} +
+
+
+
+
+
    +
  • {{ data.start_index|localize }}-{{ data.end_index|localize }} de um total de {{ total_count|localize }}
  • + {% if data.has_previous %} +
  • chevron_left
  • + {% endif %} + + {% if data.has_next %} +
  • + chevron_right +
  • + {% endif %} +
+
+
+ {% with table_id=dataset.slug fields=table.fields %} + {% include 'core/data-table.html' %} + {% endwith %} +
+
+
+
+
+
+{% if message %} + +{% endif %} +{% endlocalize %}{% endblock %} + +{% block script %} +{{ block.super }} + + +{% endblock %} \ No newline at end of file diff --git a/core/urls.py b/core/urls.py index 615d1906..6fe20911 100644 --- a/core/urls.py +++ b/core/urls.py @@ -19,6 +19,7 @@ path("dataset///", enable_ratelimit(views.dataset_table_detail), name="dataset-table-detail"), path("dataset//list_all//", views.dataset_list_detail, name="dataset-list-detail"), path("datasets/sugira/", views.dataset_suggestion, name="dataset-suggestion"), + path("datasets/sugira-clipping/", views.dataset_clipping_suggestion, name="dataset-form-clipping"), path("manifesto/", views.manifesto, name="manifesto"), path("colabore/", views.collaborate, name="collaborate"), path("doe/", views.donate, name="donate"), diff --git a/core/views.py b/core/views.py index 3a908a50..3b75d253 100644 --- a/core/views.py +++ b/core/views.py @@ -112,7 +112,15 @@ def dataset_list_detail(request, slug, listname): return redirect(f"{settings.LOGIN_URL}?next={request.get_full_path()}") try: - dataset = Dataset.objects.get(slug=slug) + clipping_dataset = [] + if listname == "tabelas": + dataset = Dataset.objects.get(slug=slug) + else: + dataset = Dataset.objects.get(slug=slug) + clipping_type_dataset = ContentType.objects.get(app_label="core", model="dataset") + clipping_dataset = list( + ClippingRelation.objects.filter(content_type=clipping_type_dataset.id, object_id=dataset.pk, clipping__published=True).distinct("clipping__vehicle") + ) except Dataset.DoesNotExist: context = {"message": "Dataset does not exist"} return render(request, "404.html", context, status=404) @@ -120,6 +128,7 @@ def dataset_list_detail(request, slug, listname): context = { "listname": listname.replace('_', ' '), "dataset": dataset, + "clipping": clipping_dataset, } return render(request, "core/dataset-list-detail.html", context, status=200) @@ -133,9 +142,15 @@ def dataset_detail(request, slug): except Dataset.DoesNotExist: context = {"message": "Dataset does not exist"} return render(request, "404.html", context, status=404) + + clipping_type_dataset = ContentType.objects.get(app_label="core", model="dataset") + clipping_dataset = list( + ClippingRelation.objects.filter(content_type=clipping_type_dataset.id, object_id=dataset.pk, clipping__published=True).distinct("clipping__vehicle") + ) context = { "dataset": dataset, + "clipping": clipping_dataset, } return render(request, "core/dataset-detail.html", context, status=200) @@ -239,31 +254,9 @@ def dataset_table_detail(request, slug, tablename=""): if not value: del querystring[key] - clipping = [] - clipping_type_dataset = ContentType.objects.get(app_label="core", model="dataset") - clipping_dataset = list( - ClippingRelation.objects.filter(content_type=clipping_type_dataset.id, object_id=dataset.pk) - ) - clipping.extend(clipping_dataset) clipping_type_table = ContentType.objects.get(app_label="core", model="table") clipping_table = list(ClippingRelation.objects.filter(content_type=clipping_type_table.id, object_id=table.pk)) - clipping.extend(clipping_table) - - message = None - if request.method == "POST": - clipping_form = ClippingForm(request.POST) - if clipping_form.is_valid(): - clipping = clipping_form.save(commit=False) - clipping.added_by = request.user - clipping.save() - clipping_form.added_by = request.user - - clipping_form = ClippingForm() - message = "Sugestão enviada com sucesso" - else: - message = "Erro: Verifique o formulário novamente" - else: - clipping_form = ClippingForm() + clipping = clipping_table context = { "clipping": clipping, @@ -277,8 +270,6 @@ def dataset_table_detail(request, slug, tablename=""): "table": table, "total_count": all_data.count(), "version": version, - "form": clipping_form, - "message": message, } status = 200 @@ -286,6 +277,28 @@ def dataset_table_detail(request, slug, tablename=""): status = 400 return render(request, "core/dataset-table-detail.html", context, status=status) +def dataset_clipping_suggestion(request): + message = None + if request.method == "POST": + clipping_form = ClippingForm(request.POST) + if clipping_form.is_valid(): + clipping = clipping_form.save(commit=False) + clipping.added_by = request.user + clipping.save() + clipping_form.added_by = request.user + + message = "Sugestão enviada com sucesso" + return render(request, "core/dataset-list.html") + else: + message = "Erro: Verifique o formulário novamente" + else: + clipping_form = ClippingForm() + + context = { + "form": clipping_form, + "message": message, + } + return render(request, "core/dataset-form-clipping.html", context) def dataset_suggestion(request): return render(request, "core/dataset-suggestion.html", {}) From 77d694505bd8d8e36b8ca2776c12fa0d6e82469b Mon Sep 17 00:00:00 2001 From: Marcel Marques Date: Mon, 13 Sep 2021 16:43:29 -0300 Subject: [PATCH 08/13] Link to dataset new template in dataset-card --- core/templates/core/dataset-card.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/templates/core/dataset-card.html b/core/templates/core/dataset-card.html index 99537fa5..bfd1f771 100644 --- a/core/templates/core/dataset-card.html +++ b/core/templates/core/dataset-card.html @@ -17,7 +17,7 @@

{{ dataset.name }}

{{ dataset.icon }} Tabelasclose - {{ dataset.name }} + {{ dataset.name }} @@ -132,8 +132,10 @@

Referências desta base de dados na mídia

-{% if message %} - +{% if messages %} + {% for message in messages %} + + {% endfor %} {% endif %} {% endlocalize %}{% endblock %} @@ -153,29 +155,6 @@

Referências desta base de dados na mídia

"ordering": false, "bInfo": false, }); - $('.datepicker').datepicker({ - i18n: { - months: ['Janeiro', 'Fevereiro', 'Março', 'Abril', 'Maio', 'Junho', 'Julho', 'Agosto', 'Setembro', 'Outubro', 'Novembro', 'Dezembro'], - monthsShort: ['Jan', 'Fev', 'Mar', 'Abr', 'Mai', 'Jun', 'Jul', 'Ago', 'Set', 'Out', 'Nov', 'Dez'], - weekdays: ['Domingo', 'Segunda', 'Terça', 'Quarta', 'Quinta', 'Sexta', 'Sabádo'], - weekdaysShort: ['Dom', 'Seg', 'Ter', 'Qua', 'Qui', 'Sex', 'Sab'], - weekdaysAbbrev: ['D', 'S', 'T', 'Q', 'Q', 'S', 'S'], - today: 'Hoje', - clear: 'Limpar', - cancel: 'Sair', - done: 'Confirmar', - labelMonthNext: 'Próximo mês', - labelMonthPrev: 'Mês anterior', - labelMonthSelect: 'Selecione um mês', - labelYearSelect: 'Selecione um ano', - selectMonths: true, - selectYears: true, - }, - yearRange: [2010,new Date().getFullYear()], - format: 'yyyy-mm-dd', - container: 'body', - maxDate: new Date(), - }); }); {% endblock %} \ No newline at end of file diff --git a/core/templates/core/dataset-form-clipping.html b/core/templates/core/dataset-form-clipping.html new file mode 100644 index 00000000..4d3496c3 --- /dev/null +++ b/core/templates/core/dataset-form-clipping.html @@ -0,0 +1,67 @@ +{% extends 'base.html' %} +{% load static %} +{% block title %}Sugerir novo link - Brasil.IO{% endblock %} +{% block content %} +
+
+ + Sugerir novo link + +
+
+ {% csrf_token %} + {% for field in form %} +
+ {{field}} + + {% if field.errors %} + {{field.errors}} + {% endif %} +
+ {% endfor %} + +
+ +
+
+
+
+
+{% if message %} + +{% endif %} +{% endblock %} + +{% block script %} +{{ block.super }} + + +{% endblock %} \ No newline at end of file diff --git a/core/templates/core/dataset-table-detail.html b/core/templates/core/dataset-table-detail.html index ce204b96..47b9d858 100644 --- a/core/templates/core/dataset-table-detail.html +++ b/core/templates/core/dataset-table-detail.html @@ -175,7 +175,7 @@

{{ table.short_description }}

{% if user.is_authenticated %} {% endif %}
@@ -250,8 +250,10 @@

Dados

-{% if message %} - +{% if messages %} + {% for message in messages %} + + {% endfor %} {% endif %} {% endlocalize %}{% endblock %} diff --git a/core/views.py b/core/views.py index 3b75d253..72f73c94 100644 --- a/core/views.py +++ b/core/views.py @@ -21,7 +21,7 @@ from core.util import cached_http_get_json from data_activities_log.activites import recent_activities from traffic_control.logging import log_blocked_request - +from django.contrib.messages import success class Echo: def write(self, value): @@ -278,6 +278,9 @@ def dataset_table_detail(request, slug, tablename=""): return render(request, "core/dataset-table-detail.html", context, status=status) def dataset_clipping_suggestion(request): + if len(request.GET) > 0 and not request.user.is_authenticated: + return redirect(f"{settings.LOGIN_URL}?next={request.get_full_path()}") + message = None if request.method == "POST": clipping_form = ClippingForm(request.POST) @@ -285,10 +288,10 @@ def dataset_clipping_suggestion(request): clipping = clipping_form.save(commit=False) clipping.added_by = request.user clipping.save() - clipping_form.added_by = request.user - message = "Sugestão enviada com sucesso" - return render(request, "core/dataset-list.html") + success(request, "Sugestão enviada com sucesso") + + return redirect(request.POST.get('next', '/')) else: message = "Erro: Verifique o formulário novamente" else: From 829c6a88ddab44f25e8caa8df192c22ea89d0fc7 Mon Sep 17 00:00:00 2001 From: Marcel Marques Date: Wed, 15 Sep 2021 17:24:47 -0300 Subject: [PATCH 10/13] Changing breadcrumb dropdown signal --- core/static/core/css/dataset-detail.css | 10 ++++++++++ core/templates/core/dataset-table-detail.html | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/core/static/core/css/dataset-detail.css b/core/static/core/css/dataset-detail.css index 02d76f43..a2f863e3 100644 --- a/core/static/core/css/dataset-detail.css +++ b/core/static/core/css/dataset-detail.css @@ -4,6 +4,16 @@ padding-bottom: 12px; } +.breadcrumb .dropdown-trigger { + padding-right: 80px; +} + + +.breadcrumb a i.material-icons { + position: fixed; + line-height: 1; +} + h1 { font-size: 25px; margin-bottom: 25px; diff --git a/core/templates/core/dataset-table-detail.html b/core/templates/core/dataset-table-detail.html index 47b9d858..54a871d6 100644 --- a/core/templates/core/dataset-table-detail.html +++ b/core/templates/core/dataset-table-detail.html @@ -17,8 +17,8 @@ {{ dataset.name }} > - - {{ table.name|capfirst }} + + {{ table.name|capfirst }} arrow_drop_down
From 6dd95ecb4eef65b9a210dca71bbfab5d5e02e926 Mon Sep 17 00:00:00 2001 From: Marcel Marques Date: Wed, 15 Sep 2021 17:42:55 -0300 Subject: [PATCH 11/13] New fields short_description and renaming field description dataset and table models --- .../0030_table_short_description.py | 19 +++++++++++++++++++ core/migrations/0031_auto_20210915_1605.py | 18 ++++++++++++++++++ core/migrations/0032_dataset_description.py | 19 +++++++++++++++++++ core/migrations/0033_auto_20210915_1731.py | 19 +++++++++++++++++++ core/models.py | 4 +++- core/templates/core/dataset-card.html | 2 +- core/templates/core/dataset-detail.html | 8 ++++---- 7 files changed, 83 insertions(+), 6 deletions(-) create mode 100644 core/migrations/0030_table_short_description.py create mode 100644 core/migrations/0031_auto_20210915_1605.py create mode 100644 core/migrations/0032_dataset_description.py create mode 100644 core/migrations/0033_auto_20210915_1731.py diff --git a/core/migrations/0030_table_short_description.py b/core/migrations/0030_table_short_description.py new file mode 100644 index 00000000..2f953c17 --- /dev/null +++ b/core/migrations/0030_table_short_description.py @@ -0,0 +1,19 @@ +# Generated by Django 3.1.8 on 2021-09-15 19:02 + +from django.db import migrations +import markdownx.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0029_auto_20201206_2132'), + ] + + operations = [ + migrations.AddField( + model_name='table', + name='short_description', + field=markdownx.models.MarkdownxField(blank=True, null=True), + ), + ] diff --git a/core/migrations/0031_auto_20210915_1605.py b/core/migrations/0031_auto_20210915_1605.py new file mode 100644 index 00000000..e3bd5955 --- /dev/null +++ b/core/migrations/0031_auto_20210915_1605.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.8 on 2021-09-15 19:05 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0030_table_short_description'), + ] + + operations = [ + migrations.RenameField( + model_name='dataset', + old_name='description', + new_name='short_description', + ), + ] diff --git a/core/migrations/0032_dataset_description.py b/core/migrations/0032_dataset_description.py new file mode 100644 index 00000000..0b339241 --- /dev/null +++ b/core/migrations/0032_dataset_description.py @@ -0,0 +1,19 @@ +# Generated by Django 3.1.8 on 2021-09-15 20:26 + +from django.db import migrations +import markdownx.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0031_auto_20210915_1605'), + ] + + operations = [ + migrations.AddField( + model_name='dataset', + name='description', + field=markdownx.models.MarkdownxField(blank=True, null=True), + ), + ] diff --git a/core/migrations/0033_auto_20210915_1731.py b/core/migrations/0033_auto_20210915_1731.py new file mode 100644 index 00000000..7740f83e --- /dev/null +++ b/core/migrations/0033_auto_20210915_1731.py @@ -0,0 +1,19 @@ +# Generated by Django 3.1.8 on 2021-09-15 20:31 + +from django.db import migrations +import markdownx.models + + +class Migration(migrations.Migration): + + dependencies = [ + ('core', '0032_dataset_description'), + ] + + operations = [ + migrations.AlterField( + model_name='dataset', + name='short_description', + field=markdownx.models.MarkdownxField(blank=True, null=True), + ), + ] diff --git a/core/models.py b/core/models.py index d3419ffd..a4cf4e0b 100644 --- a/core/models.py +++ b/core/models.py @@ -153,7 +153,8 @@ class Dataset(models.Model): author_name = models.CharField(max_length=255, null=False, blank=False) author_url = models.URLField(max_length=2000, null=True, blank=True) code_url = models.URLField(max_length=2000, null=False, blank=False) - description = models.TextField(null=False, blank=False) + short_description = MarkdownxField(null=True, blank=True) + description = MarkdownxField(null=True, blank=True) icon = models.CharField(max_length=31, null=False, blank=False) license_name = models.CharField(max_length=255, null=False, blank=False) license_url = models.URLField(max_length=2000, null=False, blank=False) @@ -311,6 +312,7 @@ class Table(models.Model): version = models.ForeignKey(Version, on_delete=models.CASCADE, null=False, blank=False) import_date = models.DateTimeField(null=True, blank=True) description = MarkdownxField(null=True, blank=True) + short_description = MarkdownxField(null=True, blank=True) hidden = models.BooleanField(default=False) api_enabled = models.BooleanField(default=True) diff --git a/core/templates/core/dataset-card.html b/core/templates/core/dataset-card.html index bfd1f771..6bdf2bf7 100644 --- a/core/templates/core/dataset-card.html +++ b/core/templates/core/dataset-card.html @@ -7,7 +7,7 @@ {{ dataset.icon }}

{{ dataset.name }}

-

{{ dataset.description }}

+

{{ dataset.short_description }}

keyboard_arrow_up diff --git a/core/templates/core/dataset-detail.html b/core/templates/core/dataset-detail.html index 045a75ab..a0becad2 100644 --- a/core/templates/core/dataset-detail.html +++ b/core/templates/core/dataset-detail.html @@ -27,9 +27,9 @@
{{ dataset.icon }}

{{ dataset.name|capfirst }}

-

{{ dataset.description }}

- {% if dataset.long_description != None %} -

{{ dataset.long_description }}

+

{{ dataset.short_description }}

+ {% if dataset.description != None %} +

{{ dataset.description }}

{% endif %} {% if dataset.info != None %}

Informações úteis

@@ -60,7 +60,7 @@

Tabelas

{{dataset.name}}

-

{{ dataset.description }}

+

{{ dataset.short_description }}