wagtail-enap-designsystem 1.2.1.204__py3-none-any.whl → 1.2.1.205__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (17) hide show
  1. enap_designsystem/migrations/0475_alter_areaaluno_body_alter_cursoeadpage_curso_and_more.py +65052 -0
  2. enap_designsystem/migrations/0476_rotapage_capsulaordemrota.py +253 -0
  3. enap_designsystem/models.py +438 -195
  4. enap_designsystem/static/enap_designsystem/blocks/capsulas.css +3507 -52
  5. enap_designsystem/templates/admin/exportar_respostas.html +0 -9
  6. enap_designsystem/templates/enap_designsystem/blocks/formulario_snippet.html +0 -6
  7. enap_designsystem/templates/enap_designsystem/blocks/material_externo_block.html +211 -0
  8. enap_designsystem/templates/enap_designsystem/form_templates/form_report.html +0 -10
  9. enap_designsystem/templates/enap_designsystem/form_templates/submission_detail.html +0 -9
  10. enap_designsystem/templates/enap_designsystem/gerador_rotas_page.html +287 -0
  11. enap_designsystem/templates/enap_designsystem/pages/capsula_index_page.html +563 -464
  12. enap_designsystem/templates/enap_designsystem/rota_page.html +560 -0
  13. {wagtail_enap_designsystem-1.2.1.204.dist-info → wagtail_enap_designsystem-1.2.1.205.dist-info}/METADATA +1 -1
  14. {wagtail_enap_designsystem-1.2.1.204.dist-info → wagtail_enap_designsystem-1.2.1.205.dist-info}/RECORD +17 -12
  15. {wagtail_enap_designsystem-1.2.1.204.dist-info → wagtail_enap_designsystem-1.2.1.205.dist-info}/WHEEL +0 -0
  16. {wagtail_enap_designsystem-1.2.1.204.dist-info → wagtail_enap_designsystem-1.2.1.205.dist-info}/licenses/LICENSE +0 -0
  17. {wagtail_enap_designsystem-1.2.1.204.dist-info → wagtail_enap_designsystem-1.2.1.205.dist-info}/top_level.txt +0 -0
@@ -6685,227 +6685,470 @@ class CapsulaPage(Page):
6685
6685
 
6686
6686
 
6687
6687
 
