Compartir un archivo en Nextcloud y crear un link público desde dired en Emacs
Como bien es sabido, el cliente para escritorio de Nextcloud resulta una herramienta muy
práctica para tener sincronizados nuestros archivos locales con un servidor Nextcloud.
Aparte de su simplicidad de uso y de su interfaz gráfica, se suele integrar de maravilla
con los navegadores de archivos, como Nautilus en Gnome o Dolphin en KDE Plasma, añadiendo
además una serie de funcionalidades que están a mano con un solo toque de ratón que
despliegue el menú contextual. Entre ellas, destaca la posibilidad de compartir un archivo
o carpeta determinados en nuestro directorio ~/Nextcloud/
y crear y copiar un link
público.
Lo malo de los usuarios de Emacs es que vivimos en el constante delirio de pensar que Emacs no sólo es el escritorio sino hasta el sistema operativo. Para más inri el ratón lo relegamos a costa del teclado. Y, por último, el propio navegador de archivos que tiene Emacs, y que atiende al nombre de Dired, es de las cosas más confortables que hay a la hora de acceder rápida y ágilmente a nuestras carpetas y documentos. Así las cosas, me preguntaba estos días si no sería posible compartir un archivo de Nextcloud desde nuestro Dired, sin salir de Emacs, al mismo tiempo que creamos el link público a dicho archivo.
A decir verdad, la pelota está más bien en el tejado de Nextcloud. Si existiera la posibilidad de hacer algo así desde la línea de comandos, no es muy difícil definir una función en Emacs que pase a una variable el nombre del archivo de Dired sobre el cual tenemos el cursor, y ejecute sobre dicha variable el comando. Y da la casualidad (¡albricias!) que el comando sí existe. Indagando por la red, encontré este hilo del foro de ayuda de Nextcloud, donde se trataba este tema y se alcanzaba la siguiente (y satisfactoria) solución:
curl -u "<usuario>:<contraseña>" -H "OCS-APIRequest: true" -X POST <dir. servidor Nextcloud>/ocs/v1.php/apps/files_sharing/api/v1/shares -d path="<carpeta donde se guardan los archivos públicos/nombre del archivo a compartir>" -d shareType=3 -d permissions=1
Eśta vendría a ser la estructura básica del comando. Lo que pongo entre <...>
es lo que
tenemos que añadir por nuestra parte, y creo que se auto-explica. Para la dirección del
servidor Nextcloud yo pondría (ya que uso el servicio Nextcloud que aporta la comunidad de
Disroot1):
... -X POST https://cloud.disroot.org/ocs/v1.php/apps/files_sharing/api/v1/shares ...
Para que esto lo podamos hacer automáticamente desde Emacs, también es bueno que tengamos
una carpeta en nuestro ~/Nextcloud/
local destinada en exclusividad a compartir
públicamente.
La función para Emacs
Bien, ya que tenemos el comando, y que lo hemos probado y funciona, pasemos a definir
nuestra función emacsiana. Podemos echar mano de alguna función nativa que nos extraiga
como lista de texto el nombre del archivo de Dired sobre el que tenemos el cursor. Nos
sirve dired-get-file-for-visit
. Pero hay una pega: esta expresión nos devuelve no sólo
el nombre del archivo sino también su ruta absoluta. Y no queremos eso, sino el nombre tal
cual junto a la extensión. Así que defino previamente esta función, donde elimino toda la
ruta hacia la carpeta Público
, ésta inclusive:
(defun nombre-archivo-solo () (interactive) (let ((nombre (dired-get-file-for-visit))) (replace-regexp-in-string "/home/juanmanuel/Nextcloud/Público/" "" nombre)))
a fin de emplearla en lugar de dired-get-file-for-visit
.
Y a continuación, la función que ejecuta el comando de Nextcloud usando el nombre del archivo que ya tenemos (¡ojo con
las comillas en el comando de Nextcloud! Hay que añadir caracteres de escape \"
):
(defun crea-link-nextcloud () (interactive) (let ((archivo (nombre-archivo-solo))) (shell-command (format "curl -u \"<usuario>:<contraseña>\" -H \"OCS-APIRequest: true\" -X POST https://cloud.disroot.org/ocs/v1.php/apps/files_sharing/api/v1/shares -d path=\"Público/%s\" -d shareType=3 -d permissions=1" archivo))))
Esta función simplemente consta de una expresión let
donde definimos la variable archivo
y le damos como valor la
función anterior que nos extrae (recordemos) sólo el nombre del archivo sin la extensión.
Poniendo en práctica la función
Abrimos Dired en nuestro Emacs y nos dirigimos a la carpeta pública. Imaginemos que queremos compartir una imagen
llamada abejorro.jpg
. Pues situamos el cursor sobre ella y llamamos a nuestra flamante función crea-link-nextcloud
,
bien por medio de algún atajo que hayamos definido o directamente por un M-x crea-link-nextcloud
. En un periquete se
abrirá una ventana a nuestra derecha con el output del comando, y hacia el final del mismo, estará esperándonos como
Penélope en su palacio el link que acabamos de crear para compartir nuestro archivo (como se muestra en la fig. 1).
Figura 1: Creando el link público de nuestro abejorro
Figura 2: Probando nuestro enlace
Actualización de 27/10/20
Recientemente he migrado de nube Nextcloud, pasando del servicio que proporciona la comunidad de Disroot al de The Good Cloud. Entre otras razones, porque su instancia de Nextcloud es más estable y robusta que la de los holandeses y porque la opción gratuita tiene un almacenaje de 2Gb y, si bien la de Disroot era casi del doble, para tener una nube de texto plano mayormente como la mía, me basta y me sobra. Y siempre tengo la opción de pasarme a la opción de pago con unos precios muy ajustados.
Bien, el caso es que en este nuevo Nextcloud he tenido que hacer unas pequeñas modificaciones en mi función para compartir un enlace, ya que el servicio de The Good Cloud no permite compartirlos sin contraseña ni sin fecha de expiración, lo que me parece (por otra parte) una buena práctica.
Para la nueva versión de mi función se me ocurrió definir dos variables locales a fin de
generar la contraseña automáticamente, gracias al paquete password-generator
y para
establecer una fecha de vencimiento tras insertar en el input del minibúfer los días que
quiero darle de vida al enlace. Esto lo logro mediante una fecha formateada con
format-time-string
a partir de las funciones time-add
y days-to-time
. Así que la
nueva función luciría tal que así:
(require 'password-generator) (defun crea-link-nextcloud () "Crea un link público de un archivo marcado en Dired en la carpeta `Público' local de Nextcloud. Trabaja con el servicio The Good Cloud, por tanto requiere una fecha de expiración y una contraseña" (interactive) (let* ((archivo (nombre-archivo-solo)) (fecha (string-to-number (read-from-minibuffer "¿En cuántos días expira este enlace...?"))) ;; en el primer argumento de `time-add' el valor `nil' es para el día actual (expira (format-time-string "%Y-%m-%d" (time-add nil (days-to-time fecha)))) ;; Como a veces no incluye un número o un carácter especial o ;; una mayúscula, tal vez haya que insistir (passwd (password-generator-strong 10 t))) (shell-command (format "curl -u \"<usuario>:<contraseña>\" -H \"OCS-APIRequest: true\" -X POST https://use01.thegood.cloud/ocs/v1.php/apps/files_sharing/api/v1/shares -d path=\"Público/%s\" -d shareType=3 -d permissions=1 -d expireDate=\"%s\" -d password=%s" archivo expira passwd)) (let ((frase (format "La contraseña es %s, el enlace expira en %s" passwd expira))) (kill-new frase) (message frase))))
∞
Publicado: 22/06/2018
Última actualización: 21/01/22
Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.
Notas al pie de página:
Si usas este estupendo servicio, convendría que les hicieses un donativo de vez en cuando a esta gente altruista, a fin de que puedan mantener la infraestructura que disfrutas. Recuerda que el software libre no equivale necesariamente a software gratuito.