From 6915f7e0b42f9b2472181a5808d0abd952f8bb41 Mon Sep 17 00:00:00 2001 From: shagi Date: Sat, 20 Nov 2021 10:33:42 +0100 Subject: [PATCH] Convertir asistencia a csv, scripts auxiliares para facilitar la web --- README.md | 22 ++- archetypes/asistencia.md | 14 -- bin/asistencia | 5 + bin/necesidades | 5 + bin/nueva_pagina | 9 + bin/nuevo_hackmeeting | 5 + bin/nuevo_nodo | 9 + bin/slugify | 41 +++++ content/2019/asistencia.csv | 2 + .../{asistencia/_index.md => asistencia.md} | 5 +- content/2019/asistencia/shagi.md | 14 -- layouts/asistencia/section.html | 42 ----- utils/csveditor.py | 169 ++++++++++++++++++ utils/readme.md | 15 ++ 14 files changed, 279 insertions(+), 78 deletions(-) delete mode 100644 archetypes/asistencia.md create mode 100755 bin/asistencia create mode 100755 bin/necesidades create mode 100755 bin/nueva_pagina create mode 100755 bin/nuevo_hackmeeting create mode 100755 bin/nuevo_nodo create mode 100755 bin/slugify create mode 100644 content/2019/asistencia.csv rename content/2019/{asistencia/_index.md => asistencia.md} (62%) delete mode 100644 content/2019/asistencia/shagi.md delete mode 100644 layouts/asistencia/section.html create mode 100755 utils/csveditor.py create mode 100644 utils/readme.md diff --git a/README.md b/README.md index 4cfee4d..d214e4b 100644 --- a/README.md +++ b/README.md @@ -31,21 +31,31 @@ que hay apuntados para cenar el sábado. ## Crear contenido -Para crear un nodo que se llame `nodo1` para el 2019: +Hay una serie de comandos auxiliares para gestionar el contenido de la web de +manera sencilla. - hugo new 2019/nodos/nodo1.md -k nodo +Todos estos comandos aceptan un parámetro opcional: el año en el que estamos +trabajando. Si no se indica año se asume el actual. -Para apuntarse como asistente: +Para crear un nodo: - hugo new 2019/asistencia/persona.md -k asistencia + bin/nuevo_nodo + +Para gestionar la asistencia: + + bin/asistencia + +Para gestionar las necesidades: + + bin/necesidades Para crear una página corriente: - hugo new 2019/como-llegar.md + bin/nueva_pagina Para empezar un nuevo hackmeeting: - hugo new 2022 -k hm + bin/nuevo_hackmeeting ## Mini intro a Hugo diff --git a/archetypes/asistencia.md b/archetypes/asistencia.md deleted file mode 100644 index 9f121f6..0000000 --- a/archetypes/asistencia.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "{{ replace .Name "-" " " | title }}" -date: {{ .Date }} -type: "asistencia" -entrada: "fecha" -salida: "fecha" -dieta: "omnivora" -camiseta: "talla(s)" -material: ["proyector", "internet"] -dormir: "si (notas)" -comer: "si (notas)" -necesidades: "" -draft: false ---- diff --git a/bin/asistencia b/bin/asistencia new file mode 100755 index 0000000..edbf3bf --- /dev/null +++ b/bin/asistencia @@ -0,0 +1,5 @@ +#!/bin/sh + +YEAR=${1:-$(date "+%Y")} + +utils/csveditor.py content/${YEAR}/asistencia.csv diff --git a/bin/necesidades b/bin/necesidades new file mode 100755 index 0000000..7e77a52 --- /dev/null +++ b/bin/necesidades @@ -0,0 +1,5 @@ +#!/bin/sh + +YEAR=${1:-$(date "+%Y")} + +utils/csveditor.py content/${YEAR}/necesidades.csv diff --git a/bin/nueva_pagina b/bin/nueva_pagina new file mode 100755 index 0000000..c3b019a --- /dev/null +++ b/bin/nueva_pagina @@ -0,0 +1,9 @@ +#!/bin/bash + +YEAR=${1:-$(date "+%Y")} + +echo -n "Titulo: " +read TITLE +SLUG=$(bin/slugify ${TITLE}) + +hugo new ${YEAR}/${SLUG}.md diff --git a/bin/nuevo_hackmeeting b/bin/nuevo_hackmeeting new file mode 100755 index 0000000..7626211 --- /dev/null +++ b/bin/nuevo_hackmeeting @@ -0,0 +1,5 @@ +#!/bin/sh + +YEAR=${1:-$(date "+%Y")} + +hugo new ${YEAR} -k hm diff --git a/bin/nuevo_nodo b/bin/nuevo_nodo new file mode 100755 index 0000000..4d3e443 --- /dev/null +++ b/bin/nuevo_nodo @@ -0,0 +1,9 @@ +#!/bin/sh + +YEAR=${1:-$(date "+%Y")} + +echo -n "Titulo: " +read TITLE +SLUG=$(bin/slugify ${TITLE}) + +hugo new ${YEAR}/nodos/${SLUG}.md -k nodo diff --git a/bin/slugify b/bin/slugify new file mode 100755 index 0000000..4ea9663 --- /dev/null +++ b/bin/slugify @@ -0,0 +1,41 @@ +#!/bin/bash + +# Versión simplificada y adaptada de bash-slugify +# https://github.com/brutus/bash-slugify +slugify () { + local name="$@" + local gluechars='-_. ' + local safechars="${gluechars}a-zA-Z0-9" + + # convert to lowercase + name=$(echo "${name}" | tr A-ZÄÖÜ a-zäöü) + + # remove special chars + name=$(echo "${name//[^${safechars}]/}") + + # consolidate spaces + name=$(echo "${name}" | tr -s '[:space:]') + + # replace spaces with dashes + name=$(echo "${name}" | tr ' ' '-') + + # remove spaces around dashes and underscores + name=$(echo "${name// -/-}") + name=$(echo "${name//- /-}") + name=$(echo "${name// _/_}") + name=$(echo "${name//_ /_}") + + # trim spaces + name=$(echo "${name}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//') + + # replace special chars + name=$(echo "${name//[^${safechars}]/$REPLACEMENT_CHAR}") + + ## REPLACE SPACES + name=$(echo "${name// /$SPACE_CHAR}") + + # return slug + echo "${name}" +} + +echo $(slugify "$@") diff --git a/content/2019/asistencia.csv b/content/2019/asistencia.csv new file mode 100644 index 0000000..8ca23fe --- /dev/null +++ b/content/2019/asistencia.csv @@ -0,0 +1,2 @@ +"Nombre","Entrada","Salida","Dieta","Camiseta","Material","Dormir","Comer","Necesidades" +"Shagi","2019-09-19","2010-09-22","omnivora","L","","sí (en furgo)","sí","" diff --git a/content/2019/asistencia/_index.md b/content/2019/asistencia.md similarity index 62% rename from content/2019/asistencia/_index.md rename to content/2019/asistencia.md index f56871b..9f69fc5 100644 --- a/content/2019/asistencia/_index.md +++ b/content/2019/asistencia.md @@ -1,10 +1,11 @@ --- title: "Asistencia" date: 2021-09-14T11:29:27+02:00 -type: "asistencia" draft: false --- Esta es la plantilla para inscribirse y que sepamos de antemano cuanta gente va a venir, para poder preparar el espacio y lo que haga falta. Avisa en matrix o -en la lista, o envía un pull request con al repositorio de esta web. +en la lista, o envía un pull request al repositorio de esta web. + +{{< csvTable file="/content/2019/asistencia.csv" class="asistencia" >}} diff --git a/content/2019/asistencia/shagi.md b/content/2019/asistencia/shagi.md deleted file mode 100644 index 67e1dd3..0000000 --- a/content/2019/asistencia/shagi.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -title: "Shagi" -date: 2021-09-17T11:42:10+02:00 -type: "asistencia" -entrada: "2019-09-19" -salida: "2010-09-22" -dieta: "omnivora" -camiseta: "L" -material: -dormir: "sí (en furgo)" -comer: "sí" -necesidades: "" -draft: false ---- diff --git a/layouts/asistencia/section.html b/layouts/asistencia/section.html deleted file mode 100644 index 8fe3d45..0000000 --- a/layouts/asistencia/section.html +++ /dev/null @@ -1,42 +0,0 @@ -{{ define "main" }} - {{ .Content }} - - - - - - - - - - - - - - - - - {{ range where .Pages "Params.type" "asistencia" }} - - - - - - - - - - - - {{ end }} - -
QuiénEntradaSalidaTipo de comidaTalla camisetaMaterial/OtrosDormirComerNecesidades Especiales
{{ .Title }}{{ .Params.entrada }}{{ .Params.salida }}{{ .Params.dieta }}{{ .Params.camiseta }}{{ .Params.material }}{{ .Params.dormir }}{{ .Params.comer }}{{ .Params.necesidades }}
-{{ end }} - -{{ define "sidebar_menu" }} - -{{ end}} diff --git a/utils/csveditor.py b/utils/csveditor.py new file mode 100755 index 0000000..232ef1f --- /dev/null +++ b/utils/csveditor.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python3 +from argparse import ArgumentParser +import atexit +import csv +import os +import readline +import sys +from cmd import Cmd + +def init_readline(): + histfile = os.path.join(os.path.expanduser("~"), ".hmwebot_history") + + try: + readline.read_history_file(histfile) + h_len = readline.get_current_history_length() + except FileNotFoundError: + open(histfile, 'wb').close() + h_len = 0 + + def save(prev_h_len, histfile): + new_h_len = readline.get_current_history_length() + readline.set_history_length(1000) + readline.append_history_file(new_h_len - prev_h_len, histfile) + atexit.register(save, h_len, histfile) + + +def rlinput(prompt, prefill=''): + readline.set_startup_hook(lambda: readline.insert_text(prefill)) + try: + return input(prompt) # or raw_input in Python 2 + finally: + readline.set_startup_hook() + + +class CSVEditor: + def __init__(self, filename): + self.filename = filename + with open(filename, 'r') as f: + reader = csv.DictReader(f) + self.fieldnames = reader.fieldnames + self.data = [data for data in reader] + + def get_list(self, title_field): + return [(idx, data[title_field]) for idx, data in enumerate(self.data)] + + def get(self, idx): + try: + return self.data[idx] + except IndexError: + return None + + def show(self, idx): + line = self.get(idx) + if line is None: + return "Índice fuera de rango" + output = [ + f"{field}: {value}" + for field, value in line.items() + ] + return "\n".join(output) + + def edit(self, idx, item): + self.data[idx] = item + + def delete(self, idx): + if idx in self.data: + del self.data[idx] + + def _edit(self, item): + editing = True + while editing: + for fieldname in self.fieldnames: + item[fieldname] = rlinput(f"{fieldname}: ", prefill=item.get(fieldname, '')) + + editing = rlinput('Terminado (s/N)?').lower() == 'n' + + def edit(self, idx): + item = self.get(idx) + if item is None: + return + self._edit(item) + self.data[idx] = item + + def add(self): + item = {} + self._edit(item) + self.data.append(item) + + def write(self): + with open(self.filename, 'w') as f: + writer = csv.DictWriter(f, fieldnames=self.fieldnames) + writer.writeheader() + writer.writerows(self.data) + + +class CSVEditorCmd(Cmd): + "Editor interactivo de ficheros csv" + + def __init__(self, filename, title_field=None): + super().__init__() + self.csveditor = CSVEditor(filename) + self.title_field = title_field + if title_field is None: + self.title_field = self.csveditor.fieldnames[0] + self.do_help('') + + def do_list(self, arg): + "Listar el contenido del csv" + for idx, item in self.csveditor.get_list(self.title_field): + print(f"{idx}) {item}") + + def do_show(self, arg): + "Mostrar la línea con el índice indicado" + try: + idx = int(arg) + except ValueError: + print("Tienes que indicar un número") + return + print(self.csveditor.show(idx)) + + def do_add(self, arg): + "Añadir una nueva entrada" + self.csveditor.add() + + def do_edit(self, arg): + "Editar la entrada con el índice indicado" + try: + idx = int(arg) + except ValueError: + print("Tienes que indicar un número") + return + self.csveditor.edit(idx) + + def do_delete(self, arg): + "Quitar la entrada con el índice indicado" + try: + idx = int(arg) + except ValueError: + print("Tienes que indicar un número") + return + self.csveditor.delete(idx) + + def do_save(self, arg): + "Guardar la lista actualizada" + self.csveditor.write() + + def do_quit(self, arg): + "Terminar" + return True + + do_EOF = do_quit + + +parser = ArgumentParser( + description='Editor sencillo de ficheros CSV') + +parser.add_argument('csvfile', help='Fichero que hay que editar.') +parser.add_argument('-t', '--title', help='Columna principal del CSV, por defecto la primera.') + + +def main(): + init_readline() + # bot = Bot() + args = parser.parse_args() + cmd = CSVEditorCmd(args.csvfile, args.title) + cmd.cmdloop() + +if __name__ == '__main__': + main() diff --git a/utils/readme.md b/utils/readme.md new file mode 100644 index 0000000..03a4b2c --- /dev/null +++ b/utils/readme.md @@ -0,0 +1,15 @@ +Tareas que hay que facilitar: + +- nuevo nodo +- nueva asistencia + igual cambiar el sistema actual para que sea también un csv, así podemos + cambiar las columnas necesarias para cada año + + el programa pregunta y añade, o busca en la lista para quitar a alguien +- necesidades + poder pedir proyectores, material de limpieza, gente, etc. + + un csv con tres columnas: texto, cantidad necesaria, cantidad actual + + el programa pregunta por una de las líneas del csv para borrar, editar, cambiar la cantidad, + también se pueden añadir nuevas líneas