Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Correctifs assistants avant mise en prod #1252

Merged
merged 16 commits into from
Jan 27, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .buildpacks
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
https://github.com/Scalingo/apt-buildpack
https://github.com/Scalingo/nodejs-buildpack
https://github.com/Scalingo/python-buildpack
https://github.com/Scalingo/python-buildpack
https://github.com/Scalingo/nginx-buildpack.git
4 changes: 2 additions & 2 deletions .secrets.baseline
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@
"filename": "core/settings.py",
"hashed_secret": "1ee34e26aeaf89c64ecc2c85efe6a961b75a50e9",
"is_verified": false,
"line_number": 220
"line_number": 219
}
],
"docker-compose.yml": [
Expand Down Expand Up @@ -207,5 +207,5 @@
}
]
},
"generated_at": "2025-01-14T12:14:14Z"
"generated_at": "2025-01-22T18:36:09Z"
}
2 changes: 1 addition & 1 deletion Aptfile
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
gdal-bin
libgdal-dev
libgdal-dev
3 changes: 0 additions & 3 deletions bin/post_compile
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,3 @@ export PROJ_LIB=/build/${REQUEST_ID}/.apt/usr/share/proj

python manage.py collectstatic --noinput

# iframe.js file should be collected without hashing
cp static/compiled/iframe.js staticfiles/
cp static/compiled/carte.js staticfiles/
5 changes: 2 additions & 3 deletions bin/start
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
#!/bin/bash

#gunicorn --timeout 300 --workers 20 --chdir core core.wsgi --log-file -
#gunicorn core.asgi --worker-class=uvicorn.workers.UvicornWorker --max-requests 10000 --max-requests-jitter 20 --workers 5 --log-file -
gunicorn core.asgi --timeout 300 --worker-class=core.custom_uvicorn_worker.CustomUvicornWorker --max-requests 2000 --max-requests-jitter 200 --workers 3 --log-file -
fabienheureux marked this conversation as resolved.
Show resolved Hide resolved
gunicorn core.wsgi --bind unix:/tmp/gunicorn.sock --workers 3 &
/app/bin/run
fabienheureux marked this conversation as resolved.
Show resolved Hide resolved
14 changes: 10 additions & 4 deletions core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
DEBUG = decouple.config("DEBUG", default=False, cast=bool)
STIMULUS_DEBUG = decouple.config("STIMULUS_DEBUG", default=False, cast=bool)
POSTHOG_DEBUG = decouple.config("POSTHOG_DEBUG", default=False, cast=bool)

ALLOWED_HOSTS = decouple.config("ALLOWED_HOSTS", default="localhost", cast=str).split(
","
)
Expand Down Expand Up @@ -330,13 +329,16 @@ def context_processors():

SHELL_PLUS_PRINT_SQL = True

# Object storage with Scaleway
AWS_ACCESS_KEY_ID = decouple.config("AWS_ACCESS_KEY_ID", default="")
AWS_SECRET_ACCESS_KEY = decouple.config("AWS_SECRET_ACCESS_KEY", default="")
AWS_STORAGE_BUCKET_NAME = decouple.config("AWS_STORAGE_BUCKET_NAME", default="")
AWS_S3_REGION_NAME = decouple.config("AWS_S3_REGION_NAME", default="")
AWS_S3_ENDPOINT_URL = decouple.config("AWS_S3_ENDPOINT_URL", default="")

USE_S3_FOR_STATIC = (
decouple.config("USE_S3_FOR_STATIC", cast=bool, default=False) and AWS_ACCESS_KEY_ID
)
AWS_DEFAULT_ACL = "public-read"
AWS_QUERYSTRING_AUTH = False

STORAGES = {
"default": {
Expand All @@ -347,7 +349,11 @@ def context_processors():
),
},
"staticfiles": {
"BACKEND": "whitenoise.storage.CompressedManifestStaticFilesStorage",
"BACKEND": (
"storages.backends.s3.S3Storage"
if USE_S3_FOR_STATIC
else "whitenoise.storage.CompressedManifestStaticFilesStorage"
),
},
}

