diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 7ece238..eb20994 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -26,8 +26,7 @@ tests: - echo "Running tests..." - source $CACHE_PATH/venv/bin/activate - pip cache purge - - pip install -U -r requirements.txt - - pip install -U -r dev-requirements.txt + - pip install -U -r requirements-dev.txt - pytest --create-db --cov --cov-report=xml - if [ "$CI_COMMIT_REF_NAME" = 'main' ] ; then exit 0 ; fi - if [ "$CI_COMMIT_REF_NAME" = 'develop' ] ; then git fetch origin main ; diff-cover coverage.xml --fail-under=90 --compare-branch origin/main --diff-range-notation '..' && exit 0 ; fi diff --git a/README.md b/README.md index ef234bd..4e6aa47 100644 --- a/README.md +++ b/README.md @@ -60,8 +60,7 @@ La Chariotte utilise Weasyprint pour la génération de PDFs, qui nécessite cer Ensuite, vous pouvez récupérer les dépendances python : ```bash -pip install -r requirements.txt -pip install -r dev-requirements.txt +pip install -r requirements-dev.txt ``` ### Base de données diff --git a/dev-requirements.txt b/dev-requirements.txt deleted file mode 100644 index f9cc9c8..0000000 --- a/dev-requirements.txt +++ /dev/null @@ -1,136 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.10 -# by the following command: -# -# pip-compile --extra=dev --output-file=dev-requirements.txt pyproject.toml -# -asgiref==3.6.0 - # via django -attrs==22.2.0 - # via pytest -black==23.3.0 - # via pytest-black -build==0.10.0 - # via pip-tools -chardet==4.0.0 - # via diff-cover - # via flake8-black -build==0.10.0 - # via pip-tools - # via pytest-black -chardet==4.0.0 - # via diff-cover -click==8.1.3 - # via - # black - # pip-tools -coverage[toml]==7.2.2 - # via pytest-cov -diff-cover==4.2.3 - # via la-chariotte (pyproject.toml) -django==4.2 - # via la-chariotte (pyproject.toml) -exceptiongroup==1.1.1 - # via pytest -importlib-metadata==6.1.0 - # via inflect -inflect==3.0.2 - # via - # diff-cover - # jinja2-pluralize -flake8==6.0.0 - # via flake8-black -flake8-black==0.3.6 - # via la-chariotte (pyproject.toml) -importlib-metadata==6.1.0 - # via inflect -inflect==3.0.2 - # via - # diff-cover - # jinja2-pluralize -iniconfig==2.0.0 - # via pytest -isort==5.12.0 - # via pytest-isort -jinja2==3.1.2 - # via - # diff-cover - # jinja2-pluralize -jinja2-pluralize==0.3.0 - # via diff-cover -markupsafe==2.1.2 - # via jinja2 -mccabe==0.7.0 - # via flake8 -mypy-extensions==1.0.0 - # via black -packaging==23.0 - # via - # black - # build - # pytest -pathspec==0.11.1 - # via black -pip-tools==6.12.3 - # via la-chariotte (pyproject.toml) -platformdirs==3.2.0 - # via black -pluggy==1.0.0 - # via - # diff-cover - # pytest -psycopg2-binary==2.9.6 - # via la-chariotte (pyproject.toml) -pygments==2.14.0 - # via diff-cover - # via la-chariotte (pyproject.toml) -pycodestyle==2.10.0 - # via flake8 -pyflakes==3.0.1 - # via flake8 -pygments==2.14.0 - # via diff-cover -pyproject-hooks==1.0.0 - # via build -pytest==7.2.2 - # via - # la-chariotte (pyproject.toml) - # pytest-black - # pytest-cov - # pytest-django - # pytest-isort -pytest-black==0.3.12 - # via la-chariotte (pyproject.toml) -pytest-cov==4.0.0 - # via la-chariotte (pyproject.toml) -pytest-django==4.5.2 - # via la-chariotte (pyproject.toml) -pytest-isort==3.1.0 - # via la-chariotte (pyproject.toml) -sqlparse==0.4.3 - # via django -toml==0.10.2 - # via pytest-black -tomli==2.0.1 - # via - # black - # build - # coverage - # pyproject-hooks - # pytest -wheel==0.40.0 - # via pip-tools -zipp==3.15.0 - # via importlib-metadata - # coverage - # flake8-black - # pyproject-hooks - # pytest -wheel==0.40.0 - # via pip-tools -zipp==3.15.0 - # via importlib-metadata - -# The following packages are considered to be unsafe in a requirements file: -# pip -# setuptools diff --git a/la_chariotte/order/templates/order/grouped_order_detail.html b/la_chariotte/order/templates/order/grouped_order_detail.html index 9516781..9c1cb41 100644 --- a/la_chariotte/order/templates/order/grouped_order_detail.html +++ b/la_chariotte/order/templates/order/grouped_order_detail.html @@ -34,6 +34,7 @@

