From b495a35c34cc65cfd4894bae7a1b53cbcd5096ea Mon Sep 17 00:00:00 2001 From: Edward <9326037+edwardoliveira@users.noreply.github.com> Date: Tue, 28 Nov 2023 14:36:17 -0800 Subject: [PATCH] Adiciona feature flag lib (#3693) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adiciona feature flag lib e refatora Solr para usá-la --- docker/docker-compose.yaml | 1 + docker/start.sh | 17 +++++++ docs/feature-flags.md | 45 +++++++++++++++++++ requirements/requirements.txt | 1 + sapl/base/forms.py | 1 - .../0059_remove_appconfig_sapl_as_sapn.py | 17 +++++++ sapl/base/models.py | 4 -- sapl/base/views.py | 6 +-- sapl/context_processors.py | 9 ++-- sapl/materia/views.py | 3 -- sapl/norma/views.py | 4 +- sapl/sessao/views.py | 3 -- sapl/settings.py | 16 ++++++- sapl/templates/base.html | 6 +-- sapl/templates/base/layouts.yaml | 2 +- .../materia/materialegislativa_filter.html | 12 ++--- .../templates/norma/normajuridica_detail.html | 1 + .../templates/norma/normajuridica_filter.html | 5 ++- sapl/templates/search/search.html | 8 ++-- .../sessao/sessaoplenaria_filter.html | 5 ++- sapl/utils.py | 6 +-- 21 files changed, 125 insertions(+), 47 deletions(-) create mode 100644 docs/feature-flags.md create mode 100644 sapl/base/migrations/0059_remove_appconfig_sapl_as_sapn.py diff --git a/docker/docker-compose.yaml b/docker/docker-compose.yaml index 2bb8d82f2..771adc64e 100644 --- a/docker/docker-compose.yaml +++ b/docker/docker-compose.yaml @@ -54,6 +54,7 @@ services: SOLR_COLLECTION: sapl SOLR_URL: http://solr:solr@saplsolr:8983 IS_ZK_EMBEDDED: 'True' + ENABLE_SAPN: 'False' TZ: America/Sao_Paulo volumes: - sapl_data:/var/interlegis/sapl/data diff --git a/docker/start.sh b/docker/start.sh index 558b7d7b5..7a9345fbb 100755 --- a/docker/start.sh +++ b/docker/start.sh @@ -39,6 +39,7 @@ create_env() { echo "SOLR_COLLECTION = ""${SOLR_COLLECTION-sapl}" >> $FILENAME echo "SOLR_URL = ""${SOLR_URL-http://localhost:8983}" >> $FILENAME echo "IS_ZK_EMBEDDED = ""${IS_ZK_EMBEDDED-False}" >> $FILENAME + echo "ENABLE_SAPN = ""${ENABLE_SAPN-False}" >> $FILENAME echo "[ENV FILE] done." } @@ -85,14 +86,30 @@ if [ "${USE_SOLR-False}" == "True" ] || [ "${USE_SOLR-False}" == "true" ]; then fi 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 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 else 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 +## 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..." user_created=$(python3 create_admin.py 2>&1) diff --git a/docs/feature-flags.md b/docs/feature-flags.md new file mode 100644 index 000000000..2e9df5b11 --- /dev/null +++ b/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 + + diff --git a/requirements/requirements.txt b/requirements/requirements.txt index f75313cb0..95ed3fadf 100644 --- a/requirements/requirements.txt +++ b/requirements/requirements.txt @@ -11,6 +11,7 @@ django-extra-views==0.12.0 django-model-utils==3.1.2 django-extensions==2.1.4 django-image-cropping==1.2 +django-waffle==3.0.0 django-webpack-loader==1.6.0 drf-spectacular==0.18.2 django-ratelimit==3.0.1 diff --git a/sapl/base/forms.py b/sapl/base/forms.py index 7fc2c6fdc..092206429 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -1009,7 +1009,6 @@ class ConfiguracoesAppForm(ModelForm): 'google_recaptcha_site_key', 'google_recaptcha_secret_key', 'google_analytics_id_metrica', - 'sapl_as_sapn', 'identificacao_de_documentos', ] diff --git a/sapl/base/migrations/0059_remove_appconfig_sapl_as_sapn.py b/sapl/base/migrations/0059_remove_appconfig_sapl_as_sapn.py new file mode 100644 index 000000000..bd2edf7bd --- /dev/null +++ b/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', + ), + ] diff --git a/sapl/base/models.py b/sapl/base/models.py index adf3f67f1..e0f00bbf2 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -107,10 +107,6 @@ class AppConfig(models.Model): default="", verbose_name=_('Esfera Federação'), 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 diff --git a/sapl/base/views.py b/sapl/base/views.py index dd8f7ef27..8417c0021 100644 --- a/sapl/base/views.py +++ b/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.settings import EMAIL_SEND_USER 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, - get_client_ip) + SEPARADOR_HASH_PROPOSICAO, show_results_filter_set, google_recaptcha_configured, + get_client_ip, sapn_is_enabled) from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, EstatisticasAcessoNormasForm) from .models import AppConfig, CasaLegislativa @@ -62,7 +62,7 @@ def get_casalegislativa(): class IndexView(TemplateView): def get(self, request, *args, **kwargs): - if sapl_as_sapn(): + if sapn_is_enabled(): return redirect('/norma/pesquisar') return TemplateView.get(self, request, *args, **kwargs) diff --git a/sapl/context_processors.py b/sapl/context_processors.py index 86110cd4f..2b8a422cb 100644 --- a/sapl/context_processors.py +++ b/sapl/context_processors.py @@ -3,8 +3,7 @@ import logging from django.conf import settings from django.utils.translation import ugettext_lazy as _ -from sapl.utils import google_recaptcha_configured as google_recaptcha_configured_utils,\ - sapl_as_sapn as sapl_as_sapn_utils +from sapl.utils import google_recaptcha_configured as google_recaptcha_configured_utils, sapn_is_enabled 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} -def sapl_as_sapn(request): +def enable_sapn(request): return { - 'sapl_as_sapn': sapl_as_sapn_utils(), + 'sapl_as_sapn': sapn_is_enabled(), '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') } diff --git a/sapl/materia/views.py b/sapl/materia/views.py index b1073cc7b..e656751dc 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -2132,9 +2132,6 @@ class MateriaLegislativaPesquisaView(FilterView): context['show_results'] = show_results_filter_set(qr) - context['USE_SOLR'] = settings.USE_SOLR if hasattr( - settings, 'USE_SOLR') else False - return context diff --git a/sapl/norma/views.py b/sapl/norma/views.py index d6d474590..fd12ebaf6 100644 --- a/sapl/norma/views.py +++ b/sapl/norma/views.py @@ -28,7 +28,7 @@ from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, MasterDetailCrud, make_pagination) from sapl.materia.models import Orgao from sapl.utils import show_results_filter_set, get_client_ip,\ - sapl_as_sapn + sapn_is_enabled from .forms import (AnexoNormaJuridicaForm, NormaFilterSet, NormaJuridicaForm, NormaPesquisaSimplesForm, NormaRelacionadaForm, @@ -187,8 +187,6 @@ class NormaPesquisaView(FilterView): context['filter_url'] = ('&' + qr.urlencode()) if len(qr) > 0 else '' context['show_results'] = show_results_filter_set(qr) - context['USE_SOLR'] = settings.USE_SOLR if hasattr( - settings, 'USE_SOLR') else False return context diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index e19cfc267..8b1537661 100755 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -3997,9 +3997,6 @@ class PesquisarSessaoPlenariaView(FilterView): context['page_range'] = make_pagination( page_obj.number, paginator.num_pages) - context['USE_SOLR'] = settings.USE_SOLR if hasattr( - settings, 'USE_SOLR') else False - return context def get(self, request, *args, **kwargs): diff --git a/sapl/settings.py b/sapl/settings.py index fc120cfe8..8d1ae2bf9 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -80,6 +80,8 @@ INSTALLED_APPS = ( 'crispy_forms', 'floppyforms', + 'waffle', + 'drf_spectacular', 'rest_framework', 'rest_framework.authtoken', @@ -137,6 +139,7 @@ MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', 'django_prometheus.middleware.PrometheusAfterMiddleware', + 'waffle.middleware.WaffleMiddleware', ] if DEBUG: INSTALLED_APPS += ('debug_toolbar',) @@ -210,8 +213,7 @@ TEMPLATES = [ 'sapl.context_processors.parliament_info', 'sapl.context_processors.mail_service_configured', 'sapl.context_processors.google_recaptcha_configured', - 'sapl.context_processors.sapl_as_sapn', - + 'sapl.context_processors.enable_sapn', ], 'debug': DEBUG }, @@ -255,6 +257,16 @@ DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', cast=str, default='') SERVER_EMAIL = config('SERVER_EMAIL', cast=str, default='') 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_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB DATA_UPLOAD_MAX_MEMORY_SIZE = 10 * 1024 * 1024 # 10MB diff --git a/sapl/templates/base.html b/sapl/templates/base.html index 21e9221f5..09fcda6bb 100644 --- a/sapl/templates/base.html +++ b/sapl/templates/base.html @@ -1,6 +1,7 @@ {% load i18n staticfiles menus %} {% load common_tags %} +{% load waffle_tags %} {% load render_bundle from webpack_loader %} {% load webpack_static from webpack_loader %} @@ -11,13 +12,10 @@
-