6688
+ class GeradorRotasPage(Page):
6689
+ """
6690
+ Página com perguntas que direcionam o usuário para uma rota específica.
6691
+ """
6692
+ texto_introducao = RichTextField(
6693
+ verbose_name="Texto de Introdução",
6694
+ help_text="Texto explicativo sobre o gerador de rotas"
6695
+ )
6696
+
6697
+ texto_botao = models.CharField(
6698
+ verbose_name="Texto do Botão",
6699
+ max_length=255,
6700
+ default="Gerar Rota",
6701
+ help_text="Texto exibido no botão de comando"
6702
+ )
6703
+
6704
+ # Relações com as páginas de destino para cada rota
6705
+ rota_docente_presencial = models.ForeignKey(
6706
+ 'wagtailcore.Page',
6707
+ null=True,
6708
+ blank=True,
6709
+ on_delete=models.SET_NULL,
6710
+ related_name='+',
6711
+ verbose_name="Rota Docente Presencial",
6712
+ help_text="Selecione a página da Rota Docente Presencial"
6713
+ )
6714
+
6715
+ rota_designer_instrucional = models.ForeignKey(
6716
+ 'wagtailcore.Page',
6717
+ null=True,
6718
+ blank=True,
6719
+ on_delete=models.SET_NULL,
6720
+ related_name='+',
6721
+ verbose_name="Rota Designer Instrucional",
6722
+ help_text="Selecione a página da Rota Designer Instrucional"
6723
+ )
6724
+
6725
+ rota_multimidia = models.ForeignKey(
6726
+ 'wagtailcore.Page',
6727
+ null=True,
6728
+ blank=True,
6729
+ on_delete=models.SET_NULL,
6730
+ related_name='+',
6731
+ verbose_name="Rota Multimídia",
6732
+ help_text="Selecione a página da Rota Multimídia"
6733
+ )
6734
+
6735
+ rota_equipe_tecnica = models.ForeignKey(
6736
+ 'wagtailcore.Page',
6737
+ null=True,
6738
+ blank=True,
6739
+ on_delete=models.SET_NULL,
6740
+ related_name='+',
6741
+ verbose_name="Rota Equipe Técnica",
6742
+ help_text="Selecione a página da Rota Equipe Técnica"
6743
+ )
6744
+
6745
+ # Textos das perguntas e opções (personalizáveis no admin)
6746
+ pergunta = models.CharField(
6747
+ verbose_name="Pergunta",
6748
+ max_length=255,
6749
+ default="O que você quer aprender?",
6750
+ help_text="Pergunta principal para direcionamento da rota"
6751
+ )
6752
+
6753
+ opcao_docente = models.CharField(
6754
+ verbose_name="Opção Docente",
6755
+ max_length=255,
6756
+ default="Quero aprender a tornar minhas aulas e eventos presenciais mais acessíveis.",
6757
+ help_text="Texto para a opção Docente Presencial"
6758
+ )
6759
+
6760
+ opcao_designer = models.CharField(
6761
+ verbose_name="Opção Designer",
6762
+ max_length=255,
6763
+ default="Quero aprender a criar conteúdos digitais acessíveis, como documentos e apresentações.",
6764
+ help_text="Texto para a opção Designer Instrucional"
6765
+ )
6766
+
6767
+ opcao_multimidia = models.CharField(
6768
+ verbose_name="Opção Multimídia",
6769
+ max_length=255,
6770
+ default="Quero aprender a tornar vídeos e materiais multimídia acessíveis.",
6771
+ help_text="Texto para a opção Multimídia"
6772
+ )
6773
+
6774
+ opcao_tecnica = models.CharField(
6775
+ verbose_name="Opção Equipe Técnica",
6776
+ max_length=255,
6777
+ default="Quero aprender a aplicar boas práticas de acessibilidade em sistemas e plataformas digitais.",
6778
+ help_text="Texto para a opção Equipe Técnica"
6779
+ )
6780
+
6781
+ content_panels = Page.content_panels + [
6782
+ FieldPanel('texto_introducao'),
6783
+ FieldPanel('pergunta'),
6784
+ MultiFieldPanel([
6785
+ FieldPanel('opcao_docente'),
6786
+ FieldPanel('opcao_designer'),
6787
+ FieldPanel('opcao_multimidia'),
6788
+ FieldPanel('opcao_tecnica'),
6789
+ ], heading="Opções de Resposta"),
6790
+ FieldPanel('texto_botao'),
6791
+ MultiFieldPanel([
6792
+ FieldPanel('rota_docente_presencial'),
6793
+ FieldPanel('rota_designer_instrucional'),
6794
+ FieldPanel('rota_multimidia'),
6795
+ FieldPanel('rota_equipe_tecnica'),
6796
+ ], heading="Páginas de Destino das Rotas"),
6797
+ ]
6798
+
6799
+ def serve(self, request):
6800
+ # Verifica se foi enviado um formulário para direcionar para uma rota
6801
+ if request.method == 'POST' and 'rota_selecionada' in request.POST:
6802
+ rota_selecionada = request.POST.get('rota_selecionada')
6803
+
6804
+ # Redireciona para a página da rota escolhida
6805
+ if rota_selecionada == 'docente_presencial' and self.rota_docente_presencial:
6806
+ return redirect(self.rota_docente_presencial.url)
6807
+ elif rota_selecionada == 'designer_instrucional' and self.rota_designer_instrucional:
6808
+ return redirect(self.rota_designer_instrucional.url)
6809
+ elif rota_selecionada == 'multimidia' and self.rota_multimidia:
6810
+ return redirect(self.rota_multimidia.url)
6811
+ elif rota_selecionada == 'equipe_tecnica' and self.rota_equipe_tecnica:
6812
+ return redirect(self.rota_equipe_tecnica.url)
6813
+
6814
+ # Se não houver rota selecionada, continua com a exibição normal da página
6815
+ return super().serve(request)
6816
+
6817
+ class Meta:
6818
+ verbose_name = "Página Geradora de Rotas"
6819
+
6688
6820
 
