Cuaderno de GNUtas

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).

abejorro-ejemplo1.png

Figura 1: Creando el link público de nuestro abejorro

abejorro-ejemplo2.png

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


Índice general

Acerca de...

Esta obra está bajo una licencia de Creative Commons Reconocimiento-NoComercial 4.0 Internacional.

Notas al pie de página:

1

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.

© Juan Manuel Macías
Creado con esmero en
GNU Emacs