From 8e290130b47b7f3b9d442c8d6531218eb2f09867 Mon Sep 17 00:00:00 2001 From: Sacha Chua Date: Tue, 11 Oct 2022 20:40:32 -0400 Subject: Yay, pads are created based on the talks.json file Also, the playbook waits until the pad is up --- README.org | 6 + docker-destroy.yaml | 4 +- docker-inventory.yaml | 1 + docker-reuse-playbook.yaml | 10 +- inventory.yaml | 3 + pad/defaults/main.yml | 3 + pad/tasks/main.yml | 56 ++- pad/templates/etherpad.init.d | 79 +++++ pad/templates/settings.json | 2 +- prod-playbook.yaml | 9 + prod-vars.yml.sample | 2 + talks.json | 1 + wiki-edit/tasks/main.yaml | 42 +++ wiki/tasks/main.yaml | 33 ++ wiki/templates/Scrubber.pm | 749 +++++++++++++++++++++++++++++++++++++++++ wiki/templates/copyright.pm | 60 ++++ wiki/templates/emacsconf.setup | 443 ++++++++++++++++++++++++ wiki/templates/htmlscrubber.pm | 132 ++++++++ wiki/templates/license.pm | 59 ++++ 19 files changed, 1684 insertions(+), 10 deletions(-) create mode 100755 pad/templates/etherpad.init.d create mode 100644 prod-playbook.yaml create mode 100644 prod-vars.yml.sample create mode 100644 talks.json create mode 100644 wiki-edit/tasks/main.yaml create mode 100644 wiki/tasks/main.yaml create mode 100644 wiki/templates/Scrubber.pm create mode 100644 wiki/templates/copyright.pm create mode 100644 wiki/templates/emacsconf.setup create mode 100755 wiki/templates/htmlscrubber.pm create mode 100644 wiki/templates/license.pm diff --git a/README.org b/README.org index 0b3c622..7554082 100644 --- a/README.org +++ b/README.org @@ -1,6 +1,8 @@ This repository contains infrastructure-as-code ansible configurations for various pieces of the EmacsConf infrastructure. +ansible-galaxy collection install community.general + * Front - publishing ** Prod To run the playbook and publish the main schedule: @@ -27,6 +29,8 @@ ansible-playbook -i docker-inventory.yaml docker-reuse-playbook.yaml --tags pad Connecting: docker exec -it emacsconf-pad /bin/bash +Creating pads +ansible-playbook -i docker-inventory.yaml docker-reuse-playbook.yaml --tags create-pads file:/docker:emacsconf-pad:/home/etherpad/etherpad/ @@ -52,4 +56,6 @@ curl "http://localhost:9001/api/1/createPad?apikey=$padkey&padID=emacsconf-2022" curl http://localhost:9001/api/1/createPad?apikey=b7a15dc34cc7f6917cca6cd9a2b4b92145af7c7cd9b341af34869ab8cd3568be&padID=emacsconf-2022 {"code":0,"message":"ok","data":null} :end: +** TODO Set etherpad_database_password and etherpad_api_key using the vault or the command-line +ansible-playbook .... --extra-vars prod-vars.yml diff --git a/docker-destroy.yaml b/docker-destroy.yaml index 4a915c3..f401dba 100644 --- a/docker-destroy.yaml +++ b/docker-destroy.yaml @@ -3,7 +3,7 @@ hosts: localhost tags: front tasks: - - name: destroy docker container + - name: destroy front docker container docker_container: name: emacsconf-front state: absent @@ -12,7 +12,7 @@ hosts: localhost tags: pad tasks: - - name: destroy docker container + - name: destroy pad docker container docker_container: name: emacsconf-pad state: absent diff --git a/docker-inventory.yaml b/docker-inventory.yaml index 6caa3e3..b1be91e 100644 --- a/docker-inventory.yaml +++ b/docker-inventory.yaml @@ -8,3 +8,4 @@ all: ansible_python_interpreter: /usr/bin/python3 localhost: ansible_connection: local + diff --git a/docker-reuse-playbook.yaml b/docker-reuse-playbook.yaml index 742a193..c187817 100644 --- a/docker-reuse-playbook.yaml +++ b/docker-reuse-playbook.yaml @@ -1,4 +1,12 @@ --- +- name: Load talks + hosts: localhost + tags: create-pads + tasks: + - include_vars: + file: talks.json + name: talks + - name: Set up the emacsconf-front wiki hosts: emacsconf-front tags: front @@ -10,4 +18,4 @@ tags: pad roles: - pad - + diff --git a/inventory.yaml b/inventory.yaml index 964b8d5..69b3213 100644 --- a/inventory.yaml +++ b/inventory.yaml @@ -6,3 +6,6 @@ prod: publish: ansible_host: front0.emacsconf.org remote_user: orga + pad: + ansible_host: front0.emacsconf.org + remote_user: orga diff --git a/pad/defaults/main.yml b/pad/defaults/main.yml index 398c9a2..386abf7 100644 --- a/pad/defaults/main.yml +++ b/pad/defaults/main.yml @@ -6,3 +6,6 @@ etherpad_database_name: emacsconf_pad etherpad_database_user: etherpad etherpad_user: etherpad etherpad_group: etherpad +etherpad_api_key: b7a15dc34cc7f6917cca6cd9a2b4b92145af7c7cd9b341af34869ab8cd3568be +etherpad_base: emacsconf +etherpad_year: 2022 diff --git a/pad/tasks/main.yml b/pad/tasks/main.yml index ab15984..8637406 100644 --- a/pad/tasks/main.yml +++ b/pad/tasks/main.yml @@ -12,6 +12,7 @@ apt: update_cache: yes name: + - systemd - sudo - nodejs - mariadb-server @@ -34,14 +35,57 @@ template: src: templates/settings.json dest: "{{ etherpad_path }}/settings.json" -# - name: Install etherpad plugins -# npm: -# name: ep_stats -# path: "{{ etherpad_path }}" -# become: true -# become_user: etherpad +- name: Set etherpad API key + copy: + content: "{{ etherpad_api_key }}" + dest: "{{ etherpad_path }}/APIKEY.txt" + owner: "{{ etherpad_user }}" + mode: "0600" - name: Install dependencies shell: cd {{ etherpad_path }}; . src/bin/functions.sh; src/bin/installDeps.sh become: true become_user: etherpad +- name: Install etherpad plugins + npm: + name: ep_pad-lister + path: "{{ etherpad_path }}" + become: true + become_user: etherpad - include: mariadb.yml +- name: Install init.d configuration + tags: system + template: + src: etherpad.init.d + dest: /etc/init.d/etherpad + owner: root + group: root + mode: 0755 +- name: Start Etherpad + tags: system + service: + name: etherpad + state: started +- tags: create-pads + include_vars: + file: talks.json + name: talks +- name: Set slugs + tags: create-pads + set_fact: + slugs: +- name: Wait for OK + tags: create-pads + uri: + url: "http://localhost:9001/api/1/createPad?apikey={{ etherpad_api_key }}&padID={{etherpad_base}}-{{etherpad_year}}" + register: _result + until: _result.status == 200 + retries: 720 + delay: 5 +- debug: + var: _result + tags: create-pads +- name: Create pads + tags: create-pads + uri: + url: "http://localhost:9001/api/1/createPad?apikey={{ etherpad_api_key }}&padID={{etherpad_base}}-{{etherpad_year}}-{{ item.slug }}" + loop: "{{ talks | json_query('talks[*]') }}" diff --git a/pad/templates/etherpad.init.d b/pad/templates/etherpad.init.d new file mode 100755 index 0000000..420ae27 --- /dev/null +++ b/pad/templates/etherpad.init.d @@ -0,0 +1,79 @@ +#!/bin/sh + +### BEGIN INIT INFO +# Provides: etherpad-lite +# Required-Start: $local_fs $remote_fs $network $syslog +# Required-Stop: $local_fs $remote_fs $network $syslog +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: starts etherpad lite +# Description: starts etherpad lite using start-stop-daemon +### END INIT INFO + +PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin" +LOGFILE="{{ etherpad_path }}/etherpad-lite.log" +EPLITE_DIR="{{ etherpad_path }}" +EPLITE_BIN="src/bin/safeRun.sh" +USER="{{ etherpad_user }}" +GROUP="{{ etherpad_group }}" +DESC="Etherpad Lite" +NAME="etherpad" + +set -e + +. /lib/lsb/init-functions + +start() { + echo "Starting $DESC... " + + start-stop-daemon --start --chuid "$USER:$GROUP" -d $EPLITE_DIR --background --make-pidfile --pidfile /var/run/$NAME.pid --exec $EPLITE_DIR/$EPLITE_BIN -- $LOGFILE || true + echo "done" +} + +#We need this function to ensure the whole process tree will be killed +killtree() { + local _pid=$1 + local _sig=${2-TERM} + for _child in $(ps -o pid --no-headers --ppid ${_pid}); do + killtree ${_child} ${_sig} + done + kill -${_sig} ${_pid} +} + +stop() { + echo "Stopping $DESC... " + if test -f /var/run/$NAME.pid; then + while test -d /proc/$(cat /var/run/$NAME.pid); do + killtree $(cat /var/run/$NAME.pid) 15 + sleep 0.5 + done + rm /var/run/$NAME.pid + fi + echo "done" +} + +status() { + status_of_proc -p /var/run/$NAME.pid "" "etherpad-lite" && exit 0 || exit $? +} + +case "$1" in + start) + start + ;; + stop) + stop + ;; + restart) + stop + start + ;; + status) + status + ;; + *) + echo "Usage: $NAME {start|stop|restart|status}" >&2 + exit 1 + ;; +esac + +exit 0 \ No newline at end of file diff --git a/pad/templates/settings.json b/pad/templates/settings.json index 137ce03..1832ef3 100644 --- a/pad/templates/settings.json +++ b/pad/templates/settings.json @@ -215,7 +215,7 @@ /* * The default text of a pad */ - "defaultPadText" : "Conference info, how to watch/participate: https://emacsconf.org/2022/\nGuidelines for conduct: https://emacsconf.org/conduct/\nIRC: channel #emacsconf via https://chat.emacsconf.org or libera.chat network\n\nExcept where otherwise noted, the material on the EmacsConf pad are dual-licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International Public License; and the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) an later version. Copies of these two licenses are included in the EmacsConf wiki repository, in the COPYING.GPL and COPYING.CC-BY-SA files (https://emacsconf.org/COPYING/)\n\nBy contributing to this pad, you agree to make your contributions available under the above licenses. You are also promising that you are the author of your changes, or that you copied them from a work in the public domain or a work released under a free license that is compatible with the above two licenses. DO NOT SUBMIT COPYRIGHTED WORK WITHOUT PERMISSION.", + "defaultPadText" : "Conference info, how to watch/participate: https://emacsconf.org/2022/\nGuidelines for conduct: https://emacsconf.org/conduct/\nIRC: channel #emacsconf via https://chat.emacsconf.org or libera.chat network\nSee end of file for license (CC Attribution-ShareAlike 4.0 + GPLv3 or later)\n----------------------------------------------------------------\nQuestions and discussion go here:\n\n----------------------------------------------------------------\nExcept where otherwise noted, the material on the EmacsConf pad are dual-licensed under the terms of the Creative Commons Attribution-ShareAlike 4.0 International Public License; and the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) an later version. Copies of these two licenses are included in the EmacsConf wiki repository, in the COPYING.GPL and COPYING.CC-BY-SA files (https://emacsconf.org/COPYING/)\n\nBy contributing to this pad, you agree to make your contributions available under the above licenses. You are also promising that you are the author of your changes, or that you copied them from a work in the public domain or a work released under a free license that is compatible with the above two licenses. DO NOT SUBMIT COPYRIGHTED WORK WITHOUT PERMISSION.", /* * Default Pad behavior. diff --git a/prod-playbook.yaml b/prod-playbook.yaml new file mode 100644 index 0000000..83f7e7f --- /dev/null +++ b/prod-playbook.yaml @@ -0,0 +1,9 @@ +- name: Set up wiki for publishing + hosts: publish + roles: + - wiki-edit +- name: Set up pad + hosts: pad + vars_files: prod-vars.yml + roles: + - pad diff --git a/prod-vars.yml.sample b/prod-vars.yml.sample new file mode 100644 index 0000000..4fd2df4 --- /dev/null +++ b/prod-vars.yml.sample @@ -0,0 +1,2 @@ +etherpad_api_key: CHANGEME +etherpad_database_password: CHANGEME diff --git a/talks.json b/talks.json new file mode 100644 index 0000000..85c716d --- /dev/null +++ b/talks.json @@ -0,0 +1 @@ +{"talks":[{"start-time":"2022-12-03T14:05:00+0000","end-time":"2022-12-03T14:25:00+0000","slug":"journalism","title":"Emacs journalism (or everything's a nail if you hit it with Emacs)","speakers":"Alfred Zanini","pronouns":"he/they","pronunciation":null,"url":"2022/talks/journalism","track":"General"},{"start-time":"2022-12-03T14:45:00+0000","end-time":"2022-12-03T15:05:00+0000","slug":"school","title":"Back to school with Emacs","speakers":"Daniel Rösel","pronouns":null,"pronunciation":"ˈrøːzl̩","url":"2022/talks/school","track":"General"},{"start-time":"2022-12-03T15:15:00+0000","end-time":"2022-12-03T15:25:00+0000","slug":"handwritten","title":"How to incorporate handwritten notes into Emacs Orgmode","speakers":"Bala Ramadurai","pronouns":"his/him","pronunciation":null,"url":"2022/talks/handwritten","track":"General"},{"start-time":"2022-12-03T15:55:00+0000","end-time":"2022-12-03T16:15:00+0000","slug":"science","title":"Writing and organizing literature notes for scientific writing","speakers":"Vidianos","pronouns":"nil","pronunciation":null,"url":"2022/talks/science","track":"General"},{"start-time":"2022-12-03T18:00:00+0000","end-time":"2022-12-03T18:10:00+0000","slug":"meetups","title":"Attending and organizing Emacs meetups","speakers":"Bhavin Gandhi","pronouns":"he/him","pronunciation":null,"url":"2022/talks/meetups","track":"General"},{"start-time":"2022-12-03T18:30:00+0000","end-time":"2022-12-03T18:40:00+0000","slug":"buddy","title":"The Emacs Buddy initiative","speakers":"Andrea","pronouns":null,"pronunciation":null,"url":"2022/talks/buddy","track":"General"},{"start-time":"2022-12-03T18:50:00+0000","end-time":"2022-12-03T19:20:00+0000","slug":"community","title":"The ship that builds itself: How we used Emacs to develop a workshop for communities","speakers":"Noorah Alhasan, Joseph Corneli, Leo Vivier","pronouns":"Noorah: she/her, Joseph: he/him, Leo: he/him","pronunciation":null,"url":"2022/talks/community","track":"General"},{"start-time":"2022-12-03T19:50:00+0000","end-time":"2022-12-03T20:10:00+0000","slug":"realestate","title":"Real estate and Org table formulas","speakers":"Daniel Gopar","pronouns":"He/Him","pronunciation":null,"url":"2022/talks/realestate","track":"General"},{"start-time":"2022-12-03T20:20:00+0000","end-time":"2022-12-03T20:40:00+0000","slug":"health","title":"Health data journaling and visualization with Org Mode and GNUplot","speakers":"David O'Toole","pronouns":"he/him","pronunciation":null,"url":"2022/talks/health","track":"General"},{"start-time":"2022-12-03T21:00:00+0000","end-time":"2022-12-03T21:10:00+0000","slug":"jupyter","title":"Edit live Jupyter notebook cells with Emacs","speakers":"Blaine Mooers","pronouns":"he/him","pronunciation":"Blane Moors","url":"2022/talks/jupyter","track":"General"},{"start-time":"2022-12-04T14:05:00+0000","end-time":"2022-12-04T14:25:00+0000","slug":"survey","title":"Results of the 2022 Emacs Survey","speakers":"Timothy","pronouns":"he/him","pronunciation":null,"url":"2022/talks/survey","track":"General"},{"start-time":"2022-12-04T14:35:00+0000","end-time":"2022-12-04T14:45:00+0000","slug":"orgyear","title":"This Year in Org","speakers":"Timothy","pronouns":"he/him","pronunciation":null,"url":"2022/talks/orgyear","track":"General"},{"start-time":"2022-12-04T15:00:00+0000","end-time":"2022-12-04T15:20:00+0000","slug":"rolodex","title":"Build a Zettelkasten with the Hyperbole Rolodex","speakers":"Ramin Honary","pronouns":"he/him","pronunciation":"\"Rah-mean\" (hard-H) \"Ho-na-ree\"","url":"2022/talks/rolodex","track":"General"},{"start-time":"2022-12-04T15:40:00+0000","end-time":"2022-12-04T15:50:00+0000","slug":"orgsuperlinks","title":"Linking headings with org-super-links (poor-man's Zettelkasten)","speakers":"Karl Voit","pronouns":"he/him","pronunciation":null,"url":"2022/talks/orgsuperlinks","track":"General"},{"start-time":"2022-12-04T16:10:00+0000","end-time":"2022-12-04T16:20:00+0000","slug":"buttons","title":"Linking personal info with Hyperbole implicit buttons","speakers":"Mats Lidell","pronouns":"He,Him,His","pronunciation":null,"url":"2022/talks/buttons","track":"General"},{"start-time":"2022-12-04T18:00:00+0000","end-time":"2022-12-04T18:30:00+0000","slug":"hyperorg","title":"Powerful productivity with Hyperbole and Org Mode","speakers":"Robert Weiner","pronouns":null,"pronunciation":"wine-er","url":"2022/talks/hyperorg","track":"General"},{"start-time":"2022-12-04T18:50:00+0000","end-time":"2022-12-04T19:10:00+0000","slug":"workflows","title":"Org workflows for developers","speakers":"George Mauer","pronouns":"he/him/they/ze","pronunciation":null,"url":"2022/talks/workflows","track":"General"},{"start-time":"2022-12-04T19:30:00+0000","end-time":"2022-12-04T19:50:00+0000","slug":"grail","title":"GRAIL---A Generalized Representation and Aggregation of Information Layers","speakers":"Sameer Pradhan","pronouns":"he/him","pronunciation":null,"url":"2022/talks/grail","track":"General"},{"start-time":"2022-12-03T21:30:00+0000","end-time":"2022-12-03T21:40:00+0000","slug":"orgvm","title":"orgvm: a simple HTTP server for org","speakers":"Corwin Brust","pronouns":"he/him/any","pronunciation":null,"url":"2022/talks/orgvm","track":"General"},{"start-time":"2022-12-04T20:20:00+0000","end-time":"2022-12-04T20:40:00+0000","slug":"indieweb","title":"Putting Org Mode on the Indieweb","speakers":"Michael Herstine","pronouns":null,"pronunciation":null,"url":"2022/talks/indieweb","track":"General"},{"start-time":"2022-12-04T21:00:00+0000","end-time":"2022-12-04T21:10:00+0000","slug":"fanfare","title":"Fanfare for the Common Emacs User","speakers":"John Cummings","pronouns":null,"pronunciation":null,"url":"2022/talks/fanfare","track":"General"},{"start-time":"2022-12-04T21:00:00+0000","end-time":"2022-12-04T21:20:00+0000","slug":"localizing","title":"Pre-localizing Emacs","speakers":"Jean-Christophe Helary","pronouns":"he/him","pronunciation":null,"url":"2022/talks/localizing","track":"Development"},{"start-time":"2022-12-03T15:00:00+0000","end-time":"2022-12-03T15:10:00+0000","slug":"treesitter","title":"Tree-sitter beyond syntax highlighting","speakers":"Abin Simon","pronouns":"nil","pronunciation":null,"url":"2022/talks/treesitter","track":"Development"},{"start-time":"2022-12-03T15:20:00+0000","end-time":"2022-12-03T15:40:00+0000","slug":"lspbridge","title":"lsp-bridge: complete asynchronous LSP client","speakers":"Andy Stewart, Matthew Zeng","pronouns":"nil","pronunciation":null,"url":"2022/talks/lspbridge","track":"Development"},{"start-time":"2022-12-03T18:00:00+0000","end-time":"2022-12-03T18:20:00+0000","slug":"sqlite","title":"Using SQLite as a data source: a framework and an example","speakers":"Andrew Hyatt","pronouns":"he/him","pronunciation":null,"url":"2022/talks/sqlite","track":"Development"},{"start-time":"2022-12-03T18:45:00+0000","end-time":"2022-12-03T19:15:00+0000","slug":"mail","title":"Revisiting the anatomy of Emacs mail user agents","speakers":"Mohsen BANAN","pronouns":"he/him","pronunciation":"MO-HH-SS-EN","url":"2022/talks/mail","track":"Development"},{"start-time":"2022-12-03T20:35:00+0000","end-time":"2022-12-03T20:40:00+0000","slug":"eev","title":"Bidirectional links with eev","speakers":"Eduardo Ochs","pronouns":"nil","pronunciation":null,"url":"2022/talks/eev","track":"Development"},{"start-time":"2022-12-03T20:50:00+0000","end-time":"2022-12-03T20:55:00+0000","slug":"python","title":"Short hyperlinks to Python docs","speakers":"Eduardo Ochs","pronouns":null,"pronunciation":null,"url":"2022/talks/python","track":"Development"},{"start-time":"2022-12-03T19:50:00+0000","end-time":"2022-12-03T20:10:00+0000","slug":"maint","title":"Maintaining the Maintainers: Attribution as an Economic Model for Open Source","speakers":"Sid Kasivajhula","pronouns":"any pronouns, commonly he/him","pronunciation":null,"url":"2022/talks/maint","track":"Development"},{"start-time":"2022-12-03T21:05:00+0000","end-time":"2022-12-03T21:35:00+0000","slug":"haskell","title":"Haskell code exploration with Emacs","speakers":"Yuchen Pei","pronouns":null,"pronunciation":"he/him/himself/his/his","url":"2022/talks/haskell","track":"Development"},{"start-time":"2022-12-04T15:00:00+0000","end-time":"2022-12-04T15:20:00+0000","slug":"rde","title":"rde Emacs introduction","speakers":"Andrew Tropin","pronouns":"he/him","pronunciation":null,"url":"2022/talks/rde","track":"Development"},{"start-time":"2022-12-04T15:45:00+0000","end-time":"2022-12-04T15:55:00+0000","slug":"justl","title":"justl: Driving recipes within Emacs","speakers":"Sibi Prabakaran","pronouns":"He/Him","pronunciation":null,"url":"2022/talks/justl","track":"Development"},{"start-time":"2022-12-04T16:05:00+0000","end-time":"2022-12-04T16:35:00+0000","slug":"tramp","title":"Elisp and the TRAMP: How to NOT write code you don't have to","speakers":"Grant Shangreaux","pronouns":"he/him","pronunciation":"Shang-groo or Shang-grow are fine","url":"2022/talks/tramp","track":"Development"},{"start-time":"2022-12-04T18:00:00+0000","end-time":"2022-12-04T18:10:00+0000","slug":"detached","title":"Getting detached from Emacs","speakers":"Niklas Eklund","pronouns":"he/him","pronunciation":null,"url":"2022/talks/detached","track":"Development"},{"start-time":"2022-12-04T18:35:00+0000","end-time":"2022-12-04T18:45:00+0000","slug":"eshell","title":"Top 10 reasons why you should be using Eshell","speakers":"Howard Abrams","pronouns":"he/him","pronunciation":null,"url":"2022/talks/eshell","track":"Development"},{"start-time":"2022-12-04T19:10:00+0000","end-time":"2022-12-04T19:30:00+0000","slug":"async","title":"Emacs was async before async was cool","speakers":"Michael Herstine","pronouns":null,"pronunciation":null,"url":"2022/talks/async","track":"Development"},{"start-time":"2022-12-03T15:50:00+0000","end-time":"2022-12-03T16:00:00+0000","slug":"asmblox","title":"asm-blox: a game based on WebAssembly that no one asked for","speakers":"Zachary Romero","pronouns":"nil","pronunciation":null,"url":"2022/talks/asmblox","track":"Development"},{"start-time":"2022-12-04T20:05:00+0000","end-time":"2022-12-04T20:25:00+0000","slug":"dbus","title":"The Wheels on D-Bus","speakers":"Ian Eure","pronouns":"he/him/his","pronunciation":"ee-uhn you-er","url":"2022/talks/dbus","track":"Development"},{"start-time":"2022-12-03T16:25:00+0000","end-time":"2022-12-03T16:35:00+0000","slug":"wayland","title":"Emacs should become a Wayland compositor","speakers":"Michael Bauer","pronouns":null,"pronunciation":null,"url":"2022/talks/wayland","track":"Development"},{"start-time":"2022-12-04T23:00:00+0000","end-time":"2022-12-04T23:05:00+0000","slug":"news","title":"Emacs News highlights","speakers":"Sacha Chua","pronouns":"she/her","pronunciation":"SA-sha CHEW-ah","url":"2022/talks/news","track":null}]} \ No newline at end of file diff --git a/wiki-edit/tasks/main.yaml b/wiki-edit/tasks/main.yaml new file mode 100644 index 0000000..570c953 --- /dev/null +++ b/wiki-edit/tasks/main.yaml @@ -0,0 +1,42 @@ +--- +- name: Set up packages + become: yes + block: + - name: Add snapshot repository + ansible.builtin.apt_repository: + repo: deb http://emacs.ganneff.de/ buster main + - name: Remove old package + ansible.builtin.apt: + name: emacs + state: absent + - name: Install Emacs snapshot + ansible.builtin.apt: + name: emacs-snapshot-nox + state: present +- name: Set up or update repositories + block: + - name: Check out wiki repository + ansible.builtin.git: + repo: git://git.emacsconf.org/emacsconf-wiki + dest: ~/emacsconf-wiki + - name: Check out emacsconf-el + ansible.builtin.git: + repo: git@git.emacsconf.org:pub/emacsconf-el + dest: ~/emacsconf-el + - name: Check out emacsconf-2022-private + ansible.builtin.git: + repo: git@git.emacsconf.org:emacsconf-2022-private + dest: ~/emacsconf-2022-private + register: private +- name: Publish + tags: publish + block: + - name: Publish the schedule + command: emacs -l ~/.emacs.d/init.el --batch --exec '(emacsconf-generate-main-schedule)' + when: private.changed and slug is not defined + - name: Update a specific talk's nav page + tags: publish-talk + command: emacs -l ~/.emacs.d/init.el --batch --exec '(emacsconf-with-talk-heading "{{ slug }}" (emacsconf-update-talk))' + when: slug is defined + - name: Commit the wiki and push + shell: cd ~/emacsconf-wiki; git commit -m 'Update from ansible' -a; git push diff --git a/wiki/tasks/main.yaml b/wiki/tasks/main.yaml new file mode 100644 index 0000000..c685515 --- /dev/null +++ b/wiki/tasks/main.yaml @@ -0,0 +1,33 @@ +--- +- name: Set up packages + ansible.builtin.apt: + pkg: + - ikiwiki + - git + - openssh-server + - wget + state: present +- name: Create ikiwiki user + user: + name: ikiwiki +- name: Set up SSH directory + ansible.builtin.file: + path: /home/ikiwiki/.ssh + state: directory + mode: '0700' +- name: Install SSH key for EmacsConf wiki + ansible.builtin.get_url: + url: https://emacsconf.org/id_rsa_anon_git_emacsconf + dest: /home/ikiwiki/.ssh/id_rsa_anon_git_emacsconf + mode: '0600' + owner: 'ikiwiki' +- name: Set up or update repositories + become: ikiwiki + ansible.builtin.git: + repo: git://git.emacsconf.org/emacsconf-wiki + dest: /home/ikiwiki/emacsconf-wiki +- name: Template the config + ansible.builtin.template: + src: /templates/emacsconf.setup + dest: /home/ikiwiki/emacsconf.setup + owner: ikiwiki diff --git a/wiki/templates/Scrubber.pm b/wiki/templates/Scrubber.pm new file mode 100644 index 0000000..2efaa10 --- /dev/null +++ b/wiki/templates/Scrubber.pm @@ -0,0 +1,749 @@ +package HTML::Scrubber; + +# ABSTRACT: Perl extension for scrubbing/sanitizing html + + +use 5.008; # enforce minimum perl version of 5.8 +use strict; +use warnings; +use HTML::Parser 3.47 (); +use HTML::Entities; +use Scalar::Util ('weaken'); + +our ( @_scrub, @_scrub_fh ); + +our $VERSION = '0.15'; # VERSION +our $AUTHORITY = 'cpan:NIGELM'; # AUTHORITY + +# my my my my, these here to prevent foolishness like +# http://perlmonks.org/index.pl?node_id=251127#Stealing+Lexicals +(@_scrub) = ( \&_scrub, "self, event, tagname, attr, attrseq, text" ); +(@_scrub_fh) = ( \&_scrub_fh, "self, event, tagname, attr, attrseq, text" ); + +sub new { + my $package = shift; + my $p = HTML::Parser->new( + api_version => 3, + default_h => \@_scrub, + marked_sections => 0, + strict_comment => 0, + unbroken_text => 1, + case_sensitive => 0, + boolean_attribute_value => undef, + empty_element_tags => 1, + ); + + my $self = { + _p => $p, + _rules => { '*' => 0, }, + _comment => 0, + _process => 0, + _r => "", + _optimize => 1, + _script => 0, + _style => 0, + }; + + $p->{"\0_s"} = bless $self, $package; + weaken( $p->{"\0_s"} ); + + return $self unless @_; + + my (%args) = @_; + + for my $f (qw[ default allow deny rules process comment ]) { + next unless exists $args{$f}; + if ( ref $args{$f} ) { + $self->$f( @{ $args{$f} } ); + } + else { + $self->$f( $args{$f} ); + } + } + + return $self; +} + + +sub comment { + return $_[0]->{_comment} + if @_ == 1; + $_[0]->{_comment} = $_[1]; + return; +} + + +sub process { + return $_[0]->{_process} + if @_ == 1; + $_[0]->{_process} = $_[1]; + return; +} + + +sub script { + return $_[0]->{_script} + if @_ == 1; + $_[0]->{_script} = $_[1]; + return; +} + + +sub style { + return $_[0]->{_style} + if @_ == 1; + $_[0]->{_style} = $_[1]; + return; +} + + +sub allow { + my $self = shift; + for my $k (@_) { + $self->{_rules}{ lc $k } = 1; + } + $self->{_optimize} = 1; # each time a rule changes, reoptimize when parse + + return; +} + + +sub deny { + my $self = shift; + + for my $k (@_) { + $self->{_rules}{ lc $k } = 0; + } + + $self->{_optimize} = 1; # each time a rule changes, reoptimize when parse + + return; +} + + +sub rules { + my $self = shift; + my (%rules) = @_; + for my $k ( keys %rules ) { + $self->{_rules}{ lc $k } = $rules{$k}; + } + + $self->{_optimize} = 1; # each time a rule changes, reoptimize when parse + + return; +} + + +sub default { + return $_[0]->{_rules}{'*'} + if @_ == 1; + + $_[0]->{_rules}{'*'} = $_[1] if defined $_[1]; + $_[0]->{_rules}{'_'} = $_[2] if defined $_[2] and ref $_[2]; + $_[0]->{_optimize} = 1; # each time a rule changes, reoptimize when parse + + return; +} + + +sub scrub_file { + if ( @_ > 2 ) { + return unless defined $_[0]->_out( $_[2] ); + } + else { + $_[0]->{_p}->handler( default => @_scrub ); + } + + $_[0]->_optimize(); #if $_[0]->{_optimize}; + + $_[0]->{_p}->parse_file( $_[1] ); + + return delete $_[0]->{_r} unless exists $_[0]->{_out}; + print { $_[0]->{_out} } $_[0]->{_r} if length $_[0]->{_r}; + delete $_[0]->{_out}; + return 1; +} + + +sub scrub { + if ( @_ > 2 ) { + return unless defined $_[0]->_out( $_[2] ); + } + else { + $_[0]->{_p}->handler( default => @_scrub ); + } + + $_[0]->_optimize(); # if $_[0]->{_optimize}; + + $_[0]->{_p}->parse( $_[1] ) if defined( $_[1] ); + $_[0]->{_p}->eof(); + + return delete $_[0]->{_r} unless exists $_[0]->{_out}; + delete $_[0]->{_out}; + return 1; +} + + +sub _out { + my ( $self, $o ) = @_; + + unless ( ref $o and ref \$o ne 'GLOB' ) { + open my $F, '>', $o or return; + binmode $F; + $self->{_out} = $F; + } + else { + $self->{_out} = $o; + } + + $self->{_p}->handler( default => @_scrub_fh ); + + return 1; +} + + +sub _validate { + my ( $s, $t, $r, $a, $as ) = @_; + return "<$t>" unless %$a; + + $r = $s->{_rules}->{$r}; + my %f; + + for my $k ( keys %$a ) { + my $check = exists $r->{$k} ? $r->{$k} : exists $r->{'*'} ? $r->{'*'} : next; + + if ( ref $check eq 'CODE' ) { + my @v = $check->( $s, $t, $k, $a->{$k}, $a, \%f ); + next unless @v; + $f{$k} = shift @v; + } + elsif ( ref $check || length($check) > 1 ) { + $f{$k} = $a->{$k} if $a->{$k} =~ m{$check}; + } + elsif ($check) { + $f{$k} = $a->{$k}; + } + } + + if (%f) { + my %seen; + return "<$t $r>" + if $r = join ' ', map { + defined $f{$_} + ? qq[$_="] . encode_entities( $f{$_} ) . q["] + : $_; # boolean attribute (TODO?) + } grep { exists $f{$_} and !$seen{$_}++; } @$as; + } + + return "<$t>"; +} + + +sub _scrub_str { + my ( $p, $e, $t, $a, $as, $text ) = @_; + + my $s = $p->{"\0_s"}; + my $outstr = ''; + + if ( $e eq 'start' ) { + if ( exists $s->{_rules}->{$t} ) # is there a specific rule + { + if ( ref $s->{_rules}->{$t} ) # is it complicated?(not simple;) + { + $outstr .= $s->_validate( $t, $t, $a, $as ); + } + elsif ( $s->{_rules}->{$t} ) # validate using default attribute rule + { + $outstr .= $s->_validate( $t, '_', $a, $as ); + } + } + elsif ( $s->{_rules}->{'*'} ) # default allow tags + { + $outstr .= $s->_validate( $t, '_', $a, $as ); + } + } + elsif ( $e eq 'end' ) { + my $place = 0; + if ( exists $s->{_rules}->{$t} ) { + $place = 1 if $s->{_rules}->{$t}; + } + elsif ( $s->{_rules}->{'*'} ) { + $place = 1; + } + if ($place) { + if ( length $text ) { + $outstr .= ""; + } + else { + substr $s->{_r}, -1, 0, ' /'; + } + } + } + elsif ( $e eq 'comment' ) { + if ( $s->{_comment} ) { + + # only copy comments through if they are well formed... + $outstr .= $text if ( $text =~ m|^$|ms ); + } + } + elsif ( $e eq 'process' ) { + $outstr .= $text if $s->{_process}; + } + elsif ( $e eq 'text' or $e eq 'default' ) { + $text =~ s//>/g; + + $outstr .= $text; + } + elsif ( $e eq 'start_document' ) { + $outstr = ""; + } + + return $outstr; +} + + +sub _scrub_fh { + my $self = $_[0]->{"\0_s"}; + print { $self->{_out} } $self->{'_r'} if length $self->{_r}; + $self->{'_r'} = _scrub_str(@_); +} + + +sub _scrub { + + $_[0]->{"\0_s"}->{_r} .= _scrub_str(@_); +} + +sub _optimize { + my ($self) = @_; + + my (@ignore_elements) = grep { not $self->{"_$_"} } qw(script style); + $self->{_p}->ignore_elements(@ignore_elements); # if @ is empty, we reset ;) + + return unless $self->{_optimize}; + + #sub allow + # return unless $self->{_optimize}; # till I figure it out (huh) + + if ( $self->{_rules}{'*'} ) { # default allow + $self->{_p}->report_tags(); # so clear it + } + else { + + my (@reports) = + grep { # report only tags we want + $self->{_rules}{$_} + } keys %{ $self->{_rules} }; + + $self->{_p}->report_tags( # default deny, so optimize + @reports + ) if @reports; + } + + # sub deny + # return unless $self->{_optimize}; # till I figure it out (huh) + my (@ignores) = + grep { not $self->{_rules}{$_} } grep { $_ ne '*' } keys %{ $self->{_rules} }; + + $self->{_p}->ignore_tags( # always ignore stuff we don't want + @ignores + ) if @ignores; + + $self->{_optimize} = 0; + return; +} + +1; + +#print sprintf q[ '%-12s => %s,], "$_'", $h{$_} for sort keys %h;# perl! +#perl -ne"chomp;print $_;print qq'\t\t# test ', ++$a if /ok\(/;print $/" test.pl >test2.pl +#perl -ne"chomp;print $_;if( /ok\(/ ){s/\#test \d+$//;print qq'\t\t# test ', ++$a }print $/" test.pl >test2.pl +#perl -ne"chomp;if(/ok\(/){s/# test .*$//;print$_,qq'\t\t# test ',++$a}else{print$_}print$/" test.pl >test2.pl + +__END__ + +=pod + +=for stopwords html cpan callback homepage Perlbrew perltidy respository + +=head1 NAME + +HTML::Scrubber - Perl extension for scrubbing/sanitizing html + +=head1 VERSION + +version 0.15 + +=head1 SYNOPSIS + + use HTML::Scrubber; + + my $scrubber = HTML::Scrubber->new( allow => [ qw[ p b i u hr br ] ] ); + print $scrubber->scrub('

bold missing

'); + # output is:

bold

+ + # more complex input + my $html = q[ + + +
+ a => link + br =>
+ b => bold + u => UNDERLINE + ]; + + print $scrubber->scrub($html); + + $scrubber->deny( qw[ p b i u hr br ] ); + + print $scrubber->scrub($html); + +=head1 DESCRIPTION + +If you want to "scrub" or "sanitize" html input in a reliable and flexible +fashion, then this module is for you. + +I wasn't satisfied with HTML::Sanitizer because it is based on +HTML::TreeBuilder, so I thought I'd write something similar that works directly +with HTML::Parser. + +=head1 METHODS + +First a note on documentation: just study the L below. It's +all the documentation you could need + +Also, be sure to read all the comments as well as L. + +If you're new to perl, good luck to you. + +=head2 comment + + warn "comments are ", $p->comment ? 'allowed' : 'not allowed'; + $p->comment(0); # off by default + +=head2 process + + warn "process instructions are ", $p->process ? 'allowed' : 'not allowed'; + $p->process(0); # off by default + +=head2 script + + warn "script tags (and everything in between) are supressed" + if $p->script; # off by default + $p->script( 0 || 1 ); + +B<**> Please note that this is implemented using HTML::Parser's ignore_elements +function, so if C