Browse Source

Adiciona feature flag lib (#3693)

Adiciona feature flag lib e refatora Solr para usá-la
pull/3694/head
Edward 1 year ago
committed by GitHub
parent
commit
b495a35c34
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      docker/docker-compose.yaml
  2. 17
      docker/start.sh
  3. 45
      docs/feature-flags.md
  4. 1
      requirements/requirements.txt
  5. 1
      sapl/base/forms.py
  6. 17
      sapl/base/migrations/0059_remove_appconfig_sapl_as_sapn.py
  7. 4
      sapl/base/models.py
  8. 6
      sapl/base/views.py
  9. 9
      sapl/context_processors.py
  10. 3
      sapl/materia/views.py
  11. 4
      sapl/norma/views.py
  12. 3
      sapl/sessao/views.py
  13. 16
      sapl/settings.py
  14. 6
      sapl/templates/base.html
  15. 2
      sapl/templates/base/layouts.yaml
  16. 12
      sapl/templates/materia/materialegislativa_filter.html
  17. 1
      sapl/templates/norma/normajuridica_detail.html
  18. 5
      sapl/templates/norma/normajuridica_filter.html
  19. 8
      sapl/templates/search/search.html
  20. 5
      sapl/templates/sessao/sessaoplenaria_filter.html
  21. 6
      sapl/utils.py

1
docker/docker-compose.yaml

@ -54,6 +54,7 @@ services:
SOLR_COLLECTION: sapl SOLR_COLLECTION: sapl
SOLR_URL: http://solr:solr@saplsolr:8983 SOLR_URL: http://solr:solr@saplsolr:8983
IS_ZK_EMBEDDED: 'True' IS_ZK_EMBEDDED: 'True'
ENABLE_SAPN: 'False'
TZ: America/Sao_Paulo TZ: America/Sao_Paulo
volumes: volumes:
- sapl_data:/var/interlegis/sapl/data - sapl_data:/var/interlegis/sapl/data

17
docker/start.sh

@ -39,6 +39,7 @@ create_env() {
echo "SOLR_COLLECTION = ""${SOLR_COLLECTION-sapl}" >> $FILENAME echo "SOLR_COLLECTION = ""${SOLR_COLLECTION-sapl}" >> $FILENAME
echo "SOLR_URL = ""${SOLR_URL-http://localhost:8983}" >> $FILENAME echo "SOLR_URL = ""${SOLR_URL-http://localhost:8983}" >> $FILENAME
echo "IS_ZK_EMBEDDED = ""${IS_ZK_EMBEDDED-False}" >> $FILENAME echo "IS_ZK_EMBEDDED = ""${IS_ZK_EMBEDDED-False}" >> $FILENAME
echo "ENABLE_SAPN = ""${ENABLE_SAPN-False}" >> $FILENAME
echo "[ENV FILE] done." echo "[ENV FILE] done."
} }
@ -85,14 +86,30 @@ if [ "${USE_SOLR-False}" == "True" ] || [ "${USE_SOLR-False}" == "true" ]; then
fi fi
python3 solr_cli.py -u $SOLR_URL -c $SOLR_COLLECTION -s $NUM_SHARDS -rf $RF -ms $MAX_SHARDS_PER_NODE $ZK_EMBEDDED & python3 solr_cli.py -u $SOLR_URL -c $SOLR_COLLECTION -s $NUM_SHARDS -rf $RF -ms $MAX_SHARDS_PER_NODE $ZK_EMBEDDED &
# Enable SOLR switch on, creating if it doesn't exist on database
./manage.py waffle_switch SOLR_SWITCH on --create
else else
echo "Solr is offline, not possible to connect." echo "Solr is offline, not possible to connect."
# Disable Solr switch off, creating if it doesn't exist on database
./manage.py waffle_switch SOLR_SWITCH off --create
fi fi
else else
echo "Solr support is not initialized." echo "Solr support is not initialized."
# Disable Solr switch off, creating if it doesn't exist on database
./manage.py waffle_switch SOLR_SWITCH off --create
fi fi
## Enable/Disable SAPN
if [ "${ENABLE_SAPN-False}" == "True" ] || [ "${ENABLE_SAPN-False}" == "true" ]; then
echo "Enabling SAPN"
./manage.py waffle_switch SAPLN_SWITCH on --create
else
echo "Enabling SAPL"
./manage.py waffle_switch SAPLN_SWITCH off --create
fi
echo "Creating admin user..." echo "Creating admin user..."
user_created=$(python3 create_admin.py 2>&1) user_created=$(python3 create_admin.py 2>&1)