6689
- from django.http import JsonResponse
6690
- from django.views.decorators.csrf import csrf_exempt
6691
- from django.utils.decorators import method_decorator
6692
- import json
6693
6821
 
6694
6822
 
6695
6823
 
6696
- class QuizRotaPage(Page):
6824
+
6825
+
6826
+
6827
+ from django.db import models
6828
+ from django.db.models.fields import TextField
6829
+ from modelcluster.fields import ParentalKey
6830
+ from wagtail.models import Orderable, Page
6831
+ from wagtail.admin.panels import (
6832
+ FieldPanel,
6833
+ InlinePanel,
6834
+ MultiFieldPanel,
6835
+ TabbedInterface,
6836
+ ObjectList
6837
+ )
6838
+ from wagtail.fields import RichTextField, StreamField
6839
+ from wagtail.blocks import StructBlock, CharBlock, TextBlock, ChoiceBlock, URLBlock
6840
+ from wagtail.images.blocks import ImageChooserBlock
6841
+
6842
+
6843
+ class MaterialExternoBlock(StructBlock):
6697
6844
  """
6698
- Página principal do Quiz de Rotas Personalizadas - VERSÃO COM SELEÇÃO MÚLTIPLA
6845
+ Bloco para materiais externos de aprofundamento.
6699
6846
  """
