#!/usr/bin/env python3 """Cree un space etudiant prive dans Docmost — pattern story S-08. Usage : DOCMOST_URL=http://localhost:3000 \\ DOCMOST_ADMIN_EMAIL=corentin@acadenice.fr \\ DOCMOST_ADMIN_PASSWORD=... \\ python docmost/setup/create-space-etudiant.py \\ --nom "Dupont" --prenom "Marie" --email "marie.dupont@acadenice.fr" Cree : - Un space "Etudiant - Marie Dupont" en visibility=private - Y invite l'etudiant en role 'writer' - Cree une page template "Bienvenue" avec instructions Idempotent : skip si space existe deja. """ import argparse import os import sys from typing import Any import requests class DocmostSpaceCreator: def __init__(self, base_url: str) -> None: self.base_url = base_url.rstrip("/") self.session = requests.Session() self.session.headers.update({"Content-Type": "application/json"}) def _post(self, path: str, body: dict[str, Any] | None = None) -> dict[str, Any]: r = self.session.post(f"{self.base_url}{path}", json=body or {}) if r.status_code >= 300: print(f" [ERROR] POST {path} → {r.status_code} resp={r.text[:300]}") r.raise_for_status() if not r.text: return {} payload = r.json() if isinstance(payload, dict) and "data" in payload and isinstance(payload["data"], (dict, list)): return payload["data"] return payload def login(self, email: str, password: str) -> None: self._post("/api/auth/login", {"email": email, "password": password}) print(f" [auth] Logged in as {email}") def list_spaces(self) -> list[dict[str, Any]]: try: data = self._post("/api/spaces/", {"page": 1, "limit": 100}) if isinstance(data, dict): return data.get("items") or [] if isinstance(data, list): return data except requests.HTTPError: pass return [] def create_space(self, name: str, description: str, slug: str, visibility: str = "private") -> str: result = self._post( "/api/spaces/create", {"name": name, "description": description, "slug": slug, "visibility": visibility}, ) return result.get("id") def add_member_by_email(self, space_id: str, email: str, role: str = "writer") -> dict[str, Any] | None: try: return self._post( "/api/spaces/members/add", {"spaceId": space_id, "userEmails": [email], "role": role}, ) except requests.HTTPError as e: print(f" [member] Echec ajout {email} : {e}") print(f" (l'etudiant doit deja exister comme user Docmost. Sinon, l'inviter d'abord via UI ou API user/create.)") return None def create_page(self, space_id: str, title: str, content_md: str) -> str: result = self._post( "/api/pages/create", {"spaceId": space_id, "title": title, "format": "markdown", "content": content_md}, ) return result.get("id") def welcome_template(prenom: str, nom: str) -> str: return f"""# Bienvenue {prenom} ! Voici ton **espace personnel** sur le wiki Acadenice. Il est **prive** : seul toi et l'admin peuvent le voir. ## Tu peux faire ce que tu veux ici - Prendre des notes pendant les cours - Garder tes ressources perso (liens, references, brouillons) - Tester les fonctionnalites du wiki : - `/mermaid` pour faire un diagramme - `/excalidraw` pour dessiner - `/drawio` pour des schemas techniques - Liste, tableaux, code blocks, embeds video, etc. ## Quelques idees pour commencer - Cree une page "Mes objectifs formation" - Une page par module avec tes notes - Un journal d'apprentissage hebdomadaire ## Acces aux supports formation Les supports officiels sont dans le space **CFA** (lecture seule pour toi). Bonne formation ! — L'equipe Acadenice """ def slugify(s: str) -> str: """Docmost exige slug = lettres + chiffres uniquement.""" import re return re.sub(r"[^a-z0-9]", "", s.lower()) def main() -> int: parser = argparse.ArgumentParser(description="Cree un space etudiant Docmost") parser.add_argument("--nom", required=True) parser.add_argument("--prenom", required=True) parser.add_argument("--email", required=True, help="Email de l'etudiant (doit exister comme user Docmost)") parser.add_argument("--no-template", action="store_true", help="Ne pas creer la page Bienvenue") args = parser.parse_args() base_url = os.environ.get("DOCMOST_URL", "http://localhost:3000") admin_email = os.environ.get("DOCMOST_ADMIN_EMAIL") admin_password = os.environ.get("DOCMOST_ADMIN_PASSWORD") if not admin_email or not admin_password: print("ERROR: set DOCMOST_ADMIN_EMAIL and DOCMOST_ADMIN_PASSWORD", file=sys.stderr) return 1 creator = DocmostSpaceCreator(base_url) space_name = f"Etudiant - {args.prenom} {args.nom}" slug = slugify(f"etudiant-{args.prenom}-{args.nom}") try: print(f"\n[1/4] Login admin") creator.login(admin_email, admin_password) print(f"\n[2/4] Check existing space '{space_name}'") existing = next((s for s in creator.list_spaces() if s.get("slug") == slug or s.get("name") == space_name), None) if existing: sid = existing["id"] print(f" [space] Reuse id={sid}") else: sid = creator.create_space( name=space_name, description=f"Space personnel de {args.prenom} {args.nom}. Libre usage.", slug=slug, visibility="private", ) print(f" [space] Created id={sid}") print(f"\n[3/4] Add etudiant {args.email} as writer") creator.add_member_by_email(sid, args.email, role="writer") if not args.no_template: print(f"\n[4/4] Welcome page template") try: creator.create_page(sid, "Bienvenue", welcome_template(args.prenom, args.nom)) print(f" [page] Created Bienvenue") except requests.HTTPError as e: print(f" [page] Skip (peut-etre deja existante) : {e}") print(f"\n=== Space etudiant OK ===") print(f" Name : {space_name}") print(f" Slug : {slug}") print(f" URL : {base_url} (login {args.email})") except requests.HTTPError as e: print(f"\nHTTP error: {e}", file=sys.stderr) return 2 return 0 if __name__ == "__main__": sys.exit(main())