45
docs/feature-flags.md

@ -0,0 +1,45 @@
### Types
Waffle supports three types of feature flippers:
### Flags
_"Flags can be used to enable a feature for specific users, groups, users meeting
certain criteria (such as being authenticated, or superusers) or a certain percentage
of visitors."_
https://waffle.readthedocs.io/en/stable/types/flag.html
### Switches
_"Switches are simple booleans: they are on or off, for everyone, all the time.
They do not require a request object and can be used in other contexts, such
as management commands and tasks."_
Enabling/Disabling via CLI (example):
./manage.py waffle_switch SOLR_SWITCH on --create
./manage.py waffle_switch SOLR_SWITCH off --create
https://waffle.readthedocs.io/en/stable/types/switch.html
### Samples
_"Samples are on a given percentage of the time. They do not require a request
object and can be used in other contexts, such as management commands and tasks."_
Liga e desliga baseado em amostragem aleatória.
https://waffle.readthedocs.io/en/stable/types/sample.html
### Reference
* Documentation: https://waffle.readthedocs.io/
* Managing from CLI: https://waffle.readthedocs.io/en/stable/usage/cli.html
* Templates: https://waffle.readthedocs.io/en/stable/usage/templates.html
* Views: https://waffle.readthedocs.io/en/stable/usage/views.html
* Decorators: https://waffle.readthedocs.io/en/stable/usage/decorators.html

1
requirements/requirements.txt

@ -11,6 +11,7 @@ django-extra-views==0.12.0
django-model-utils==3.1.2 django-model-utils==3.1.2
django-extensions==2.1.4 django-extensions==2.1.4
django-image-cropping==1.2 django-image-cropping==1.2
django-waffle==3.0.0
django-webpack-loader==1.6.0 django-webpack-loader==1.6.0
drf-spectacular==0.18.2 drf-spectacular==0.18.2
django-ratelimit==3.0.1 django-ratelimit==3.0.1

1
sapl/base/forms.py

@ -1009,7 +1009,6 @@ class ConfiguracoesAppForm(ModelForm):
'google_recaptcha_site_key', 'google_recaptcha_site_key',
'google_recaptcha_secret_key', 'google_recaptcha_secret_key',
'google_analytics_id_metrica', 'google_analytics_id_metrica',
'sapl_as_sapn',
'identificacao_de_documentos', 'identificacao_de_documentos',
] ]

17
sapl/base/migrations/0059_remove_appconfig_sapl_as_sapn.py

@ -0,0 +1,17 @@
# Generated by Django 2.2.28 on 2023-11-27 00:23
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('base', '0058_appconfig_ordenacao_pesquisa_materia'),
]
operations = [
migrations.RemoveField(
model_name='appconfig',
name='sapl_as_sapn',
),
]

4
sapl/base/models.py

@ -107,10 +107,6 @@ class AppConfig(models.Model):
default="", default="",
verbose_name=_('Esfera Federação'), verbose_name=_('Esfera Federação'),
choices=ESFERA_FEDERACAO_CHOICES) choices=ESFERA_FEDERACAO_CHOICES)
sapl_as_sapn = models.BooleanField(
verbose_name=_(
'Utilizar SAPL apenas como SAPL-Normas?'),
choices=YES_NO_CHOICES, default=False)
# MÓDULO PARLAMENTARES # MÓDULO PARLAMENTARES

6
sapl/base/views.py

