mirror of
https://github.com/suitenumerique/docs.git
synced 2026-05-06 15:12:27 +02:00
Compare commits
1 Commits
helm/produ
...
use-intern
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b60bc57e6 |
4
.github/workflows/docker-hub.yml
vendored
4
.github/workflows/docker-hub.yml
vendored
@@ -156,7 +156,7 @@ jobs:
|
||||
name: Run trivy scan
|
||||
uses: numerique-gouv/action-trivy-cache@main
|
||||
with:
|
||||
docker-build-args: '-f src/frontend/servers/y-provider/Dockerfile --target y-provider'
|
||||
docker-build-args: '-f src/frontend/Dockerfile --target y-provider'
|
||||
docker-image-name: 'docker.io/lasuite/impress-frontend:${{ github.sha }}'
|
||||
continue-on-error: true
|
||||
-
|
||||
@@ -164,7 +164,7 @@ jobs:
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
file: ./src/frontend/servers/y-provider/Dockerfile
|
||||
file: ./src/frontend/Dockerfile
|
||||
target: y-provider
|
||||
build-args: DOCKER_USER=${{ env.DOCKER_USER }}:-1000
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
|
||||
12
.github/workflows/impress-frontend.yml
vendored
12
.github/workflows/impress-frontend.yml
vendored
@@ -95,12 +95,12 @@ jobs:
|
||||
- name: Set e2e env variables
|
||||
run: cat env.d/development/common.e2e.dist >> env.d/development/common.dist
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: cd src/frontend/apps/e2e && yarn install --frozen-lockfile && yarn install-playwright chromium
|
||||
|
||||
- name: Start Docker services
|
||||
run: make bootstrap FLUSH_ARGS='--no-input' cache=
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: cd src/frontend/apps/e2e && yarn install-playwright chromium
|
||||
|
||||
# Tool to wait for a service to be ready
|
||||
- name: Install Dockerize
|
||||
run: |
|
||||
@@ -151,12 +151,12 @@ jobs:
|
||||
- name: Set e2e env variables
|
||||
run: cat env.d/development/common.e2e.dist >> env.d/development/common.dist
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: cd src/frontend/apps/e2e && yarn install --frozen-lockfile && yarn install-playwright firefox webkit chromium
|
||||
|
||||
- name: Start Docker services
|
||||
run: make bootstrap FLUSH_ARGS='--no-input' cache=
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: cd src/frontend/apps/e2e && yarn install-playwright firefox webkit chromium
|
||||
|
||||
- name: Run e2e tests
|
||||
run: cd src/frontend/ && yarn e2e:test --project=firefox --project=webkit
|
||||
|
||||
|
||||
21
CHANGELOG.md
21
CHANGELOG.md
@@ -11,25 +11,8 @@ and this project adheres to
|
||||
|
||||
## Added
|
||||
|
||||
🔧(helm) add option to disable default tls setting by @dominikkaminski #519
|
||||
📸(helm) production-example #529
|
||||
|
||||
|
||||
## [1.10.0] - 2024-12-17
|
||||
|
||||
## Added
|
||||
|
||||
- ✨(backend) add server-to-server API endpoint to create documents #467
|
||||
- ✨(email) white brand email #412
|
||||
- ✨(y-provider) create a markdown converter endpoint #488
|
||||
|
||||
## Changed
|
||||
|
||||
- ⚡️(docker) improve y-provider image #422
|
||||
|
||||
## Fixed
|
||||
|
||||
- ⚡️(e2e) reduce flakiness on e2e tests #511
|
||||
|
||||
|
||||
## [1.9.0] - 2024-12-11
|
||||
@@ -38,6 +21,7 @@ and this project adheres to
|
||||
|
||||
- ✨(backend) annotate number of accesses on documents in list view #429
|
||||
- ✨(backend) allow users to mark/unmark documents as favorite #429
|
||||
- ✨(y-provider) create a markdown converter endpoint #488
|
||||
|
||||
## Changed
|
||||
|
||||
@@ -326,8 +310,7 @@ and this project adheres to
|
||||
- 🚀 Impress, project to manage your documents easily and collaboratively.
|
||||
|
||||
|
||||
[unreleased]: https://github.com/numerique-gouv/impress/compare/v1.10.0...main
|
||||
[v1.10.0]: https://github.com/numerique-gouv/impress/releases/v1.10.0
|
||||
[unreleased]: https://github.com/numerique-gouv/impress/compare/v1.9.0...main
|
||||
[v1.9.0]: https://github.com/numerique-gouv/impress/releases/v1.9.0
|
||||
[v1.8.2]: https://github.com/numerique-gouv/impress/releases/v1.8.2
|
||||
[v1.8.1]: https://github.com/numerique-gouv/impress/releases/v1.8.1
|
||||
|
||||
@@ -20,7 +20,7 @@ docker_build(
|
||||
docker_build(
|
||||
'localhost:5001/impress-y-provider:latest',
|
||||
context='..',
|
||||
dockerfile='../src/frontend/servers/y-provider/Dockerfile',
|
||||
dockerfile='../src/frontend/Dockerfile',
|
||||
only=['./src/frontend/', './docker/', './.dockerignore'],
|
||||
target = 'y-provider',
|
||||
live_update=[
|
||||
|
||||
@@ -159,13 +159,17 @@ services:
|
||||
user: ${DOCKER_USER:-1000}
|
||||
build:
|
||||
context: .
|
||||
dockerfile: ./src/frontend/servers/y-provider/Dockerfile
|
||||
dockerfile: ./src/frontend/Dockerfile
|
||||
target: y-provider
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- env.d/development/common
|
||||
ports:
|
||||
- "4444:4444"
|
||||
volumes:
|
||||
- ./src/frontend/servers/y-provider:/home/frontend/servers/y-provider
|
||||
- /home/frontend/servers/y-provider/node_modules/
|
||||
- /home/frontend/servers/y-provider/dist/
|
||||
|
||||
kc_postgresql:
|
||||
image: postgres:14.3
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
# For the CI job test-e2e
|
||||
SUSTAINED_THROTTLE_RATES="200/hour"
|
||||
BURST_THROTTLE_RATES="200/minute"
|
||||
DJANGO_SERVER_TO_SERVER_API_TOKENS=test-e2e
|
||||
Y_PROVIDER_API_KEY=yprovider-api-key
|
||||
Y_PROVIDER_API_BASE_URL=http://y-provider:4444/api/
|
||||
|
||||
@@ -275,7 +275,7 @@ class ServerCreateDocumentSerializer(serializers.Serializer):
|
||||
language = user.language or language
|
||||
|
||||
try:
|
||||
document_content = YdocConverter().convert_markdown(
|
||||
converter_response = YdocConverter().convert_markdown(
|
||||
validated_data["content"]
|
||||
)
|
||||
except ConversionError as err:
|
||||
@@ -283,7 +283,7 @@ class ServerCreateDocumentSerializer(serializers.Serializer):
|
||||
|
||||
document = models.Document.objects.create(
|
||||
title=validated_data["title"],
|
||||
content=document_content,
|
||||
content=converter_response["content"],
|
||||
creator=user,
|
||||
)
|
||||
|
||||
|
||||
@@ -594,7 +594,7 @@ class Document(BaseModel):
|
||||
name=sender_name
|
||||
),
|
||||
"message": _(
|
||||
'{name} invited you with the role "{role}" on the following document:'
|
||||
"{name} invited you with the role ``{role}`` on the following document:"
|
||||
).format(name=sender_name_email, role=role.lower()),
|
||||
}
|
||||
subject = _("{name} shared a document with you: {title}").format(
|
||||
|
||||
@@ -35,10 +35,29 @@ AI_ACTIONS = {
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
AI_TRANSLATE = (
|
||||
"Translate the markdown text to {language:s}, preserving markdown formatting. "
|
||||
'Return JSON: {{"answer": "your translated markdown text in {language:s}"}}. '
|
||||
"Do not provide any other information."
|
||||
"""
|
||||
You are a professional translator for `{language:s}`.
|
||||
|
||||
### Guidelines:
|
||||
1. **Preserve exactly as-is:**
|
||||
- All formatting, markdown, symbols, tags
|
||||
- Names, numbers, URLs, citations
|
||||
- Code blocks and technical terms
|
||||
|
||||
2. **Translation Rules:**
|
||||
- Use natural expressions in the target language
|
||||
- Match the tone of the source text (default: professional)
|
||||
- Maintain original meaning precisely
|
||||
- Adapt idioms to suit the target culture
|
||||
- Ensure grammatical correctness stylistic coherence
|
||||
|
||||
3. **Do Not:**
|
||||
- Add, remove, or explain any content
|
||||
|
||||
Output only the translated text, keeping all original formatting intact.
|
||||
"""
|
||||
)
|
||||
|
||||
|
||||
@@ -59,32 +78,14 @@ class AIService:
|
||||
"""Helper method to call the OpenAI API and process the response."""
|
||||
response = self.client.chat.completions.create(
|
||||
model=settings.AI_MODEL,
|
||||
response_format={"type": "json_object"},
|
||||
messages=[
|
||||
{"role": "system", "content": system_content},
|
||||
{"role": "user", "content": json.dumps({"markdown_input": text})},
|
||||
{"role": "user", "content": text},
|
||||
],
|
||||
)
|
||||
|
||||
content = response.choices[0].message.content
|
||||
|
||||
try:
|
||||
sanitized_content = re.sub(r'\s*"answer"\s*:\s*', '"answer": ', content)
|
||||
sanitized_content = re.sub(r"\s*\}", "}", sanitized_content)
|
||||
sanitized_content = re.sub(r"(?<!\\)\n", "\\\\n", sanitized_content)
|
||||
sanitized_content = re.sub(r"(?<!\\)\t", "\\\\t", sanitized_content)
|
||||
|
||||
json_response = json.loads(sanitized_content)
|
||||
except (json.JSONDecodeError, IndexError):
|
||||
try:
|
||||
json_response = json.loads(content)
|
||||
except json.JSONDecodeError as err:
|
||||
raise RuntimeError("AI response is not valid JSON", content) from err
|
||||
|
||||
if "answer" not in json_response:
|
||||
raise RuntimeError("AI response does not contain an answer")
|
||||
|
||||
return json_response
|
||||
return {"answer": content}
|
||||
|
||||
def transform(self, text, action):
|
||||
"""Transform text based on specified action."""
|
||||
|
||||
@@ -26,7 +26,6 @@ class CollaborationService:
|
||||
# same pod thanks to a parameter
|
||||
endpoint_url = f"{settings.COLLABORATION_API_URL}{endpoint}/?room={room}"
|
||||
|
||||
# Note: Collaboration microservice accepts only raw token, which is not recommended
|
||||
headers = {"Authorization": settings.COLLABORATION_SERVER_SECRET}
|
||||
if user_id:
|
||||
headers["X-User-Id"] = user_id
|
||||
|
||||
@@ -31,8 +31,7 @@ class YdocConverter:
|
||||
@property
|
||||
def auth_header(self):
|
||||
"""Build microservice authentication header."""
|
||||
# Note: Yprovider microservice accepts only raw token, which is not recommended
|
||||
return settings.Y_PROVIDER_API_KEY
|
||||
return f"Bearer {settings.CONVERSION_API_KEY}"
|
||||
|
||||
def convert_markdown(self, text):
|
||||
"""Convert a Markdown text into our internal format using an external microservice."""
|
||||
@@ -42,7 +41,7 @@ class YdocConverter:
|
||||
|
||||
try:
|
||||
response = requests.post(
|
||||
f"{settings.Y_PROVIDER_API_BASE_URL}{settings.CONVERSION_API_ENDPOINT}/",
|
||||
settings.CONVERSION_API_URL,
|
||||
json={
|
||||
"content": text,
|
||||
},
|
||||
@@ -51,7 +50,6 @@ class YdocConverter:
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
timeout=settings.CONVERSION_API_TIMEOUT,
|
||||
verify=settings.CONVERSION_API_SECURE,
|
||||
)
|
||||
response.raise_for_status()
|
||||
conversion_response = response.json()
|
||||
|
||||
@@ -173,7 +173,7 @@ def test_api_document_accesses_create_authenticated_administrator(via, mock_user
|
||||
email_content = " ".join(email.body.split())
|
||||
assert f"{user.full_name} shared a document with you!" in email_content
|
||||
assert (
|
||||
f"{user.full_name} ({user.email}) invited you with the role "{role}" "
|
||||
f"{user.full_name} ({user.email}) invited you with the role ``{role}`` "
|
||||
f"on the following document: {document.title}"
|
||||
) in email_content
|
||||
assert "docs/" + str(document.id) + "/" in email_content
|
||||
@@ -231,7 +231,7 @@ def test_api_document_accesses_create_authenticated_owner(via, mock_user_teams):
|
||||
email_content = " ".join(email.body.split())
|
||||
assert f"{user.full_name} shared a document with you!" in email_content
|
||||
assert (
|
||||
f"{user.full_name} ({user.email}) invited you with the role "{role}" "
|
||||
f"{user.full_name} ({user.email}) invited you with the role ``{role}`` "
|
||||
f"on the following document: {document.title}"
|
||||
) in email_content
|
||||
assert "docs/" + str(document.id) + "/" in email_content
|
||||
|
||||
@@ -406,7 +406,7 @@ def test_api_document_invitations_create_privileged_members(
|
||||
email_content = " ".join(email.body.split())
|
||||
assert f"{user.full_name} shared a document with you!" in email_content
|
||||
assert (
|
||||
f"{user.full_name} ({user.email}) invited you with the role "{invited}" "
|
||||
f"{user.full_name} ({user.email}) invited you with the role ``{invited}`` "
|
||||
f"on the following document: {document.title}"
|
||||
) in email_content
|
||||
assert "My brand name" in email_content
|
||||
@@ -536,7 +536,7 @@ def test_api_document_invitations_create_email_full_name_empty():
|
||||
email_content = " ".join(email.body.split())
|
||||
assert f"{user.email} shared a document with you!" in email_content
|
||||
assert (
|
||||
f"{user.email.capitalize()} invited you with the role "reader" on the "
|
||||
f"{user.email.capitalize()} invited you with the role ``reader`` on the "
|
||||
f"following document: {document.title}" in email_content
|
||||
)
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ def mock_convert_markdown():
|
||||
with patch.object(
|
||||
YdocConverter,
|
||||
"convert_markdown",
|
||||
return_value="Converted document content",
|
||||
return_value={"content": "Converted document content"},
|
||||
) as mock:
|
||||
yield mock
|
||||
|
||||
|
||||
@@ -441,7 +441,7 @@ def test_models_documents__email_invitation__success():
|
||||
email_content = " ".join(email.body.split())
|
||||
|
||||
assert (
|
||||
f"Test Sender (sender@example.com) invited you with the role "editor" "
|
||||
f"Test Sender (sender@example.com) invited you with the role ``editor`` "
|
||||
f"on the following document: {document.title}" in email_content
|
||||
)
|
||||
assert f"docs/{document.id}/" in email_content
|
||||
@@ -476,8 +476,8 @@ def test_models_documents__email_invitation__success_fr():
|
||||
email_content = " ".join(email.body.split())
|
||||
|
||||
assert (
|
||||
f"Test Sender2 (sender2@example.com) vous a invité avec le rôle "propriétaire" "
|
||||
f"sur le document suivant: {document.title}" in email_content
|
||||
f"Test Sender2 (sender2@example.com) vous a invité avec le rôle ``propriétaire`` "
|
||||
f"sur le document suivant : {document.title}" in email_content
|
||||
)
|
||||
assert f"docs/{document.id}/" in email_content
|
||||
|
||||
|
||||
@@ -16,9 +16,9 @@ from core.services.converter_services import (
|
||||
|
||||
def test_auth_header(settings):
|
||||
"""Test authentication header generation."""
|
||||
settings.Y_PROVIDER_API_KEY = "test-key"
|
||||
settings.CONVERSION_API_KEY = "test-key"
|
||||
converter = YdocConverter()
|
||||
assert converter.auth_header == "test-key"
|
||||
assert converter.auth_header == "Bearer test-key"
|
||||
|
||||
|
||||
def test_convert_markdown_empty_text():
|
||||
@@ -97,9 +97,8 @@ def test_convert_markdown_missing_content_field(mock_post, settings):
|
||||
def test_convert_markdown_full_integration(mock_post, settings):
|
||||
"""Test full integration with all settings."""
|
||||
|
||||
settings.Y_PROVIDER_API_BASE_URL = "http://test.com/"
|
||||
settings.Y_PROVIDER_API_KEY = "test-key"
|
||||
settings.CONVERSION_API_ENDPOINT = "conversion-endpoint"
|
||||
settings.CONVERSION_API_URL = "http://test.com"
|
||||
settings.CONVERSION_API_KEY = "test-key"
|
||||
settings.CONVERSION_API_TIMEOUT = 5
|
||||
settings.CONVERSION_API_CONTENT_FIELD = "content"
|
||||
|
||||
@@ -114,14 +113,13 @@ def test_convert_markdown_full_integration(mock_post, settings):
|
||||
|
||||
assert result == expected_content
|
||||
mock_post.assert_called_once_with(
|
||||
"http://test.com/conversion-endpoint/",
|
||||
"http://test.com",
|
||||
json={"content": "test markdown"},
|
||||
headers={
|
||||
"Authorization": "test-key",
|
||||
"Authorization": "Bearer test-key",
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
timeout=5,
|
||||
verify=False,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -505,20 +505,13 @@ class Base(Configuration):
|
||||
"day": 200,
|
||||
}
|
||||
|
||||
# Y provider microservice
|
||||
Y_PROVIDER_API_KEY = values.Value(
|
||||
environ_name="Y_PROVIDER_API_KEY",
|
||||
# Conversion microservice
|
||||
CONVERSION_API_KEY = values.Value(
|
||||
environ_name="CONVERSION_API_KEY",
|
||||
environ_prefix=None,
|
||||
)
|
||||
Y_PROVIDER_API_BASE_URL = values.Value(
|
||||
environ_name="Y_PROVIDER_API_BASE_URL",
|
||||
environ_prefix=None,
|
||||
)
|
||||
|
||||
# Conversion endpoint
|
||||
CONVERSION_API_ENDPOINT = values.Value(
|
||||
default="convert-markdown",
|
||||
environ_name="CONVERSION_API_ENDPOINT",
|
||||
CONVERSION_API_URL = values.Value(
|
||||
environ_name="CONVERSION_API_URL",
|
||||
environ_prefix=None,
|
||||
)
|
||||
CONVERSION_API_CONTENT_FIELD = values.Value(
|
||||
@@ -531,11 +524,6 @@ class Base(Configuration):
|
||||
environ_name="CONVERSION_API_TIMEOUT",
|
||||
environ_prefix=None,
|
||||
)
|
||||
CONVERSION_API_SECURE = values.Value(
|
||||
default=False,
|
||||
environ_name="CONVERSION_API_SECURE",
|
||||
environ_prefix=None,
|
||||
)
|
||||
|
||||
# Logging
|
||||
# We want to make it easy to log to console but by default we log production
|
||||
|
||||
Binary file not shown.
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-people\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-12-17 15:50+0000\n"
|
||||
"PO-Revision-Date: 2024-12-17 15:53\n"
|
||||
"POT-Creation-Date: 2024-12-13 15:17+0000\n"
|
||||
"PO-Revision-Date: 2024-12-13 15:22\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: German\n"
|
||||
"Language: de_DE\n"
|
||||
@@ -220,7 +220,7 @@ msgstr ""
|
||||
|
||||
#: core/models.py:597
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgid "{name} invited you with the role ``{role}`` on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: core/models.py:600
|
||||
|
||||
Binary file not shown.
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-people\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-12-17 15:50+0000\n"
|
||||
"PO-Revision-Date: 2024-12-17 15:53\n"
|
||||
"POT-Creation-Date: 2024-12-13 15:17+0000\n"
|
||||
"PO-Revision-Date: 2024-12-13 15:22\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: English\n"
|
||||
"Language: en_US\n"
|
||||
@@ -220,7 +220,7 @@ msgstr ""
|
||||
|
||||
#: core/models.py:597
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgid "{name} invited you with the role ``{role}`` on the following document:"
|
||||
msgstr ""
|
||||
|
||||
#: core/models.py:600
|
||||
|
||||
Binary file not shown.
@@ -2,8 +2,8 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: lasuite-people\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2024-12-17 15:50+0000\n"
|
||||
"PO-Revision-Date: 2024-12-17 15:53\n"
|
||||
"POT-Creation-Date: 2024-12-13 15:17+0000\n"
|
||||
"PO-Revision-Date: 2024-12-13 16:47\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: French\n"
|
||||
"Language: fr_FR\n"
|
||||
@@ -220,8 +220,8 @@ msgstr "{name} a partagé un document avec vous!"
|
||||
|
||||
#: core/models.py:597
|
||||
#, python-brace-format
|
||||
msgid "{name} invited you with the role \"{role}\" on the following document:"
|
||||
msgstr "{name} vous a invité avec le rôle \"{role}\" sur le document suivant:"
|
||||
msgid "{name} invited you with the role ``{role}`` on the following document:"
|
||||
msgstr "{name} vous a invité avec le rôle ``{role}`` sur le document suivant :"
|
||||
|
||||
#: core/models.py:600
|
||||
#, python-brace-format
|
||||
|
||||
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "impress"
|
||||
version = "1.10.0"
|
||||
version = "1.9.0"
|
||||
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
@@ -25,7 +25,7 @@ license = { file = "LICENSE" }
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"boto3==1.35.81",
|
||||
"boto3==1.35.79",
|
||||
"Brotli==1.1.0",
|
||||
"celery[redis]==5.4.0",
|
||||
"django-configurations==2.5.1",
|
||||
@@ -47,7 +47,7 @@ dependencies = [
|
||||
"jsonschema==4.23.0",
|
||||
"markdown==3.7",
|
||||
"nested-multipart-parser==1.5.0",
|
||||
"openai==1.57.4",
|
||||
"openai==1.57.2",
|
||||
"psycopg[binary]==3.2.3",
|
||||
"PyJWT==2.10.1",
|
||||
"pypandoc==1.14",
|
||||
@@ -74,7 +74,7 @@ dev = [
|
||||
"freezegun==1.5.1",
|
||||
"ipdb==0.13.13",
|
||||
"ipython==8.30.0",
|
||||
"pyfakefs==5.7.3",
|
||||
"pyfakefs==5.7.2",
|
||||
"pylint-django==2.6.1",
|
||||
"pylint==3.3.2",
|
||||
"pytest-cov==6.0.0",
|
||||
|
||||
@@ -1,3 +1,33 @@
|
||||
FROM node:20-alpine AS frontend-deps-y-provider
|
||||
|
||||
WORKDIR /home/frontend/
|
||||
|
||||
COPY ./src/frontend/package.json ./package.json
|
||||
COPY ./src/frontend/yarn.lock ./yarn.lock
|
||||
COPY ./src/frontend/servers/y-provider/package.json ./servers/y-provider/package.json
|
||||
COPY ./src/frontend/packages/eslint-config-impress/package.json ./packages/eslint-config-impress/package.json
|
||||
|
||||
RUN yarn install
|
||||
|
||||
COPY ./src/frontend/ .
|
||||
|
||||
# Copy entrypoint
|
||||
COPY ./docker/files/usr/local/bin/entrypoint /usr/local/bin/entrypoint
|
||||
|
||||
# ---- y-provider ----
|
||||
FROM frontend-deps-y-provider AS y-provider
|
||||
|
||||
WORKDIR /home/frontend/servers/y-provider
|
||||
RUN yarn build
|
||||
|
||||
# Un-privileged user running the application
|
||||
ARG DOCKER_USER
|
||||
USER ${DOCKER_USER}
|
||||
|
||||
ENTRYPOINT [ "/usr/local/bin/entrypoint" ]
|
||||
|
||||
CMD ["yarn", "start"]
|
||||
|
||||
FROM node:20-alpine AS frontend-deps
|
||||
|
||||
WORKDIR /home/frontend/
|
||||
@@ -10,9 +40,7 @@ COPY ./src/frontend/packages/eslint-config-impress/package.json ./packages/eslin
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
||||
COPY .dockerignore ./.dockerignore
|
||||
COPY ./src/frontend/.prettierrc.js ./.prettierrc.js
|
||||
COPY ./src/frontend/packages/eslint-config-impress ./packages/eslint-config-impress
|
||||
COPY ./src/frontend/apps/impress ./apps/impress
|
||||
COPY ./src/frontend/ .
|
||||
|
||||
### ---- Front-end builder image ----
|
||||
FROM frontend-deps AS impress
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { expect, test } from '@playwright/test';
|
||||
|
||||
import { createDoc, goToGridDoc, keyCloakSignIn, randomName } from './common';
|
||||
import { createDoc } from './common';
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/');
|
||||
@@ -29,47 +29,3 @@ test.describe('Doc Create', () => {
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Doc Create: Not loggued', () => {
|
||||
test.use({ storageState: { cookies: [], origins: [] } });
|
||||
|
||||
test('it creates a doc server way', async ({
|
||||
page,
|
||||
browserName,
|
||||
request,
|
||||
}) => {
|
||||
const markdown = `This is a normal text\n\n# And this is a large heading`;
|
||||
const [title] = randomName('My server way doc create', browserName, 1);
|
||||
const data = {
|
||||
title,
|
||||
content: markdown,
|
||||
sub: `user@${browserName}.e2e`,
|
||||
email: `user@${browserName}.e2e`,
|
||||
};
|
||||
|
||||
const newDoc = await request.post(
|
||||
`http://localhost:8071/api/v1.0/documents/create-for-owner/`,
|
||||
{
|
||||
data,
|
||||
headers: {
|
||||
Authorization: 'Bearer test-e2e',
|
||||
format: 'json',
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
expect(newDoc.ok()).toBeTruthy();
|
||||
|
||||
await keyCloakSignIn(page, browserName);
|
||||
|
||||
await goToGridDoc(page, { title });
|
||||
|
||||
await expect(page.getByRole('heading', { name: title })).toBeVisible();
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
await expect(editor.getByText('This is a normal text')).toBeVisible();
|
||||
await expect(
|
||||
editor.locator('h1').getByText('And this is a large heading'),
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -233,7 +233,7 @@ test.describe('Doc Editor', () => {
|
||||
test.skip(browserName === 'webkit', 'This test is very flaky with webkit');
|
||||
|
||||
// Check the first doc
|
||||
const [doc] = await createDoc(page, 'doc-quit-1', browserName, 1);
|
||||
const doc = await goToGridDoc(page);
|
||||
await expect(page.locator('h2').getByText(doc)).toBeVisible();
|
||||
|
||||
const editor = page.locator('.ProseMirror');
|
||||
@@ -272,8 +272,8 @@ test.describe('Doc Editor', () => {
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test('it adds an image to the doc editor', async ({ page, browserName }) => {
|
||||
await createDoc(page, 'doc-image', browserName, 1);
|
||||
test('it adds an image to the doc editor', async ({ page }) => {
|
||||
await goToGridDoc(page);
|
||||
|
||||
const fileChooserPromise = page.waitForEvent('filechooser');
|
||||
|
||||
|
||||
@@ -120,14 +120,13 @@ test.describe('Doc Header', () => {
|
||||
|
||||
await editor.locator('h1').fill('');
|
||||
|
||||
// eslint-disable-next-line playwright/no-wait-for-timeout
|
||||
await page.waitForTimeout(500);
|
||||
|
||||
await docHeader
|
||||
.getByRole('heading', { name: 'Top World', level: 2 })
|
||||
.fill(' ');
|
||||
|
||||
await page.getByText('Created at').click();
|
||||
await page.getByText('Created at').click({
|
||||
delay: 200,
|
||||
});
|
||||
|
||||
await expect(
|
||||
docHeader.getByRole('heading', { name: 'Untitled document', level: 2 }),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-e2e",
|
||||
"version": "1.10.0",
|
||||
"version": "1.9.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint . --ext .ts",
|
||||
@@ -12,7 +12,7 @@
|
||||
"test:ui::chromium": "yarn test:ui --project=chromium"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.49.1",
|
||||
"@playwright/test": "1.49.0",
|
||||
"@types/node": "*",
|
||||
"@types/pdf-parse": "1.1.4",
|
||||
"eslint-config-impress": "*",
|
||||
|
||||
@@ -19,7 +19,6 @@ export default defineConfig({
|
||||
forbidOnly: !!process.env.CI,
|
||||
/* Retry on CI only */
|
||||
retries: process.env.CI ? 2 : 0,
|
||||
maxFailures: process.env.CI ? 3 : 0,
|
||||
/* Opt out of parallel tests on CI. */
|
||||
workers: process.env.CI ? 3 : undefined,
|
||||
/* Reporter to use. See https://playwright.dev/docs/test-reporters */
|
||||
|
||||
2
src/frontend/apps/impress/next-env.d.ts
vendored
2
src/frontend/apps/impress/next-env.d.ts
vendored
@@ -2,4 +2,4 @@
|
||||
/// <reference types="next/image-types/global" />
|
||||
|
||||
// NOTE: This file should not be edited
|
||||
// see https://nextjs.org/docs/pages/api-reference/config/typescript for more information.
|
||||
// see https://nextjs.org/docs/pages/building-your-application/configuring/typescript for more information.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-impress",
|
||||
"version": "1.10.0",
|
||||
"version": "1.9.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
@@ -19,33 +19,33 @@
|
||||
"@blocknote/mantine": "*",
|
||||
"@blocknote/react": "*",
|
||||
"@gouvfr-lasuite/integration": "1.0.2",
|
||||
"@hocuspocus/provider": "2.15.0",
|
||||
"@hocuspocus/provider": "2.14.0",
|
||||
"@openfun/cunningham-react": "2.9.4",
|
||||
"@sentry/nextjs": "8.45.1",
|
||||
"@tanstack/react-query": "5.62.7",
|
||||
"@sentry/nextjs": "8.42.0",
|
||||
"@tanstack/react-query": "5.62.2",
|
||||
"crisp-sdk-web": "1.0.25",
|
||||
"i18next": "24.1.0",
|
||||
"i18next-browser-languagedetector": "8.0.2",
|
||||
"idb": "8.0.1",
|
||||
"i18next": "24.0.5",
|
||||
"i18next-browser-languagedetector": "8.0.0",
|
||||
"idb": "8.0.0",
|
||||
"lodash": "4.17.21",
|
||||
"luxon": "3.5.0",
|
||||
"next": "15.1.0",
|
||||
"next": "15.0.3",
|
||||
"react": "*",
|
||||
"react-aria-components": "1.5.0",
|
||||
"react-dom": "*",
|
||||
"react-i18next": "15.2.0",
|
||||
"react-select": "5.9.0",
|
||||
"react-i18next": "15.1.3",
|
||||
"react-select": "5.8.3",
|
||||
"styled-components": "6.1.13",
|
||||
"y-protocols": "1.0.6",
|
||||
"yjs": "*",
|
||||
"zustand": "5.0.2"
|
||||
"zustand": "5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@svgr/webpack": "8.1.0",
|
||||
"@tanstack/react-query-devtools": "5.62.7",
|
||||
"@tanstack/react-query-devtools": "5.62.2",
|
||||
"@testing-library/dom": "10.4.0",
|
||||
"@testing-library/jest-dom": "6.6.3",
|
||||
"@testing-library/react": "16.1.0",
|
||||
"@testing-library/react": "16.0.1",
|
||||
"@testing-library/user-event": "14.5.2",
|
||||
"@types/jest": "29.5.14",
|
||||
"@types/lodash": "4.17.13",
|
||||
@@ -60,12 +60,12 @@
|
||||
"jest": "29.7.0",
|
||||
"jest-environment-jsdom": "29.7.0",
|
||||
"node-fetch": "2.7.0",
|
||||
"prettier": "3.4.2",
|
||||
"stylelint": "16.12.0",
|
||||
"prettier": "3.4.1",
|
||||
"stylelint": "16.11.0",
|
||||
"stylelint-config-standard": "36.0.1",
|
||||
"stylelint-prettier": "5.0.2",
|
||||
"typescript": "*",
|
||||
"webpack": "5.97.1",
|
||||
"webpack": "5.97.0",
|
||||
"workbox-webpack-plugin": "7.1.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,29 +2,27 @@ import '@blocknote/mantine/style.css';
|
||||
import {
|
||||
FormattingToolbar,
|
||||
FormattingToolbarController,
|
||||
FormattingToolbarProps,
|
||||
getFormattingToolbarItems,
|
||||
} from '@blocknote/react';
|
||||
import React, { useCallback } from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { AIGroupButton } from './AIButton';
|
||||
import { MarkdownButton } from './MarkdownButton';
|
||||
|
||||
export const BlockNoteToolbar = () => {
|
||||
const formattingToolbar = useCallback(
|
||||
({ blockTypeSelectItems }: FormattingToolbarProps) => (
|
||||
<FormattingToolbar>
|
||||
{getFormattingToolbarItems(blockTypeSelectItems)}
|
||||
return (
|
||||
<FormattingToolbarController
|
||||
formattingToolbar={({ blockTypeSelectItems }) => (
|
||||
<FormattingToolbar>
|
||||
{getFormattingToolbarItems(blockTypeSelectItems)}
|
||||
|
||||
{/* Extra button to do some AI powered actions */}
|
||||
<AIGroupButton key="AIButton" />
|
||||
{/* Extra button to do some AI powered actions */}
|
||||
<AIGroupButton key="AIButton" />
|
||||
|
||||
{/* Extra button to convert from markdown to json */}
|
||||
<MarkdownButton key="customButton" />
|
||||
</FormattingToolbar>
|
||||
),
|
||||
[],
|
||||
{/* Extra button to convert from markdown to json */}
|
||||
<MarkdownButton key="customButton" />
|
||||
</FormattingToolbar>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
|
||||
return <FormattingToolbarController formattingToolbar={formattingToolbar} />;
|
||||
};
|
||||
|
||||
@@ -65,6 +65,10 @@ const DocPage = ({ id }: DocProps) => {
|
||||
|
||||
setDoc(docQuery);
|
||||
setCurrentDoc(docQuery);
|
||||
|
||||
return () => {
|
||||
setCurrentDoc(undefined);
|
||||
};
|
||||
}, [docQuery, setCurrentDoc]);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -25,7 +25,7 @@ export const useSentryStore = create<SentryState>((set, get) => ({
|
||||
release: packageJson.version,
|
||||
replaysSessionSampleRate: 0.1,
|
||||
replaysOnErrorSampleRate: 1.0,
|
||||
tracesSampleRate: 0.1,
|
||||
tracesSampleRate: 1.0,
|
||||
}),
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "impress",
|
||||
"version": "1.10.0",
|
||||
"version": "1.9.0",
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
@@ -28,13 +28,13 @@
|
||||
"server:test": "yarn COLLABORATION_SERVER run test"
|
||||
},
|
||||
"resolutions": {
|
||||
"@blocknote/core": "0.21.0",
|
||||
"@blocknote/mantine": "0.21.0",
|
||||
"@blocknote/react": "0.21.0",
|
||||
"@types/node": "22.10.2",
|
||||
"@blocknote/core": "0.20.0",
|
||||
"@blocknote/mantine": "0.20.0",
|
||||
"@blocknote/react": "0.20.0",
|
||||
"@types/node": "22.10.1",
|
||||
"@types/react-dom": "18.3.1",
|
||||
"@typescript-eslint/eslint-plugin": "8.18.0",
|
||||
"@typescript-eslint/parser": "8.18.0",
|
||||
"@typescript-eslint/eslint-plugin": "8.17.0",
|
||||
"@typescript-eslint/parser": "8.17.0",
|
||||
"cross-env": "7.0.3",
|
||||
"eslint": "8.57.0",
|
||||
"react": "18.3.1",
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"name": "eslint-config-impress",
|
||||
"version": "1.10.0",
|
||||
"version": "1.9.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .js ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@next/eslint-plugin-next": "15.1.0",
|
||||
"@next/eslint-plugin-next": "15.0.3",
|
||||
"@tanstack/eslint-plugin-query": "5.62.1",
|
||||
"@typescript-eslint/eslint-plugin": "*",
|
||||
"@typescript-eslint/parser": "*",
|
||||
"eslint": "*",
|
||||
"eslint-config-next": "15.1.0",
|
||||
"eslint-config-next": "15.0.3",
|
||||
"eslint-config-prettier": "9.1.0",
|
||||
"eslint-plugin-import": "2.31.0",
|
||||
"eslint-plugin-jest": "28.9.0",
|
||||
@@ -19,7 +19,7 @@
|
||||
"eslint-plugin-playwright": "2.1.0",
|
||||
"eslint-plugin-prettier": "5.2.1",
|
||||
"eslint-plugin-react": "7.37.2",
|
||||
"eslint-plugin-testing-library": "7.1.1",
|
||||
"prettier": "3.4.2"
|
||||
"eslint-plugin-testing-library": "7.0.0",
|
||||
"prettier": "3.4.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "packages-i18n",
|
||||
"version": "1.10.0",
|
||||
"version": "1.9.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"extract-translation": "yarn extract-translation:impress",
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
FROM node:20-alpine AS y-provider-builder
|
||||
|
||||
WORKDIR /home/frontend/
|
||||
|
||||
COPY ./src/frontend/package.json ./package.json
|
||||
COPY ./src/frontend/yarn.lock ./yarn.lock
|
||||
COPY ./src/frontend/servers/y-provider/package.json ./servers/y-provider/package.json
|
||||
COPY ./src/frontend/packages/eslint-config-impress/package.json ./packages/eslint-config-impress/package.json
|
||||
|
||||
RUN yarn install
|
||||
|
||||
COPY ./src/frontend/packages/eslint-config-impress ./packages/eslint-config-impress
|
||||
COPY ./src/frontend/servers/y-provider ./servers/y-provider
|
||||
|
||||
WORKDIR /home/frontend/servers/y-provider
|
||||
RUN yarn build
|
||||
|
||||
FROM node:20-alpine AS y-provider
|
||||
|
||||
WORKDIR /home/frontend/
|
||||
|
||||
COPY ./src/frontend/package.json ./package.json
|
||||
COPY ./src/frontend/yarn.lock ./yarn.lock
|
||||
COPY ./src/frontend/servers/y-provider/package.json ./servers/y-provider/package.json
|
||||
|
||||
WORKDIR /home/frontend/servers/y-provider
|
||||
|
||||
COPY --from=y-provider-builder \
|
||||
/home/frontend/servers/y-provider/dist \
|
||||
./dist
|
||||
|
||||
RUN NODE_ENV=production yarn install --frozen-lockfile
|
||||
|
||||
# Un-privileged user running the application
|
||||
ARG DOCKER_USER
|
||||
USER ${DOCKER_USER}
|
||||
|
||||
# Copy entrypoint
|
||||
COPY ./docker/files/usr/local/bin/entrypoint /usr/local/bin/entrypoint
|
||||
ENTRYPOINT [ "/usr/local/bin/entrypoint" ]
|
||||
|
||||
CMD ["yarn", "start"]
|
||||
@@ -14,7 +14,6 @@ jest.mock('../src/env', () => {
|
||||
PORT: port,
|
||||
COLLABORATION_SERVER_ORIGIN: origin,
|
||||
COLLABORATION_SERVER_SECRET: 'test-secret-api-key',
|
||||
Y_PROVIDER_API_KEY: 'yprovider-api-key',
|
||||
};
|
||||
});
|
||||
|
||||
@@ -102,21 +101,11 @@ describe('Server Tests', () => {
|
||||
expect(response.body.error).toBe('Forbidden: Invalid API Key');
|
||||
});
|
||||
|
||||
test('POST /api/convert-markdown with a Bearer token', async () => {
|
||||
const response = await request(app as any)
|
||||
.post('/api/convert-markdown')
|
||||
.set('Origin', origin)
|
||||
.set('Authorization', 'Bearer test-secret-api-key');
|
||||
|
||||
// Warning: Changing the authorization header to Bearer token format will break backend compatibility with this microservice.
|
||||
expect(response.status).toBe(403);
|
||||
});
|
||||
|
||||
test('POST /api/convert-markdown with missing body param content', async () => {
|
||||
const response = await request(app as any)
|
||||
.post('/api/convert-markdown')
|
||||
.set('Origin', origin)
|
||||
.set('Authorization', 'yprovider-api-key');
|
||||
.set('Authorization', 'test-secret-api-key');
|
||||
|
||||
expect(response.status).toBe(400);
|
||||
expect(response.body.error).toBe('Invalid request: missing content');
|
||||
@@ -126,7 +115,7 @@ describe('Server Tests', () => {
|
||||
const response = await request(app as any)
|
||||
.post('/api/convert-markdown')
|
||||
.set('Origin', origin)
|
||||
.set('Authorization', 'yprovider-api-key')
|
||||
.set('Authorization', 'test-secret-api-key')
|
||||
.send({
|
||||
content: '',
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "server-y-provider",
|
||||
"version": "1.10.0",
|
||||
"version": "1.9.0",
|
||||
"description": "Y.js provider for docs",
|
||||
"repository": "https://github.com/numerique-gouv/impress",
|
||||
"license": "MIT",
|
||||
@@ -16,17 +16,17 @@
|
||||
"node": ">=18"
|
||||
},
|
||||
"dependencies": {
|
||||
"@blocknote/server-util": "0.21.0",
|
||||
"@hocuspocus/server": "2.15.0",
|
||||
"@sentry/node": "8.45.1",
|
||||
"@sentry/profiling-node": "8.45.1",
|
||||
"express": "4.21.2",
|
||||
"@blocknote/server-util": "0.20.0",
|
||||
"@hocuspocus/server": "2.14.0",
|
||||
"@sentry/node": "8.41.0",
|
||||
"@sentry/profiling-node": "8.41.0",
|
||||
"express": "4.21.1",
|
||||
"express-ws": "5.0.2",
|
||||
"y-protocols": "1.0.6",
|
||||
"yjs": "13.6.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@hocuspocus/provider": "2.15.0",
|
||||
"@hocuspocus/provider": "2.14.0",
|
||||
"@types/express": "5.0.0",
|
||||
"@types/express-ws": "3.0.5",
|
||||
"@types/jest": "29.5.14",
|
||||
@@ -35,7 +35,7 @@
|
||||
"@types/ws": "8.5.13",
|
||||
"eslint-config-impress": "*",
|
||||
"jest": "29.7.0",
|
||||
"nodemon": "3.1.9",
|
||||
"nodemon": "3.1.7",
|
||||
"supertest": "7.0.0",
|
||||
"ts-jest": "29.2.5",
|
||||
"ts-node": "10.9.2",
|
||||
|
||||
@@ -4,7 +4,5 @@ export const COLLABORATION_SERVER_ORIGIN =
|
||||
process.env.COLLABORATION_SERVER_ORIGIN || 'http://localhost:3000';
|
||||
export const COLLABORATION_SERVER_SECRET =
|
||||
process.env.COLLABORATION_SERVER_SECRET || 'secret-api-key';
|
||||
export const Y_PROVIDER_API_KEY =
|
||||
process.env.Y_PROVIDER_API_KEY || 'yprovider-api-key';
|
||||
export const PORT = Number(process.env.PORT || 4444);
|
||||
export const SENTRY_DSN = process.env.SENTRY_DSN || '';
|
||||
|
||||
@@ -4,13 +4,10 @@ import * as ws from 'ws';
|
||||
import {
|
||||
COLLABORATION_SERVER_ORIGIN,
|
||||
COLLABORATION_SERVER_SECRET,
|
||||
Y_PROVIDER_API_KEY,
|
||||
} from '@/env';
|
||||
|
||||
import { logger } from './utils';
|
||||
|
||||
const VALID_API_KEYS = [COLLABORATION_SERVER_SECRET, Y_PROVIDER_API_KEY];
|
||||
|
||||
export const httpSecurity = (
|
||||
req: Request,
|
||||
res: Response,
|
||||
@@ -28,9 +25,8 @@ export const httpSecurity = (
|
||||
}
|
||||
|
||||
// Secret API Key check
|
||||
// Note: Changing this header to Bearer token format will break backend compatibility with this microservice.
|
||||
const apiKey = req.headers['authorization'];
|
||||
if (!apiKey || !VALID_API_KEYS.includes(apiKey)) {
|
||||
if (apiKey !== COLLABORATION_SERVER_SECRET) {
|
||||
res.status(403).json({ error: 'Forbidden: Invalid API Key' });
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,6 @@ import { SENTRY_DSN } from '../env';
|
||||
Sentry.init({
|
||||
dsn: SENTRY_DSN,
|
||||
integrations: [nodeProfilingIntegration()],
|
||||
tracesSampleRate: 0.1,
|
||||
tracesSampleRate: 1.0,
|
||||
profilesSampleRate: 1.0,
|
||||
});
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,13 +11,10 @@ backend:
|
||||
DJANGO_CSRF_TRUSTED_ORIGINS: https://impress.127.0.0.1.nip.io
|
||||
DJANGO_CONFIGURATION: Feature
|
||||
DJANGO_ALLOWED_HOSTS: impress.127.0.0.1.nip.io
|
||||
DJANGO_SERVER_TO_SERVER_API_TOKENS: secret-api-key
|
||||
DJANGO_SECRET_KEY: {{ .Values.djangoSecretKey }}
|
||||
DJANGO_SETTINGS_MODULE: impress.settings
|
||||
DJANGO_SUPERUSER_PASSWORD: admin
|
||||
DJANGO_EMAIL_BRAND_NAME: "La Suite Numérique"
|
||||
DJANGO_EMAIL_HOST: "mailcatcher"
|
||||
DJANGO_EMAIL_LOGO_IMG: https://impress.127.0.0.1.nip.io/assets/logo-suite-numerique.png
|
||||
DJANGO_EMAIL_PORT: 1025
|
||||
DJANGO_EMAIL_USE_SSL: False
|
||||
LOGGING_LEVEL_HANDLERS_CONSOLE: ERROR
|
||||
@@ -49,12 +46,13 @@ backend:
|
||||
POSTGRES_PASSWORD: pass
|
||||
REDIS_URL: redis://default:pass@redis-master:6379/1
|
||||
AWS_S3_ENDPOINT_URL: http://minio.impress.svc.cluster.local:9000
|
||||
AWS_S3_ACCESS_KEY_ID: root
|
||||
AWS_S3_ACCESS_KEY_ID: impress
|
||||
AWS_S3_SECRET_ACCESS_KEY: password
|
||||
AWS_STORAGE_BUCKET_NAME: impress-media-storage
|
||||
STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
|
||||
Y_PROVIDER_API_BASE_URL: http://impress-y-provider:443/api/
|
||||
Y_PROVIDER_API_KEY: my-secret
|
||||
AI_API_KEY: **ask antoine**
|
||||
AI_BASE_URL: https://albertine.beta.numerique.gouv.fr/v1/
|
||||
AI_MODEL: meta-llama/Llama-3.1-8B-Instruct
|
||||
|
||||
migrate:
|
||||
command:
|
||||
@@ -107,7 +105,6 @@ yProvider:
|
||||
COLLABORATION_LOGGING: true
|
||||
COLLABORATION_SERVER_ORIGIN: https://impress.127.0.0.1.nip.io
|
||||
COLLABORATION_SERVER_SECRET: my-secret
|
||||
Y_PROVIDER_API_KEY: my-secret
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
image:
|
||||
repository: lasuite/impress-backend
|
||||
pullPolicy: Always
|
||||
tag: "v1.10.0"
|
||||
|
||||
backend:
|
||||
migrateJobAnnotations:
|
||||
argocd.argoproj.io/hook: PostSync
|
||||
argocd.argoproj.io/hook-delete-policy: HookSucceeded
|
||||
envVars:
|
||||
AI_API_KEY:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: AI_API_KEY
|
||||
AI_BASE_URL: https://albert.api.etalab.gouv.fr/v1/
|
||||
AI_MODEL: meta-llama/Meta-Llama-3.1-70B-Instruct
|
||||
COLLABORATION_API_URL: https://docs.numerique.gouv.fr/collaboration/api/
|
||||
COLLABORATION_SERVER_SECRET:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: COLLABORATION_SERVER_SECRET
|
||||
DJANGO_CSRF_TRUSTED_ORIGINS: https://docs.numerique.gouv.fr
|
||||
DJANGO_CONFIGURATION: Production
|
||||
DJANGO_ALLOWED_HOSTS: docs.numerique.gouv.fr
|
||||
DJANGO_SECRET_KEY:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: DJANGO_SECRET_KEY
|
||||
DJANGO_SERVER_TO_SERVER_API_TOKENS:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: DJANGO_SERVER_TO_SERVER_API_TOKENS
|
||||
DJANGO_SETTINGS_MODULE: impress.settings
|
||||
DJANGO_SUPERUSER_EMAIL:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: DJANGO_SUPERUSER_EMAIL
|
||||
DJANGO_SUPERUSER_PASSWORD:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: DJANGO_SUPERUSER_PASSWORD
|
||||
DJANGO_EMAIL_BRAND_NAME: "La Suite Numérique"
|
||||
DJANGO_EMAIL_HOST: "smtp.tem.scw.cloud"
|
||||
DJANGO_EMAIL_LOGO_IMG: https://docs.numerique.gouv.fr/assets/logo-suite-numerique.png
|
||||
DJANGO_EMAIL_PORT: 587
|
||||
DJANGO_EMAIL_USE_TLS: True
|
||||
DJANGO_EMAIL_FROM: "noreply@docs.beta.numerique.gouv.fr"
|
||||
DJANGO_EMAIL_HOST_USER:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: DJANGO_EMAIL_HOST_USER
|
||||
DJANGO_EMAIL_HOST_PASSWORD:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: DJANGO_EMAIL_HOST_PASSWORD
|
||||
DJANGO_SILENCED_SYSTEM_CHECKS: security.W008,security.W004
|
||||
OIDC_OP_JWKS_ENDPOINT: https://auth.agentconnect.gouv.fr/api/v2/jwks
|
||||
OIDC_OP_AUTHORIZATION_ENDPOINT: https://auth.agentconnect.gouv.fr/api/v2/authorize
|
||||
OIDC_OP_TOKEN_ENDPOINT: https://auth.agentconnect.gouv.fr/api/v2/token
|
||||
OIDC_OP_USER_ENDPOINT: https://auth.agentconnect.gouv.fr/api/v2/userinfo
|
||||
OIDC_OP_LOGOUT_ENDPOINT: https://auth.agentconnect.gouv.fr/api/v2/session/end
|
||||
OIDC_RP_CLIENT_ID:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: OIDC_RP_CLIENT_ID
|
||||
OIDC_RP_CLIENT_SECRET:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: OIDC_RP_CLIENT_SECRET
|
||||
OIDC_RP_SIGN_ALGO: RS256
|
||||
OIDC_RP_SCOPES: "openid email given_name usual_name"
|
||||
USER_OIDC_FIELD_TO_SHORTNAME: "given_name"
|
||||
USER_OIDC_FIELDS_TO_FULLNAME: "given_name,usual_name"
|
||||
OIDC_REDIRECT_ALLOWED_HOSTS: https://docs.numerique.gouv.fr
|
||||
OIDC_AUTH_REQUEST_EXTRA_PARAMS: "{'acr_values': 'eidas1'}"
|
||||
LOGIN_REDIRECT_URL: https://docs.numerique.gouv.fr
|
||||
LOGIN_REDIRECT_URL_FAILURE: https://docs.numerique.gouv.fr
|
||||
LOGOUT_REDIRECT_URL: https://docs.numerique.gouv.fr
|
||||
DB_HOST:
|
||||
secretKeyRef:
|
||||
name: postgresql.postgres.libre.sh
|
||||
key: host
|
||||
DB_NAME:
|
||||
secretKeyRef:
|
||||
name: postgresql.postgres.libre.sh
|
||||
key: database
|
||||
DB_USER:
|
||||
secretKeyRef:
|
||||
name: postgresql.postgres.libre.sh
|
||||
key: username
|
||||
DB_PASSWORD:
|
||||
secretKeyRef:
|
||||
name: postgresql.postgres.libre.sh
|
||||
key: password
|
||||
DB_PORT:
|
||||
secretKeyRef:
|
||||
name: postgresql.postgres.libre.sh
|
||||
key: port
|
||||
POSTGRES_USER:
|
||||
secretKeyRef:
|
||||
name: postgresql.postgres.libre.sh
|
||||
key: username
|
||||
POSTGRES_DB:
|
||||
secretKeyRef:
|
||||
name: postgresql.postgres.libre.sh
|
||||
key: database
|
||||
POSTGRES_PASSWORD:
|
||||
secretKeyRef:
|
||||
name: postgresql.postgres.libre.sh
|
||||
key: password
|
||||
REDIS_URL:
|
||||
secretKeyRef:
|
||||
name: redis.redis.libre.sh
|
||||
key: url
|
||||
AWS_S3_ENDPOINT_URL:
|
||||
secretKeyRef:
|
||||
name: impress-media-storage.bucket.libre.sh
|
||||
key: url
|
||||
AWS_S3_ACCESS_KEY_ID:
|
||||
secretKeyRef:
|
||||
name: impress-media-storage.bucket.libre.sh
|
||||
key: accessKey
|
||||
AWS_S3_SECRET_ACCESS_KEY:
|
||||
secretKeyRef:
|
||||
name: impress-media-storage.bucket.libre.sh
|
||||
key: secretKey
|
||||
AWS_STORAGE_BUCKET_NAME:
|
||||
secretKeyRef:
|
||||
name: impress-media-storage.bucket.libre.sh
|
||||
key: bucket
|
||||
AWS_S3_REGION_NAME: local
|
||||
STORAGES_STATICFILES_BACKEND: django.contrib.staticfiles.storage.StaticFilesStorage
|
||||
Y_PROVIDER_API_BASE_URL: http://impress-y-provider:443/api/
|
||||
Y_PROVIDER_API_KEY:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: Y_PROVIDER_API_KEY
|
||||
|
||||
createsuperuser:
|
||||
command:
|
||||
- "/bin/sh"
|
||||
- "-c"
|
||||
- |
|
||||
python manage.py createsuperuser --email $DJANGO_SUPERUSER_EMAIL --password $DJANGO_SUPERUSER_PASSWORD
|
||||
restartPolicy: Never
|
||||
|
||||
frontend:
|
||||
image:
|
||||
repository: lasuite/impress-frontend
|
||||
pullPolicy: Always
|
||||
tag: "v1.10.0"
|
||||
|
||||
yProvider:
|
||||
image:
|
||||
repository: lasuite/impress-y-provider
|
||||
pullPolicy: Always
|
||||
tag: "v1.10.0"
|
||||
|
||||
envVars:
|
||||
COLLABORATION_LOGGING: true
|
||||
COLLABORATION_SERVER_ORIGIN: https://docs.numerique.gouv.fr
|
||||
COLLABORATION_SERVER_SECRET:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: COLLABORATION_SERVER_SECRET
|
||||
Y_PROVIDER_API_KEY:
|
||||
secretKeyRef:
|
||||
name: backend
|
||||
key: Y_PROVIDER_API_KEY
|
||||
|
||||
ingress:
|
||||
enabled: true
|
||||
host: docs.numerique.gouv.fr
|
||||
className: nginx
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt
|
||||
|
||||
ingressCollaborationWS:
|
||||
enabled: true
|
||||
host: docs.numerique.gouv.fr
|
||||
className: nginx
|
||||
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt
|
||||
nginx.ingress.kubernetes.io/auth-url: https://docs.numerique.gouv.fr/api/v1.0/documents/collaboration-auth/
|
||||
|
||||
ingressCollaborationApi:
|
||||
enabled: true
|
||||
host: docs.numerique.gouv.fr
|
||||
className: nginx
|
||||
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt
|
||||
|
||||
ingressAdmin:
|
||||
enabled: true
|
||||
host: docs.numerique.gouv.fr
|
||||
className: nginx
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt
|
||||
nginx.ingress.kubernetes.io/auth-signin: https://oauth2-proxy.beta.numerique.gouv.fr/oauth2/start
|
||||
nginx.ingress.kubernetes.io/auth-url: https://oauth2-proxy.beta.numerique.gouv.fr/oauth2/auth
|
||||
|
||||
ingressMedia:
|
||||
enabled: true
|
||||
host: docs.numerique.gouv.fr
|
||||
|
||||
annotations:
|
||||
cert-manager.io/cluster-issuer: letsencrypt
|
||||
nginx.ingress.kubernetes.io/auth-response-headers: "Authorization, X-Amz-Date, X-Amz-Content-SHA256"
|
||||
nginx.ingress.kubernetes.io/auth-url: https://docs.numerique.gouv.fr/api/v1.0/documents/media-auth/
|
||||
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
|
||||
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/rewrite-target: /impress-impress-media-storage/$1
|
||||
nginx.ingress.kubernetes.io/ssl-redirect: "true"
|
||||
nginx.ingress.kubernetes.io/upstream-vhost: s3.hedy-lamarr.indiehosters.net
|
||||
|
||||
serviceMedia:
|
||||
host: s3.hedy-lamarr.indiehosters.net
|
||||
port: 443
|
||||
@@ -2,4 +2,4 @@ apiVersion: v2
|
||||
name: extra
|
||||
description: A Helm chart to add some manifests to impress
|
||||
type: application
|
||||
version: 1.10.0
|
||||
version: 1.9.0
|
||||
|
||||
@@ -62,6 +62,6 @@ releases:
|
||||
environments:
|
||||
dev:
|
||||
values:
|
||||
- version: 1.10.0
|
||||
- version: 1.9.0
|
||||
secrets:
|
||||
- env.d/{{ .Environment.Name }}/secrets.enc.yaml
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
apiVersion: v2
|
||||
type: application
|
||||
name: impress
|
||||
version: 1.10.0
|
||||
version: 1.9.0
|
||||
@@ -29,7 +29,7 @@ spec:
|
||||
{{- if .Values.ingress.tls.enabled }}
|
||||
tls:
|
||||
{{- if .Values.ingress.host }}
|
||||
- secretName: {{ .Values.ingress.tls.secretName | default (printf "%s-tls" $fullName) | quote }}
|
||||
- secretName: {{ $fullName }}-tls
|
||||
hosts:
|
||||
- {{ .Values.ingress.host | quote }}
|
||||
{{- end }}
|
||||
@@ -115,3 +115,4 @@ spec:
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ spec:
|
||||
{{- if .Values.ingressAdmin.tls.enabled }}
|
||||
tls:
|
||||
{{- if .Values.ingressAdmin.host }}
|
||||
- secretName: {{ .Values.ingressAdmin.tls.secretName | default (printf "%s-tls" $fullName) | quote }}
|
||||
- secretName: {{ $fullName }}-tls
|
||||
hosts:
|
||||
- {{ .Values.ingressAdmin.host | quote }}
|
||||
{{- end }}
|
||||
@@ -95,3 +95,4 @@ spec:
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ spec:
|
||||
{{- if .Values.ingressCollaborationApi.tls.enabled }}
|
||||
tls:
|
||||
{{- if .Values.ingressCollaborationApi.host }}
|
||||
- secretName: {{ .Values.ingressCollaborationApi.tls.secretName | default (printf "%s-tls" $fullName) | quote }}
|
||||
- secretName: {{ $fullName }}-tls
|
||||
hosts:
|
||||
- {{ .Values.ingressCollaborationApi.host | quote }}
|
||||
{{- end }}
|
||||
@@ -69,3 +69,4 @@ spec:
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ spec:
|
||||
{{- if .Values.ingressCollaborationWS.tls.enabled }}
|
||||
tls:
|
||||
{{- if .Values.ingressCollaborationWS.host }}
|
||||
- secretName: {{ .Values.ingressCollaborationWS.tls.secretName | default (printf "%s-tls" $fullName) | quote }}
|
||||
- secretName: {{ $fullName }}-tls
|
||||
hosts:
|
||||
- {{ .Values.ingressCollaborationWS.host | quote }}
|
||||
{{- end }}
|
||||
@@ -69,3 +69,4 @@ spec:
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ spec:
|
||||
{{- if .Values.ingressMedia.tls.enabled }}
|
||||
tls:
|
||||
{{- if .Values.ingressMedia.host }}
|
||||
- secretName: {{ .Values.ingressMedia.tls.secretName | default (printf "%s-tls" $fullName) | quote }}
|
||||
- secretName: {{ $fullName }}-tls
|
||||
hosts:
|
||||
- {{ .Values.ingressMedia.host | quote }}
|
||||
{{- end }}
|
||||
|
||||
@@ -37,14 +37,12 @@ ingress:
|
||||
## @param ingress.hosts Additional host to configure for the Ingress
|
||||
hosts: []
|
||||
# - chart-example.local
|
||||
## @param ingress.tls.enabled Weather to enable TLS for the Ingress
|
||||
## @param ingress.tls.secretName Secret name for TLS config
|
||||
## @param ingress.tls.enabled Wether to enable TLS for the Ingress
|
||||
## @skip ingress.tls.additional
|
||||
## @extra ingress.tls.additional[].secretName Secret name for additional TLS config
|
||||
## @extra ingress.tls.additional[].hosts[] Hosts for additional TLS config
|
||||
tls:
|
||||
enabled: true
|
||||
secretName: null
|
||||
additional: []
|
||||
|
||||
## @param ingress.customBackends Add custom backends to ingress
|
||||
@@ -62,23 +60,21 @@ ingressCollaborationWS:
|
||||
## @param ingress.hosts Additional host to configure for the Ingress
|
||||
hosts: []
|
||||
# - chart-example.local
|
||||
## @param ingressCollaborationWS.tls.enabled Weather to enable TLS for the Ingress
|
||||
## @param ingressCollaborationWS.tls.secretName Secret name for TLS config
|
||||
## @param ingressCollaborationWS.tls.enabled Wether to enable TLS for the Ingress
|
||||
## @skip ingressCollaborationWS.tls.additional
|
||||
## @extra ingressCollaborationWS.tls.additional[].secretName Secret name for additional TLS config
|
||||
## @extra ingressCollaborationWS.tls.additional[].hosts[] Hosts for additional TLS config
|
||||
tls:
|
||||
enabled: true
|
||||
secretName: null
|
||||
additional: []
|
||||
|
||||
## @param ingressCollaborationWS.customBackends Add custom backends to ingress
|
||||
customBackends: []
|
||||
|
||||
annotations:
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/auth-response-headers: "Authorization, X-Can-Edit, X-User-Id"
|
||||
nginx.ingress.kubernetes.io/auth-url: https://impress.example.com/api/v1.0/documents/collaboration-auth/
|
||||
nginx.ingress.kubernetes.io/enable-websocket: "true"
|
||||
nginx.ingress.kubernetes.io/enable-websocket: "true"
|
||||
nginx.ingress.kubernetes.io/proxy-read-timeout: "86400"
|
||||
nginx.ingress.kubernetes.io/proxy-send-timeout: "86400"
|
||||
nginx.ingress.kubernetes.io/upstream-hash-by: $arg_room
|
||||
@@ -95,23 +91,20 @@ ingressCollaborationApi:
|
||||
## @param ingress.hosts Additional host to configure for the Ingress
|
||||
hosts: []
|
||||
# - chart-example.local
|
||||
## @param ingressCollaborationApi.tls.enabled Weather to enable TLS for the Ingress
|
||||
## @param ingressCollaborationApi.tls.secretName Secret name for TLS config
|
||||
## @param ingressCollaborationApi.tls.enabled Wether to enable TLS for the Ingress
|
||||
## @skip ingressCollaborationApi.tls.additional
|
||||
## @extra ingressCollaborationApi.tls.additional[].secretName Secret name for additional TLS config
|
||||
## @extra ingressCollaborationApi.tls.additional[].hosts[] Hosts for additional TLS config
|
||||
tls:
|
||||
enabled: true
|
||||
secretName: null
|
||||
additional: []
|
||||
|
||||
## @param ingressCollaborationApi.customBackends Add custom backends to ingress
|
||||
customBackends: []
|
||||
|
||||
annotations:
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/upstream-hash-by: $arg_room
|
||||
|
||||
|
||||
## @param ingressAdmin.enabled whether to enable the Ingress or not
|
||||
## @param ingressAdmin.className IngressClass to use for the Ingress
|
||||
## @param ingressAdmin.host Host for the Ingress
|
||||
@@ -124,14 +117,12 @@ ingressAdmin:
|
||||
## @param ingressAdmin.hosts Additional host to configure for the Ingress
|
||||
hosts: [ ]
|
||||
# - chart-example.local
|
||||
## @param ingressAdmin.tls.enabled Weather to enable TLS for the Ingress
|
||||
## @param ingressAdmin.tls.secretName Secret name for TLS config
|
||||
## @param ingressAdmin.tls.enabled Wether to enable TLS for the Ingress
|
||||
## @skip ingressAdmin.tls.additional
|
||||
## @extra ingressAdmin.tls.additional[].secretName Secret name for additional TLS config
|
||||
## @extra ingressAdmin.tls.additional[].hosts[] Hosts for additional TLS config
|
||||
tls:
|
||||
enabled: true
|
||||
secretName: null
|
||||
additional: []
|
||||
|
||||
## @param ingressMedia.enabled whether to enable the Ingress or not
|
||||
@@ -146,14 +137,12 @@ ingressMedia:
|
||||
## @param ingressMedia.hosts Additional host to configure for the Ingress
|
||||
hosts: [ ]
|
||||
# - chart-example.local
|
||||
## @param ingressMedia.tls.enabled Weather to enable TLS for the Ingress
|
||||
## @param ingressMedia.tls.secretName Secret name for TLS config
|
||||
## @param ingressMedia.tls.enabled Wether to enable TLS for the Ingress
|
||||
## @skip ingressMedia.tls.additional
|
||||
## @extra ingressMedia.tls.additional[].secretName Secret name for additional TLS config
|
||||
## @extra ingressMedia.tls.additional[].hosts[] Hosts for additional TLS config
|
||||
tls:
|
||||
enabled: true
|
||||
secretName: null
|
||||
additional: []
|
||||
|
||||
annotations:
|
||||
@@ -453,4 +442,4 @@ yProvider:
|
||||
extraVolumeMounts: []
|
||||
|
||||
## @param yProvider.extraVolumes Additional volumes to mount on the yProvider.
|
||||
extraVolumes: []
|
||||
extraVolumes: []
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mail_mjml",
|
||||
"version": "1.10.0",
|
||||
"version": "1.9.0",
|
||||
"description": "An util to generate html and text django's templates from mjml templates",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
|
||||
Reference in New Issue
Block a user