Skip to main content
Espace documentaire

Connecteur NextCloud et chaîne d'édition en ligne

Cette page décrit l’architecture et le fonctionnement des composants qui étendent l’espace documentaire de l’ENT :

  • le connecteur Nextcloud pour la synchronisation des fichiers,
  • le connecteur lool pour l’intégration WOPI
Fiche fonctionnelle

Ce que voit l'utilisateur : Espace documentaire.

Vue d'ensemble

Trois chemins d'accès à un fichier coexistent, avec des stockages différents :

CheminOù est le fichierModule ENTProtocole
Espace documentaire natifstorage de l'ENT (gridfs/disque)workspace (entcore)interne
Documents synchronisésserveur NextCloudfr.openent~nextcloudOCS + WebDAV
Édition en ligne d'un document natifstorage de l'ENTfr.openent~loolWOPI
Édition en ligne d'un document synchroniséserveur NextCloudapp NextCloud richdocumentsWOPI (interne à NextCloud)

Le point à retenir : c'est le serveur d'édition qui rappelle l'ENT (server-to-server) pour lire et écrire le document. L'adresse par laquelle il rappelle — le WOPISrc — doit être explicitement autorisée côté Collabora, faute de quoi le document refuse de s'ouvrir.

Activation / désactivation

Deux interrupteurs indépendants, tous deux dans le bloc config du module workspace de ent-core.yaml (même fichier utilisé en développement et poussé en production via le chart Helm) :

CléContrôleEffet si false / vide
enable-nextcloudl'entrée « Documents synchronisés » dans l'arbre de l'espace documentaire (workspace.html, variable ENABLE_NEXTCLOUD injectée côté serveur)l'entrée disparaît de l'espace documentaire lui-même
publicConf.folder-servicela liste des fournisseurs proposés par le picker réutilisable (directive virtual-media-library, utilisé pour joindre une pièce depuis diary, edt, calendar…)retirer nextcloud de la liste masque NextCloud dans ce picker
- name: org.entcore~workspace~${ENTCORE_VERSION}-patched
config:
enable-nextcloud: false
publicConf:
folder-service: [] # retirer "nextcloud" de la liste ; laisser les autres fournisseurs
Deux interrupteurs, pas un

Les deux clés sont indépendantes : n'en changer qu'une laisse NextCloud visible dans un des deux écrans. folder-service est une liste statique (pas de condition possible dans le YAML) — elle n'est pas recalculée à partir de enable-nextcloud, il faut l'éditer explicitement en miroir.

