Actualmente tengo un tema en un sitio, que me gustaría tener también en otro sitio. Si bien podría hipervincularlo, lo que realmente me encantaría es la capacidad de editarlo en cualquiera de los sitios y que los cambios se reflejen en ambos. Esto me evita tener una versión del tema que está muy desactualizada y, en cambio, mantiene ambos temas constantemente actualizados. También me proporciona una forma de descentralizar la información de mi sitio.
Algunas ideas sobre la funcionalidad
Como punto de partida, un sitio seguiría siendo el anfitrión/propietario del tema, y el otro (u otros) lo reflejarían esencialmente. Yendo más allá, incluso me pregunto si un tema podría ser heredado de alguna manera por un tema espejo si el original se elimina.
El tema debería conservar la capacidad de ocultarse, cerrarse, etc. en los sitios espejo.
Las respuestas no deben sincronizarse: cada sitio tiene una base de usuarios diferente, por lo que no veo cómo funcionaría la sincronización de respuestas.
Entiendo que la implementación de una característica de este tipo está muy lejos de ser trivial, pero me pregunto si esto se ha considerado alguna vez y qué resultados/experimentos existen.
¿Podrías darme un poco más de información sobre esto? Desde mi perspectiva, esto reduciría el contenido duplicado.
La copia de seguridad no es el objetivo, sino crear un único punto de verdad para temas que tendrían sentido en más de un sitio.
Para dar un ejemplo concreto, estoy pensando en cambiar mi Visa. Tengo un Tema en mi Discourse privado que es básicamente una lista de verificación de lo que hay que hacer. Sin embargo, mis amigos también podrían encontrarlo útil, así que creo el mismo tema en nuestro Discourse compartido. El problema es que necesito sincronizar la información de ambos temas por separado en lugar de simplemente actualizar un solo tema. Esto significa que a menudo uno de los temas carece de información clave.
Supongo que esto podría ser posible incluso con solo una clave API al otro sitio. Quizás algo como un botón/sección en el editor donde se pueda crear una lista de claves API y URL para el tema de destino. Cuando realizas cambios en un tema de origen, puedes hacer clic en algo como “enviar cambios a los clones de este tema”. Todo lo que haría sería enviar la actualización a los temas en otras instancias.
Pon la información en un solo lugar donde todos puedan verla. Un enlace es la forma de hacerlo.
Pero tienes información secreta que quieres hacer disponible en otro lugar. Eso es otra cosa. Es bastante posible con un plugin. Es el tipo de problema donde la solución forzada requiere 10 veces más trabajo que el que requeriría el problema real. (A menudo paso horas automatizando una tarea que solo necesita ocurrir una vez, por ejemplo).
Pero necesitarías ponerlo en algún lugar donde solo esté disponible para el usuario que lo publicó. ¿O hacerlo en todo el sitio?
De nuevo, necesitan ser por usuario y en el serializador solo para el usuario actual (¿o tal vez almacenarlo en el perfil del usuario?). Y necesitarías alguna estructura de datos para mapear las claves API a los diferentes sitios. Parece algo que pensaría que podría hacer en 2-5 horas.
Así que necesitas almacenar en algún lugar la URL de los otros sitios que se supone que tienen este tema. Cómo crear esa publicación también podría ser complicado; la forma más fácil es simplemente crearla a mano e incluir la URL de ese tema en el sitio de origen. Probablemente podrías almacenar eso en la publicación sin formato en algún tipo de BBcode o algo así. Eso te permitiría crear un componente que crearía el botón y el enlace para cada uno de ellos y luego tendrías código de Rails que pondría en cola un trabajo que intentaría publicarlo en el(los) otro(s) sitio(s). Pero los sitios receptores no necesitarían ningún código; podrías usar la API para enviar una edición a la publicación.
Parece el tipo de cosa que pensaría que podría hacer en 5-10 horas, pero probablemente tomaría el doble. Si eso te divierte, podría ser un proyecto interesante.
Esto también podría hacerse a través de una pequeña aplicación externa que escucharía una webhook enviada en las ediciones de tu sitio de origen y luego usaría la API para publicar en el sitio espejo.
Un plugin podría añadir un campo de tema personalizado para la URL de la fuente del documento principal. (Supongo que también necesitaría campos para un nombre de usuario remoto y una clave API si el documento principal debe ocultarse, como creo que es tu caso, pero esa parte podría esperar. O quizás podrían vivir en un campo personalizado de usuario. Dependería de quien generara la clave ver que la clave API tiene privilegios de solo lectura).
Al crear un tema, introducirías algo como “remote: https://meta.discourse.org/t/synchronising-crossposting-topics-across-different-discourse-sites/263269” y cuando se creara el tema, Discourse extraerá el texto sin formato del tema remoto, lo insertará en raw como una edición e instanciará el topic_custom_field con la URL remota, quizás añadiendo un “copiado de url” en la parte superior.
En este punto, has copiado el tema remoto localmente y tienes un registro del mismo.
Luego podría haber un botón “comprobar fuente” que extraería el tema remoto y guardaría el updated_at del tema remoto e incluso el raw en otros campos personalizados (un trabajo también podría hacer esto periódicamente, ahorrando un poco de UX). Luego podrías tener un botón de actualización que reemplazaría el raw existente con el remoto como una edición.
Si el sitio principal es público, entonces esta parte es realmente fácil. Añadir una clave API para extraer de un sitio privado complica las cosas, gestionar un conjunto de claves API en múltiples sitios, lo complica aún más. Si la fuente original necesitara ser reemplazada, podrías hacerlo con la tarea rake de reasignación, o añadir la capacidad de editar el campo personalizado con la URL remota cuando lo necesites.
Esta parte viene gratis, ya que esta solución tiene los sitios secundarios extrayendo los datos del principal.
Correcto. Y puede haber un enlace de vuelta al sitio de origen, para que la gente pueda ir al origen para ver esos comentarios, o quizás incluso incrustarlos a través de Embed comments from Discourse in your single page app.
Si tienes algún presupuesto para esto, no dudes en contactarme.
Lo he tenido en mente por un tiempo, aunque no ha progresado mucho hasta hace poco. Desafortunadamente, la sincronización de Discourse a Discourse perdió valor para mí (solo eran un puñado de temas), pero lo que aumentó de valor fue el deseo de sincronizar archivos markdown de otras plataformas en general.
Nuestro caso de uso dominante en la empresa era tener los readmes y wikis de los proyectos de Gitlab disponibles dentro de Discourse (para comentarios y búsqueda), pero con el archivo de Gitlab permaneciendo como la única fuente de verdad. Mi falta de conocimiento de Ruby resultó en un script de Python que es definitivamente excesivo en su implementación, pero satisfactorio en su funcionalidad. La primera versión decente hace parte de lo que también describiste. Algunas funcionalidades:
Contiene un enlace a la fuente original (archivo en Gitlab)
Contiene un enlace a la revisión específica (commit # de Gitlab)
Maneja imágenes y URLs de imágenes
Descarga imágenes del repositorio de Gitlab
Las sube a Discourse
Reemplaza la URL de imagen original con la URL corta de la carga
Añade una etiqueta “synced_with_gitlab” para que sea fácil encontrarlas todas
Funcionó más o menos igual con Github también. Ambos tienen más o menos el mismo sabor de markdown, lo que lo hace bastante elegante.
Me encantaría hacerlo de código abierto, pero tendré que ver qué dice el departamento legal. Además, todavía es un desastre de Python un poco improvisado. La intención es convertir esto en un plugin de Ruby en algún momento, pero tendré que ver si puedo encontrar el tiempo necesario.
Cierto. Estoy intentando de nuevo este proyecto y actualmente estoy considerando crear una base de datos con:
Una tabla por plataforma (tabla de Discourse, tabla de Gitlab, etc.) para tener en cuenta posibles matices
Cada tabla de plataforma que admita webhooks y sondeos a través de clave API
Cifrado de la base de datos o de la clave API: actualmente creo que lo mejor es cifrar toda la base de datos e interactuar con ella a través del script y una frase de contraseña
¿Suena esto a una locura y a una sobreingeniería? Una parte de mí quiere construir una solución adecuada para esto, lo que significaría tener en cuenta ambas posibilidades: webhook y sondeo.
Además, agradecería mucho sugerencias sobre cómo mantener seguro el contenido de la base de datos. El pensamiento actual es cifrar la base de datos con una frase de contraseña que debe proporcionarse como argumento al iniciar el script, por ejemplo:
discourse-sync run password123
Solo como inspiración, el webhook puede ser súper rápido:
Estos eran dos temas en dos instancias diferentes. El tema de la izquierda es el tema de origen, el tema de la derecha es el destino.
Por lo que vale, esta idea también se me ha ocurrido un número de veces. No estoy seguro de que tengamos un tema dedicado a esto aquí todavía, ¡pero si no, deberíamos!
Teóricamente estoy de acuerdo, desafortunadamente el mundo corporativo complica las cosas:
Los webhooks no son posibles en la empresa debido a las políticas de TI (estamos alojados fuera de la empresa por CDCK + no podemos permitir el reenvío de puertos al mundo exterior sin un proceso pesado), por lo tanto, la versión de la API es imprescindible.
Los webhooks son rápidos, geniales y perfectamente razonables para todos los demás, así que tiene sentido acomodarlos también
Así que logré una versión aproximada de esto hace un tiempo, funciona de maravilla pero no es extensible. Mal diseño de mi parte: estaba explorando la idea de usar un tema con una tabla de markdown como entrada. Genial hasta que tienes más de 30 entradas, entonces es un desastre.
Parte del caso de uso de discourse a discourse que veo es: un único punto de verdad para la documentación (Meta) se sincroniza con las publicaciones respectivas en otras instancias. Esto significa que si el equipo cambia Core y actualiza la documentación del usuario Meta, tengo una versión actualizada de esa documentación en mi instancia de forma nativa para que todos los usuarios la encuentren.
Para la V2 planeo usar una base de datos SQLlite como entrada como se mencionó anteriormente, y probablemente escribiré en Rust esta vez en lugar de Python.
A continuación, un boceto aproximado.
graph TB
A[terminal] -- ~\u003ediscourse-sync run $PASSWORD --\u003e B[Rust Script]
B -- SQLCipher:Decrypt DB using Password --\u003e C[( sqlite: sources-and-targets')]
C -- 'Discourse' Table Data --\u003e B
B -.-\u003e D{Decision on Type}
D -- Webhook --\u003e E[Listen for Webhook Info]
D -- Polling --\u003e F[Polling API]
E --\u003e G[Receive New Information]
F --\u003e G
G --\u003e H[Parse and Process Data]
H --\u003e I[POST\n tgt_domain, tgt_usr, tgt_key, post_id]
I --'raw' and images--\u003e J[ Target Post ]
subgraph Rust Script Operations
B
D
E
F
G
H
I
end
Estaría muy contento de recibir comentarios y sugerencias sobre esto
Sí, esto ahora está soportado por el plugin ActivityPub. Estamos muy cerca de usarlo internamente para sincronizar la documentación entre meta y una instancia interna, de hecho, está en mi lista de tareas para la próxima semana.
Se aplica a instancias privadas, en la versión actual del plugin AP, las instancias privadas pueden seguir categorías en instancias públicas de Discourse y, por lo tanto, recibir actividades publicadas de esas instancias. (Pero el contenido de la instancia privada no se publica, por lo que es una sincronización unidireccional, solo de público a privado).
Entonces, parece que ActivityPub puede funcionar de la siguiente manera:
Público -- Público
Público -- Privado
Privado -- Público
Privado -- Privado
Esto es ciertamente útil en muchos casos, como la difusión de documentación de Meta. Desafortunadamente, esto aún no cumple uno de mis casos de uso, que es publicar desde una instancia privada a otra instancia privada. Por lo que he investigado, ¿tengo razón al pensar que el complemento ActivityPub es poco probable que admita esos casos de uso en el futuro? Me parece que ActivityPub fue diseñado pensando en Público a Público.
@Tris20 ¡Interesante! Gracias por compartir tus pensamientos y algunos detalles sobre esto.
Lo que has descrito es (uno de) los problemas que ActivityPub fue construido para resolver. No quiero desanimarte demasiado, pero para ser honesto, te enfrentarás a una amplia gama de desafíos tratando de lograr esto de la manera que lo describes. No te daré un recuento exhaustivo de cada desafío que necesitarás superar, pero para darte una idea, el plugin ActivityPub ya tiene casi 700 pruebas rspec y después de un año de desarrollo, solo recientemente ha admitido la sincronización completa de tema a tema.
No hay ninguna limitación inherente que pueda ver para admitir la publicación de Privado a Público y de Privado a Privado a través de ActivityPub. La cuestión es garantizar que se cumplan las preocupaciones de acceso y seguridad al trabajar con instancias privadas.
Si pudiera hacer una sugerencia. Quizás piensa en cómo puedes aprovechar el trabajo que el plugin ActivityPub (y ActivityPub como estándar) ya ha hecho en este sentido. De hecho, existe una solución al problema de la sincronización de contenido de Discourse a Discourse que funciona actualmente. Aún no cubre tu caso de uso, pero resuelve la mayoría de los problemas que necesitarás resolver para satisfacer tus necesidades.
Quizás podrías pensar en cómo podría funcionar una sincronización de privado a privado en el plugin, es decir, ¿cómo se abordarían las cuestiones de acceso y seguridad? Luego, quizás tú y yo podríamos trabajar juntos en un PR para agregarlo como una característica. Tal vez llegues a un punto en el que sientas que realmente no es posible lograr lo que quieres lograr en el contexto del plugin (o de ActivityPub como estándar), pero el trabajo que habrías hecho para llegar a ese punto sería efectivamente el mismo trabajo que necesitarías hacer para una solución independiente, por lo que no sería en vano.
Hay mucha gente inteligente en el mundo de ActivityPub, y no me sorprendería que este tipo de problema (es decir, la publicación privada) se haya considerado en profundidad antes. Un lugar donde podrías encontrar algo de arte previo sobre ello es SocialHub, el principal foro comunitario de ActivityPub (Discourse, por supuesto) que ahora utiliza el plugin Discourse ActivityPub