6700
- template = "enap_designsystem/pages/quiz_rota_page.html"
6701
-
6702
- navbar = models.ForeignKey(
6703
- "EnapNavbarSnippet",
6847
+ titulo = CharBlock(required=True, help_text="Título do material")
6848
+ descricao = TextBlock(required=False, help_text="Breve descrição do material")
6849
+ tipo = ChoiceBlock(
6850
+ choices=[
6851
+ ('curso', 'Curso'),
6852
+ ('publicacao', 'Publicação'),
6853
+ ('video', 'Vídeo'),
6854
+ ('guia', 'Guia'),
6855
+ ('outro', 'Outro'),
6856
+ ],
6857
+ help_text="Tipo de material"
6858
+ )
6859
+ url = URLBlock(required=True, help_text="Link para o material")
6860
+ imagem = ImageChooserBlock(required=False, help_text="Imagem ilustrativa (opcional)")
6861
+
6862
+ class Meta:
6863
+ template = 'enap_designsystem/blocks/material_externo_block.html'
6864
+ icon = 'link'
6865
+ label = 'Material Externo'
6866
+
6867
+
6868
+ class CapsulaOrdemRota(Orderable):
6869
+ """
6870
+ Item ordenável para vincular e ordenar cápsulas em uma rota.
6871
+ """
6872
+ page = ParentalKey('RotaPage', related_name='capsulas_vinculadas')
6873
+ capsula = models.ForeignKey(
6874
+ 'wagtailcore.Page',
6875
+ on_delete=models.CASCADE,
6876
+ related_name='+',
6877
+ verbose_name="Cápsula",
6878
+ help_text="Selecione uma cápsula para vincular a esta rota"
6879
+ )
6880
+ destaque = models.BooleanField(
6881
+ default=False,
6882
+ verbose_name="Destaque",
6883
+ help_text="Marque para destacar esta cápsula como prioritária"
6884
+ )
6885
+ ordem = models.IntegerField(
6886
+ default=0,
6887
+ verbose_name="Ordem",
6888
+ help_text="Número para ordenar as cápsulas (menor = mais importante)"
6889
+ )
6890
+ texto_contextualizacao = models.TextField(
6891
+ blank=True,
6892
+ verbose_name="Texto de Contextualização",
6893
+ help_text="Texto explicando a relevância desta cápsula para esta rota específica"
6894
+ )
6895
+
6896
+ panels = [
6897
+ FieldPanel('capsula'),
6898
+ FieldPanel('destaque'),
6899
+ FieldPanel('ordem'),
6900
+ FieldPanel('texto_contextualizacao'),
6901
+ ]
6902
+
6903
+ class Meta:
6904
+ ordering = ['ordem']
6905
+
6906
+
6907
+ class RotaPage(Page):
6908
+ """
6909
+ Modelo de página para as rotas temáticas específicas.
6910
+ """
6911
+ # Campo para identificar o tipo de rota (para filtragem e personalização)
6912
+ tipo_rota = models.CharField(
6913
+ max_length=100,
6914
+ choices=[
6915
+ ('docente_presencial', 'Docente Presencial'),
6916
+ ('designer_instrucional', 'Designer Instrucional'),
6917
+ ('multimidia', 'Multimídia'),
6918
+ ('equipe_tecnica', 'Equipe Técnica'),
6919
+ ],
6920
+ verbose_name="Tipo de Rota",
6921
+ help_text="Selecione o tipo de rota"
6922
+ )
6923
+
6924
+ # Imagem de capa/banner da rota
6925
+ imagem_capa = models.ForeignKey(
6926
+ 'wagtailimages.Image',
6704
6927
  null=True,
6705
6928
  blank=True,
6706
6929
  on_delete=models.SET_NULL,
6707
- related_name="+",
6930
+ related_name='+',
6931
+ verbose_name="Imagem de Capa",
6932
+ help_text="Imagem principal da rota (banner)"
6708
6933
  )
6709
-
6710
- footer = models.ForeignKey(
6711
- "EnapFooterSnippet",
6934
+
6935
+ # Cor principal da rota (para personalização visual)
6936
+ cor_principal = models.CharField(
6937
+ max_length=20,
6938
+ default="#0066cc",
6939
+ verbose_name="Cor Principal",
6940
+ help_text="Código de cor hexadecimal (ex: #0066cc)"
6941
+ )
6942
+
6943
+ # Ícone representativo da rota
6944
+ icone = models.ForeignKey(
6945
+ 'wagtailimages.Image',
6712
6946
  null=True,
6713
6947
  blank=True,
6714
6948
  on_delete=models.SET_NULL,
6715
- related_name="+",
6949
+ related_name='+',
6950
+ verbose_name="Ícone",
6951
+ help_text="Ícone representativo da rota"
6716
6952
  )
6717
6953
 
6718
- introducao = RichTextField(
6719
- verbose_name="Texto introdutório",
6720
- help_text="Explica como funciona o direcionamento personalizado"
6954
+ # Descrição curta para uso em listagens e cards
6955
+ descricao_curta = models.CharField(
6956
+ max_length=255,
6957
+ blank=True,
6958
+ verbose_name="Descrição Curta",
6959
+ help_text="Breve descrição para uso em listagens (máx. 255 caracteres)"
6721
6960
  )
6722
6961
 
6723
- texto_resultado = RichTextField(
6724
- blank=True,
6725
- verbose_name="Texto de apresentação do resultado",
6726
- help_text="Aparece na página de resultado antes das cápsulas"
6962
+ # 1. Apresentação da Rota
6963
+ apresentacao = RichTextField(
6964
+ verbose_name="Apresentação da Rota",
6965
+ help_text="Texto introdutório explicando o foco da rota"
6966
+ )
6967
+
6968
+ # 2. Por onde começar?
6969
+ por_onde_comecar = RichTextField(
6970
+ verbose_name="Por onde começar?",
6971
+ help_text="Indicação dos conceitos ou conteúdos iniciais que ajudarão o usuário"
6972
+ )
6973
+
6974
+ # 3. Texto introdutório para as Cápsulas
6975
+ texto_capsulas = RichTextField(
6976
+ verbose_name="Texto sobre as Cápsulas",
6977
+ help_text="Texto explicativo sobre as cápsulas recomendadas para esta rota",
6978
+ blank=True
6727
6979
  )
6728
6980
 
6981
+ # 4. Onde posso aprender mais?
6982
+ texto_materiais_extras = RichTextField(
6983
+ verbose_name="Introdução aos Materiais Extras",
6984
+ help_text="Texto introdutório para a seção de materiais de aprofundamento",
6985
+ blank=True
6986
+ )
6987
+
6988
+ # Materiais externos para aprofundamento
6989
+ materiais_externos = StreamField([
6990
+ ('material', MaterialExternoBlock()),
6991
+ ], blank=True, verbose_name="Materiais Externos", use_json_field=True)
6992
+
6993
+ # Painéis para o admin - Usamos FieldPanel para todos os campos, incluindo imagens
6729
6994
  content_panels = Page.content_panels + [
6730
- FieldPanel('introducao'),
6731
- FieldPanel('texto_resultado'),
6732
- FieldPanel('navbar'),
6733
- FieldPanel('footer'),
6995
+ FieldPanel('descricao_curta'),
6996
+ FieldPanel('tipo_rota'),
6997
+ MultiFieldPanel([
6998
+ FieldPanel('imagem_capa'),
6999
+ FieldPanel('icone'),
7000
+ FieldPanel('cor_principal'),
7001
+ ], heading="Identidade Visual"),
7002
+ MultiFieldPanel([
7003
+ FieldPanel('apresentacao'),
7004
+ FieldPanel('por_onde_comecar'),
7005
+ ], heading="Conteúdo Introdutório"),
7006
+ MultiFieldPanel([
7007
+ FieldPanel('texto_capsulas'),
7008
+ InlinePanel('capsulas_vinculadas', label="Cápsulas"),
7009
+ ], heading="Cápsulas Essenciais"),
7010
+ MultiFieldPanel([
7011
+ FieldPanel('texto_materiais_extras'),
7012
+ FieldPanel('materiais_externos'),
7013
+ ], heading="Materiais de Aprofundamento"),
6734
7014
  ]
6735
7015
 
6736
- def serve(self, request):
6737
- """Override para gerenciar requisições de resultado"""
6738
-
6739
- # Se tiver parâmetros de resposta na URL, salvar na sessão
6740
- if request.GET.get('perfil') or request.GET.get('recurso') or request.GET.get('formato'):
6741
- self.salvar_respostas_url(request)
6742
-
6743
- # Se for requisição de resultado
6744
- if request.GET.get('resultado') == '1':
6745
- return self.servir_resultado(request)
6746
-
6747
- # Renderização normal do quiz
6748
- return super().serve(request)
7016
+ # Template
7017
+ template = 'enap_designsystem/rota_page.html'
6749
7018
 
6750
- def salvar_respostas_url(self, request):
6751
- """Salva respostas vindas da URL na sessão - com suporte a múltipla escolha"""
6752
- respostas = {}
6753
-
6754
- # Perfil profissional (múltiplos, separados por vírgula)
6755
- if request.GET.get('perfil'):
6756
- perfil_valores = request.GET.get('perfil').split(',')
6757
- perfil_textos = request.GET.get('perfil_texto', '').split(', ')
6758
-
6759
- # Garantir que temos o mesmo número de textos e valores
6760
- if len(perfil_textos) < len(perfil_valores):
6761
- perfil_textos.extend([perfil_valores[i] for i in range(len(perfil_textos), len(perfil_valores))])
6762
-
6763
- respostas['perfil_profissional'] = {
6764
- 'valor': perfil_valores,
6765
- 'texto': request.GET.get('perfil_texto') # Manter o texto original com vírgulas
6766
- }
6767
-
6768
- # Tipo de recurso (múltiplos, separados por vírgula)
6769
- if request.GET.get('recurso'):
6770
- recurso_valores = request.GET.get('recurso').split(',')
6771
- recurso_textos = request.GET.get('recurso_texto', '').split(', ')
6772
-
6773
- # Garantir que temos o mesmo número de textos e valores
6774
- if len(recurso_textos) < len(recurso_valores):
6775
- recurso_textos.extend([recurso_valores[i] for i in range(len(recurso_textos), len(recurso_valores))])
6776
-
6777
- respostas['tipo_recurso'] = {
6778
- 'valor': recurso_valores,
6779
- 'texto': request.GET.get('recurso_texto') # Manter o texto original com vírgulas
6780
- }
6781
-
6782
- # Formato de ação (múltiplos, separados por vírgula)
6783
- if request.GET.get('formato'):
6784
- formato_valores = request.GET.get('formato').split(',')
6785
- formato_textos = request.GET.get('formato_texto', '').split(', ')
6786
-
6787
- # Garantir que temos o mesmo número de textos e valores
6788
- if len(formato_textos) < len(formato_valores):
6789
- formato_textos.extend([formato_valores[i] for i in range(len(formato_textos), len(formato_valores))])
6790
-
6791
- respostas['formato_acao'] = {
6792
- 'valor': formato_valores,
6793
- 'texto': request.GET.get('formato_texto') # Manter o texto original com vírgulas
6794
- }
6795
-
6796
- # Salvar na sessão
6797
- request.session['quiz_respostas'] = respostas
7019
+ class Meta:
7020
+ verbose_name = "Página de Rota Temática"
7021
+
7022
+
7023
+ # Modelo para a página do Gerador de Rotas
7024
+ class GeradorRotasPage(Page):
7025
+ """
7026
+ Página com perguntas que direcionam o usuário para uma rota específica.
7027
+ """
7028
+ texto_introducao = RichTextField(
7029
+ verbose_name="Texto de Introdução",
7030
+ help_text="Texto explicativo sobre o gerador de rotas"
7031
+ )
6798
7032
 
6799
- def servir_resultado(self, request):
6800
- """Renderiza página de resultado com cápsulas filtradas"""
6801
-
6802
- # Recuperar respostas da sessão
6803
- respostas = request.session.get('quiz_respostas', {})
6804
-
6805
- if not respostas:
6806
- return redirect(self.url)
6807
-
6808
- # Buscar cápsulas baseadas nas respostas
6809
- capsulas = self.filtrar_capsulas(respostas)
6810
-
6811
- context = self.get_context(request)
6812
- context.update({
6813
- 'e_resultado': True,
6814
- 'respostas': respostas,
6815
- 'capsulas_recomendadas': capsulas,
6816
- 'total_capsulas': len(capsulas),
6817
- })
6818
-
6819
- return render(request, self.get_template(request), context)
7033
+ texto_botao = models.CharField(
7034
+ verbose_name="Texto do Botão",
7035
+ max_length=255,
7036
+ default="Gerar Rota",
7037
+ help_text="Texto exibido no botão de comando"
7038
+ )
6820
7039
 
6821
- def filtrar_capsulas(self, respostas):
6822
- """
6823
- Filtra cápsulas baseado nas respostas do quiz.
6824
- MODIFICADO: Agora usa lógica de união (OR) para múltiplas seleções
6825
- do mesmo tipo de filtro - uma cápsula é incluída se corresponder
6826
- a pelo menos um dos valores selecionados para cada categoria.
6827
- """
6828
- from enap_designsystem.models import CapsulaPage
6829
-
6830
- # Começar com todas as cápsulas
6831
- all_capsulas = list(CapsulaPage.objects.live().public())
6832
-
6833
- # Lista resultante
6834
- capsulas_filtradas = []
6835
-
6836
- # Primeiro, filtrar por cada categoria separadamente
6837
- perfis_filtrados = self._filtrar_por_categoria(
6838
- all_capsulas,
6839
- 'perfil_profissional' in respostas,
6840
- 'perfis_profissionais',
6841
- respostas.get('perfil_profissional', {}).get('valor', [])
6842
- )
6843
-
6844
- recursos_filtrados = self._filtrar_por_categoria(
6845
- all_capsulas,
6846
- 'tipo_recurso' in respostas,
6847
- 'tipos_recurso',
6848
- respostas.get('tipo_recurso', {}).get('valor', [])
6849
- )
6850
-
6851
- formatos_filtrados = self._filtrar_por_categoria(
6852
- all_capsulas,
6853
- 'formato_acao' in respostas,
6854
- 'formatos_acao',
6855
- respostas.get('formato_acao', {}).get('valor', [])
6856
- )
6857
-
6858
- # Intersecção das três listas para obter apenas cápsulas que atendem a todos os critérios
6859
- # Para cada cápsula, verificamos se ela está presente em todas as listas filtradas relevantes
6860
- for capsula in all_capsulas:
6861
- deve_incluir = True
6862
-
6863
- # Verificar se a cápsula está na lista de perfis filtrados (se houver filtro de perfil)
6864
- if 'perfil_profissional' in respostas and capsula not in perfis_filtrados:
6865
- deve_incluir = False
6866
-
6867
- # Verificar se a cápsula está na lista de recursos filtrados (se houver filtro de recurso)
6868
- if 'tipo_recurso' in respostas and capsula not in recursos_filtrados:
6869
- deve_incluir = False
6870
-
6871
- # Verificar se a cápsula está na lista de formatos filtrados (se houver filtro de formato)
6872
- if 'formato_acao' in respostas and capsula not in formatos_filtrados:
6873
- deve_incluir = False
6874
-
6875
- # Se a cápsula atender a todos os critérios, inclua na lista final
6876
- if deve_incluir:
6877
- capsulas_filtradas.append(capsula)
6878
-
6879
- # Ordenar por prioridade (obrigatório primeiro)
6880
- capsulas_filtradas.sort(key=lambda c: (c.prioridade != 'obrigatorio', c.title))
6881
-
6882
- return capsulas_filtradas
7040
+ # Relações com as páginas de destino para cada rota
7041
+ rota_docente_presencial = models.ForeignKey(
7042
+ 'wagtailcore.Page',
7043
+ null=True,
7044
+ blank=True,
7045
+ on_delete=models.SET_NULL,
7046
+ related_name='+',
7047
+ verbose_name="Rota Docente Presencial",
7048
+ help_text="Selecione a página da Rota Docente Presencial"
7049
+ )
6883
7050
 
6884
- def _filtrar_por_categoria(self, capsulas, tem_filtro, campo_capsula, valores_filtro):
6885
- """
6886
- Filtra cápsulas por uma categoria específica.
6887
- Usa lógica de união (OR) para múltiplas seleções do mesmo filtro.
6888
-
6889
- Retorna todas as cápsulas se não houver filtro para esta categoria.
6890
- """
6891
- if not tem_filtro or not valores_filtro:
6892
- return capsulas
6893
-
6894
- resultado = []
6895
-
6896
- for capsula in capsulas:
6897
- valores_capsula = getattr(capsula, campo_capsula, None)
6898
-
6899
- if valores_capsula:
6900
- # Verifica se há alguma correspondência entre os valores da cápsula
6901
- # e os valores selecionados no filtro (lógica OR)
6902
- if any(valor in valores_capsula for valor in valores_filtro):
6903
- resultado.append(capsula)
6904
-
6905
- return resultado
7051
+ rota_designer_instrucional = models.ForeignKey(
7052
+ 'wagtailcore.Page',
7053
+ null=True,
7054
+ blank=True,
7055
+ on_delete=models.SET_NULL,
7056
+ related_name='+',
7057
+ verbose_name="Rota Designer Instrucional",
7058
+ help_text="Selecione a página da Rota Designer Instrucional"
7059
+ )
6906
7060
 
6907
- subpage_types = []
7061
+ rota_multimidia = models.ForeignKey(
7062
+ 'wagtailcore.Page',
7063
+ null=True,
7064
+ blank=True,
7065
+ on_delete=models.SET_NULL,
7066
+ related_name='+',
7067
+ verbose_name="Rota Multimídia",
7068
+ help_text="Selecione a página da Rota Multimídia"
7069
+ )
7070
+
7071
+ rota_equipe_tecnica = models.ForeignKey(
7072
+ 'wagtailcore.Page',
7073
+ null=True,
7074
+ blank=True,
7075
+ on_delete=models.SET_NULL,
7076
+ related_name='+',
7077
+ verbose_name="Rota Equipe Técnica",
7078
+ help_text="Selecione a página da Rota Equipe Técnica"
7079
+ )
7080
+
7081
+ # Textos das perguntas e opções (personalizáveis no admin)
7082
+ pergunta = models.CharField(
7083
+ verbose_name="Pergunta",
7084
+ max_length=255,
7085
+ default="O que você quer aprender?",
7086
+ help_text="Pergunta principal para direcionamento da rota"
7087
+ )
7088
+
7089
+ opcao_docente = models.CharField(
7090
+ verbose_name="Opção Docente",
7091
+ max_length=255,
7092
+ default="Quero aprender a tornar minhas aulas e eventos presenciais mais acessíveis.",
7093
+ help_text="Texto para a opção Docente Presencial"
7094
+ )
7095
+
7096
+ opcao_designer = models.CharField(
7097
+ verbose_name="Opção Designer",
7098
+ max_length=255,
7099
+ default="Quero aprender a criar conteúdos digitais acessíveis, como documentos e apresentações.",
7100
+ help_text="Texto para a opção Designer Instrucional"
7101
+ )
6908
7102
 
7103
+ opcao_multimidia = models.CharField(
7104
+ verbose_name="Opção Multimídia",
7105
+ max_length=255,
7106
+ default="Quero aprender a tornar vídeos e materiais multimídia acessíveis.",
7107
+ help_text="Texto para a opção Multimídia"
7108
+ )
7109
+
7110
+ opcao_tecnica = models.CharField(
7111
+ verbose_name="Opção Equipe Técnica",
7112
+ max_length=255,
7113
+ default="Quero aprender a aplicar boas práticas de acessibilidade em sistemas e plataformas digitais.",
7114
+ help_text="Texto para a opção Equipe Técnica"
7115
+ )
7116
+
7117
+ content_panels = Page.content_panels + [
7118
+ FieldPanel('texto_introducao'),
7119
+ FieldPanel('pergunta'),
7120
+ MultiFieldPanel([
7121
+ FieldPanel('opcao_docente'),
7122
+ FieldPanel('opcao_designer'),
7123
+ FieldPanel('opcao_multimidia'),
7124
+ FieldPanel('opcao_tecnica'),
7125
+ ], heading="Opções de Resposta"),
7126
+ FieldPanel('texto_botao'),
7127
+ MultiFieldPanel([
7128
+ FieldPanel('rota_docente_presencial'),
7129
+ FieldPanel('rota_designer_instrucional'),
7130
+ FieldPanel('rota_multimidia'),
7131
+ FieldPanel('rota_equipe_tecnica'),
7132
+ ], heading="Páginas de Destino das Rotas"),
7133
+ ]
7134
+
7135
+ def serve(self, request):
7136
+ # Verifica se foi enviado um formulário para direcionar para uma rota
7137
+ if request.method == 'POST' and 'rota_selecionada' in request.POST:
7138
+ rota_selecionada = request.POST.get('rota_selecionada')
7139
+
7140
+ # Redireciona para a página da rota escolhida
7141
+ if rota_selecionada == 'docente_presencial' and self.rota_docente_presencial:
7142
+ return redirect(self.rota_docente_presencial.url)
7143
+ elif rota_selecionada == 'designer_instrucional' and self.rota_designer_instrucional:
7144
+ return redirect(self.rota_designer_instrucional.url)
7145
+ elif rota_selecionada == 'multimidia' and self.rota_multimidia:
7146
+ return redirect(self.rota_multimidia.url)
7147
+ elif rota_selecionada == 'equipe_tecnica' and self.rota_equipe_tecnica:
7148
+ return redirect(self.rota_equipe_tecnica.url)
7149
+
7150
+ # Se não houver rota selecionada, continua com a exibição normal da página
7151
+ return super().serve(request)
7152
+
6909
7153
  class Meta:
6910
- verbose_name = "Quiz de Rotas"
6911
- verbose_name_plural = "Quiz de Rotas"
7154
+ verbose_name = "Página Geradora de Rotas"