Vous trouverez ci-dessous une collection d’opérations en lot pouvant être lancées depuis la ligne de commande. Vous aurez besoin d’un accès SSH ; si vous êtes un client hébergé, vous devrez contacter l’équipe Discourse pour exécuter ces commandes.
Avant de travailler avec la console, il est extrêmement important que vous disposiez d’une sauvegarde récente. Des erreurs peuvent toujours survenir !
La première chose à faire est d’entrer dans le conteneur de votre site :
cd /var/discourse
./launcher enter app
Guides supplémentaires :
- Performing bulk actions as a moderator
- Comment définir par défaut les niveaux de suivi des balises historiquement
- (Obsolete) Set category tracking level defaults historically
- Change ownership of all posts by a specific user
- Replace a string in all posts
- Edit a user preference for everyone or a subset of users
- Modify trust level for all users
- Apply auto-close to existing topics
- Logout all users through the rails console
- Convert all existing topics in category to wikis
Changer le statut des sujets
Avant d’exécuter les commandes suivantes, lancez rails c pour entrer dans la console.
-
Masquer tous les sujets d’une catégorie (exclut l’action sur les messages)
Vous pouvez remplacer
visibleparclosedouarchivedet ajuster les valeurs true/false selon vos besoinscat_id = Category.find_by_slug('admins').id Topic.where(category_id: cat_id, visible: true).update_all(visible: false) -
Masquer tous les sujets d’une catégorie (inclut l’action sur les messages)
cat_id = Category.find_by_slug("admins").id Topic.where(category_id: cat_id, visible: true).find_each do |topic| topic.update_status('visible', false, Discourse.system_user) end -
Fermer tous les sujets créés avant une date spécifiée (inclut l’action sur les messages)
Topic.where(closed: false).where("created_at < '2015-01-01'").find_each do |topic| topic.update_status('closed', true, Discourse.system_user) end
Déplacer des sujets
Déplacer un ensemble de sujets d’une catégorie à une autre
rails c
topic_ids = [12,16,29]
cat_to = Category.find_by_slug('faq')
Topic.where(id: topic_ids).update_all(category_id: cat_to.id)
Category.update_stats
Utilisateurs
Supprimer un sous-ensemble d’utilisateurs
Supprimer les utilisateurs qui n’ont jamais publié et qui n’ont pas visité depuis une date spécifiée
rails c
User.joins(:user_stat).where("user_stats.post_count = 0 AND previous_visit_at <= '2016-05-20'::timestamp").destroy_all
Suspendre un ensemble d’utilisateurs selon des critères
Définir qui sera enregistré comme ayant suspendu les utilisateurs
rails c
logger = StaffActionLogger.new(User.find_by(username_lower: "tshenry"))
Créer une durée de suspension et un motif
suspend_till = DateTime.new(2057,12,31)
reason = 'Cours terminé'
Dans cet exemple, nos critères d’utilisateurs seront l’appartenance à un groupe.
target_group = Group.find_by_name("summer_students")
users = User.joins(:group_users).where(group_users: {group_id: target_group.id})
Suspendre chaque utilisateur selon les valeurs établies ci-dessus :
users.find_each do |u|
u.suspended_till = suspend_till
u.suspended_at = DateTime.now
u.save!
logger.log_user_suspend(u,reason)
putc '.'
end
Mettre à jour les motifs de suspension des utilisateurs
Peut-être avez-vous suspendu des utilisateurs ayant terminé un cours (voir l’exemple ci-dessus), et vous souhaitez maintenant ajouter l’année du cours car vous l’avez enseigné plusieurs années.
UserHistory.where(action: 10, details: "Cours terminé").update_all(details: "Cours 2018 terminé")
Lever la suspension des utilisateurs
Si vous devez lever la suspension d’utilisateurs en lot, par exemple parce qu’ils faisaient partie d’une cohorte de l’année précédente et qu’ils reviennent cette année, vous pouvez le faire comme indiqué ci-dessous. Dans l’exemple, nous trouvons les utilisateurs par leur ID.
user_list = [1, 3, 5, 7, 11]
users = User.where("id in (?)", user_list)
users.each do |user|
user.suspended_till = nil
user.suspended_at = nil
user.save!
StaffActionLogger.new(User.find(-1)).log_user_unsuspend(user)
DiscourseEvent.trigger(:user_unsuspended, user: user)
end
Exporter/Importer
Exporter/Importer tous les paramètres du site
Pour simplement afficher tous les paramètres qui ont été modifiés sur votre site, lancez :
rake site_settings:export
Si vous souhaitez exporter les paramètres vers un fichier :
rake site_settings:export > saved_settings.yml
Si vous souhaitez importer des paramètres depuis un fichier :
rake site_settings:import < saved_settings.yml
Exporter/Importer les catégories
Il existe deux options pour l’exportation et une méthode pour gérer l’importation.
Exporter un ensemble de catégories complètes
Obtenez d’abord la liste des IDs de vos catégories :
rake categories:list
Ensuite, séparez les IDs des catégories par des espaces dans la tâche rake d’exportation. Par exemple :
rake export:categories["12 6"]
Exporter la structure des catégories de votre site
Il s’agit essentiellement de copier le « squelette » de votre site Discourse. Cela inclut chaque catégorie ainsi que tous les groupes associés aux permissions de catégorie existantes. Cela n’inclut pas les sujets :
rake export:category_structure
Si vous souhaitez la structure des catégories ainsi que tous les groupes associés aux permissions de catégorie et tous les membres de ces groupes :
rake export:category_structure[true]
Importer un fichier de catégorie
Utilisez le nom du fichier exporté comme dans l’exemple ci-dessous :
rake import:file["category-export-2019-05-16-052430.json"]
Exporter/Importer les groupes
Exporter tous les groupes d’utilisateurs
rake export:groups
Exporter tous les groupes d’utilisateurs, y compris les utilisateurs
rake export:groups[true]
Importer un fichier de groupe
Utilisez le nom du fichier exporté comme dans l’exemple ci-dessous :
rake import:file["group-export-2019-05-16-052430.json"]
Définir les permissions pour plusieurs catégories
Notez que cela supprimera toutes les restrictions d’accès existantes que vous avez définies pour les catégories concernées. Assurez-vous d’inclure toutes les permissions pertinentes.
-
Obtenir la liste des catégories ainsi que leurs IDs
rails c Category.all.pluck("name", "id") -
Créer un tableau avec les IDs des catégories que vous souhaitez cibler.
category_ids = [6,7,8,10] -
Modifier les permissions. La fonction
set_permissionspeut utiliser les paramètres suivants ::full,:create_post,:readonly-
Une seule permission. Par exemple, rendre un ensemble de catégories réservé au personnel :
Category.where(id: category_ids).find_each do |category| category.set_permissions(:staff => :full) category.save! end -
Plusieurs permissions. Par exemple, rendre un ensemble de catégories en lecture seule pour les utilisateurs normaux :
Category.where(id: category_ids).find_each do |category| category.set_permissions(:everyone => :readonly, :staff => :full) category.save! end -
Permissions de groupe d’utilisateurs. Par exemple, accorder des permissions complètes à un groupe et en lecture seule à un autre groupe pour un ensemble de catégories :
artists_group = Group.find_by_name("artists") buyers_group = Group.find_by_name("buyers") Category.where(id: category_ids).find_each do |category| category.set_permissions(artists_group.id => :full, buyers_group.id => :readonly) category.save! end
-
Baliser en lot tous les sujets selon un mot-clé
Le script suivant vous permettra de baliser les sujets en fonction de la présence d’un mot-clé dans le titre du sujet ou dans ses messages. Commencez par créer un tableau de mots-clés :
rails c
keywords = ['pommes','oranges']
Ensuite, nous devons définir une méthode :
def tag_by_keyword(word, tag_name)
tag = Tag.find_by_name(tag_name) || Tag.create(name: tag_name)
keyword_topics = Topic.joins(:posts).where("topics.title ~* :keyword or posts.raw ~* :keyword", keyword: "\\y#{word}\\y").distinct
keyword_topics.each do |topic|
if topic.tags.exclude?(tag)
topic.tags << tag
end
end
end
Et enfin, exécuter chaque mot-clé à travers la méthode. Ce qui suit balisera chaque sujet pertinent avec une balise nommée « fruit » :
keywords.each { |word| tag_by_keyword(word, 'fruit') }
Baliser en lot tous les sujets d’une catégorie
Modèle : rake tags:bulk_tag_category["<tag>|<tag>",<category_id>]
Cela serait particulièrement utile lors de la tentative de conversion d’une catégorie en balise.
Tout d’abord, utilisez la tâche rake suivante pour trouver l’ID de la catégorie pertinente.
rake categories:list
Baliser tous les sujets de la catégorie que vous spécifiez. Dans cet exemple, vous baliseriez tous les sujets de la catégorie avec l’ID 6 avec la balise « support ».
cela supprimera toutes les autres balises de chaque sujet.
rake tags:bulk_tag_category["support",6]
Ajouter la balise à tous les sujets de la catégorie que vous spécifiez. Dans cet exemple, vous ajouteriez la balise « support » à tous les sujets de la catégorie avec l’ID 6, tout en conservant les balises existantes.
rake tags:bulk_tag_category["support",6,true]
Déplacer tous les sujets avec une balise spécifique vers une seule catégorie
Lors de la tentative de restructuration de votre site Discourse, vous pourriez souhaiter déplacer un ensemble de sujets sans déclencher de notifications. Une façon de faire est de créer une balise temporaire, d’appliquer cette balise aux sujets appropriés, de déplacer les sujets vers une catégorie spécifique en utilisant le code ci-dessous, puis enfin de supprimer la balise temporaire.
Obtenir la balise.
rails c
tag = Tag.find_by_name("tutoriel")
Obtenir la catégorie de destination.
- Pour les catégories régulières :
cat_to = Category.find_by_slug('guides')
- Pour les sous-catégories :
cat_to = Category.find_by_slug('slug-enfant','slug-parent')
Déplacer les sujets balisés vers la catégorie de destination.
Topic.joins(:topic_tags).where("topic_tags.tag_id = ?", tag.id).update_all(category_id: cat_to.id)
Mettre à jour les comptes de sujets des catégories concernées.
Category.update_stats
CategoryTagStat.update_topic_counts
Déplacer tous les sujets d’une catégorie à une autre
Trouvez les IDs des catégories avec la tâche rake suivante :
rake categories:list
La première valeur devrait être l’ID de la catégorie de départ. La deuxième valeur devrait être l’ID de la catégorie de destination.
rake categories:move_topics[15,6]
Script de la console Rails
cat_from_id = XX # Catégorie depuis laquelle déplacer les sujets
cat_to_id = XX # Catégorie vers laquelle déplacer les sujets
Topic.where(category_id: cat_from_id).update_all(category_id: cat_to_id)
Category.update_stats
CategoryTagStat.update_topic_counts
Changer le propriétaire de tous les sujets dans les catégories
Trouvez les IDs des catégories avec la tâche rake suivante :
rake categories:list
Spécifiez le nouveau propriétaire et les catégories sur lesquelles opérer. Les catégories doivent être un tableau d’IDs de catégories, les catégories 1, 2 et 3 dans l’exemple :
rails c
user = User.find_by(username_lower: "nom-utilisateur-en-minuscules")
categories = [1, 2, 3]
Obtenir tous les IDs de sujets pour les catégories données et changer le propriétaire du premier message dans tous les sujets correspondants.
topics = Topic.where(category_id: categories).pluck(:id)
topics.each do |topic|
PostOwnerChanger.new(
post_ids: Post.where(topic_id: topic).where(post_number: 1).pluck(:id),
topic_id: topic,
new_owner: user,
acting_user: Discourse.system_user,
skip_revision: true
).change_owner!
end
Accorder un badge à tous les membres d’un groupe
Accorder un badge à tous les utilisateurs appartenant à un groupe spécifique. La première valeur est l’ID du groupe et la deuxième est l’ID du badge.
rails c
Group.find_by_name("participants_evenement").id
Badge.find_by_name("badge_evenement").id
exit
rake groups:grant_badge[42,102]
Notez que la tâche rake ci-dessus accorde uniquement un badge ; elle ne révoquera pas un badge précédemment accordé si un utilisateur ne fait plus partie du groupe spécifié. Si vous devez révoquer en lot des badges pour tous les utilisateurs qui ne font plus partie d’un groupe, vous pouvez exécuter ce qui suit :
rails c
badge_id = Badge.find_by_name("Membre d'un groupe").id
group = Group.find_by_name("Some_Group")
group_user_id = group.users.pluck("id")
userBadge = UserBadge.where.not(user_id: group_user_id).where(badge_id: badge_id)
userBadge.each do |ub|
BadgeGranter.revoke(ub, revoked_by: Discourse.system_user)
end
exit
S’assurer que tous les utilisateurs sont à leur niveau de confiance automatique
Disons que vous avez défini le niveau de confiance par défaut pour les nouveaux utilisateurs ou les utilisateurs invités sur une valeur qui ne fonctionne pas tout à fait comme prévu (comme TL4). Maintenant, vous souhaitez le modifier afin que vos utilisateurs soient au niveau de confiance auquel ils seraient automatiquement, étant donné leurs statistiques actuelles. Les commandes suivantes s’assureront que tous les utilisateurs sont au niveau de confiance qu’ils devraient avoir selon Understanding Discourse Trust Levels. Remarque : les utilisateurs avec un niveau de confiance verrouillé ne seront pas affectés.
Assurez-vous que tous les utilisateurs sont définis sur le bon niveau de confiance :
rails c
User.all.find_each do |user|
Promotion.recalculate(user)
end
Actualiser les statistiques des groupes pour refléter les changements :
Group.ensure_consistency!
Scripts de maintenance des sujets
Les scripts Ruby suivants démontrent comment effectuer une maintenance automatisée des sujets en fonction des dates d’activité et d’autres critères. Ces scripts combinent des requêtes SQL pour identifier les sujets avec du code Ruby pour effectuer des actions sur eux, et doivent être exécutés via la console Rails de votre site.
Chaque script suit un modèle similaire :
- Une requête SQL qui identifie les sujets pertinents
- Du code Ruby qui traite chaque sujet et applique les actions souhaitées
- Une gestion d’erreurs et une journalisation de base
Ces scripts peuvent être personnalisés en :
- Ajustant les périodes de temps (par exemple, « 6 MOIS », « 1 AN », « 2 ANS »)
- Changeant les sélections de catégories pour correspondre à la structure de votre forum
- Modifiant les actions à entreprendre (fermer, masquer ou déplacer)
- Ajoutant des conditions supplémentaires comme le nombre de messages ou les seuils de vues
Fermer, masquer et déplacer les sujets inactifs
Ce script identifie les sujets qui répondent aux critères suivants :
- Dans une catégorie spécifique
- Ouverts
- Non résolus (en utilisant le plugin Discourse Solved)
- Aucune activité récente dans un délai spécifique
Puis effectue plusieurs actions :
- Les ferme,
- Les masque,
- Et les déplace vers une catégorie désignée pour le contenu obsolète
Requête SQL
WITH topic_list AS (
SELECT ua.target_topic_id, MAX(ua.created_at) "created_at"
FROM user_actions ua
INNER JOIN topics t ON t.id = ua.target_topic_id
INNER JOIN categories c ON c.id = t.category_id
LEFT JOIN discourse_solved_solved_topics solved ON solved.topic_id = t.id
WHERE t.closed = false
AND t.category_id = [CATEGORY_ID]
AND solved.topic_id IS NULL
AND t.deleted_at IS NULL
GROUP BY ua.target_topic_id
HAVING MAX(ua.created_at) <= (CURRENT_DATE - (INTERVAL '[TIME_PERIOD]'))
ORDER BY "created_at" DESC
)
SELECT '' AS total, target_topic_id AS topic_id, created_at
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY created_at DESC
SQL + Script combinés
sql = "WITH topic_list AS (
SELECT ua.target_topic_id, MAX(ua.created_at) \"created_at\"
FROM user_actions ua
INNER JOIN topics t ON t.id = ua.target_topic_id
INNER JOIN categories c ON c.id = t.category_id
LEFT JOIN discourse_solved_solved_topics solved ON solved.topic_id = t.id
WHERE t.closed = false
AND t.category_id = [CATEGORY_ID]
AND solved.topic_id IS NULL
AND t.deleted_at IS NULL
GROUP BY ua.target_topic_id
HAVING MAX(ua.created_at) <= (CURRENT_DATE - (INTERVAL '[TIME_PERIOD]'))
ORDER BY \"created_at\" DESC
)
SELECT '' AS total, target_topic_id AS topic_id, created_at
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY created_at DESC"
results = ActiveRecord::Base.connection.execute(sql)
user = Discourse.system_user
destination_category = Category.find([DESTINATION_CATEGORY_ID])
puts "#{results.count} sujets trouvés à traiter"
results.each do |row|
begin
topic = Topic.find(row["topic_id"])
# 1. Déplacer vers la catégorie de destination
topic.update!(category_id: destination_category.id)
puts "#{topic.id} déplacé vers la catégorie de destination"
# 2. Fermer le sujet
topic.update_status('closed', true, user, until: nil)
puts "#{topic.id} est fermé"
# 3. Masquer le sujet
topic.update_status('visible', false, user, until: nil)
puts "#{topic.id} est masqué"
# Gestion des erreurs
rescue => e
puts "Erreur lors du traitement du sujet #{row["topic_id"]}: #{e.message}"
end
end
puts "Processus terminé"
Fermer les sujets résolus sans activité récente
Ce script ferme les sujets résolus qui sont inactifs depuis une période définie. Cela peut aider à garder votre forum ordonné tout en préservant les sujets résolus précieux.
Ce script identifie les sujets qui répondent aux critères suivants :
- Dans une catégorie spécifique
- Ouverts
- Résolus (en utilisant le plugin Discourse Solved)
- Aucune activité récente dans un délai spécifique
Requête SQL
WITH topic_list AS (
SELECT ua.target_topic_id, MAX(ua.created_at) "created_at"
FROM user_actions ua
INNER JOIN topics t ON t.id = ua.target_topic_id
INNER JOIN categories c ON c.id = t.category_id
INNER JOIN discourse_solved_solved_topics solved ON solved.topic_id = t.id
WHERE t.closed = false
AND t.category_id IN ([CATEGORY_IDS])
AND t.deleted_at IS NULL
GROUP BY ua.target_topic_id
HAVING MAX(ua.created_at) <= (CURRENT_DATE - (INTERVAL '[TIME_PERIOD]'))
ORDER BY "created_at" DESC
)
SELECT '' AS total, target_topic_id AS topic_id, created_at
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY created_at DESC
SQL + Script combinés
sql = "WITH topic_list AS (
SELECT ua.target_topic_id, MAX(ua.created_at) \"created_at\"
FROM user_actions ua
INNER JOIN topics t ON t.id = ua.target_topic_id
INNER JOIN categories c ON c.id = t.category_id
INNER JOIN discourse_solved_solved_topics solved ON solved.topic_id = t.id
WHERE t.closed = false
AND t.category_id IN ([CATEGORY_IDS])
AND t.deleted_at IS NULL
GROUP BY ua.target_topic_id
HAVING MAX(ua.created_at) <= (CURRENT_DATE - (INTERVAL '[TIME_PERIOD]'))
ORDER BY \"created_at\" DESC
)
SELECT '' AS total, target_topic_id AS topic_id, created_at
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY created_at DESC"
results = ActiveRecord::Base.connection.execute(sql)
user = Discourse.system_user
puts "#{results.count} sujets trouvés à traiter"
results.each do |row|
begin
topic = Topic.find(row["topic_id"])
# Fermer le sujet
topic.update_status('closed', true, user, until: nil)
puts "#{topic.id} est fermé"
# Gestion des erreurs
rescue => e
puts "Erreur lors du traitement du sujet #{row["topic_id"]}: #{e.message}"
end
end
puts "Processus terminé"
Archiver les sujets précédemment fermés
Ce script identifie les sujets qui ont été précédemment fermés avant une date spécifique et les déplace vers une catégorie d’archive tout en les masquant.
Requête SQL
WITH topic_list AS (
SELECT
t.id AS topic_id,
tt.execute_at AS closed_at
FROM topics t
INNER JOIN categories c ON c.id = t.category_id
LEFT JOIN topic_timers tt ON tt.topic_id = t.id AND tt.status_type IN (1, 8)
WHERE t.closed = true
AND t.category_id IN ([CATEGORY_IDS])
AND t.deleted_at IS NULL
AND tt.execute_at IS NOT NULL
AND tt.execute_at <= (CURRENT_DATE - INTERVAL '[TIME_PERIOD]')
ORDER BY tt.execute_at DESC
)
SELECT '' AS total, topic_id, closed_at
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY closed_at DESC
SQL + Script combinés
sql = "WITH topic_list AS (
SELECT
t.id AS topic_id,
tt.execute_at AS closed_at
FROM topics t
INNER JOIN categories c ON c.id = t.category_id
LEFT JOIN topic_timers tt ON tt.topic_id = t.id AND tt.status_type IN (1, 8)
WHERE t.closed = true
AND t.category_id IN ([CATEGORY_IDS])
AND t.deleted_at IS NULL
AND tt.execute_at IS NOT NULL
AND tt.execute_at <= (CURRENT_DATE - INTERVAL '[TIME_PERIOD]')
ORDER BY tt.execute_at DESC
)
SELECT '' AS total, topic_id, closed_at
FROM topic_list
UNION
SELECT ''||COUNT(*), 0, CURRENT_DATE
FROM topic_list
ORDER BY closed_at DESC"
results = ActiveRecord::Base.connection.execute(sql)
user = Discourse.system_user
archive_category = Category.find([ARCHIVE_CATEGORY_ID])
puts "#{results.count} sujets trouvés à traiter"
results.each do |row|
begin
topic = Topic.find(row["topic_id"])
# 1. Déplacer vers la catégorie d'archive
topic.update!(category_id: archive_category.id)
puts "#{topic.id} déplacé vers la catégorie d'archive"
# 2. Masquer le sujet
topic.update_status('visible', false, user, until: nil)
puts "#{topic.id} est masqué"
# Gestion des erreurs
rescue => e
puts "Erreur lors du traitement du sujet #{row["topic_id"]}: #{e.message}"
end
end
puts "Processus terminé"
Tâches rake destructives
Supprimer des catégories entières
Ce qui suit vous permettra de détruire plusieurs catégories, ainsi que toutes les sous-catégories et les sujets qui leur appartiennent.
Afficher la liste des IDs de catégories
rake categories:list
Détruire un ensemble de catégories basé sur leur ID
rake destroy:categories[10,11,12,18,30]
Supprimer tous les sujets d’une catégorie
Supprimer tous les messages personnels
rake destroy:private_messages
Détruire tous les groupes
rake destroy:groups
Détruire tous les utilisateurs non administrateurs
rake destroy:users
Détruire les statistiques du site
rake destroy:stats
Anonymiser tous les utilisateurs sauf le personnel
rake users:anonymize_all
Supprimer définitivement un ensemble de messages
La tâche rake suivante supprimera définitivement une liste de messages basée sur leur ID. Si un message est le premier message d’un sujet, tous les messages de ce sujet seront supprimés définitivement. Avant de pouvoir exécuter avec succès la tâche, le paramètre du site can_permanently_delete doit être activé.
Une fois qu’un message est supprimé par cette tâche, il n’existera plus dans la base de données et ne pourra pas être restauré.
Il existe deux approches possibles :
-
Option 1 – Passer une liste séparée par des virgules d’IDs de messages comme argument
rake destroy:posts[4,8,15,16,23,42] -
Option 2 – Spécifier un fichier texte contenant une liste séparée par des virgules d’IDs de messages (idéal pour de grands ensembles de messages).
cat post_ids.txt | rake destroy:posts
J’ai essayé d’inclure les tâches rake les plus utiles dans ce sujet, mais il en existe beaucoup d’autres livrées avec Discourse. Si vous souhaitez voir une liste complète, vous pouvez utiliser ce qui suit :
Toutes les tâches qui ont des descriptions
rake --tasks
Toutes les tâches, y compris celles qui n’ont pas de descriptions
rake -AT