Expand Down
2 changes: 1 addition & 1 deletion jinja2/qfdmo/_addresses_partials/filters/_modal.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
qf-h-[90vh] qf-h-[90svh] {# Keep both values help keep support for vh in firefox #}
qf-inset-0 qf-font-black qf-bg-white
qf-flex qf-flex-col
qf-overflow-scroll
qf-overflow-auto
qf-origin-bottom
qf-drop-shadow-[0_0_100px_#5555]
data-[visible=false]:qf-hidden
Expand Down
2 changes: 1 addition & 1 deletion jinja2/qfdmo/acteur/_actions.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div
class="qf-flex qf-justify-start qf-space-x-5w"
class="qf-flex qf-justify-start qf-space-x-5w qf-overflow-auto"
>
{% if itineraire_url %}
{% with text="Itinéraire",url=itineraire_url,icon="fr-icon-send-plane-line" %}
Expand Down
2 changes: 1 addition & 1 deletion jinja2/qfdmo/carte/modals/a_propos.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ <h3 class="fr-card__title">
Donner votre avis
</a>
</h3>
<p class="fr-card__desc">Cette carte doit-être la vôtre ! Si vous avez des idées pour l'améliorer, on vous écoute.</p>
<p class="fr-card__desc">Cette carte doit être la vôtre ! Si vous avez des idées pour l'améliorer, on vous écoute.</p>
</div>
</div>
</div>
Expand Down
4 changes: 2 additions & 2 deletions jinja2/qfdmo/shared/main.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
qf-flex
max-md:qf-h-main-svh
{# Is useful for digital view so that the users can scrol in the results #}
qf-overflow-scroll
qf-overflow-auto
"
tabindex="0"
>
Expand Down Expand Up @@ -77,7 +77,7 @@
qf-relative qf-z-30
aria-[hidden=false]:qf-flex qf-hidden qf-flex-col
{% if is_carte %}md:qf-h-[calc(100vh_-_120px)]{% else %}md:qf-h-[calc(100vh_-_250px)]{% endif %}
max-md:qf-snap-y md:qf-overflow-scroll qf-scroll-mt-[65vh]
max-md:qf-snap-y md:qf-overflow-auto qf-scroll-mt-[65vh]
max-md:qf-snap-mandatory
qf-bg-white
qf-px-2w
Expand Down
2 changes: 1 addition & 1 deletion jinja2/qfdmo/shared/results.html
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
qf-flex-grow
qf-shadow
{% if is_digital %}
max-md:qf-overflow-scroll
max-md:qf-overflow-auto
{% endif %}
"
{% if not is_digital %}
Expand Down
4 changes: 3 additions & 1 deletion qfdmd/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,4 +82,6 @@ class ContactForm(DsfrBaseForm):
),
],
)
message = forms.CharField(label="Votre message", widget=forms.Textarea)
message = forms.CharField(
label="Votre message", widget=forms.Textarea(attrs={"rows": 4})
)
13 changes: 8 additions & 5 deletions qfdmd/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,9 @@ def en_savoir_plus(self):
.order_by("poids")
)

if not produit_liens:
return