Désactiver ces deux clés ne retire pas le connecteur : le module fr.openent~nextcloud reste déclaré et ses routes /nextcloud/* répondent toujours. Un utilisateur sans droit qui accède directement à une URL du module obtient la page d'erreur générique 401 (e401.page), pas une 404 — c'est attendu (comportement identique à n'importe quel module ENT sans droit attribué), pas un bug. Pour retirer le connecteur lui-même (plus aucune route, y compris ce 401), il faut supprimer le bloc - name: fr.openent~nextcloud~${...} d'ent-core.yaml.

Côté Helm, nextcloud.enabled (values.yaml) est un troisième réglage, sans rapport avec les deux précédents : il pilote uniquement le déploiement de l'infrastructure NextCloud interne au chart (pod, base de données, Collabora) — utile si l'ENT ne se connecte pas à un serveur NextCloud externe. Il n'a aucun effet sur la visibilité de la fonctionnalité dans l'interface.

Connecteur NextCloud (fr.openent~nextcloud)

Module Vert.x, port 8060, chemin /nextcloud. Il ne stocke aucun fichier : il agit comme mandataire authentifié entre l'utilisateur ENT et un serveur NextCloud.

Configuration (ent-core.yaml)

CléRôle
nextcloud-hostURL du serveur NextCloud (variable NEXTCLOUD_HOST)
admin-credentialcompte d'administration NextCloud, utilisé pour le provisioning OCS
endpoint.ocs-api / endpoint.webdav-apipréfixes d'API (/ocs/v1.php, /remote.php/dav/files)
quotaquota appliqué aux comptes créés
is-nextcloud-url-hiddenmasque l'URL NextCloud dans l'interface
nextcloud-providersune entrée par host ENT (voir ci-dessous)
db-schema: nextcloudschéma PostgreSQL du connecteur

nextcloud-providers mérite une explication : le connecteur résout sa configuration par host de la requête (nextcloudConfigMapByHost). Sans entrée correspondant au host reçu, la résolution renvoie null et la requête échoue en 500 sans trace. Tout alias par lequel l'ENT peut être joint doit donc y figurer.

Comptes et sessions

Le connecteur crée le compte NextCloud à la volée puis conserve un mot de passe d'application dans PostgreSQL :

CREATE TABLE nextcloud.user (
id bigserial NOT NULL,
user_id varchar(255) NOT NULL, -- identifiant ENT
username varchar(255) NOT NULL, -- identifiant NextCloud
password varchar(255) NOT NULL, -- jeton de session applicatif
last_modified timestamp DEFAULT now(),
PRIMARY KEY (user_id)
);

DefaultUserService.provideUserSession vérifie la validité du jeton stocké ; s'il est périmé, il régénère une session (changeUserPassword + OCS) ; si le compte n'existe pas encore, il le crée (/cloud/users). L'utilisateur ne saisit jamais de mot de passe NextCloud.

Principaux points d'entrée

RouteUsage
GET /nextcloud/files/user/:useridlister un dossier (WebDAV PROPFIND)
PUT /nextcloud/files/user/:userid/uploaddéposer un fichier
GET /nextcloud/files/user/:userid/editouvrir en édition (Direct Editing NextCloud)
POST /nextcloud/files/user/:userid/sharepartage nominatif (OCS files_sharing)
POST /nextcloud/files/user/:userid/create/documentcréer un document Office vierge (docx/xlsx/pptx) à partir d'un modèle
PUT …/workspace/move/cloud, PUT …/move/workspacetransferts espace ENT ↔ espace synchronisé
GET/PUT /nextcloud/desktop/config[/structure/:id]réglages nationaux / par établissement
GET /nextcloud/admin/share-structurespartage inter-établissements

create/document fonctionne comme la création côté lool (mêmes modèles vierges docx/xlsx/ pptx, réutilisés depuis public/nextcloud-templates/) : le fichier modèle est stocké temporairement dans le Storage de l'ENT (storage.writeBuffer), puis déposé sur NextCloud via WebDAV (uploadFile, deleteFromStorage=true — pas de copie durable côté ENT). Le type de fichier est validé contre une liste blanche stricte (docx/xlsx/pptx) côté contrôleur avant toute lecture disque, type alimentant directement le chemin du modèle.

Réglages hérités et extensions interdites

La résolution établissement > national > défaut (extensions bloquées, nom du dossier synchronisé, bande passante) est décrite dans Détails techniques — Espace documentaire.

Connecteur lool (WOPI direct)

Module Vert.x, port 8333, chemin /lool. Il permet d'éditer dans le navigateur un document resté dans le storage de l'ENT : aucun stockage externe, aucune copie côté NextCloud.

Configuration

- name: fr.openent~lool~${LOOL_VERSION}
config:
port: 8333
app-address: /lool
wopi:
provider:
type: ${LOOL_WOPI_TYPE} # LibreOfficeOnline | OnlyOffice
url: ${LOOL_WOPI_URL} # URL du serveur d'édition
hour-duration-token: 10
templates: [docx, pptx, xlsx]

templates pilote les modèles proposés à la création. Le défaut du fournisseur LibreOfficeOnline ([odt, odp, ods]) laisse les cartes Word/PowerPoint/Excel non sélectionnables côté interface, qui ne reconnaît que docx/pptx/xlsx.

Côté workspace, l'affichage dépend de deux conditions : enable-lool: true dans la configuration, et le droit workflow de l'utilisateur.

Déroulé d'une ouverture

  1. L'utilisateur sélectionne un document et clique ÉditerGET /lool/documents/:id/open.
  2. Le connecteur génère un jeton WOPI (Mongo wopi_token, durée hour-duration-token), lit l'urlsrc correspondant au type de fichier dans la collection lool_discover, et rend la vue doc.html qui porte l'iframe de l'éditeur.
  3. Le serveur d'édition rappelle le connecteur avec le jeton : GET /lool/wopi/files/:id (métadonnées), GET …/contents (lecture), POST …/contents (enregistrement).
  4. À la fermeture, le jeton est révoqué (DELETE /lool/wopi/documents/:id/tokens/:token, ou POST du même chemin via sendBeacon).

La collection lool_discover est alimentée au démarrage par un GET /hosting/discovery sur le serveur d'édition. Cet appel est serveur→serveur, mais LOOL_WOPI_URL doit malgré tout porter l'URL publique de Collabora : la même variable compose le frame-src de la content-security-policy (ent-core.yaml), et l'iframe de l'éditeur pointe sur le host public issu de l'attribut urlsrc du discovery. Avec une URL interne, le discovery aboutit — capacités remontées, route en 200 — mais le navigateur refuse le cadre :

Framing 'https://collabora…' violates the Content Security Policy directive: "frame-src …"

Le symptôme est trompeur : page de l'éditeur servie normalement, aucune erreur serveur, et un cadre vide.

Points d'entrée

RouteDroitUsage
GET /loolworkflow viewpage du module
GET /lool/modal/createauthentifiéfenêtre de création (iframe ouverte par le workspace sur #/lool)
GET /lool/document · POST /lool/documentworkflow create.documentcréer un document bureautique
GET /lool/documents/:id/openworkflow open.fileouvrir un document dans l'éditeur
GET /lool/providers/contextauthentifiéfournisseur, capacités issues du discovery, modèles
GET /lool/discoversuper-administrateurrelancer le discovery
GET/POST /lool/wopi/files/:id[/contents]jeton WOPIdialogue avec le serveur d'édition

Droits

Le module déclare quatre actions (view, open.file, create.document, monitoring) et trois rôles (Lecture, Gestion, Administration). Comme pour tout module ENT, ces rôles doivent être attribués à des groupes de profils dans la console d'administration : tant qu'aucun groupe n'est rattaché, le bouton Éditer n'apparaît pas dans l'espace documentaire, alors même que le connecteur répond correctement.

Serveur d'édition (Collabora)

coolwsd n'accepte de servir un document que si l'hôte qui a émis le WOPISrc figure dans un de ses aliasgroupN. Deux appelants coexistent donc :

VariableHôtes attendusÉmetteur du WOPISrc
aliasgroup1hosts NextCloud (public + service interne)app richdocuments de NextCloud
aliasgroup2hosts de l'ENTconnecteur lool

Chaque variable vaut une liste d'URLs scheme://host séparées par des virgules : la première est l'hôte du groupe, les suivantes ses alias. coolwsd en extrait le nom d'hôte en analysant l'URL, puis compare ce nom d'hôte à l'entrée prise comme expression régulière — les points sont donc échappés, mais le schéma doit rester littéral. Un https?:// (tentant, pour couvrir les deux protocoles) empêche l'analyse : plus aucune règle n'est enregistrée.

Un alias manquant — ou rendu illisible de cette façon — produit « Hôte WOPI non autorisé » côté éditeur, avec dans le journal de Collabora :

No authorized hosts found matching the target host [www.exemple.fr] in config

Le même écran apparaît sur une simple erreur réseau, d'où la confusion fréquente : c'est le journal qui tranche.

Déploiement Kubernetes

Le chart openent-monolithe déploie NextCloud, MariaDB, Collabora (et éventuellement OnlyOffice) et câble l'ensemble automatiquement :

RéglageEffet
nextcloud.enableddéploie la brique et injecte NEXTCLOUD_HOST / identifiants admin dans le launcher
nextcloud.collabora.exposepath (sous le host NextCloud) ou host (domaine dédié)
nextcloud.collabora.entAliaseshosts de l'ENT pour aliasgroup2 — vide = tous les ingress.hosts
nextcloud.collabora.allowEntWopifalse réserve Collabora à NextCloud (pas d'aliasgroup2)
nextcloud.collabora.loolProviderUrlvaleur de LOOL_WOPI_URL — vide = URL publique de Collabora (requis par le frame-src)

Le routage /lool (port 8333) et /nextcloud (port 8060) est déclaré dans service.modules, qui génère à la fois les ports du Service et les règles d'Ingress pour chaque domaine.

En développement, dev/nextcloud/docker-compose.yml reproduit la même topologie : un nginx place NextCloud et Collabora derrière une URL unique, et Collabora tourne en network_mode: host pour que localhost désigne la même machine dans le conteneur et dans le navigateur.

Diagnostic

SymptômeCause probableVérification
/lool/... en 404 ou 502module non routé (Ingress/Service) ou non démarréGET /lool/providers/context doit répondre 200
Capacités vides dans providers/contextdiscovery en échec (serveur d'édition injoignable)journal du module : LibreOfficeOnline discover wopi1 OK
« Hôte WOPI non autorisé »aliasgroup incomplet ou schéma non analysablejournal Collabora : « No authorized hosts found matching… »
Bouton Éditer absentdroit workflow lool.openFile non attribuéconsole d'administration, rôles lool
Éditeur ouvert mais cadre videframe-src de la CSP sans le host public de Collabora (LOOL_WOPI_URL interne)console du navigateur : « violates … frame-src »
500 sans trace sur /nextcloud/...host absent de nextcloud-providersconfiguration du module
Documents synchronisés videssession NextCloud périmée ou compte non provisionnétable nextcloud.user

Couverture de tests

Scénarios e2e du dossier apps/open-ent-e2e/src/modules/12_espace_documentaire couvrant ces briques :

  • 06_documents_synchronises_acces.spec.ts — accès à l'espace synchronisé (connecteur NextCloud) ;
  • 07_partage_nominatif.spec.ts — partage OCS entre deux comptes ENT ;
  • 08_edition_en_ligne.spec.ts — édition d'un document stocké dans NextCloud (Direct Editing) ;
  • 09_blocage_extensions_dangereuses.spec.ts — refus des extensions interdites ;
  • 10_edition_document_natif_lool.spec.ts — connecteur lool : fournisseur WOPI joignable, discovery abouti, ouverture d'un document natif de l'ENT dans l'éditeur.
  • 11_creation_document_nextcloud.spec.ts — bouton « Créer un document » : création d'un docx à partir d'un modèle, ouverture immédiate dans l'éditeur en ligne.
Limitation Playwright connue (session fraîche)

06, 08 et 11 dépendent du nœud « Documents synchronisés » dans l'arbre du workspace. Ce nœud est invisible en session Playwright fraîche (jamais utilisée manuellement au préalable pour le même compte), alors qu'il fonctionne normalement en navigateur réel — cause non identifiée à ce jour (registre applicatif ? préférence utilisateur initialisée seulement après une première vraie interaction ?). Les trois tests skippent proprement (pas d'échec) plutôt que d'échouer dans ce cas ; 11_creation_document_nextcloud.spec.ts a été validé manuellement (backend + interface) faute de pouvoir produire les captures automatiques tant que ce point n'est pas résolu.