Livraison le {{ grouped_order.delivery_date }} +

{% if user == grouped_order.orga %} @@ -184,4 +185,4 @@ document.getElementById("inputs-parent").addEventListener("change", function() { }) }); {% endblock %} - \ No newline at end of file + diff --git a/la_chariotte/order/tests/test_views/test_grouped_order_event_view.py b/la_chariotte/order/tests/test_views/test_grouped_order_event_view.py new file mode 100644 index 0000000..ade25ed --- /dev/null +++ b/la_chariotte/order/tests/test_views/test_grouped_order_event_view.py @@ -0,0 +1,25 @@ +import pytest +from django.urls import reverse + +from la_chariotte.order.tests.utils import create_grouped_order + +pytestmark = pytest.mark.django_db + + +def test_get_ical(client, other_user): + grouped_order = create_grouped_order( + days_before_delivery_date=5, + days_before_deadline=2, + name="gr order test", + orga_user=other_user, + ) + + detail_url = reverse( + "order:grouped_order_event", + kwargs={ + "code": grouped_order.code, + }, + ) + response = client.get(detail_url) + assert response.status_code == 200 + assert b"DTSTART" in response.content diff --git a/la_chariotte/order/urls.py b/la_chariotte/order/urls.py index 6e0381c..9ca4541 100644 --- a/la_chariotte/order/urls.py +++ b/la_chariotte/order/urls.py @@ -11,6 +11,11 @@ urlpatterns = [ views.GroupedOrderDetailView.as_view(), name="grouped_order_detail", ), + path( + "/ics/", + views.GroupedOrderEventView.as_view(), + name="grouped_order_event", + ), path( "/gerer", views.GroupedOrderOverview.as_view(), diff --git a/la_chariotte/order/views/__init__.py b/la_chariotte/order/views/__init__.py index 99aac03..8e12745 100644 --- a/la_chariotte/order/views/__init__.py +++ b/la_chariotte/order/views/__init__.py @@ -7,6 +7,7 @@ from .grouped_order import ( GroupedOrderDeleteView, GroupedOrderDetailView, GroupedOrderDuplicateView, + GroupedOrderEventView, GroupedOrderExportView, GroupedOrderOverview, GroupedOrderUpdateView, diff --git a/la_chariotte/order/views/grouped_order.py b/la_chariotte/order/views/grouped_order.py index dd0de50..1497136 100644 --- a/la_chariotte/order/views/grouped_order.py +++ b/la_chariotte/order/views/grouped_order.py @@ -1,5 +1,6 @@ import csv import json +from datetime import timedelta from io import BytesIO from django import http @@ -12,6 +13,7 @@ from django.utils import timezone from django.views import generic from django_weasyprint import WeasyTemplateResponseMixin from django_weasyprint.views import WeasyTemplateResponse, WeasyTemplateView +from icalendar import Calendar, Event, vCalAddress, vText from xhtml2pdf import pisa from ..forms import GroupedOrderForm, Item, JoinGroupedOrderForm @@ -64,6 +66,37 @@ class JoinGroupedOrderView(generic.FormView, generic.RedirectView, LoginRequired ) +class GroupedOrderEventView(generic.DetailView): + model = GroupedOrder + slug_field = "code" + slug_url_kwarg = "code" + content_type = "text/calendar" + response_class = http.HttpResponse + + def get_content(self): + event = Event() + event.add("summary", self.object.name) + event.add("dtstart", self.object.delivery_date) + event.add("dtend", self.object.delivery_date + timedelta(days=1)) + event.add("location", vText(self.object.place)) + event.add("description", vText(self.object.description)) + organizer = vCalAddress("MAILTO:" + self.object.orga.email) + organizer.params["cn"] = vText( + self.object.orga.first_name + " " + self.object.orga.last_name + ) + event.add("organizer", organizer) + cal = Calendar() + cal.add_component(event) + return cal.to_ical() + + def render_to_response(self, context, **response_kwargs): + response_kwargs.setdefault("content_type", self.content_type) + + response = self.response_class(content=self.get_content(), **response_kwargs) + response["Content-Disposition"] = f"attachment; filename={self.object.code}.ics" + return response + + class GroupedOrderDetailView(generic.DetailView): model = GroupedOrder template_name = "order/grouped_order_detail.html" diff --git a/pyproject.toml b/pyproject.toml index 32ab2e2..e3efe3f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,6 +12,10 @@ dependencies = [ "psycopg2-binary>=2,<3", "sentry-sdk<1", "xhtml2pdf", + "icalendar", + "base36", + "django-weasyprint", + "html2text", ] [tool.setuptools] diff --git a/requirements-dev.txt b/requirements-dev.txt new file mode 100644 index 0000000..5d35b64 --- /dev/null +++ b/requirements-dev.txt @@ -0,0 +1,218 @@ +# +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: +# +# pip-compile --extra=dev --output-file=requirements-dev.txt +# +arabic-reshaper==3.0.0 + # via xhtml2pdf +asgiref==3.6.0 + # via django +asn1crypto==1.5.1 + # via + # oscrypto + # pyhanko + # pyhanko-certvalidator +attrs==22.2.0 + # via pytest +base36==0.1.1 + # via la-chariotte (pyproject.toml) +black==23.3.0 + # via pytest-black +brotli==1.0.9 + # via fonttools +build==0.10.0 + # via pip-tools +certifi==2023.7.22 + # via + # requests + # sentry-sdk +cffi==1.15.1 + # via + # cryptography + # weasyprint +chardet==4.0.0 + # via diff-cover +charset-normalizer==3.2.0 + # via requests +click==8.1.3 + # via + # black + # pip-tools + # pyhanko +coverage[toml]==7.2.2 + # via pytest-cov +cryptography==41.0.3 + # via + # pyhanko + # pyhanko-certvalidator +cssselect2==0.7.0 + # via + # svglib + # weasyprint +diff-cover==4.2.3 + # via la-chariotte (pyproject.toml) +django==4.2 + # via + # django-weasyprint + # la-chariotte (pyproject.toml) +django-weasyprint==2.2.1 + # via la-chariotte (pyproject.toml) +fonttools[woff]==4.42.1 + # via weasyprint +html2text==2020.1.16 + # via la-chariotte (pyproject.toml) +html5lib==1.1 + # via + # weasyprint + # xhtml2pdf +icalendar==5.0.7 + # via la-chariotte (pyproject.toml) +idna==3.4 + # via requests +importlib-metadata==6.1.0 + # via inflect +inflect==3.0.2 + # via + # diff-cover + # jinja2-pluralize +iniconfig==2.0.0 + # via pytest +isort==5.12.0 + # via pytest-isort +jinja2==3.1.2 + # via + # diff-cover + # jinja2-pluralize +jinja2-pluralize==0.3.0 + # via diff-cover +lxml==4.9.3 + # via svglib +markupsafe==2.1.2 + # via jinja2 +mypy-extensions==1.0.0 + # via black +oscrypto==1.3.0 + # via pyhanko-certvalidator +packaging==23.0 + # via + # black + # build + # pytest +pathspec==0.11.1 + # via black +pillow==10.0.0 + # via + # reportlab + # weasyprint + # xhtml2pdf +pip-tools==6.12.3 + # via la-chariotte (pyproject.toml) +platformdirs==3.2.0 + # via black +pluggy==1.0.0 + # via + # diff-cover + # pytest +psycopg2-binary==2.9.6 + # via la-chariotte (pyproject.toml) +pycparser==2.21 + # via cffi +pydyf==0.7.0 + # via weasyprint +pygments==2.14.0 + # via diff-cover +pyhanko==0.20.0 + # via xhtml2pdf +pyhanko-certvalidator==0.23.0 + # via + # pyhanko + # xhtml2pdf +pypdf==3.15.4 + # via xhtml2pdf +pyphen==0.14.0 + # via weasyprint +pypng==0.20220715.0 + # via qrcode +pyproject-hooks==1.0.0 + # via build +pytest==7.2.2 + # via + # la-chariotte (pyproject.toml) + # pytest-black + # pytest-cov + # pytest-django + # pytest-isort +pytest-black==0.3.12 + # via la-chariotte (pyproject.toml) +pytest-cov==4.0.0 + # via la-chariotte (pyproject.toml) +pytest-django==4.5.2 + # via la-chariotte (pyproject.toml) +pytest-isort==3.1.0 + # via la-chariotte (pyproject.toml) +python-bidi==0.4.2 + # via xhtml2pdf +python-dateutil==2.8.2 + # via icalendar +pytz==2023.3 + # via icalendar +pyyaml==6.0.1 + # via pyhanko +qrcode==7.4.2 + # via pyhanko +reportlab==3.6.13 + # via + # svglib + # xhtml2pdf +requests==2.31.0 + # via + # pyhanko + # pyhanko-certvalidator +sentry-sdk==0.20.3 + # via la-chariotte (pyproject.toml) +six==1.16.0 + # via + # html5lib + # python-bidi + # python-dateutil +sqlparse==0.4.3 + # via django +svglib==1.5.1 + # via xhtml2pdf +tinycss2==1.2.1 + # via + # cssselect2 + # svglib + # weasyprint +toml==0.10.2 + # via pytest-black +typing-extensions==4.7.1 + # via qrcode +tzlocal==5.0.1 + # via pyhanko +uritools==4.0.1 + # via pyhanko-certvalidator +urllib3==2.0.4 + # via + # requests + # sentry-sdk +weasyprint==59.0 + # via django-weasyprint +webencodings==0.5.1 + # via + # cssselect2 + # html5lib + # tinycss2 +wheel==0.40.0 + # via pip-tools +xhtml2pdf==0.2.11 + # via la-chariotte (pyproject.toml) +zipp==3.15.0 + # via importlib-metadata +zopfli==0.2.2 + # via fonttools + +# The following packages are considered to be unsafe in a requirements file: +# pip +# setuptools diff --git a/requirements.txt b/requirements.txt index 72d77a0..d201e9a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,7 +2,7 @@ # This file is autogenerated by pip-compile with Python 3.11 # by the following command: # -# pip-compile +# pip-compile --output-file=requirements.txt # arabic-reshaper==3.0.0 # via xhtml2pdf @@ -14,13 +14,17 @@ asn1crypto==1.5.1 # pyhanko # pyhanko-certvalidator base36==0.1.1 - # à la main + # via la-chariotte (pyproject.toml) +brotli==1.0.9 + # via fonttools certifi==2023.5.7 # via # requests # sentry-sdk cffi==1.15.1 - # via cryptography + # via + # cryptography + # weasyprint charset-normalizer==3.1.0 # via requests click==8.1.3 @@ -30,13 +34,25 @@ cryptography==40.0.2 # pyhanko # pyhanko-certvalidator cssselect2==0.7.0 - # via svglib + # via + # svglib + # weasyprint django==4.2.1 + # via + # django-weasyprint + # la-chariotte (pyproject.toml) +django-weasyprint==2.2.1 # via la-chariotte (pyproject.toml) +fonttools[woff]==4.42.1 + # via weasyprint html2text==2020.1.16 - # à la main + # via la-chariotte (pyproject.toml) html5lib==1.1 - # via xhtml2pdf + # via + # weasyprint + # xhtml2pdf +icalendar==5.0.7 + # via la-chariotte (pyproject.toml) idna==3.4 # via requests lxml==4.9.2 @@ -46,11 +62,14 @@ oscrypto==1.3.0 pillow==9.5.0 # via # reportlab + # weasyprint # xhtml2pdf psycopg2-binary==2.9.6 # via la-chariotte (pyproject.toml) pycparser==2.21 # via cffi +pydyf==0.7.0 + # via weasyprint pyhanko==0.18.1 # via xhtml2pdf pyhanko-certvalidator==0.22.0 @@ -59,10 +78,16 @@ pyhanko-certvalidator==0.22.0 # xhtml2pdf pypdf==3.9.0 # via xhtml2pdf +pyphen==0.14.0 + # via weasyprint pypng==0.20220715.0 # via qrcode python-bidi==0.4.2 # via xhtml2pdf +python-dateutil==2.8.2 + # via icalendar +pytz==2023.3 + # via icalendar pyyaml==6.0 # via pyhanko qrcode==7.4.2 @@ -81,6 +106,7 @@ six==1.16.0 # via # html5lib # python-bidi + # python-dateutil sqlparse==0.4.4 # via django svglib==1.5.1 @@ -89,6 +115,7 @@ tinycss2==1.2.1 # via # cssselect2 # svglib + # weasyprint typing-extensions==4.6.2 # via qrcode tzlocal==5.0.1 @@ -99,12 +126,14 @@ urllib3==2.0.2 # via # requests # sentry-sdk +weasyprint==59.0 + # via django-weasyprint webencodings==0.5.1 # via # cssselect2 # html5lib # tinycss2 -weasyprint==58.0 #django-weasyprint doesn't work with weasyprint 59.0 -django-weasyprint==2.2.0 xhtml2pdf==0.2.11 # via la-chariotte (pyproject.toml) +zopfli==0.2.2 + # via fonttools