@ -50,8 +50,8 @@ from sapl.relatorios.views import (relatorio_estatisticas_acesso_normas)
from sapl.sessao.models import (Bancada, SessaoPlenaria) from sapl.sessao.models import (Bancada, SessaoPlenaria)
from sapl.settings import EMAIL_SEND_USER from sapl.settings import EMAIL_SEND_USER
from sapl.utils import (gerar_hash_arquivo, intervalos_tem_intersecao, mail_service_configured, from sapl.utils import (gerar_hash_arquivo, intervalos_tem_intersecao, mail_service_configured,
SEPARADOR_HASH_PROPOSICAO, show_results_filter_set, google_recaptcha_configured, sapl_as_sapn, SEPARADOR_HASH_PROPOSICAO, show_results_filter_set, google_recaptcha_configured,
get_client_ip) get_client_ip, sapn_is_enabled)
from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, EstatisticasAcessoNormasForm) from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, EstatisticasAcessoNormasForm)
from .models import AppConfig, CasaLegislativa from .models import AppConfig, CasaLegislativa
@ -62,7 +62,7 @@ def get_casalegislativa():
class IndexView(TemplateView): class IndexView(TemplateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if sapl_as_sapn(): if sapn_is_enabled():
return redirect('/norma/pesquisar') return redirect('/norma/pesquisar')
return TemplateView.get(self, request, *args, **kwargs) return TemplateView.get(self, request, *args, **kwargs)

9
sapl/context_processors.py

@ -3,8 +3,7 @@ import logging
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from sapl.utils import google_recaptcha_configured as google_recaptcha_configured_utils,\ from sapl.utils import google_recaptcha_configured as google_recaptcha_configured_utils, sapn_is_enabled
sapl_as_sapn as sapl_as_sapn_utils
from sapl.utils import mail_service_configured as mail_service_configured_utils from sapl.utils import mail_service_configured as mail_service_configured_utils
@ -36,10 +35,10 @@ def google_recaptcha_configured(request):
return {'google_recaptcha_configured': True} return {'google_recaptcha_configured': True}
def sapl_as_sapn(request): def enable_sapn(request):
return { return {
'sapl_as_sapn': sapl_as_sapn_utils(), 'sapl_as_sapn': sapn_is_enabled(),
'nome_sistema': _('Sistema de Apoio ao Processo Legislativo') 'nome_sistema': _('Sistema de Apoio ao Processo Legislativo')
if not sapl_as_sapn_utils() if not sapn_is_enabled()
else _('Sistema de Apoio à Publicação de Leis e Normas') else _('Sistema de Apoio à Publicação de Leis e Normas')
} }

3
sapl/materia/views.py

@ -2132,9 +2132,6 @@ class MateriaLegislativaPesquisaView(FilterView):
context['show_results'] = show_results_filter_set(qr) context['show_results'] = show_results_filter_set(qr)
context['USE_SOLR'] = settings.USE_SOLR if hasattr(
settings, 'USE_SOLR') else False
return context return context

4
sapl/norma/views.py

@ -28,7 +28,7 @@ from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
MasterDetailCrud, make_pagination) MasterDetailCrud, make_pagination)
from sapl.materia.models import Orgao from sapl.materia.models import Orgao
from sapl.utils import show_results_filter_set, get_client_ip,\ from sapl.utils import show_results_filter_set, get_client_ip,\
sapl_as_sapn sapn_is_enabled
from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm, from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm,
NormaPesquisaSimplesForm, NormaRelacionadaForm, NormaPesquisaSimplesForm, NormaRelacionadaForm,
@ -187,8 +187,6 @@ class NormaPesquisaView(FilterView):
context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else ''
context['show_results'] = show_results_filter_set(qr) context['show_results'] = show_results_filter_set(qr)
context['USE_SOLR'] = settings.USE_SOLR if hasattr(
settings, 'USE_SOLR') else False
return context return context

3
sapl/sessao/views.py

@ -3997,9 +3997,6 @@ class PesquisarSessaoPlenariaView(FilterView):
context['page_range'] = make_pagination( context['page_range'] = make_pagination(
page_obj.number, paginator.num_pages) page_obj.number, paginator.num_pages)
context['USE_SOLR'] = settings.USE_SOLR if hasattr(
settings, 'USE_SOLR') else False
return context return context
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):

16
sapl/settings.py

