From 75e99dd0b85611ff29e6d7a6e60c9b8cab449205 Mon Sep 17 00:00:00 2001 From: Jan-Hendrik Stobbe Date: Mon, 31 Aug 2026 07:58:20 +0200 Subject: [PATCH] humhub: Umfragen anlegen und auflisten (poll-create / poll-list) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Die Polls-REST-API ist auf der Instanz aktiv, der Skill kannte sie nicht. Zwei Abweichungen vom Muster der Post-API, die beide in HTTP 500 'Internal error while save a poll!' enden: * Der Controller macht $poll->load(Yii::$app->request->post()) — die Felder gehoeren unter den Yii-Formnamen 'Poll', nicht unter 'data'. * Die Optionen heissen beim Anlegen 'newAnswers'; 'answers' ist die Leseform und wird beim POST ignoriert. Beim Lesen ist limit Pflicht: ohne Begrenzung antwortet die Instanz ab etwa 25 Umfragen ebenfalls mit 500. Quelle: humhub/polls, controllers/rest/PollsController.php + models/Poll.php. Verifiziert an Space inmedias (Umfrage 36). Co-Authored-By: Claude Opus 5 (1M context) --- .gitignore | 6 ++ README.md | 5 +- plugins/humhub/.claude-plugin/plugin.json | 4 +- plugins/humhub/skills/humhub/SKILL.md | 27 +++++++- plugins/humhub/skills/humhub/humhub.py | 76 +++++++++++++++++++++++ 5 files changed, 111 insertions(+), 7 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1df7ae6 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Python +__pycache__/ +*.py[cod] + +# lokale Umgebungs-/Secret-Dateien +.env diff --git a/README.md b/README.md index 9b53c6a..366d1fc 100644 --- a/README.md +++ b/README.md @@ -79,9 +79,10 @@ natürlicher klingen. Basiert auf Wikipedias „Signs of AI writing". ### humhub -HumHub (humhub.inmedias.it) über die REST-API: Wiki-Seiten und Posts auflisten, +HumHub (humhub.inmedias.it) über die REST-API: Wiki-Seiten, Posts und Umfragen auflisten, anzeigen, anlegen und aktualisieren — via mitgelieferter, self-contained -`humhub.py` (`wiki-list/get/update/create`, `post-list/create/update`). +`humhub.py` (`wiki-list/get/update/create`, `post-list/create/update`, +`poll-list/create`). - Voraussetzung: `HUMHUB_API_TOKEN` als Umgebungsvariable bzw. dotenv-Datei (kein Token im Plugin). Token nur als berechtigter Benutzer unter diff --git a/plugins/humhub/.claude-plugin/plugin.json b/plugins/humhub/.claude-plugin/plugin.json index 5ade752..ed8e959 100644 --- a/plugins/humhub/.claude-plugin/plugin.json +++ b/plugins/humhub/.claude-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "humhub", - "version": "0.1.0", - "description": "HumHub via REST-API: Wiki-Seiten und Posts auflisten, anzeigen, anlegen und aktualisieren (humhub.py).", + "version": "0.2.0", + "description": "HumHub via REST-API: Wiki-Seiten, Posts und Umfragen auflisten, anzeigen, anlegen und aktualisieren (humhub.py).", "author": { "name": "inmedias.it" } diff --git a/plugins/humhub/skills/humhub/SKILL.md b/plugins/humhub/skills/humhub/SKILL.md index b6ff490..7463e2d 100644 --- a/plugins/humhub/skills/humhub/SKILL.md +++ b/plugins/humhub/skills/humhub/SKILL.md @@ -1,13 +1,13 @@ --- name: humhub -description: HumHub Wiki-Seiten und Posts lesen/erstellen/aktualisieren via REST-API. Use when the user mentions "HumHub", "Space", "Wiki-Seite in HumHub" or "Post/Beitrag". -version: 0.1.0 +description: HumHub Wiki-Seiten, Posts und Umfragen lesen/erstellen/aktualisieren via REST-API. Use when the user mentions "HumHub", "Space", "Wiki-Seite in HumHub", "Post/Beitrag" or "Umfrage/Poll". +version: 0.2.0 --- # HumHub (humhub.py) Interagiert mit HumHub (https://humhub.inmedias.it) über die REST-API: -Wiki-Seiten und Posts auflisten, anzeigen, anlegen und aktualisieren — über die +Wiki-Seiten, Posts und Umfragen auflisten, anzeigen, anlegen und aktualisieren — über die mitgelieferte, self-contained `humhub.py`. ## Ausführen @@ -59,6 +59,27 @@ werden nicht committet). ./humhub.py post-update [datei|-] ``` +### Umfragen + +```bash +./humhub.py poll-list [--limit N] +./humhub.py poll-create "" --answers "A|B|C" \ + [--file beschreibung.md] [--anonymous] [--multiple] [--hide-results] +``` + +Antwortoptionen mit `|` trennen, mindestens zwei. Der Beschreibungstext kommt +wie überall aus einer Datei oder `-`; Markdown ist erlaubt. Ohne `--anonymous` +ist sichtbar, wer wie gestimmt hat — bei Anmeldungen mit begrenzten Plätzen ist +das der Sinn der Sache. + +Zwei Eigenheiten der Polls-API, die zu `HTTP 500 "Internal error while save a +poll!"` führen, wenn man dem Muster der Post-API folgt: die Felder gehören +unter den Yii-Formnamen **`Poll`** (nicht `data`), und die Optionen heißen beim +Anlegen **`newAnswers`** (beim Lesen `answers`). Beim Lesen ist `limit` Pflicht +und nicht Komfort — ohne Begrenzung antwortet die Instanz ab ~25 Umfragen +ebenfalls mit 500. Ein fehlgeschlagener POST legt nichts an; vor einem zweiten +Versuch trotzdem mit `poll-list` prüfen. + Inhalte (Markdown) aus Datei oder `-` (stdin) übergeben — nicht als langes Shell-Argument (Sonderzeichen). `container_id` akzeptiert eine numerische Container-ID, einen **Space-Slug** oder eine **Space-URL** (`resolve_container` diff --git a/plugins/humhub/skills/humhub/humhub.py b/plugins/humhub/skills/humhub/humhub.py index 8219c79..03597ec 100755 --- a/plugins/humhub/skills/humhub/humhub.py +++ b/plugins/humhub/skills/humhub/humhub.py @@ -212,6 +212,61 @@ def cmd_post_create(args: argparse.Namespace) -> None: print(f"Topics: {', '.join(saved_topics)}") +def cmd_poll_list(args: argparse.Namespace) -> None: + session, _ = get_session() + container_id = resolve_container(session, args.container_id) + # limit ist Pflicht, nicht Komfort: ohne Begrenzung antwortet die Instanz + # bei vielen Umfragen mit HTTP 500 statt mit einer Liste. + data = api_get(session, f"/polls/container/{container_id}?limit={args.limit}") + results = data.get("results", []) + if not results: + print("(keine Umfragen)") + return + for poll in results: + antworten = [a.get("answer", "") for a in poll.get("answers", [])] + zu = " [geschlossen]" if poll.get("closed") else "" + print(f"ID {poll.get('id')}{zu}: {poll.get('question', '')}") + print(f" {' | '.join(antworten)}") + + +def cmd_poll_create(args: argparse.Namespace) -> None: + """Umfrage anlegen. + + Zwei Abweichungen von der Post-API, die beide mit HTTP 500 + ("Internal error while save a poll!") enden, wenn man sie übersieht: + + * Der Controller macht `$poll->load(Yii::$app->request->post())` — Yii + erwartet die Felder deshalb unter dem Formnamen **`Poll`**, nicht unter + `data` wie bei Posts und Wiki-Seiten. + * Die Optionen heißen beim Anlegen **`newAnswers`**; `answers` ist die + Leseform und wird beim POST ignoriert. + + Quelle: humhub/polls, controllers/rest/PollsController.php + models/Poll.php. + Pflicht sind `question` und mindestens zwei Antworten. + """ + session, _ = get_session() + container_id = resolve_container(session, args.container_id) + antworten = [a.strip() for a in args.answers.split("|") if a.strip()] + if len(antworten) < 2: + sys.exit("Error: mindestens zwei Antwortoptionen nötig " + "(--answers 'Ja|Nein').") + beschreibung = read_file(args.file) if args.file else "" + + payload = {"Poll": { + "question": args.question, + "description": beschreibung, + "newAnswers": antworten, + "anonymous": 1 if args.anonymous else 0, + "allow_multiple": 1 if args.multiple else 0, + "show_result_after_close": 1 if args.hide_results else 0, + "is_random": 0, + }} + data = api_post(session, f"/polls/container/{container_id}", payload) + print(f"Umfrage erstellt (ID {data.get('id')}): {data.get('question')}") + print("Optionen: " + " | ".join(a.get("answer", "") + for a in data.get("answers", []))) + + def cmd_post_update(args: argparse.Namespace) -> None: session, _ = get_session() message = read_file(args.file) @@ -412,6 +467,27 @@ def main() -> None: p.add_argument("--topics", default=None, help="Komma-getrennte Topic-Namen (ersetzt bestehende)") p.set_defaults(func=cmd_post_update) + # poll-list + p = sub.add_parser("poll-list", help="Umfragen eines Containers auflisten") + p.add_argument("container_id", help="Space-Slug, URL oder numerische Container-ID") + p.add_argument("--limit", type=int, default=10, help="Max. Anzahl (Standard: 10)") + p.set_defaults(func=cmd_poll_list) + + # poll-create + p = sub.add_parser("poll-create", help="Neue Umfrage anlegen") + p.add_argument("container_id", help="Space-Slug, URL oder numerische Container-ID") + p.add_argument("question", help="Die Frage (Pflicht)") + p.add_argument("--answers", required=True, + help="Antwortoptionen, mit | getrennt: 'Ja|Nein|Vielleicht' " + "(mindestens zwei)") + p.add_argument("--file", default=None, + help="Markdown-Datei mit dem Beschreibungstext, '-' für stdin") + p.add_argument("--anonymous", action="store_true", help="anonyme Abstimmung") + p.add_argument("--multiple", action="store_true", help="Mehrfachauswahl erlauben") + p.add_argument("--hide-results", action="store_true", + help="Ergebnis erst nach Ende der Umfrage zeigen") + p.set_defaults(func=cmd_poll_create) + args = parser.parse_args() args.func(args)