From c8b0b78d665765e0b3f3555ae2992f7d887fdcd2 Mon Sep 17 00:00:00 2001 From: Leandro Roberto Date: Sat, 16 Feb 2019 17:30:50 -0200 Subject: [PATCH] impl channels tutorial 1 e 2 --- requirements/requirements.txt | 5 +- sapl/base/consumers.py | 48 ++++++++++++ sapl/base/routing.py | 7 ++ sapl/base/urls.py | 7 +- sapl/base/views.py | 101 +++++++++++++++---------- sapl/routing.py | 13 +++- sapl/settings.py | 18 +++-- sapl/templates/base/channel_index.html | 27 +++++++ sapl/templates/base/channel_room.html | 47 ++++++++++++ setup.py | 6 -- 10 files changed, 223 insertions(+), 56 deletions(-) create mode 100644 sapl/base/consumers.py create mode 100644 sapl/base/routing.py create mode 100644 sapl/templates/base/channel_index.html create mode 100644 sapl/templates/base/channel_room.html diff --git a/requirements/requirements.txt b/requirements/requirements.txt index 023d80ced..cf7cf609c 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -15,7 +15,6 @@ django-extensions==2.1.4 django-image-cropping==1.2 django-webpack-loader==0.6.0 drf-yasg==1.13.0 -channels==2.1.7 easy-thumbnails==2.5 python-decouple==3.1 psycopg2-binary==2.7.6.1 @@ -34,5 +33,9 @@ whoosh==2.7.4 pyoai==2.5.0 +daphne==2.2.5 +channels_redis==2.3.3 +channels==2.1.7 + git+git://github.com/interlegis/trml2pdf.git git+git://github.com/interlegis/django-admin-bootstrapped diff --git a/sapl/base/consumers.py b/sapl/base/consumers.py new file mode 100644 index 000000000..db0365cf4 --- /dev/null +++ b/sapl/base/consumers.py @@ -0,0 +1,48 @@ +import json + +from asgiref.sync import async_to_sync +from channels.generic.websocket import WebsocketConsumer + + +class ChatConsumer(WebsocketConsumer): + def connect(self): + self.room_name = self.scope['url_route']['kwargs']['room_name'] + self.room_group_name = 'chat_%s' % self.room_name + + # Join room group + async_to_sync(self.channel_layer.group_add)( + self.room_group_name, + self.channel_name + ) + + self.accept() + + def disconnect(self, close_code): + # Leave room group + async_to_sync(self.channel_layer.group_discard)( + self.room_group_name, + self.channel_name + ) + + # Receive message from WebSocket + def receive(self, text_data): + text_data_json = json.loads(text_data) + message = text_data_json['message'] + + # Send message to room group + async_to_sync(self.channel_layer.group_send)( + self.room_group_name, + { + 'type': 'chat_message', + 'message': message + } + ) + + # Receive message from room group + def chat_message(self, event): + message = event['message'] + + # Send message to WebSocket + self.send(text_data=json.dumps({ + 'message': message + })) diff --git a/sapl/base/routing.py b/sapl/base/routing.py new file mode 100644 index 000000000..d16571f00 --- /dev/null +++ b/sapl/base/routing.py @@ -0,0 +1,7 @@ +from django.conf.urls import url + +from . import consumers + +websocket_urlpatterns = [ + url(r'^ws/chat/(?P[^/]+)/$', consumers.ChatConsumer), +] \ No newline at end of file diff --git a/sapl/base/urls.py b/sapl/base/urls.py index 005f12d71..2ee2788c3 100644 --- a/sapl/base/urls.py +++ b/sapl/base/urls.py @@ -8,6 +8,7 @@ from django.contrib.auth.views import (password_reset, password_reset_complete, password_reset_done) from django.views.generic.base import RedirectView, TemplateView +from sapl import base from sapl.base.views import AutorCrud, ConfirmarEmailView, TipoAutorCrud from sapl.settings import EMAIL_SEND_USER, MEDIA_URL @@ -97,7 +98,7 @@ urlpatterns = [ url(r'^sistema/app-config/', include(AppConfigCrud.get_urls())), # TODO mover estas telas para a app 'relatorios' - url(r'^sistema/relatorios/$', + url(r'^sistema/relatorios/$', RelatoriosListView.as_view(), name='relatorios_list'), url(r'^sistema/relatorios/materia-por-autor$', RelatorioMateriasPorAutorView.as_view(), name='materia_por_autor'), @@ -185,4 +186,8 @@ urlpatterns = [ LogotipoView.as_view(), name='logotipo'), + url(r'^channel$', base.views.chanel_index, name='channel_index'), + url(r'^channel/(?P[^/]+)/$', + base.views.chanel_room, name='channel_room'), + ] + recuperar_senha + alterar_senha + admin_user diff --git a/sapl/base/views.py b/sapl/base/views.py index 00271babc..66c3d093d 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -1,6 +1,7 @@ import collections -import itertools import datetime +import itertools +import json import logging import os @@ -15,11 +16,13 @@ from django.core.urlresolvers import reverse, reverse_lazy from django.db import connection from django.db.models import Count, Q, ProtectedError from django.http import Http404, HttpResponseRedirect +from django.shortcuts import render from django.template import TemplateDoesNotExist from django.template.loader import get_template from django.utils import timezone from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode +from django.utils.safestring import mark_safe from django.utils.translation import string_concat from django.utils.translation import ugettext_lazy as _ from django.views.generic import (CreateView, DeleteView, FormView, ListView, @@ -61,6 +64,16 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm, from .models import AppConfig, CasaLegislativa +def chanel_index(request): + return render(request, 'base/channel_index.html', {}) + + +def chanel_room(request, room_name): + return render(request, 'base/channel_room.html', { + 'room_name_json': mark_safe(json.dumps(room_name)) + }) + + def filtra_url_materias_em_tramitacao(qr, qs, campo_url, local_ou_status): id_materias = [] filtro_url = qr[campo_url] @@ -289,7 +302,7 @@ class AutorCrud(CrudAux): class RelatoriosListView(TemplateView): - template_name='base/relatorios_list.html' + template_name = 'base/relatorios_list.html' def get_context_data(self, **kwargs): context = super(TemplateView, self).get_context_data(**kwargs) @@ -799,15 +812,15 @@ class RelatorioNormasPublicadasMesView(FilterView): context['ano'] = self.request.GET['ano'] normas_mes = collections.OrderedDict() - meses = {1: 'Janeiro', 2: 'Fevereiro', 3:'Março', 4: 'Abril', 5: 'Maio', 6:'Junho', - 7: 'Julho', 8: 'Agosto', 9:'Setembro', 10:'Outubro', 11:'Novembro', 12:'Dezembro'} + meses = {1: 'Janeiro', 2: 'Fevereiro', 3: 'Março', 4: 'Abril', 5: 'Maio', 6: 'Junho', + 7: 'Julho', 8: 'Agosto', 9: 'Setembro', 10: 'Outubro', 11: 'Novembro', 12: 'Dezembro'} for norma in context['object_list']: if not meses[norma.data.month] in normas_mes: normas_mes[meses[norma.data.month]] = [] normas_mes[meses[norma.data.month]].append(norma) - + context['normas_mes'] = normas_mes - + quant_normas_mes = {} for key in normas_mes.keys(): quant_normas_mes[key] = len(normas_mes[key]) @@ -833,19 +846,20 @@ class RelatorioNormasVigenciaView(FilterView): vigencia = kwargs['data']['vigencia'] if ano: qs = qs.filter(ano=ano) - + if vigencia == 'True': qs_dt_not_null = qs.filter(data_vigencia__isnull=True) - qs = (qs_dt_not_null | qs.filter(data_vigencia__gte=datetime.datetime.now().date())).distinct() + qs = (qs_dt_not_null | qs.filter( + data_vigencia__gte=datetime.datetime.now().date())).distinct() else: - qs = qs.filter(data_vigencia__lt=datetime.datetime.now().date()) + qs = qs.filter( + data_vigencia__lt=datetime.datetime.now().date()) kwargs.update({ 'queryset': qs }) return kwargs - def get_context_data(self, **kwargs): context = super(RelatorioNormasVigenciaView, self).get_context_data(**kwargs) @@ -855,17 +869,20 @@ class RelatorioNormasVigenciaView(FilterView): if not self.filterset.form.is_valid(): return context - normas_totais = NormaJuridica.objects.filter(ano=self.request.GET['ano']) - + normas_totais = NormaJuridica.objects.filter( + ano=self.request.GET['ano']) + context['quant_total'] = len(normas_totais) if self.request.GET['vigencia'] == 'True': context['vigencia'] = 'Vigente' context['quant_vigente'] = len(context['object_list']) - context['quant_nao_vigente'] = context['quant_total'] - context['quant_vigente'] + context['quant_nao_vigente'] = context['quant_total'] - \ + context['quant_vigente'] else: context['vigencia'] = 'Não vigente' context['quant_nao_vigente'] = len(context['object_list']) - context['quant_vigente'] = context['quant_total'] - context['quant_nao_vigente'] + context['quant_vigente'] = context['quant_total'] - \ + context['quant_nao_vigente'] qr = self.request.GET.copy() context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' @@ -891,7 +908,7 @@ class EstatisticasAcessoNormas(TemplateView): return self.render_to_response(context) context['ano'] = self.request.GET['ano'] - + query = ''' select norma_id, ano, extract(month from horario_acesso) as mes, count(*) from norma_normaestatisticas @@ -904,20 +921,21 @@ class EstatisticasAcessoNormas(TemplateView): rows = cursor.fetchall() normas_mes = collections.OrderedDict() - meses = {1: 'Janeiro', 2: 'Fevereiro', 3:'Março', 4: 'Abril', 5: 'Maio', 6:'Junho', - 7: 'Julho', 8: 'Agosto', 9:'Setembro', 10:'Outubro', 11:'Novembro', 12:'Dezembro'} - + meses = {1: 'Janeiro', 2: 'Fevereiro', 3: 'Março', 4: 'Abril', 5: 'Maio', 6: 'Junho', + 7: 'Julho', 8: 'Agosto', 9: 'Setembro', 10: 'Outubro', 11: 'Novembro', 12: 'Dezembro'} + for row in rows: if not meses[int(row[2])] in normas_mes: normas_mes[meses[int(row[2])]] = [] norma_est = [NormaJuridica.objects.get(id=row[0]), row[3]] normas_mes[meses[int(row[2])]].append(norma_est) - + # Ordena por acesso e limita em 5 for n in normas_mes: - sorted_by_value = sorted(normas_mes[n], key=lambda kv: kv[1], reverse=True) + sorted_by_value = sorted( + normas_mes[n], key=lambda kv: kv[1], reverse=True) normas_mes[n] = sorted_by_value[0:5] - + context['normas_mes'] = normas_mes return self.render_to_response(context) @@ -952,8 +970,8 @@ class ListarInconsistenciasView(PermissionRequiredMixin, ListView): tabela.append( ('mandato_sem_data_inicio', 'Mandatos sem data inicial', - len(mandato_sem_data_inicio()) - ) + len(mandato_sem_data_inicio()) + ) ) tabela.append( ('parlamentares_mandatos_intersecao', @@ -977,7 +995,7 @@ class ListarInconsistenciasView(PermissionRequiredMixin, ListView): ('legislatura_infindavel', 'Legislaturas sem data fim', len(legislatura_infindavel()) - ) + ) ) return tabela @@ -1000,14 +1018,14 @@ class ListarLegislaturaInfindavelView(PermissionRequiredMixin, ListView): def get_context_data(self, **kwargs): context = super( ListarLegislaturaInfindavelView, self - ).get_context_data(**kwargs) + ).get_context_data(**kwargs) paginator = context['paginator'] page_obj = context['page_obj'] context['page_range'] = make_pagination( page_obj.number, paginator.num_pages) context[ 'NO_ENTRIES_MSG' - ] = 'Nenhuma encontrada.' + ] = 'Nenhuma encontrada.' return context @@ -1050,14 +1068,14 @@ class ListarBancadaComissaoAutorExternoView(PermissionRequiredMixin, ListView): def get_context_data(self, **kwargs): context = super( ListarBancadaComissaoAutorExternoView, self - ).get_context_data(**kwargs) + ).get_context_data(**kwargs) paginator = context['paginator'] page_obj = context['page_obj'] context['page_range'] = make_pagination( page_obj.number, paginator.num_pages) context[ 'NO_ENTRIES_MSG' - ] = 'Nenhum encontrado.' + ] = 'Nenhum encontrado.' return context @@ -1084,7 +1102,7 @@ class ListarAutoresDuplicadosView(PermissionRequiredMixin, ListView): page_obj.number, paginator.num_pages) context[ 'NO_ENTRIES_MSG' - ] = 'Nenhum encontrado.' + ] = 'Nenhum encontrado.' return context @@ -1097,10 +1115,12 @@ def parlamentares_mandatos_intersecao(): for c in combinacoes: data_inicio_mandato1 = c[0].data_inicio_mandato - data_fim_mandato1 = c[0].data_fim_mandato if c[0].data_fim_mandato else timezone.now().date() + data_fim_mandato1 = c[0].data_fim_mandato if c[0].data_fim_mandato else timezone.now( + ).date() data_inicio_mandato2 = c[1].data_inicio_mandato - data_fim_mandato2 = c[1].data_fim_mandato if c[1].data_fim_mandato else timezone.now().date() + data_fim_mandato2 = c[1].data_fim_mandato if c[1].data_fim_mandato else timezone.now( + ).date() if data_inicio_mandato1 and data_inicio_mandato2: exists = intervalos_tem_intersecao( @@ -1131,7 +1151,7 @@ class ListarParlMandatosIntersecaoView(PermissionRequiredMixin, ListView): page_obj.number, paginator.num_pages) context[ 'NO_ENTRIES_MSG' - ] = 'Nenhum encontrado.' + ] = 'Nenhum encontrado.' return context @@ -1152,14 +1172,14 @@ class ListarMandatoSemDataInicioView(PermissionRequiredMixin, ListView): def get_context_data(self, **kwargs): context = super( ListarMandatoSemDataInicioView, self - ).get_context_data(**kwargs) + ).get_context_data(**kwargs) paginator = context['paginator'] page_obj = context['page_obj'] context['page_range'] = make_pagination( page_obj.number, paginator.num_pages) context[ 'NO_ENTRIES_MSG' - ] = 'Nenhum encontrada.' + ] = 'Nenhum encontrada.' return context @@ -1187,27 +1207,27 @@ class ListarMatProtocoloInexistenteView(PermissionRequiredMixin, ListView): def get_context_data(self, **kwargs): context = super( ListarMatProtocoloInexistenteView, self - ).get_context_data(**kwargs) + ).get_context_data(**kwargs) paginator = context['paginator'] page_obj = context['page_obj'] context['page_range'] = make_pagination( page_obj.number, paginator.num_pages) context[ 'NO_ENTRIES_MSG' - ] = 'Nenhuma encontrada.' + ] = 'Nenhuma encontrada.' return context def protocolos_com_materias(): protocolos = {} - + for m in MateriaLegislativa.objects.filter(numero_protocolo__isnull=False).order_by('-ano', 'numero_protocolo'): if Protocolo.objects.filter(numero=m.numero_protocolo, ano=m.ano).exists(): key = "{}/{}".format(m.numero_protocolo, m.ano) val = protocolos.get(key, list()) val.append(m) protocolos[key] = val - + return [(v[0], len(v)) for (k, v) in protocolos.items() if len(v) > 1] @@ -1230,7 +1250,7 @@ class ListarProtocolosComMateriasView(PermissionRequiredMixin, ListView): page_obj.number, paginator.num_pages) context[ 'NO_ENTRIES_MSG' - ] = 'Nenhum encontrado.' + ] = 'Nenhum encontrado.' return context @@ -1244,6 +1264,7 @@ def protocolos_duplicados(): return [(v[0], len(v)) for (k, v) in protocolos.items() if len(v) > 1] + class ListarProtocolosDuplicadosView(PermissionRequiredMixin, ListView): model = get_user_model() template_name = 'base/protocolos_duplicados.html' @@ -1263,7 +1284,7 @@ class ListarProtocolosDuplicadosView(PermissionRequiredMixin, ListView): page_obj.number, paginator.num_pages) context[ 'NO_ENTRIES_MSG' - ] = 'Nenhum encontrado.' + ] = 'Nenhum encontrado.' return context diff --git a/sapl/routing.py b/sapl/routing.py index 7dcf4c575..e668b49a4 100644 --- a/sapl/routing.py +++ b/sapl/routing.py @@ -1,5 +1,12 @@ -from channels.routing import ProtocolTypeRouter +from channels.auth import AuthMiddlewareStack +from channels.routing import ProtocolTypeRouter, URLRouter +import sapl.base.routing + application = ProtocolTypeRouter({ - # Empty for now (http->django views is added by default) -}) \ No newline at end of file + 'websocket': AuthMiddlewareStack( + URLRouter( + sapl.base.routing.websocket_urlpatterns + ) + ), +}) diff --git a/sapl/settings.py b/sapl/settings.py index 74b31a6b6..0e8a8dab6 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -207,6 +207,14 @@ TEMPLATES = [ WSGI_APPLICATION = 'sapl.wsgi.application' ASGI_APPLICATION = "sapl.routing.application" +CHANNEL_LAYERS = { + 'default': { + 'BACKEND': 'channels_redis.core.RedisChannelLayer', + 'CONFIG': { + "hosts": [('127.0.0.1', 6379)], + }, + }, +} # Database # https://docs.djangoproject.com/en/1.8/ref/settings/#databases @@ -347,11 +355,11 @@ LOGGING = { 'level': 'INFO', 'propagate': True, }, - 'django': { - 'handlers': ['applogfile'], - 'level': 'ERROR', - 'propagate': True, - }, + #'django': { + # 'handlers': ['applogfile'], + # 'level': 'ERROR', + # 'propagate': True, + #}, } } diff --git a/sapl/templates/base/channel_index.html b/sapl/templates/base/channel_index.html new file mode 100644 index 000000000..adc2f8127 --- /dev/null +++ b/sapl/templates/base/channel_index.html @@ -0,0 +1,27 @@ + + + + + + Chat Rooms + + + What chat room would you like to enter?
+
+ + + + + \ No newline at end of file diff --git a/sapl/templates/base/channel_room.html b/sapl/templates/base/channel_room.html new file mode 100644 index 000000000..9f190d4ba --- /dev/null +++ b/sapl/templates/base/channel_room.html @@ -0,0 +1,47 @@ + + + + + + Chat Room + + +
+
+ + + + \ No newline at end of file diff --git a/setup.py b/setup.py index aca98d2b7..1887518b0 100644 --- a/setup.py +++ b/setup.py @@ -44,13 +44,7 @@ install_requires = [ 'channels==2.1.7', # 'git+git://github.com/interlegis/trml2pdf.git', -<<<<<<< HEAD # 'git+git://github.com/interlegis/django-admin-bootstrapped', -======= - # 'git+git://github.com/jasperlittle/django-rest-framework-docs', - # 'git+git://github.com/interlegis/django-admin-bootstrapped', - ->>>>>>> config inicial ] setup( name='interlegis-sapl',