@ -80,6 +80,8 @@ INSTALLED_APPS = (
'crispy_forms', 'crispy_forms',
'floppyforms', 'floppyforms',
'waffle',
'drf_spectacular', 'drf_spectacular',
'rest_framework', 'rest_framework',
'rest_framework.authtoken', 'rest_framework.authtoken',
@ -137,6 +139,7 @@ MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware', 'django.middleware.security.SecurityMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware',
'django_prometheus.middleware.PrometheusAfterMiddleware', 'django_prometheus.middleware.PrometheusAfterMiddleware',
'waffle.middleware.WaffleMiddleware',
] ]
if DEBUG: if DEBUG:
INSTALLED_APPS += ('debug_toolbar',) INSTALLED_APPS += ('debug_toolbar',)
@ -210,8 +213,7 @@ TEMPLATES = [
'sapl.context_processors.parliament_info', 'sapl.context_processors.parliament_info',
'sapl.context_processors.mail_service_configured', 'sapl.context_processors.mail_service_configured',
'sapl.context_processors.google_recaptcha_configured', 'sapl.context_processors.google_recaptcha_configured',
'sapl.context_processors.sapl_as_sapn', 'sapl.context_processors.enable_sapn',
], ],
'debug': DEBUG 'debug': DEBUG
}, },
@ -255,6 +257,16 @@ DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', cast=str, default='')
SERVER_EMAIL = config('SERVER_EMAIL', cast=str, default='') SERVER_EMAIL = config('SERVER_EMAIL', cast=str, default='')
EMAIL_RUNNING = None EMAIL_RUNNING = None
# Feature Flag
WAFFLE_FLAG_DEFAULT = False
WAFFLE_SWITCH_DEFAULT = False
WAFFLE_CREATE_MISSING_FLAGS = True
WAFFLE_LOG_MISSING_FLAGS = True
WAFFLE_CREATE_MISSING_SWITCHES = True
WAFFLE_LOG_MISSING_SWITCHES = True
WAFFLE_ENABLE_ADMIN_PAGES = True
MAX_DOC_UPLOAD_SIZE = 150 * 1024 * 1024 # 150MB MAX_DOC_UPLOAD_SIZE = 150 * 1024 * 1024 # 150MB
MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB
DATA_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024 # 10MB DATA_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024 # 10MB

6
sapl/templates/base.html

@ -1,6 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
{% load i18n staticfiles menus %} {% load i18n staticfiles menus %}
{% load common_tags %} {% load common_tags %}
{% load waffle_tags %}
{% load render_bundle from webpack_loader %} {% load render_bundle from webpack_loader %}
{% load webpack_static from webpack_loader %} {% load webpack_static from webpack_loader %}
@ -11,13 +12,10 @@
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<title>{% block head_title %}{% if sapl_as_sapn %}SAPL-Normas - {% else %}SAPL - {%endif%}{{nome_sistema}}{% endblock %}</title> <title>{% block head_title %}{% switch "SAPLN_SWITCH" %}SAPL-Normas - {% else %}SAPL - {%endswitch%}{{nome_sistema}}{% endblock %}</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="theme-color" content="#343a40"> <meta name="theme-color" content="#343a40">
{% block head_content %} {% block head_content %}
<link rel="icon" href="{% webpack_static 'img/favicon.ico' %}" type="image/png"> <link rel="icon" href="{% webpack_static 'img/favicon.ico' %}" type="image/png">
{% block webpack_loader_css %} {% block webpack_loader_css %}

2
sapl/templates/base/layouts.yaml

@ -20,7 +20,7 @@ UserDetail:
AppConfig: AppConfig:
{% trans 'Configurações Gerais' %}: {% trans 'Configurações Gerais' %}:
- esfera_federacao sapl_as_sapn - esfera_federacao
#{% trans 'Módulo Parlamentares' %}: #{% trans 'Módulo Parlamentares' %}:
#{% trans 'Módulo Mesa Diretora' %}: #{% trans 'Módulo Mesa Diretora' %}:

12
sapl/templates/materia/materialegislativa_filter.html

@ -1,18 +1,18 @@
{% extends "crud/detail.html" %} {% extends "crud/detail.html" %}
{% load i18n %} {% load i18n %}
{% load tz %} {% load tz %}
{% load waffle_tags %}
{% load crispy_forms_tags common_tags%} {% load crispy_forms_tags common_tags%}
{% load webpack_static from webpack_loader %} {% load webpack_static from webpack_loader %}
{% block actions %} {% block actions %}
<div class="actions btn-group" role="group"> <div class="actions btn-group" role="group">
{% if USE_SOLR %} {% switch "SOLR_SWITCH" %}
<a href="{% url 'sapl.base:haystack_search' %}" class="btn btn-outline-primary"> <a href="{% url 'sapl.base:haystack_search' %}" class="btn btn-outline-primary">
Pesquisa Textual Pesquisa Textual
</a> </a>
{% endif %} {% endswitch %}
{% if perms.materia.add_materialegislativa %} {% if perms.materia.add_materialegislativa %}
<a href="{% url 'sapl.materia:materialegislativa_create' %}" class="btn btn-outline-primary"> <a href="{% url 'sapl.materia:materialegislativa_create' %}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar Matéria Legislativa {% endblocktrans %} {% blocktrans with verbose_name=view.verbose_name %} Adicionar Matéria Legislativa {% endblocktrans %}

1
sapl/templates/norma/normajuridica_detail.html

