Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 17e28c487c | |||
| fbe8a26dba | |||
| 3e974be9f4 | |||
| 10f9d25920 | |||
| 4178693e63 | |||
| 53be6de5f8 | |||
| 4ff90abdee | |||
| 544dd00c16 | |||
| a3cd4c51ea |
@@ -0,0 +1,78 @@
|
||||
---
|
||||
description: Rules for writing Python with Django
|
||||
globs: src/backend/**/*.py
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
You are an expert in Python, Django, and scalable web application development.
|
||||
|
||||
Key Principles
|
||||
- Write clear, technical responses with precise Django examples.
|
||||
- Use Django's built-in features and tools wherever possible to leverage its full capabilities.
|
||||
- Prioritize readability and maintainability; follow Django's coding style guide (PEP 8 compliance for the most part, with the one exception being 100 characters per line instead of 79).
|
||||
- Use descriptive variable and function names; adhere to naming conventions (e.g., lowercase with underscores for functions and variables).
|
||||
|
||||
Django/Python
|
||||
- Use Django REST Framework viewsets for API endpoints.
|
||||
- Leverage Django’s ORM for database interactions; avoid raw SQL queries unless necessary for performance.
|
||||
- Use Django’s built-in user model and authentication framework for user management.
|
||||
- Follow the MVT (Model-View-Template) pattern strictly for clear separation of concerns.
|
||||
- Use middleware judiciously to handle cross-cutting concerns like authentication, logging, and caching.
|
||||
|
||||
Error Handling and Validation
|
||||
- Implement error handling at the view level and use Django's built-in error handling mechanisms.
|
||||
- Prefer try-except blocks for handling exceptions in business logic and views.
|
||||
|
||||
Dependencies
|
||||
- Django
|
||||
- Django REST Framework (for API development)
|
||||
- Celery (for background tasks)
|
||||
- Redis (for caching and task queues)
|
||||
- PostgreSQL (preferred databases for production)
|
||||
- Minio (file storage for production)
|
||||
- OIDC prodiver (for managing authentication)
|
||||
|
||||
Django-Specific Guidelines
|
||||
- Use Django templates for rendering HTML and DRF serializers for JSON responses.
|
||||
- Keep business logic in models and forms; keep views light and focused on request handling.
|
||||
- Use Django's URL dispatcher (urls.py) to define clear and RESTful URL patterns.
|
||||
- Apply Django's security best practices (e.g., CSRF protection, SQL injection protection, XSS prevention).
|
||||
- Use Django’s built-in tools for testing (pytest-django) to ensure code quality and reliability.
|
||||
- Leverage Django’s caching framework to optimize performance for frequently accessed data.
|
||||
- Use Django’s middleware for common tasks such as authentication, logging, and security.
|
||||
|
||||
Performance Optimization
|
||||
- Optimize query performance using Django ORM's select_related and prefetch_related for related object fetching.
|
||||
- Use Django’s cache framework with backend support (e.g., Redis or Memcached) to reduce database load.
|
||||
- Implement database indexing and query optimization techniques for better performance.
|
||||
- Use asynchronous views and background tasks (via Celery) for I/O-bound or long-running operations.
|
||||
- Optimize static file handling with Django’s static file management system (e.g., WhiteNoise).
|
||||
|
||||
Logging
|
||||
- As a general rule, we should have logs for every expected and unexpected actions of the application, using the appropriate log level.
|
||||
- We should also be logging these exceptions to Sentry with the Sentry Python SDK. Python exceptions should almost always be captured automatically without extra instrumentation, but custom ones (such as failed requests to external services, query errors, or Celery task failures) can be tracked using capture_exception().
|
||||
|
||||
Log Levels
|
||||
- A log level or log severity is a piece of information telling how important a given log message is:
|
||||
- DEBUG: should be used for information that may be needed for diagnosing issues and troubleshooting or when running application in the test environment for the purpose of making sure everything is running correctly
|
||||
- INFO: should be used as standard log level, indicating that something happened
|
||||
- WARN: should be used when something unexpected happened but the code can continue the work
|
||||
- ERROR: should be used when the application hits an issue preventing one or more functionalities from properly functioning
|
||||
|
||||
Security
|
||||
- Don’t log sensitive information. Make sure you never log:
|
||||
- authorization tokens
|
||||
- passwords
|
||||
- financial data
|
||||
- health data
|
||||
- PII (Personal Identifiable Information)
|
||||
|
||||
Testing
|
||||
- All new packages and most new significant functionality should come with unit tests
|
||||
|
||||
Unit tests
|
||||
- A good unit test should:
|
||||
- focus on a single use-case at a time
|
||||
- have a minimal set of assertions per test
|
||||
- demonstrate every use case. The rule of thumb is: if it can happen, it should be covered
|
||||
Refer to Django documentation for best practices in views, models, forms, and security considerations.
|
||||
@@ -127,12 +127,9 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name != 'pull_request'
|
||||
steps:
|
||||
-
|
||||
name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
-
|
||||
name: Call argocd github webhook
|
||||
run: |
|
||||
data='{"ref": "'$GITHUB_REF'","repository": {"html_url":"'$GITHUB_SERVER_URL'/${{ secrets.DEPLOYMENT_REPO_URL }}"}}'
|
||||
sig=$(echo -n ${data} | openssl dgst -sha256 -hmac "${{ secrets.ARGOCD_PREPROD_WEBHOOK_SECRET }}" | awk '{print "X-Hub-Signature-256: sha256="$2}')
|
||||
curl -X POST -H 'X-GitHub-Event:push' -H "Content-Type: application/json" -H "${sig}" --data "${data}" ${{ vars.ARGOCD_PREPROD_WEBHOOK_URL }}
|
||||
- uses: numerique-gouv/action-argocd-webhook-notification@main
|
||||
id: notify
|
||||
with:
|
||||
deployment_repo_path: "${{ secrets.DEPLOYMENT_REPO_URL }}"
|
||||
argocd_webhook_secret: "${{ secrets.ARGOCD_PREPROD_WEBHOOK_SECRET }}"
|
||||
argocd_url: "${{ vars.ARGOCD_PREPROD_WEBHOOK_URL }}"
|
||||
|
||||
+11
-3
@@ -8,6 +8,12 @@ and this project adheres to
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## Fixed
|
||||
|
||||
- 🐛(back) validate document content in serializer #822
|
||||
|
||||
## [3.0.0] - 2025-03-28
|
||||
|
||||
## Added
|
||||
|
||||
- 📄(legal) Require contributors to sign a DCO #779
|
||||
@@ -15,13 +21,14 @@ and this project adheres to
|
||||
## Changed
|
||||
|
||||
- ♻️(frontend) Integrate UI kit #783
|
||||
- 🏗️(y-provider) manage auth in y-provider app
|
||||
- 🏗️(y-provider) manage auth in y-provider app #804
|
||||
|
||||
## Fixed
|
||||
|
||||
- 🐛(backend) compute ancestor_links in get_abilities if needed #725
|
||||
- 🔒️(back) restrict access to document accesses #801
|
||||
|
||||
|
||||
## [2.6.0] - 2025-03-21
|
||||
|
||||
## Added
|
||||
@@ -503,8 +510,9 @@ and this project adheres to
|
||||
- ✨(frontend) Coming Soon page (#67)
|
||||
- 🚀 Impress, project to manage your documents easily and collaboratively.
|
||||
|
||||
[unreleased]: https://github.com/numerique-gouv/impress/compare/v2.6.0...main
|
||||
[v2.5.0]: https://github.com/numerique-gouv/impress/releases/v2.6.0
|
||||
[unreleased]: https://github.com/numerique-gouv/impress/compare/v3.0.0...main
|
||||
[v3.0.0]: https://github.com/numerique-gouv/impress/releases/v3.0.0
|
||||
[v2.6.0]: https://github.com/numerique-gouv/impress/releases/v2.6.0
|
||||
[v2.5.0]: https://github.com/numerique-gouv/impress/releases/v2.5.0
|
||||
[v2.4.0]: https://github.com/numerique-gouv/impress/releases/v2.4.0
|
||||
[v2.3.0]: https://github.com/numerique-gouv/impress/releases/v2.3.0
|
||||
|
||||
@@ -24,6 +24,8 @@ Welcome to Docs! The open source document editor where your notes can become kno
|
||||
|
||||
## Why use Docs ❓
|
||||
|
||||
⚠️ **Note that Docs provides docs/pdf exporters by loading [two BlockNote packages](https://github.com/suitenumerique/docs/blob/main/src/frontend/apps/impress/package.json#L22C7-L23C53), which we use under the AGPL-3.0 licence. Until we comply with the terms of this license, we recommend that you don't run Docs as a commercial product, unless you are willing to sponsor [BlockNote](https://github.com/TypeCellOS/BlockNote).**
|
||||
|
||||
Docs is a collaborative text editor designed to address common challenges in knowledge building and sharing.
|
||||
|
||||
### Write
|
||||
|
||||
+12
@@ -16,6 +16,18 @@ the following command inside your docker container:
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
## [3.0.0] - 2025-03-28
|
||||
|
||||
We are not using the nginx auth request anymore to access the collaboration server (`yProvider`)
|
||||
The authentication is now managed directly from the yProvider server.
|
||||
You must remove the annotation `nginx.ingress.kubernetes.io/auth-url` from the `ingressCollaborationWS`.
|
||||
|
||||
This means as well that the yProvider server must be able to access the Django server.
|
||||
To do so, you must set the `COLLABORATION_BACKEND_BASE_URL` environment variable to the `yProvider`
|
||||
service.
|
||||
|
||||
## [2.2.0] - 2025-02-10
|
||||
|
||||
- AI features are now limited to users who are authenticated. Before this release, even anonymous
|
||||
users who gained editor access on a document with link reach used to get AI feature.
|
||||
IF you want anonymous users to keep access on AI features, you must now define the
|
||||
|
||||
+94
@@ -0,0 +1,94 @@
|
||||
# Docs variables
|
||||
|
||||
Here we describe all environment variables that can be set for the docs application.
|
||||
|
||||
## impress-backend container
|
||||
|
||||
These are the environmental variables you can set for the impress-backend container.
|
||||
|
||||
| Option | Description | default |
|
||||
| ----------------------------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
||||
| DJANGO_ALLOWED_HOSTS | allowed hosts | [] |
|
||||
| DJANGO_SECRET_KEY | secret key | |
|
||||
| DJANGO_SERVER_TO_SERVER_API_TOKENS | | [] |
|
||||
| DB_ENGINE | engine to use for database connections | django.db.backends.postgresql_psycopg2 |
|
||||
| DB_NAME | name of the database | impress |
|
||||
| DB_USER | user to authenticate with | dinum |
|
||||
| DB_PASSWORD | password to authenticate with | pass |
|
||||
| DB_HOST | host of the database | localhost |
|
||||
| DB_PORT | port of the database | 5432 |
|
||||
| MEDIA_BASE_URL | | |
|
||||
| STORAGES_STATICFILES_BACKEND | | whitenoise.storage.CompressedManifestStaticFilesStorage |
|
||||
| AWS_S3_ENDPOINT_URL | S3 endpoint | |
|
||||
| AWS_S3_ACCESS_KEY_ID | access id for s3 endpoint | |
|
||||
| AWS_S3_SECRET_ACCESS_KEY | access key for s3 endpoint | |
|
||||
| AWS_S3_REGION_NAME | region name for s3 endpoint | |
|
||||
| AWS_STORAGE_BUCKET_NAME | bucket name for s3 endpoint | impress-media-storage |
|
||||
| DOCUMENT_IMAGE_MAX_SIZE | maximum size of document in bytes | 10485760 |
|
||||
| LANGUAGE_CODE | default language | en-us |
|
||||
| API_USERS_LIST_THROTTLE_RATE_SUSTAINED | throttle rate for api | 180/hour |
|
||||
| API_USERS_LIST_THROTTLE_RATE_BURST | throttle rate for api on burst | 30/minute |
|
||||
| SPECTACULAR_SETTINGS_ENABLE_DJANGO_DEPLOY_CHECK | | false |
|
||||
| TRASHBIN_CUTOFF_DAYS | trashbin cutoff | 30 |
|
||||
| DJANGO_EMAIL_BACKEND | email backend library | django.core.mail.backends.smtp.EmailBackend |
|
||||
| DJANGO_EMAIL_BRAND_NAME | brand name for email | |
|
||||
| DJANGO_EMAIL_HOST | host name of email | |
|
||||
| DJANGO_EMAIL_HOST_USER | user to authenticate with on the email host | |
|
||||
| DJANGO_EMAIL_HOST_PASSWORD | password to authenticate with on the email host | |
|
||||
| DJANGO_EMAIL_LOGO_IMG | logo for the email | |
|
||||
| DJANGO_EMAIL_PORT | port used to connect to email host | |
|
||||
| DJANGO_EMAIL_USE_TLS | use tls for email host connection | false |
|
||||
| DJANGO_EMAIL_USE_SSL | use sstl for email host connection | false |
|
||||
| DJANGO_EMAIL_FROM | email adress used as sender | from@example.com |
|
||||
| DJANGO_CORS_ALLOW_ALL_ORIGINS | allow all CORS origins | true |
|
||||
| DJANGO_CORS_ALLOWED_ORIGINS | list of origins allowed for CORS | [] |
|
||||
| DJANGO_CORS_ALLOWED_ORIGIN_REGEXES | list of origins allowed for CORS using regulair expressions | [] |
|
||||
| SENTRY_DSN | sentry host | |
|
||||
| COLLABORATION_API_URL | collaboration api host | |
|
||||
| COLLABORATION_SERVER_SECRET | collaboration api secret | |
|
||||
| COLLABORATION_WS_URL | collaboration websocket url | |
|
||||
| FRONTEND_THEME | frontend theme to use | |
|
||||
| POSTHOG_KEY | posthog key for analytics | |
|
||||
| CRISP_WEBSITE_ID | crisp website id for support | |
|
||||
| DJANGO_CELERY_BROKER_URL | celery broker url | redis://redis:6379/0 |
|
||||
| DJANGO_CELERY_BROKER_TRANSPORT_OPTIONS | celery broker transport options | {} |
|
||||
| OIDC_CREATE_USER | create used on OIDC | false |
|
||||
| OIDC_RP_SIGN_ALGO | verification algorithm used OIDC tokens | RS256 |
|
||||
| OIDC_RP_CLIENT_ID | client id used for OIDC | impress |
|
||||
| OIDC_RP_CLIENT_SECRET | client secret used for OIDC | |
|
||||
| OIDC_OP_JWKS_ENDPOINT | JWKS endpoint for OIDC | |
|
||||
| OIDC_OP_AUTHORIZATION_ENDPOINT | Autorization endpoint for OIDC | |
|
||||
| OIDC_OP_TOKEN_ENDPOINT | Token endpoint for OIDC | |
|
||||
| OIDC_OP_USER_ENDPOINT | User endpoint for OIDC | |
|
||||
| OIDC_OP_LOGOUT_ENDPOINT | Logout endpoint for OIDC | |
|
||||
| OIDC_AUTH_REQUEST_EXTRA_PARAMS | OIDC extra auth paramaters | {} |
|
||||
| OIDC_RP_SCOPES | scopes requested for OIDC | openid email |
|
||||
| LOGIN_REDIRECT_URL | login redirect url | |
|
||||
| LOGIN_REDIRECT_URL_FAILURE | login redirect url on failure | |
|
||||
| LOGOUT_REDIRECT_URL | logout redirect url | |
|
||||
| OIDC_USE_NONCE | use nonce for OIDC | true |
|
||||
| OIDC_REDIRECT_REQUIRE_HTTPS | Require https for OIDC redirect url | false |
|
||||
| OIDC_REDIRECT_ALLOWED_HOSTS | Allowed hosts for OIDC redirect url | [] |
|
||||
| OIDC_STORE_ID_TOKEN | Store OIDC token | true |
|
||||
| OIDC_FALLBACK_TO_EMAIL_FOR_IDENTIFICATION | faillback to email for identification | true |
|
||||
| OIDC_ALLOW_DUPLICATE_EMAILS | Allow dupplicate emails | false |
|
||||
| USER_OIDC_ESSENTIAL_CLAIMS | essential claims in OIDC token | [] |
|
||||
| USER_OIDC_FIELDS_TO_FULLNAME | OIDC token claims to create full name | ["first_name", "last_name"] |
|
||||
| USER_OIDC_FIELD_TO_SHORTNAME | OIDC token claims to create shortname | first_name |
|
||||
| ALLOW_LOGOUT_GET_METHOD | Allow get logout method | true |
|
||||
| AI_API_KEY | AI key to be used for AI Base url | |
|
||||
| AI_BASE_URL | OpenAI compatible AI base url | |
|
||||
| AI_MODEL | AI Model to use | |
|
||||
| AI_ALLOW_REACH_FROM | Users that can use AI must be this level. options are "public", "authenticated", "restricted" | authenticated |
|
||||
| Y_PROVIDER_API_KEY | Y provider API key | |
|
||||
| Y_PROVIDER_API_BASE_URL | Y Provider url | |
|
||||
| CONVERSION_API_ENDPOINT | Conversion API endpoint | convert-markdown |
|
||||
| CONVERSION_API_CONTENT_FIELD | Conversion api content field | content |
|
||||
| CONVERSION_API_TIMEOUT | Conversion api timeout | 30 |
|
||||
| CONVERSION_API_SECURE | Require secure conversion api | false |
|
||||
| LOGGING_LEVEL_LOGGERS_ROOT | default logging level. options are "DEBUG", "INFO", "WARN", "ERROR", "CRITICAL" | INFO |
|
||||
| LOGGING_LEVEL_LOGGERS_APP | application logging level. options are "DEBUG", "INFO", "WARN", "ERROR", "CRITICAL" | INFO |
|
||||
| API_USERS_LIST_LIMIT | Limit on API users | 5 |
|
||||
| DJANGO_CSRF_TRUSTED_ORIGINS | CSRF trusted origins | [] |
|
||||
| REDIS_URL | cache url | redis://redis:6379/1 |
|
||||
| CACHES_DEFAULT_TIMEOUT | cache default timeout | 30 |
|
||||
+10
-11
@@ -2,7 +2,6 @@
|
||||
|
||||
This document is a step-by-step guide that describes how to install Docs on a k8s cluster without AI features. It's a teaching document to learn how it's work. It needs to be adapt for production environment.
|
||||
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- k8s cluster with an nginx-ingress controller
|
||||
@@ -23,7 +22,7 @@ To be able to use the script, you will need to install:
|
||||
- Helm (https://helm.sh/docs/intro/quickstart/#install-helm)
|
||||
|
||||
```
|
||||
./bin/start-kind.sh
|
||||
./bin/start-kind.sh
|
||||
% Total % Received % Xferd Average Speed Time Time Time Current
|
||||
Dload Upload Total Spent Left Speed
|
||||
100 4700 100 4700 0 0 92867 0 --:--:-- --:--:-- --:--:-- 94000
|
||||
@@ -46,11 +45,11 @@ It will expire on 24 March 2027 🗓
|
||||
2. Create kind cluster with containerd registry config dir enabled
|
||||
Creating cluster "suite" ...
|
||||
✓ Ensuring node image (kindest/node:v1.27.3) 🖼
|
||||
✓ Preparing nodes 📦
|
||||
✓ Writing configuration 📜
|
||||
✓ Starting control-plane 🕹️
|
||||
✓ Installing CNI 🔌
|
||||
✓ Installing StorageClass 💾
|
||||
✓ Preparing nodes 📦
|
||||
✓ Writing configuration 📜
|
||||
✓ Starting control-plane 🕹️
|
||||
✓ Installing CNI 🔌
|
||||
✓ Installing StorageClass 💾
|
||||
Set kubectl context to "kind-suite"
|
||||
You can now use your cluster with:
|
||||
|
||||
@@ -96,9 +95,10 @@ ingress-nginx-admission-create-t55ph 0/1 Completed 0 2m56s
|
||||
ingress-nginx-admission-patch-94dvt 0/1 Completed 1 2m56s
|
||||
ingress-nginx-controller-57c548c4cd-2rx47 1/1 Running 0 2m56s
|
||||
```
|
||||
When your k8s cluster is ready (the ingress nginx controller is up), you can start the deployment. This cluster is special because it uses the *.127.0.0.1.nip.io domain and mkcert certificates to have full HTTPS support and easy domain name management.
|
||||
|
||||
Please remember that *.127.0.0.1.nip.io will always resolve to 127.0.0.1, except in the k8s cluster where we configure CoreDNS to answer with the ingress-nginx service IP.
|
||||
When your k8s cluster is ready (the ingress nginx controller is up), you can start the deployment. This cluster is special because it uses the \*.127.0.0.1.nip.io domain and mkcert certificates to have full HTTPS support and easy domain name management.
|
||||
|
||||
Please remember that \*.127.0.0.1.nip.io will always resolve to 127.0.0.1, except in the k8s cluster where we configure CoreDNS to answer with the ingress-nginx service IP.
|
||||
|
||||
## Preparation
|
||||
|
||||
@@ -227,5 +227,4 @@ impress-docs-ws <none> impress.127.0.0.1.nip.io localhost
|
||||
keycloak <none> keycloak.127.0.0.1.nip.io localhost 80 49m
|
||||
```
|
||||
|
||||
You can use impress on https://impress.127.0.0.1.nip.io. The provisionning user in keycloak is impress/impress.
|
||||
|
||||
You can use impress on https://impress.127.0.0.1.nip.io. The provisionning user in keycloak is impress/impress.
|
||||
@@ -1,6 +1,8 @@
|
||||
"""Client serializers for the impress core app."""
|
||||
|
||||
import binascii
|
||||
import mimetypes
|
||||
from base64 import b64decode
|
||||
|
||||
from django.conf import settings
|
||||
from django.db.models import Q
|
||||
@@ -299,6 +301,18 @@ class DocumentSerializer(ListDocumentSerializer):
|
||||
|
||||
return value
|
||||
|
||||
def validate_content(self, value):
|
||||
"""Validate the content field."""
|
||||
if not value:
|
||||
return None
|
||||
|
||||
try:
|
||||
b64decode(value, validate=True)
|
||||
except binascii.Error as err:
|
||||
raise serializers.ValidationError("Invalid base64 content.") from err
|
||||
|
||||
return value
|
||||
|
||||
def save(self, **kwargs):
|
||||
"""
|
||||
Process the content field to extract attachment keys and update the document's
|
||||
|
||||
@@ -328,3 +328,22 @@ def test_api_documents_update_administrator_or_owner_of_another(via, mock_user_t
|
||||
other_document.refresh_from_db()
|
||||
other_document_values = serializers.DocumentSerializer(instance=other_document).data
|
||||
assert other_document_values == old_document_values
|
||||
|
||||
|
||||
def test_api_documents_update_invalid_content():
|
||||
"""
|
||||
Updating a document with a non base64 encoded content should raise a validation error.
|
||||
"""
|
||||
user = factories.UserFactory(with_owned_document=True)
|
||||
client = APIClient()
|
||||
client.force_login(user)
|
||||
|
||||
document = factories.DocumentFactory(users=[[user, "owner"]])
|
||||
|
||||
response = client.put(
|
||||
f"/api/v1.0/documents/{document.id!s}/",
|
||||
{"content": "invalid content"},
|
||||
format="json",
|
||||
)
|
||||
assert response.status_code == 400
|
||||
assert response.json() == {"content": ["Invalid base64 content."]}
|
||||
|
||||
@@ -7,7 +7,7 @@ build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "impress"
|
||||
version = "2.6.0"
|
||||
version = "3.0.0"
|
||||
authors = [{ "name" = "DINUM", "email" = "dev@mail.numerique.gouv.fr" }]
|
||||
classifiers = [
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-e2e",
|
||||
"version": "2.6.0",
|
||||
"version": "3.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"lint": "eslint . --ext .ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "app-impress",
|
||||
"version": "2.6.0",
|
||||
"version": "3.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
|
||||
@@ -161,6 +161,7 @@ export const ModalExport = ({ onClose, doc }: ModalExportProps) => {
|
||||
</Text>
|
||||
<Select
|
||||
clearable={false}
|
||||
fullWidth
|
||||
label={t('Template')}
|
||||
options={templateOptions}
|
||||
value={templateSelected}
|
||||
|
||||
@@ -21,9 +21,11 @@ describe('useSWRegister', () => {
|
||||
reject('error');
|
||||
}),
|
||||
);
|
||||
|
||||
Object.defineProperty(navigator, 'serviceWorker', {
|
||||
value: {
|
||||
register: registerSpy,
|
||||
addEventListener: jest.fn(),
|
||||
},
|
||||
writable: true,
|
||||
});
|
||||
@@ -31,6 +33,10 @@ describe('useSWRegister', () => {
|
||||
render(<TestComponent />);
|
||||
|
||||
expect(registerSpy).toHaveBeenCalledWith('/service-worker.js?v=123456');
|
||||
expect(navigator.serviceWorker.addEventListener).toHaveBeenCalledWith(
|
||||
'controllerchange',
|
||||
expect.any(Function),
|
||||
);
|
||||
});
|
||||
|
||||
it('checks service-worker is not register', () => {
|
||||
|
||||
@@ -8,9 +8,33 @@ export const useSWRegister = () => {
|
||||
) {
|
||||
navigator.serviceWorker
|
||||
.register(`/service-worker.js?v=${process.env.NEXT_PUBLIC_BUILD_ID}`)
|
||||
.then((registration) => {
|
||||
registration.onupdatefound = () => {
|
||||
const newWorker = registration.installing;
|
||||
if (!newWorker) {
|
||||
return;
|
||||
}
|
||||
|
||||
newWorker.onstatechange = () => {
|
||||
if (
|
||||
newWorker.state === 'installed' &&
|
||||
navigator.serviceWorker.controller
|
||||
) {
|
||||
newWorker.postMessage({ type: 'SKIP_WAITING' });
|
||||
}
|
||||
};
|
||||
};
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Service worker registration failed:', err);
|
||||
});
|
||||
|
||||
const currentController = navigator.serviceWorker.controller;
|
||||
navigator.serviceWorker.addEventListener('controllerchange', () => {
|
||||
if (currentController) {
|
||||
window.location.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
}, []);
|
||||
};
|
||||
|
||||
@@ -65,6 +65,13 @@ self.addEventListener('install', function (event) {
|
||||
event.waitUntil(self.skipWaiting());
|
||||
});
|
||||
|
||||
self.addEventListener('message', (event) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
|
||||
if (event.data?.type === 'SKIP_WAITING') {
|
||||
void self.skipWaiting();
|
||||
}
|
||||
});
|
||||
|
||||
self.addEventListener('activate', function (event) {
|
||||
const cacheAllow = SW_VERSION;
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "impress",
|
||||
"version": "2.6.0",
|
||||
"version": "3.0.0",
|
||||
"private": true,
|
||||
"workspaces": {
|
||||
"packages": [
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "eslint-config-impress",
|
||||
"version": "2.6.0",
|
||||
"version": "3.0.0",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"lint": "eslint --ext .js ."
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "packages-i18n",
|
||||
"version": "2.6.0",
|
||||
"version": "3.0.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"extract-translation": "yarn extract-translation:impress",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "server-y-provider",
|
||||
"version": "2.6.0",
|
||||
"version": "3.0.0",
|
||||
"description": "Y.js provider for docs",
|
||||
"repository": "https://github.com/numerique-gouv/impress",
|
||||
"license": "MIT",
|
||||
|
||||
@@ -124,6 +124,7 @@ yProvider:
|
||||
tag: "latest"
|
||||
|
||||
envVars:
|
||||
COLLABORATION_BACKEND_BASE_URL: https://impress.127.0.0.1.nip.io
|
||||
COLLABORATION_LOGGING: true
|
||||
COLLABORATION_SERVER_ORIGIN: https://impress.127.0.0.1.nip.io
|
||||
COLLABORATION_SERVER_SECRET: my-secret
|
||||
@@ -136,9 +137,6 @@ ingress:
|
||||
ingressCollaborationWS:
|
||||
enabled: true
|
||||
host: impress.127.0.0.1.nip.io
|
||||
|
||||
annotations:
|
||||
nginx.ingress.kubernetes.io/auth-url: https://impress.127.0.0.1.nip.io/api/v1.0/documents/collaboration-auth/
|
||||
|
||||
ingressCollaborationApi:
|
||||
enabled: true
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
environments:
|
||||
dev:
|
||||
values:
|
||||
- version: 2.6.0
|
||||
- version: 3.0.0
|
||||
---
|
||||
repositories:
|
||||
- name: bitnami
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
apiVersion: v2
|
||||
type: application
|
||||
name: docs
|
||||
version: 2.6.0
|
||||
version: 3.0.0
|
||||
appVersion: latest
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "mail_mjml",
|
||||
"version": "2.6.0",
|
||||
"version": "3.0.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