return render_to_string(
"components/produit/_en_savoir_plus.html",
{"liens": [produit_lien.lien for produit_lien in produit_liens]},
Expand All @@ -139,16 +142,16 @@ def content_display(self) -> list[dict[str, str]]:
return [
item
for item in [
{
"id": "Comment consommer responsable ?",
"title": "Comment consommer responsable ?",
"content": self.comment_les_eviter,
},
{
"id": "Que va-t-il devenir ?",
"title": "Que va-t-il devenir ?",
"content": self.que_va_t_il_devenir,
},
{
"id": "Comment consommer responsable ?",
"title": "Comment consommer responsable ?",
"content": self.comment_les_eviter,
},
{
"id": "En savoir plus",
"title": "En savoir plus",
Expand Down
2 changes: 1 addition & 1 deletion qfdmd/templatetags/qfdmd_tags.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def patchwork() -> dict:
produits = (
Synonyme.objects.exclude(picto="")
.exclude(picto=None)
.filter(pin_on_homepage=True)
.filter(pin_on_homepage=True)[:19]
)
return {"top": produits[:10], "left": produits[10:14], "right": produits[16:19]}

Expand Down
2 changes: 1 addition & 1 deletion qfdmd/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def get_assistant_script(request):
urlpatterns = [
path("dechet/", HomeView.as_view(), name="home"),
path("assistant/recherche", search_view, name="search"),
path("<slug:slug>/", SynonymeDetailView.as_view(), name="synonyme-detail"),
path("dechet/<slug:slug>/", SynonymeDetailView.as_view(), name="synonyme-detail"),
path("assistant/nous-contacter", ContactFormView.as_view(), name="nous-contacter"),
path(
"assistant/nous-contacter/confirmation",
Expand Down
21 changes: 21 additions & 0 deletions qfdmd/views.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
import logging
from functools import wraps
from typing import Any

from django.conf import settings
from django.http import HttpResponse
from django.shortcuts import render
from django.urls import reverse_lazy
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django.views.generic import DetailView, FormView, ListView

from core.notion import create_new_row_in_notion_table
Expand Down Expand Up @@ -73,6 +76,22 @@ def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
return context


def cache_page_for_guests(*cache_args, **cache_kwargs):
def inner_decorator(func):
@wraps(func)
def inner_function(request, *args, **kwargs):
if not request.user.is_authenticated and "nocache" not in request.GET:
return cache_page(*cache_args, **cache_kwargs)(func)(
request, *args, **kwargs
)
return func(request, *args, **kwargs)

return inner_function

return inner_decorator


@method_decorator(cache_page_for_guests(60 * 15), name="dispatch")
class HomeView(BaseView, ListView):
template_name = "qfdmd/home.html"
model = Suggestion
Expand All @@ -96,9 +115,11 @@ def get_context_data(self, **kwargs: Any) -> dict[str, Any]:
return context


@method_decorator(cache_page_for_guests(60 * 15), name="dispatch")
fabienheureux marked this conversation as resolved.
Show resolved Hide resolved
class SynonymeDetailView(BaseView, DetailView):
model = Synonyme


@method_decorator(cache_page_for_guests(60 * 15), name="dispatch")
class CMSPageDetailView(BaseView, DetailView):
model = CMSPage
4 changes: 2 additions & 2 deletions qfdmo/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,8 @@ def load_choices(self, request: HttpRequest, **kwargs) -> None:
},
),
label=mark_safe(
"<span class='fr-icon--sm fr-icon-percent-line'></span>"
"&nbsp;Adresses proposant le Bonus Réparation"
"<div><span class='fr-icon--sm fr-icon-percent-line'></span>"
"&nbsp;Adresses proposant le Bonus Réparation</div>"
),
help_text=mark_safe(
"Afficher uniquement les adresses éligibles (uniquement valable lorsque l'"
Expand Down
10 changes: 10 additions & 0 deletions qfdmo/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
from django.conf import settings
from django.shortcuts import redirect
from django.templatetags.static import static
from django.urls import path
from django.views.generic import TemplateView
from django.views.generic.base import RedirectView
Expand All @@ -18,8 +20,16 @@
from qfdmo.views.configurator import AdvancedConfiguratorView, ConfiguratorView
from qfdmo.views.dags import DagsValidation


def get_carte_iframe_script(request):
return redirect(request.build_absolute_uri(static("carte.js")))


urlpatterns = [
path("", direct_access, name="direct_access"),
# This route needs to be touched with care is it is embedded
# on many website, enabling the load of LVAO as an iframe
path("static/carte.js", get_carte_iframe_script, name="script"),
path("carte", CarteSearchActeursView.as_view(), name="carte"),
path("carte.json", CarteSearchActeursView.as_view(), name="carte_json"),
path("formulaire", FormulaireSearchActeursView.as_view(), name="formulaire"),
Expand Down
3 changes: 1 addition & 2 deletions requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,9 @@ sentry-sdk
shortuuid
tqdm
unidecode
uvicorn
whitenoise
django-widget-tweaks
django-cors-headers
django-dsfr
django-colorfield
rapidfuzz
rapidfuzz
45 changes: 45 additions & 0 deletions script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
// k6 configuration file to simulate user behavior
import http from "k6/http"
import { sleep } from "k6"

export const options = {
stages: [
{ duration: "30s", target: 40 }, // Ramp-up to 19,110 concurrent users
{ duration: "10s", target: 40 }, // Maintain 19,110 users
{ duration: "5s", target: 0 }, // Ramp-down to 0 users
],
}

export default function () {
// Step 1: Visit the homepage
http.get("https://quefairedemesobjets-preprod.osc-fr1.scalingo.io/dechet/")
console.log("Visited homepage")
sleep(0.568) // Time spent on the page in seconds

// Step 2: Navigate to the first detailed page
http.get("https://quefairedemesobjets-preprod.osc-fr1.scalingo.io/papier-et-carton")
console.log("Visited page: Papier et Carton")
sleep(0.59) // Time spent on the page in seconds

// Step 3: Navigate to another detailed page
http.get("https://quefairedemesobjets-preprod.osc-fr1.scalingo.io/plastique")
console.log("Visited page: Plastique")
sleep(0.797) // Time spent on the page in seconds

// Step 4: Return to homepage with a theme parameter
http.get("https://quefairedemesobjets-preprod.osc-fr1.scalingo.io/?theme=dechets")
console.log("Visited homepage with theme parameter")
sleep(1.903) // Time spent on the page in seconds

// Step 5: Visit a different detailed page
http.get("https://quefairedemesobjets-preprod.osc-fr1.scalingo.io/verre")
console.log("Visited page: Verre")
sleep(1.5) // Time spent on the page in seconds

// Simulate user leaving the page
http.get("https://quefairedemesobjets-preprod.osc-fr1.scalingo.io/batteries")
console.log("Visited page: Batteries")
sleep(3.0) // Time spent on the page in seconds

// End of scenario
}
28 changes: 28 additions & 0 deletions servers.conf.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
proxy_cache_path /tmp/nginx_assistant_cache levels=1:2 keys_zone=assistant:10m max_size=1g inactive=60m use_temp_path=off;

server {
listen <%= ENV["PORT"] %>;
server_name _;


location /static/ {
expires max;
alias /app/staticfiles/;
}

location / {
proxy_pass http://unix:/tmp/gunicorn.sock;
proxy_cache assistant;
proxy_cache_key $request_method$request_uri;
proxy_cache_lock on;
proxy_cache_lock_timeout 10s;
proxy_cache_use_stale error timeout updating;
proxy_cache_background_update on;
add_header X-Cache-Status $upstream_cache_status;
}
fabienheureux marked this conversation as resolved.
Show resolved Hide resolved

location ~ ^/(favicon(?:-\d+)?.(?:jpe?g|png|ico))$ {
access_log off;
log_not_found off;
}
}
Loading
Loading