@ -1,5 +1,6 @@
{% extends "crud/detail.html" %} {% extends "crud/detail.html" %}
{% load i18n common_tags %} {% load i18n common_tags %}
{% load waffle_tags %}
{% load render_bundle from webpack_loader %} {% load render_bundle from webpack_loader %}
{% block webpack_loader_css %} {% block webpack_loader_css %}

5
sapl/templates/norma/normajuridica_filter.html

@ -1,14 +1,15 @@
{% extends "crud/detail.html" %} {% extends "crud/detail.html" %}
{% load i18n %} {% load i18n %}
{% load waffle_tags %}
{% load crispy_forms_tags common_tags %} {% load crispy_forms_tags common_tags %}
{% block actions %} {% block actions %}
<div class="actions btn-group float-right" role="group"> <div class="actions btn-group float-right" role="group">
{% if USE_SOLR %} {% switch "SOLR_SWITCH" %}
<a href="{% url 'sapl.base:haystack_search' %}" class="btn btn-outline-primary"> <a href="{% url 'sapl.base:haystack_search' %}" class="btn btn-outline-primary">
Pesquisa Textual Pesquisa Textual
</a> </a>
{% endif %} {% endswitch %}
{% if perms.norma.add_normajuridica %} {% if perms.norma.add_normajuridica %}
<a href="{% url 'sapl.norma:normajuridica_create' %}" class="btn btn-outline-primary"> <a href="{% url 'sapl.norma:normajuridica_create' %}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar Norma Jurídica {% endblocktrans %} {% blocktrans with verbose_name=view.verbose_name %} Adicionar Norma Jurídica {% endblocktrans %}

8
sapl/templates/search/search.html

@ -1,7 +1,7 @@
{% extends 'crud/form.html' %} {% extends 'crud/form.html' %}
{% load crispy_forms_tags %} {% load crispy_forms_tags %}
{% load common_tags %} {% load common_tags %}
{% load waffle_tags %}
{% block base_content %} {% block base_content %}
<h1><legend>Pesquisa Textual</legend></h1> <h1><legend>Pesquisa Textual</legend></h1>
</br> </br>
@ -11,9 +11,7 @@
{{ form.q|as_crispy_field }} {{ form.q|as_crispy_field }}
</div> </div>
</div> </div>
{% switch "SAPLN_SWITCH" %}
{% if not sapl_as_sapn %}
<div class="row"> <div class="row">
<div class="col-md-8"> <div class="col-md-8">
<h3> Em quais tipos de documento deseja pesquisar?</h3> <h3> Em quais tipos de documento deseja pesquisar?</h3>
@ -27,7 +25,7 @@
{{ form.models }} {{ form.models }}
</div> </div>
</div> </div>
{% endif %} {% endswitch %}
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">

5
sapl/templates/sessao/sessaoplenaria_filter.html

@ -1,14 +1,15 @@
{% extends "crud/detail.html" %} {% extends "crud/detail.html" %}
{% load i18n %} {% load i18n %}
{% load waffle_tags %}
{% load crispy_forms_tags common_tags %} {% load crispy_forms_tags common_tags %}
{% block actions %} {% block actions %}
<div class="actions btn-group float-right" role="group"> <div class="actions btn-group float-right" role="group">
{% if USE_SOLR %} {% switch "SOLR_SWITCH" %}
<a href="{% url 'sapl.base:haystack_search' %}" class="btn btn-outline-primary"> <a href="{% url 'sapl.base:haystack_search' %}" class="btn btn-outline-primary">
Pesquisa Textual Pesquisa Textual
</a> </a>
{% endif %} {% endswitch %}
{% if perms.sessao %} {% if perms.sessao %}
<a href="{% url 'sapl.sessao:sessaoplenaria_create' %}" class="btn btn-outline-primary"> <a href="{% url 'sapl.sessao:sessaoplenaria_create' %}" class="btn btn-outline-primary">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar Sessão Plenária {% endblocktrans %} {% blocktrans with verbose_name=view.verbose_name %} Adicionar Sessão Plenária {% endblocktrans %}

6
sapl/utils.py

@ -1061,9 +1061,9 @@ def google_recaptcha_configured():
return not AppConfig.attr('google_recaptcha_site_key') == '' return not AppConfig.attr('google_recaptcha_site_key') == ''
def sapl_as_sapn(): def sapn_is_enabled():
from sapl.base.models import AppConfig import waffle
return AppConfig.attr('sapl_as_sapn') return waffle.switch_is_active('SAPLN_SWITCH')
def timing(f): def timing(f):

Loading…
Cancel
Save