Plugin ActivityPub

Salut :wave:
Tout d’abord, merci pour l’excellent travail accompli pour que cela se produise. Je ne pourrais pas être plus heureux de la décision de déplacer notre communauté vers Discourse grâce à cela.

J’ai ajouté le plugin à notre instance et configuré un acteur. Cependant, lorsque je publie dans une catégorie avec un acteur associé, je reçois une “Erreur interne du serveur”. Je n’ai pas trouvé grand-chose dans les journaux, à part que la requête a échoué avec une erreur 500 :

[pas d'horodatage] par PostsController#create en JSON
[pas d'horodatage] Paramètres : {"raw"=>"Ceci est juste un test test test", "title"=>"Ceci est juste un test test test", "unlist_topic"=>"false", "category"=>"10", "is_warning"=>"false", "archetype"=>"regular", "typing_duration_msecs"=>"200", "composer_open_duration_msecs"=>"3160", "shared_draft"=>"false", "draft_key"=>"new_topic", "activity_pub_visibility"=>"public", "nested_post"=>"true"}
25 sept. 15:06:38 - Traitement par PostsController#create en JSON
25 sept. 15:06:38 - Paramètres : {"raw"=>"Ceci est juste un test test test", "title"=>"Ceci est juste un test test test", "unlist_topic"=>"false", "category"=>"10", "is_warning"=>"false", "archetype"=>"regular", "typing_duration_msecs"=>"200", "composer_open_duration_msecs"=>"3160", "shared_draft"=>"false", "draft_key"=>"new_topic", "activity_pub_visibility"=>"public", "nested_post"=>"true"}
25 sept. 15:06:38 - 172.18.0.1 - - [25/sept./2024:13:06:38 +0000] "POST /message-bus/3e2e0add2e9a41cc9ce7041980fe4f81/poll HTTP/1.1" 200 2438 "https://community.tuist.io/c/announcements/10" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:130.0) Gecko/20100101 Firefox/130.0"
25 sept. 15:06:38 - 172.18.0.1 - - [25/sept./2024:13:06:38 +0000] "POST /message-bus/3e2e0add2e9a41cc9ce7041980fe4f81/poll HTTP/1.1" 200 115 "https://community.tuist.io/c/announcements/10" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:130.0) Gecko/20100101 Firefox/130.0"
[pas d'horodatage] 2024-09-25T13:06:38Z cloudron 37a832f8-20ab-41d7-9d4d-82052354c0eb 1101 37a832f8-20ab-41d7-9d4d-82052354c0eb - 172.18.0.1 - - [25/sept./2024:13:06:38 +0000] "POST /message-bus/3e2e0add2e9a41cc9ce7041980fe4f81/poll HTTP/1.1" 200 115 "https://community.tuist.io/c/announcements/10" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:130.0) Gecko/20100101 Firefox/130.0"
[pas d'horodatage] début
25 sept. 15:06:39 - début
[pas d'horodatage] début
25 sept. 15:06:39 - début
[pas d'horodatage] terminé
25 sept. 15:06:39 - terminé
[pas d'horodatage] début
25 sept. 15:06:39 - début
[pas d'horodatage] début
[pas d'horodatage] début
25 sept. 15:06:39 - début
25 sept. 15:06:39 - début
[pas d'horodatage] terminé
25 sept. 15:06:39 - terminé
[pas d'horodatage] terminé
25 sept. 15:06:39 - terminé
[pas d'horodatage] Erreur interne du serveur 500 en 476 ms (ActiveRecord : 0.0 ms | Allocations : 56364)
[pas d'horodatage] terminé
25 sept. 15:06:39 - Terminé Erreur interne du serveur 500 en 476 ms (ActiveRecord : 0.0 ms | Allocations : 56364)
25 sept. 15:06:39 - terminé
25 sept. 15:06:39 - 172.18.0.1 - - [25/sept./2024:13:06:39 +0000] "POST /posts HTTP/1.1" 500 46 "https://community.tuist.io/c/announcements/10" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:130.0) Gecko/20100101 Firefox/130.0"
[pas d'horodatage] début
25 sept. 15:06:39 - début
[pas d'horodatage] terminé
25 sept. 15:06:39 - terminé
[pas d'horodatage] terminé
25 sept. 15:06:39 - terminé

Quelle est la voie recommandée pour déboguer ce problème ?

La prochaine étape consiste à aller sur /logs sur votre forum, à trouver la ligne de journal correspondante et à poster la trace de la pile ici.

3 « J'aime »

Voici l’erreur :

Message

NoMethodError (undefined method `moderating_groups' for #<Category id: 10, name: "Announcements", color: "652D90", topic_id: 55, topic_count: 5, created_at: "2024-09-25 09:23:28.181772000 +0000", updated_at: "2024-09-27 11:53:47.131692000 +0000", user_id: 3, topics_year: 4, topics_month: 4, topics_week: 4, slug: "announcements", description: "This category is used for announcements by the mai...", text_color: "FFFFFF", read_restricted: false, auto_close_hours: nil, post_count: 4, latest_post_id: 108, latest_topic_id: 83, position: 7, parent_category_id: nil, posts_year: 4, posts_month: 4, posts_week: 4, email_in: nil, email_in_allow_strangers: false, topics_day: 0, posts_day: 0, allow_badges: true, name_lower: "announcements", auto_close_based_on_last_post: false, topic_template: nil, contains_messages: nil, sort_order: nil, sort_ascending: nil, uploaded_logo_id: nil, uploaded_background_id: nil, topic_featured_link_allowed: true, all_topics_wiki: false, show_subcategory_list: false, num_featured_topics: 3, default_view: nil, subcategory_list_style: "rows_with_featured_topics", default_top_period: "all", mailinglist_mirror: false, minimum_required_tags: 0, navigate_to_first_post_after_read: false, search_priority: 0, allow_global_tags: false, reviewable_by_group_id: nil, read_only_banner: nil, default_list_filter: "all", allow_unlimited_owner_edits_on_first_post: false, default_slow_mode_seconds: nil, uploaded_logo_dark_id: nil, uploaded_background_dark_id: nil>)
lib/plugin/instance.rb:376:in `public_send'
lib/plugin/instance.rb:376:in `block (2 levels) in add_to_class'
lib/plugin/instance.rb:376:in `public_send'
lib/plugin/instance.rb:376:in `block (2 levels) in add_to_class'
lib/plugin/instance.rb:376:in `public_send'
lib/plugin/instance.rb:376:in `block (2 levels) in add_to_class'
lib/plugin/instance.rb:376:in `public_send'
lib/plugin/instance.rb:376:in `block (2 levels) in add_to_class'
lib/plugin/instance.rb:576:in `block in on'
lib/discourse_event.rb:12:in `bl...

Backtrace

activemodel (7.1.3.4) lib/active_model/attribute_methods.rb:489:in `method_missing'
plugins/discourse-activity-pub/plugin.rb:367:in `block (2 levels) in activate!'
lib/plugin/instance.rb:376:in `public_send'
lib/plugin/instance.rb:376:in `block (2 levels) in add_to_class'
plugins/discourse-activity-pub/plugin.rb:331:in `block (2 levels) in activate!'
lib/plugin/instance.rb:376:in `public_send'
lib/plugin/instance.rb:376:in `block (2 levels) in add_to_class'
plugins/discourse-activity-pub/plugin.rb:337:in `block (2 levels) in activate!'
lib/plugin/instance.rb:376:in `public_send'
lib/plugin/instance.rb:376:in `block (2 levels) in add_to_class'
plugins/discourse-activity-pub/app/models/discourse_activity_pub_object.rb:99:in `after_scheduled'
plugins/discourse-activity-pub/app/models/discourse_activity_pub_activity.rb:109:in `after_scheduled'
plugins/discourse-activity-pub/lib/discourse_activity_pub/delivery_handler.rb:89:in `after_scheduled'
plugins/discourse-activity-pub/lib/discourse_activity_pub/delivery_handler.rb:15:in `perform'
plugins/discourse-activity-pub/lib/discourse_activity_pub/delivery_handler.rb:27:in `perform'
plugins/discourse-activity-pub/app/models/concerns/discourse_activity_pub/ap/model_callbacks.rb:160:in `block in activity_pub_deliver_activity'
plugins/discourse-activity-pub/app/models/concerns/discourse_activity_pub/ap/model_callbacks.rb:159:in `each'
plugins/discourse-activity-pub/app/models/concerns/discourse_activity_pub/ap/model_callbacks.rb:159:in `activity_pub_deliver_activity'
plugins/discourse-activity-pub/app/models/concerns/discourse_activity_pub/ap/model_callbacks.rb:41:in `perform_activity_pub_activity'
plugins/discourse-activity-pub/plugin.rb:455:in `block (2 levels) in activate!'
lib/plugin/instance.rb:376:in `public_send'
lib/plugin/instance.rb:376:in `block (2 levels) in add_to_class'
plugins/discourse-activity-pub/plugin.rb:661:in `block (2 levels) in activate!'
lib/plugin/instance.rb:576:in `block in on'
lib/discourse_event.rb:12:in `block in trigger'
/home/cloudron/rbenv/versions/3.2.2/lib/ruby/3.2.0/set.rb:511:in `each_key'
/home/cloudron/rbenv/versions/3.2.2/lib/ruby/3.2.0/set.rb:511:in `each'
lib/discourse_event.rb:12:in `trigger'
lib/post_creator.rb:258:in `trigger_after_events'
lib/post_creator.rb:220:in `create'
lib/new_post_manager.rb:318:in `perform_create_post'
lib/new_post_manager.rb:252:in `perform'
app/controllers/posts_controller.rb:215:in `create'
actionpack (7.1.3.4) lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
actionpack (7.1.3.4) lib/abstract_controller/base.rb:224:in `process_action'
actionpack (7.1.3.4) lib/action_controller/metal/rendering.rb:165:in `process_action'
actionpack (7.1.3.4) lib/abstract_controller/callbacks.rb:259:in `block in process_action'
activesupport (7.1.3.4) lib/active_support/callbacks.rb:121:in `block in run_callbacks'
app/controllers/application_controller.rb:424:in `block in with_resolved_locale'
i18n (1.14.5) lib/i18n.rb:351:in `with_locale'
app/controllers/application_controller.rb:424:in `with_resolved_locale'
activesupport (7.1.3.4) lib/active_support/callbacks.rb:130:in `block in run_callbacks'
activesupport (7.1.3.4) lib/active_support/callbacks.rb:141:in `run_callbacks'
actionpack (7.1.3.4) lib/abstract_controller/callbacks.rb:258:in `process_action'
actionpack (7.1.3.4) lib/action_controller/metal/rescue.rb:25:in `process_action'
actionpack (7.1.3.4) lib/action_controller/metal/instrumentation.rb:74:in `block in process_action'
activesupport (7.1.3.4) lib/active_support/notifications.rb:206:in `block in instrument'
activesupport (7.1.3.4) lib/active_support/notifications/instrumenter.rb:58:in `instrument'
activesupport (7.1.3.4) lib/active_support/notifications.rb:206:in `instrument'
actionpack (7.1.3.4) lib/action_controller/metal/instrumentation.rb:73:in `process_action'
actionpack (7.1.3.4) lib/action_controller/metal/params_wrapper.rb:261:in `process_action'
activerecord (7.1.3.4) lib/active_record/railties/controller_runtime.rb:32:in `process_action'
actionpack (7.1.3.4) lib/abstract_controller/base.rb:160:in `process'
actionview (7.1.3.4) lib/action_view/rendering.rb:40:in `process'
rack-mini-profiler (3.3.1) lib/mini_profiler/profiling_methods.rb:89:in `block in profile_method'
actionpack (7.1.3.4) lib/action_controller/metal.rb:227:in `dispatch'
actionpack (7.1.3.4) lib/action_controller/metal.rb:309:in `dispatch'
actionpack (7.1.3.4) lib/action_dispatch/routing/route_set.rb:49:in `dispatch'
actionpack (7.1.3.4) lib/action_dispatch/routing/route_set.rb:32:in `serve'
actionpack (7.1.3.4) lib/action_dispatch/journey/router.rb:51:in `block in serve'
actionpack (7.1.3.4) lib/action_dispatch/journey/router.rb:131:in `block in find_routes'
actionpack (7.1.3.4) lib/action_dispatch/journey/router.rb:124:in `each'
actionpack (7.1.3.4) lib/action_dispatch/journey/router.rb:124:in `find_routes'
actionpack (7.1.3.4) lib/action_dispatch/journey/router.rb:32:in `serve'
actionpack (7.1.3.4) lib/action_dispatch/routing/route_set.rb:882:in `call'
lib/middleware/omniauth_bypass_middleware.rb:64:in `call'
rack (2.2.9) lib/rack/tempfile_reaper.rb:15:in `call'
rack (2.2.9) lib/rack/conditional_get.rb:40:in `call'
rack (2.2.9) lib/rack/head.rb:12:in `call'
actionpack (7.1.3.4) lib/action_dispatch/http/permissions_policy.rb:36:in `call'
lib/content_security_policy/middleware.rb:12:in `call'
lib/middleware/anonymous_cache.rb:393:in `call'
lib/middleware/csp_script_nonce_injector.rb:12:in `call'
config/initializers/008-rack-cors.rb:14:in `call'
rack (2.2.9) lib/rack/session/abstract/id.rb:266:in `context'
rack (2.2.9) lib/rack/session/abstract/id.rb:260:in `call'
actionpack (7.1.3.4) lib/action_dispatch/middleware/cookies.rb:689:in `call'
actionpack (7.1.3.4) lib/action_dispatch/middleware/callbacks.rb:29:in `block in call'
activesupport (7.1.3.4) lib/active_support/callbacks.rb:101:in `run_callbacks'
actionpack (7.1.3.4) lib/action_dispatch/middleware/callbacks.rb:28:in `call'
actionpack (7.1.3.4) lib/action_dispatch/middleware/debug_exceptions.rb:29:in `call'
actionpack (7.1.3.4) lib/action_dispatch/middleware/show_exceptions.rb:31:in `call'
logster (2.20.0) lib/logster/middleware/reporter.rb:40:in `call'
lib/freedom_patches/rails_rack_logger_from_rails_7_2.rb:35:in `call_app'
lib/freedom_patches/rails_rack_logger_from_rails_7_2.rb:22:in `call'
config/initializers/100-quiet_logger.rb:20:in `call'
config/initializers/100-silence_logger.rb:29:in `call'
actionpack (7.1.3.4) lib/action_dispatch/middleware/request_id.rb:28:in `call'
lib/middleware/enforce_hostname.rb:24:in `call'
rack (2.2.9) lib/rack/method_override.rb:24:in `call'
actionpack (7.1.3.4) lib/action_dispatch/middleware/executor.rb:14:in `call'
actionpack (7.1.3.4) lib/action_dispatch/middleware/static.rb:25:in `call'
rack (2.2.9) lib/rack/sendfile.rb:110:in `call'
rack-mini-profiler (3.3.1) lib/mini_profiler.rb:191:in `call'
message_bus (4.3.8) lib/message_bus/rack/middleware.rb:60:in `call'
lib/middleware/request_tracker.rb:360:in `call'
actionpack (7.1.3.4) lib/action_dispatch/middleware/remote_ip.rb:92:in `call'
railties (7.1.3.4) lib/rails/engine.rb:536:in `call'
railties (7.1.3.4) lib/rails/railtie.rb:226:in `public_send'
railties (7.1.3.4) lib/rails/railtie.rb:226:in `method_missing'
rack (2.2.9) lib/rack/urlmap.rb:74:in `block in call'
rack (2.2.9) lib/rack/urlmap.rb:58:in `each'
rack (2.2.9) lib/rack/urlmap.rb:58:in `call'
unicorn (6.1.0) lib/unicorn/http_server.rb:634:in `process_client'
unicorn (6.1.0) lib/unicorn/http_server.rb:739:in `worker_loop'
unicorn (6.1.0) lib/unicorn/http_server.rb:547:in `spawn_missing_workers'
unicorn (6.1.0) lib/unicorn/http_ser

Env

HTTP HOSTS: community.tuist.io

Salut, je suis l’administrateur de lemmy.dbzer0.com et j’aimerais voir une plus grande interaction entre Lemmy et Discourse, car j’ai l’impression que ces deux éléments s’emboîtent beaucoup plus naturellement que Discourse et Mastodon.

Je suis principalement intéressé par un moyen pour les utilisateurs de Lemmy de pouvoir voir et interagir avec des sujets sans avoir à créer de nouveaux comptes pour chaque forum Discourse.

D’après ce que j’ai compris, le plus gros problème est que le plugin apub ne représente pas les catégories Discourse comme des groupes apub, ce qui empêche Lemmy de les voir, n’est-ce pas ?

Quoi qu’il en soit, je souhaite me rendre disponible au cas où vous voudriez avoir accès à une instance Lemmy et à un administrateur pour tester. Mon compte sur Lemmy est https://lemmy.dbzer0.com/u/db0

5 « J'aime »

Salut à tous, je serai de retour pour fournir un support régulier à ce plugin dès maintenant et jusqu’en mars de l’année prochaine au moins. Si vous avez utilisé ce plugin et que vous rencontrez des difficultés, faites-le moi savoir ! Je répondrai au plus grand nombre de questions en suspens que je pourrai.

Chaque utilisateur de Discourse est dans un Acteur. Le processus de suivi dans Discourse fonctionne de la même manière que dans Lemmy, et comme détaillé plus loin dans FEP-1b12. La raison pour laquelle vous ne pouvez pas encore suivre les Acteurs Discourse (c’est-à-dire que l’accent principal a été mis sur le suivi des catégories) est que les forums sont intrinsèquement centrés sur le sujet, c’est-à-dire des discussions qui impliquent intrinsèquement plusieurs utilisateurs. En effet, c’est l’approche adoptée par d’autres applications ActivityPub de type forum, et c’est ce sur quoi nous avons travaillé au sein du groupe de travail W3C Forum et Threaded Discussion (ainsi que NodeBB et des logiciels similaires).

Ce que vous décrivez est la différence entre la fédération “Premier message uniquement” et “Sujet complet”. Ce que vous attendez est la façon dont fonctionne la fédération “Sujet complet”. Veuillez consulter la documentation et les vidéos explicatives à ce sujet ici.

Cette erreur signifie que vous n’utilisez pas une version à jour de Discourse. Le plugin ActivityPub nécessite actuellement la dernière version de Discourse pour fonctionner.

Non, le plugin ActivityPub est entièrement conforme à la FEP-1b12, qui a été rédigée par Nutomic (le créateur de Lemmy) pour décrire la fédération basée sur les groupes. Avez-vous essayé de fédérer entre Lemmy et Discourse ?

2 « J'aime »

Êtes-vous en mesure d’enquêter sur le fait que meta n’affiche pas correctement mon domaine et n’affiche aucun contenu de meta ?

1 « J'aime »

Existe-t-il un serveur Discourse avec ce plugin avec lequel nous pouvons tester ? Je suppose que ce forum ne l’utilise pas, n’est-ce pas ?

1 « J'aime »

Meta utilise activitypub, par exemple ce sujet n’était pas fédéré :

Et celui-ci l’était :

Où puis-je voir ces informations ? De plus, le deuxième lien n’est pas accessible pour moi

L’URL (par opposition à l’URI AP) de cette page est

Vous pouvez voir les informations AP en cliquant sur l’icône AP.

1 « J'aime »

J’ai du mal à trouver ne serait-ce qu’un seul sujet Apub. La plupart du temps, l’icône n’existe pas

Et s’il existe, il est désactivé.

Néanmoins, j’ai suivi le lien que vous avez posté et j’ai recherché l’URL dans lemmy (qui est la façon dont on récupérerait les liens auxquels on ne s’était pas abonné auparavant) et il ne peut pas être trouvé. Je ne trouve pas non plus du tout le forum d’annonces afin de pouvoir m’y abonner.

1 « J'aime »

OK, j’ai réussi à le trouver en le recherchant comme announcements@meta.discourse.org et je me suis abonné. Je vais essayer de m’abonner à quelques autres sujets pour voir si je peux voir de nouveaux messages dans lemmy.

EDIT : Certaines communautés sont trouvables comme Feature et Announcements, mais Support, Plugin et Bug ne peuvent pas être trouvées https://lemmy.dbzer0.com/search?q=!plugin%40meta.discourse.org&type=Communities&listingType=All&page=1&sort=TopAll

2 « J'aime »

C’est parce qu’ils n’ont pas d’Acteurs. Veuillez consulter la documentation et les vidéos pédagogiques. Vous verrez que chaque Catégorie doit se voir attribuer un Acteur avant d’être trouvable.

Sur meta, je pense que seuls Announcements et Feature ont eu des Acteurs créés pour eux.

4 « J'aime »

Mais je suis une instance externe qui essaie d’obtenir du contenu fédéré de votre part. Je n’ai pas la visibilité nécessaire, n’est-ce pas ?

EDIT : Ah, je vois maintenant l’onglet de fédération, mais seulement parfois. D’autres fois, il n’apparaît pas.

2 « J'aime »

Oui, cela sera bientôt résolu. Si vous ne le voyez pas, actualisez simplement la page et il apparaîtra. Tenez-moi au courant de vos progrès.

Juste pour information, @mcdanlj et moi discutons de cela en privé. Il s’agit probablement d’un problème historique (c’est-à-dire parce que Michael était un adoptant précoce).

4 « J'aime »

Oui, deux questions :

  1. Qu’en est-il de l’impossibilité de trouver un fil fédéré existant comme New and improved About page at /about is live - Announcements - Discourse Meta ? J’ai essayé de le rechercher sur lemmy mais il n’apparaît pas.
  2. Pourquoi certains fils d’un sujet sont-ils fédérés, mais d’autres non ? Comment puis-je le savoir ?

Quoi qu’il en soit, peut-être que Following an ActivityPub Actor pourrait également être mis à jour avec des informations relatives à lemmy ?

1 « J'aime »

Vous pourriez demander aux développeurs de Lemmy et à @angus sur Lemmy - SocialHub afin qu’ils puissent mieux coordonner. L’interopérabilité avec Lemmy serait :tada:


@angus, dans un récent article de blog de Mastodon il y a quelque chose qui mérite d’être implémenté, par exemple, pour le sujet mis en avant dans le profil d’un utilisateur, si ce sujet a été initié par cet utilisateur :

Nous avons décidé de créer un nouveau type de balise OpenGraph — le même type de balises que vous avez sur votre site Web pour déterminer quelle miniature apparaîtra dans l’aperçu de la page lorsqu’elle est partagée sur Discord, iMessage ou Mastodon. Cela ressemble à ceci : <meta name="fediverse:creator" content="@Gargron@mastodon.social" />.

La balise meta apparaîtrait sur le sujet, afin que Mastodon puisse lier au profil de l’utilisateur. Je sais qu’il n’y a pas d’acteur utilisateur dans Discourse, mais si l’acteur ActivityPub est, disons, une société d’édition, et que le sujet concerne leur catalogue, alors le cas d’utilisation a du sens. :wink:

1 « J'aime »

Oui, comme le suggère @hellekin, je pense qu’une discussion plus approfondie sur Lemmy / Discourse serait mieux traitée ici :

Comme je reprends le travail sur ce plugin, veuillez y poster vos questions plus détaillées sur Lemmy et je vous répondrai bientôt.

Merci, j’y réfléchirai.

Il y a des Acteurs Utilisateurs dans Discourse. Vous ne pouvez tout simplement pas les suivre (actuellement). Comme cette idée fausse est apparue trois fois aujourd’hui, je pense à la mettre en évidence quelque part dans l’interface utilisateur. Pour répondre à la question de suivi “Pourquoi ne peut-on pas suivre les acteurs utilisateurs s’ils existent ?”, la question précédente “Pourquoi voudrait-on suivre les acteurs utilisateurs dans Discourse ?” doit d’abord être répondue (c’est-à-dire quel est un cas d’utilisation réel).

(Je suis conscient que Discourse Follow existe - je l’ai construit - cependant, il y a une différence entre suivre un utilisateur au sein d’une instance à des fins de notification/découverte et suivre un Acteur Utilisateur dans le fediverse)

4 « J'aime »

Cela sera corrigé une fois que ceci sera fusionné.

Notez également que j’écrirai bientôt un sujet « comment faire » sur Lemmy <> Discourse ici sur meta avec une vidéo d’instruction. Si vous utilisez, ou souhaitez utiliser, Lemmy pour vous fédérer avec Discourse, veuillez partager vos réflexions / expériences ici et je veillerai à les aborder dans les instructions.

2 « J'aime »

Oh, joli changement qui vient d’arriver :

:tada:

3 « J'aime »