DEV: Move discourse-zendesk-plugin to core (#33570)

https://meta.discourse.org/t/373574

Internal `/t/-/156778`
This commit is contained in:
Jarek Radosz
2025-07-15 16:38:05 +02:00
parent 4525a9aeb4
commit 5e86f2c21f
76 changed files with 1783 additions and 0 deletions
+4
View File
@@ -54,6 +54,10 @@ discourse-openid-connect:
- changed-files:
- any-glob-to-any-file: plugins/discourse-openid-connect/**/*
discourse-zendesk-plugin:
- changed-files:
- any-glob-to-any-file: plugins/discourse-zendesk-plugin/**/*
footnote:
- changed-files:
- any-glob-to-any-file: plugins/footnote/**/*
+1
View File
@@ -56,6 +56,7 @@
!/plugins/discourse-microsoft-auth
!/plugins/discourse-oauth2-basic
!/plugins/discourse-openid-connect
!/plugins/discourse-zendesk-plugin
/plugins/*/auto_generated
/spec/fixtures/plugins/my_plugin/auto_generated
+6
View File
@@ -281,3 +281,9 @@ end
gem "dry-initializer", "~> 3.1"
gem "parallel"
# for discourse-zendesk-plugin
gem "inflection", "1.0.0", require: false
gem "multipart-post", "2.2.3", require: false
gem "faraday-multipart", "1.0.4", require: false
gem "zendesk_api", "1.38.0.rc1", require: false
+19
View File
@@ -157,6 +157,8 @@ GEM
faraday-net_http (>= 2.0, < 3.5)
json
logger
faraday-multipart (1.0.4)
multipart-post (~> 2)
faraday-net_http (3.4.1)
net-http (>= 0.5.0)
faraday-retry (2.3.2)
@@ -213,6 +215,7 @@ GEM
progress (~> 3.0, >= 3.0.1)
image_size (3.4.0)
in_threads (1.6.0)
inflection (1.0.0)
io-console (0.8.0)
irb (1.15.2)
pp (>= 0.6.0)
@@ -290,6 +293,7 @@ GEM
multi_json (1.16.0)
multi_xml (0.7.2)
bigdecimal (~> 3.1)
multipart-post (2.2.3)
mustache (1.1.1)
net-http (0.6.0)
uri
@@ -643,6 +647,13 @@ GEM
yaml-lint (0.1.2)
yard (0.9.37)
zeitwerk (2.7.3)
zendesk_api (1.38.0.rc1)
faraday (> 2.0.0)
faraday-multipart
hashie (>= 3.5.2, < 6.0.0)
inflection
mini_mime
multipart-post (~> 2.0)
PLATFORMS
aarch64-linux
@@ -700,6 +711,7 @@ DEPENDENCIES
fabrication
faker
faraday
faraday-multipart (= 1.0.4)
faraday-retry
fast_blank
fastimage
@@ -707,6 +719,7 @@ DEPENDENCIES
htmlentities
http_accept_language
image_optim
inflection (= 1.0.0)
iso8601
json
json_schemer
@@ -730,6 +743,7 @@ DEPENDENCIES
minio_runner
mocha
multi_json
multipart-post (= 2.2.3)
mustache
net-http
net-imap
@@ -801,6 +815,7 @@ DEPENDENCIES
yaml-lint
yard
zeitwerk
zendesk_api (= 1.38.0.rc1)
CHECKSUMS
actionmailer (7.2.2.1) sha256=b02ae523c32c8ad762d4db941e76f3c108c106030132247ee7a7b8c86bc7b21f
@@ -870,6 +885,7 @@ CHECKSUMS
fabrication (3.0.0) sha256=a6a0bfad9071348ad3cb1701df788524b888c0cdd044b988893e7509f7463be3
faker (3.5.2) sha256=f9a80291b2e3f259801d1dd552f0732fe04dce5d1f74e798365bc0413789c473
faraday (2.13.2) sha256=5c19762e3bbe78e61d8007c5119f2968373c5296d6c6d6aa05b6f9cec34f2a1a
faraday-multipart (1.0.4) sha256=9012021ab57790f7d712f590b48d5f948b19b43cfa11ca83e6459f06090b0725
faraday-net_http (3.4.1) sha256=095757fae7872b94eac839c08a1a4b8d84fd91d6886cfbe75caa2143de64ab3b
faraday-retry (2.3.2) sha256=2402d2029032ebd238a2046221e67f6ef0da78c5a8ce8cd4f8b9c62e4d6451d1
fast_blank (1.0.1) sha256=269fc30414fed4e6403bc4a49081e1ea539f8b9226e59276ed1efaefabaa17ea
@@ -902,6 +918,7 @@ CHECKSUMS
image_optim (0.31.4) sha256=5bffd0891268e8d189d46ee4b8599918581bba1032d244e6ace4779a434776c0
image_size (3.4.0) sha256=c6a580513fe74947e25e5d3f0aea1e33add6c20f7d0007efa65504317b7f029a
in_threads (1.6.0) sha256=91a7e6138d279dc632f59b8a9a409e47148948e297c0f69c92f9a2479a182149
inflection (1.0.0) sha256=ceba9b26fc28b9af82e33e822d28f78a4312af75687efec81d5ef1062498d355
io-console (0.8.0) sha256=cd6a9facbc69871d69b2cb8b926fc6ea7ef06f06e505e81a64f14a470fddefa2
irb (1.15.2) sha256=222f32952e278da34b58ffe45e8634bf4afc2dc7aa9da23fed67e581aa50fdba
iso8601 (0.13.0) sha256=298c2b15b7be5fa95a1372813d36a2257656cd8e906dfbc1f5cb409851425aa2
@@ -948,6 +965,7 @@ CHECKSUMS
msgpack (1.8.0) sha256=e64ce0212000d016809f5048b48eb3a65ffb169db22238fb4b72472fecb2d732
multi_json (1.16.0) sha256=111f3120b69989829e7819321e3f626b943c04017cedf912b8fc7125fefa7636
multi_xml (0.7.2) sha256=307a96dc48613badb7b2fc174fd4e62d7c7b619bc36ea33bfd0c49f64f5787ce
multipart-post (2.2.3) sha256=462979de2971b8df33c2ee797fd497731617241f9dcd93960cc3caccb2dd13d8
mustache (1.1.1) sha256=90891fdd50b53919ca334c8c1031eada1215e78d226d5795e523d6123a2717d0
net-http (0.6.0) sha256=9621b20c137898af9d890556848c93603716cab516dc2c89b01a38b894e259fb
net-imap (0.5.9) sha256=d95905321e1bd9f294ffc7ff8697be218eee1ec96c8504c0960964d0a0be33fc
@@ -1105,6 +1123,7 @@ CHECKSUMS
yaml-lint (0.1.2) sha256=e3960b171766ae187338a169815e99fe10fcb0d9c22b1c539e8d57e114324c8a
yard (0.9.37) sha256=a6e910399e78e613f80ba9add9ba7c394b1a935f083cccbef82903a3d2a26992
zeitwerk (2.7.3) sha256=b2e86b4a9b57d26ba68a15230dcc7fe6f040f06831ce64417b0621ad96ba3e85
zendesk_api (1.38.0.rc1) sha256=9ebe2575d223ed1c0651b2d10df6c010141cda49d524c38532b472f7e8bb3f7a
RUBY VERSION
ruby 3.3.1p55
@@ -0,0 +1,5 @@
# Discourse Zendesk Plugin
Zendesk for Discourse
For more information, please see: https://meta.discourse.org/t/discourse-zendesk-plugin/68005
@@ -0,0 +1,22 @@
# frozen_string_literal: true
module DiscourseZendeskPlugin
class IssuesController < ApplicationController
include ::DiscourseZendeskPlugin::Helper
requires_plugin ::DiscourseZendeskPlugin::PLUGIN_NAME
def create
topic = Topic.find(params[:topic_id])
if topic.custom_fields[::DiscourseZendeskPlugin::ZENDESK_ID_FIELD].blank?
create_ticket(topic.first_post)
end
topic_view = ::TopicView.new(topic.id, current_user)
topic_view_serializer =
::TopicViewSerializer.new(topic_view, scope: topic_view.guardian, root: false)
render_json_dump topic_view_serializer
end
end
end
@@ -0,0 +1,57 @@
# frozen_string_literal: true
module DiscourseZendeskPlugin
class SyncController < ApplicationController
include ::DiscourseZendeskPlugin::Helper
requires_plugin ::DiscourseZendeskPlugin::PLUGIN_NAME
layout false
before_action :zendesk_token_valid?, only: :webhook
skip_before_action :check_xhr,
:preload_json,
:verify_authenticity_token,
:redirect_to_login_if_required,
only: :webhook
def webhook
unless SiteSetting.zendesk_enabled? && SiteSetting.sync_comments_from_zendesk
return render json: failed_json, status: 422
end
ticket_id = params[:ticket_id]
raise Discourse::InvalidParameters.new(:ticket_id) if ticket_id.blank?
topic = Topic.find_by_id(params[:topic_id])
raise Discourse::InvalidParameters.new(:topic_id) if topic.blank?
return if !DiscourseZendeskPlugin::Helper.autogeneration_category?(topic.category_id)
user = User.find_by_email(params[:email]) || Discourse.system_user
latest_comment = get_latest_comment(ticket_id)
if latest_comment.present?
existing_comment =
PostCustomField.where(
name: ::DiscourseZendeskPlugin::ZENDESK_ID_FIELD,
value: latest_comment.id,
).first
if existing_comment.blank?
post = topic.posts.create!(user: user, raw: latest_comment.body)
update_post_custom_fields(post, latest_comment)
end
end
render json: {}, status: 204
end
private
def zendesk_token_valid?
params.require(:token)
if SiteSetting.zendesk_incoming_webhook_token.blank? ||
SiteSetting.zendesk_incoming_webhook_token != params[:token]
raise Discourse::InvalidAccess.new
end
end
end
end
@@ -0,0 +1,22 @@
# frozen_string_literal: true
module Jobs
class MigrateZendeskAutogenerateCategoriesSiteSettings < ::Jobs::Onceoff
def execute_onceoff(_)
site_setting =
SiteSetting.where(
name: "zendesk_autogenerate_categories",
data_type: SiteSettings::TypeSupervisor.types[:list],
)
return unless site_setting.exists?
site_setting = site_setting.first
site_setting.update!(
data_type: SiteSettings::TypeSupervisor.types[:category_list],
value: Category.where(name: site_setting.value.split("|")).pluck(:id).join("|"),
)
end
end
end
@@ -0,0 +1,45 @@
# frozen_string_literal: true
module Jobs
class ZendeskJob < ::Jobs::Base
sidekiq_options backtrace: true
include ::DiscourseZendeskPlugin::Helper
def execute(args)
return unless SiteSetting.zendesk_enabled?
return if SiteSetting.zendesk_jobs_email.blank? || SiteSetting.zendesk_jobs_api_token.blank?
if args[:post_id].present?
push_post!(args[:post_id])
elsif args[:topic_id].present?
push_topic!(args[:topic_id])
end
end
private
def push_topic!(topic_id)
topic = Topic.find_by(id: topic_id)
return if !DiscourseZendeskPlugin::Helper.autogeneration_category?(topic.category_id)
if topic.present? &&
DiscourseZendeskPlugin::Helper.autogeneration_category?(topic.category_id)
topic.post_ids.each { |post_id| push_post!(post_id) }
end
end
def push_post!(post_id)
post = Post.find_by(id: post_id)
return if !post || post.user_id < 1
return if post.custom_fields[::DiscourseZendeskPlugin::ZENDESK_ID_FIELD].present?
return if !DiscourseZendeskPlugin::Helper.autogeneration_category?(post.topic.category_id)
return if !SiteSetting.zendesk_job_push_all_posts? && post.post_number > 1
ticket_id = post.topic.custom_fields[::DiscourseZendeskPlugin::ZENDESK_ID_FIELD]
if ticket_id.present?
add_comment(post, ticket_id) if comment_eligible_for_sync?(post)
else
create_ticket(post)
end
end
end
end
@@ -0,0 +1,69 @@
import Component from "@ember/component";
import { action } from "@ember/object";
import { classNames, tagName } from "@ember-decorators/component";
import DButton from "discourse/components/d-button";
import { ajax } from "discourse/lib/ajax";
import { i18n } from "discourse-i18n";
@tagName("span")
@classNames("after-topic-footer-buttons-outlet", "zendesk-topic-actions")
export default class ZendeskTopicActions extends Component {
init() {
super.init(...arguments);
const zendesk_id = this.topic.get("discourse_zendesk_plugin_zendesk_id");
if (zendesk_id && zendesk_id !== "") {
this.set("zendesk_id", zendesk_id);
}
this.setProperties({
zendesk_url: this.topic.get("discourse_zendesk_plugin_zendesk_url"),
valid_zendesk_credential: this.get(
"currentUser.discourse_zendesk_plugin_status"
),
});
}
@action
createZendeskIssue() {
let self = this;
self.set("dirty", true);
ajax("/zendesk-plugin/issues", {
type: "POST",
data: {
topic_id: this.get("topic").get("id"),
},
}).then((topic) => {
self.setProperties({
zendesk_id: topic.discourse_zendesk_plugin_zendesk_id,
zendesk_url: topic.discourse_zendesk_plugin_zendesk_url,
});
});
}
<template>
{{#if this.currentUser.staff}}
{{#if this.valid_zendesk_credential}}
{{#if this.zendesk_id}}
<a
href={{this.zendesk_url}}
target="_blank"
class="btn-primary btn"
rel="noopener noreferrer"
>
<i class="fa fa-clone"></i>
{{i18n "topic.view_zendesk_issue"}}
</a>
{{else}}
<DButton
class="btn-primary"
{{! template-lint-disable no-action }}
@action={{action "createZendeskIssue"}}
@label="topic.create_zendesk_issue"
@disabled={{this.dirty}}
/>
{{/if}}
{{else}}
<p>{{i18n "zendesk.credentials_not_setup"}}</p>
{{/if}}
{{/if}}
</template>
}
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
ar:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "إنشاء تذكرة Zendesk"
view_zendesk_issue: "العرض على Zendesk"
zendesk:
credentials_not_setup: لم تقم بإعداد بيانات اعتماد Zendesk الخاصة بك.
url_not_set: لم يتم تحديد عنوان URL لـ Zendesk حاليًا.
general_error: حدث خطأ ما.
site_settings:
zendesk_url: 'عنوان URL لـ Zendesk. على سبيل المثال: https://YOUR_SUBDOMAIN.zendesk.com/api/v2'
zendesk_enabled: تفعيل المكوِّن الإضافي Zendesk
zendesk_autogenerate_all_categories: إنشاء تذاكر تلقائيًا لجميع الفئات. يتم تجاهل `zendesk_enabled_categories` في حال التفعيل.
zendesk_autogenerate_categories: قائمة بالفئات التي تُنشئ تذاكر Zendesk تلقائيًا.
zendesk_jobs_api_token: الرمز المميَّز لواجهة برمجة التطبيقات لمصادقة Zendesk
zendesk_jobs_email: البريد الإلكتروني الذي سيتم استخدامه في مصادقة Zendesk
zendesk_job_push_all_posts: هل تريد إرسال جميع المنشورات في موضوع كتعليقات Zendesk؟ إذا تم إيقاف هذا الخيار، فسيتم إرسال المنشور الأول فقط إلى Zendesk.
zendesk_job_push_only_author_posts: إرسال المنشورات بواسطة المؤلف الأصلي فقط إلى Zendesk. ينطبق ذلك فقط في حال تفعيل `zendesk_job_push_all_posts`
sync_comments_from_zendesk: نشر التعليقات تلقائيًا من Zendesk إلى Discourse. ينطبق ذلك فقط للموضوعات في `zendesk_autogenerate_categories`.
zendesk_incoming_webhook_token: الرمز المميَّز المرسل في الحمولة من خطاف ويب Zendesk الصادر. مطلوب فقط إذا كان `sync_comments_from_zendesk` مفعلًا.
zendesk_tags: قائمة الوسوم التي سيتم إضافتها إلى كل تذكرة
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
be:
js:
zendesk:
general_error: Нешта пайшло не так.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
bg:
js:
zendesk:
general_error: Нещо се обърка.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
bs_BA:
js:
zendesk:
general_error: Nešto je krenulo pogrešno.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
ca:
js:
zendesk:
general_error: Alguna cosa ha anat malament
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
cs:
js:
zendesk:
general_error: Něco se pokazilo.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
da:
js:
zendesk:
general_error: Noget gik galt.
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
de:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "Zendesk-Ticket erstellen"
view_zendesk_issue: "Auf Zendesk anzeigen"
zendesk:
credentials_not_setup: Du hast deine Zendesk-Anmeldedaten nicht eingerichtet.
url_not_set: Deine Zendesk-URL ist derzeit nicht festgelegt.
general_error: Etwas ist schiefgelaufen.
site_settings:
zendesk_url: 'Deine Zendesk-URL. Zum Beispiel: https://YOUR_SUBDOMAIN.zendesk.com/api/v2'
zendesk_enabled: Zendesk-Plug-in aktivieren
zendesk_autogenerate_all_categories: Erstelle automatisch Tickets für alle Kategorien. Wenn diese Option aktiviert ist, wird `zendesk_autogenerate_categories` ignoriert.
zendesk_autogenerate_categories: Liste der Kategorien, aus denen automatisch Zendesk-Tickets erstellt werden.
zendesk_jobs_api_token: API-Token für die Zendesk-Authentifizierung
zendesk_jobs_email: E-Mail-Adresse für die Zendesk-Authentifizierung
zendesk_job_push_all_posts: Alle Beiträge in einem Thema als Zendesk-Kommentare weiterleiten? Wenn diese Option deaktiviert ist, wird nur der erste Beitrag an Zendesk weitergeleitet.
zendesk_job_push_only_author_posts: Nur Beiträge des ursprünglichen Themen-Verfassers an Zendesk weiterleiten. Gilt nur, wenn `zendesk_job_push_all_posts` aktiviert ist
sync_comments_from_zendesk: Kommentare von Zendesk automatisch auf Discourse veröffentlichen. Gilt nur für Themen in `zendesk_autogenerate_categories`.
zendesk_incoming_webhook_token: Token, das im Payload vom ausgehenden Zendesk-Webhook gesendet wird. Nur erforderlich, wenn `sync_comments_from_zendesk` aktiviert ist.
zendesk_tags: Liste der Schlagwörter, die zu jedem Ticket hinzugefügt werden
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
el:
js:
zendesk:
general_error: Κάτι δεν πήγε καλά.
@@ -0,0 +1,26 @@
en:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "Create Zendesk Ticket"
view_zendesk_issue: "View on Zendesk"
zendesk:
credentials_not_setup: You haven't setup your Zendesk credentials.
url_not_set: Your Zendesk URL is not currently set.
general_error: Something went wrong.
site_settings:
zendesk_url: Your Zendesk URL. e.g. https://YOUR_SUBDOMAIN.zendesk.com/api/v2
zendesk_enabled: Enable Zendesk plugin
zendesk_autogenerate_all_categories: Automatically create tickets for all categories. If enabled, `zendesk_autogenerate_categories` is ignored.
zendesk_autogenerate_categories: List of categories that will automatically create Zendesk tickets.
zendesk_jobs_api_token: API token for Zendesk authentication
zendesk_jobs_email: Email to use for Zendesk authentication
zendesk_job_push_all_posts: Push all posts in a topic as Zendesk comments? If disabled only first post will be pushed to Zendesk.
zendesk_job_push_only_author_posts: Only push posts by the original topic author to zendesk. Only applies if `zendesk_job_push_all_posts` is enabled
sync_comments_from_zendesk: Autopost comments from Zendesk to Discourse. Only applies for topics in `zendesk_autogenerate_categories`.
zendesk_incoming_webhook_token: Token sent in the payload from the Zendesk outgoing webhook. Required only if `sync_comments_from_zendesk` is enabled.
zendesk_tags: List of tags to add to each ticket
@@ -0,0 +1,7 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
en_GB:
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
es:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Zendesk de Discourse"
js:
topic:
create_zendesk_issue: "Crear una incidencia en Zendesk"
view_zendesk_issue: "Ver en Zendesk"
zendesk:
credentials_not_setup: No has configurado tus credenciales de Zendesk.
url_not_set: Tu URL de Zendesk no está configurada actualmente.
general_error: Algo salió mal.
site_settings:
zendesk_url: Tu URL de Zendesk. Por ejemplo, https://TU_SUBDOMINIO.zendesk.com/api/v2
zendesk_enabled: Activar el plugin de Zendesk
zendesk_autogenerate_all_categories: Crear automáticamente incidencias para todas las categorías. Si está habilitado, se ignora `zendesk_autogenerate_categories`.
zendesk_autogenerate_categories: Lista de categorías que crearán automáticamente incidencias de Zendesk.
zendesk_jobs_api_token: Token de la API para la autenticación de Zendesk
zendesk_jobs_email: Correo electrónico que se utilizará para la autenticación de Zendesk
zendesk_job_push_all_posts: '¿Enviar todos los mensajes en un tema como comentarios de Zendesk? Si está deshabilitado solo se enviará el primer mensaje a Zendesk.'
zendesk_job_push_only_author_posts: Enviar a Zendesk solo los mensajes del autor del tema original. Solo se aplica si `zendesk_job_push_all_posts` está activado
sync_comments_from_zendesk: Publicar automáticamente los comentarios de Zendesk en Discourse. Solo se aplica a los temas en `zendesk_autogenerate_categories`.
zendesk_incoming_webhook_token: Token enviado en la carga útil del webhook de salida de Zendesk. Solo es necesario si `sync_comments_from_zendesk` está activado.
zendesk_tags: Lista de etiquetas para añadir a cada incidencia
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
et:
js:
zendesk:
general_error: Miskit läks nihu.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
fa_IR:
js:
zendesk:
general_error: اشتباهی روی داد.
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
fi:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "Luo Zendesk-palvelupyyntö"
view_zendesk_issue: "Näytä Zendeskissä"
zendesk:
credentials_not_setup: Et ole määrittänyt Zendesk-tunnistetietojasi.
url_not_set: Zendeskin URL-osoitettasi ei ole asetettu.
general_error: Jokin meni vikaan.
site_settings:
zendesk_url: Zendeskin URL-osoitteesi. Esim. https://VERKKOTUNNUKSESI.zendesk.com/api/v2
zendesk_enabled: Ota Zendesk-lisäosa käyttöön
zendesk_autogenerate_all_categories: Luo palvelupyynnöt kaikista kategorioista automaattisesti. Jos tämä on käytössä, ei "zendesk_enabled_categories"-asetusta huomioida.
zendesk_autogenerate_categories: Listaus kategorioista, joista luodaan palvelupyynnöt Zendeskiin automaattisesti.
zendesk_jobs_api_token: API-tunnus Zendesk-todennusta varten
zendesk_jobs_email: Sähköpostiosoite Zendesk-todennusta varten
zendesk_job_push_all_posts: Työnnetäänkö kaikki ketjun viestit Zendesk-kommentteina? Jos tämä ei ole käytössä, vain ensimmäinen viesti työnnetään Zendeskiin.
zendesk_job_push_only_author_posts: Työnnä vain ketjun alkuperäisen kirjoittajan viestit Zendeskiin. Pätee vain, jos "zendesk_job_push_all_posts" on käytössä.
sync_comments_from_zendesk: Julkaise Zendesk-kommentit automaattisesti Discoursessa. Koskee vain "zendesk_enabled_categories"-asetuksen aiheita.
zendesk_incoming_webhook_token: Tunnus, joka lähetetään tiedoissa Zendeskin lähtevästä webhookista. Vaaditaan vain, jos "sync_comments_from_zendesk" on käytössä.
zendesk_tags: Luettelo jokaiseen palvelupyyntöön lisättävistä tunnisteista
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
fr:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "Créer un ticket Zendesk"
view_zendesk_issue: "Afficher sur Zendesk"
zendesk:
credentials_not_setup: Vous n'avez pas configuré vos informations d'identification Zendesk.
url_not_set: Votre adresse URL Zendesk n'est pas définie actuellement.
general_error: Une erreur est survenue.
site_settings:
zendesk_url: Votre adresse URL Zendesk. P. ex., https://YOUR_SUBDOMAIN.zendesk.com/api/v2
zendesk_enabled: Activer l'extension Zendesk
zendesk_autogenerate_all_categories: Créez automatiquement des tickets pour toutes les catégories. Si cette option est activée, « zendesk_autogenerate_categories » est ignoré.
zendesk_autogenerate_categories: Liste des catégories qui créeront automatiquement des tickets Zendesk.
zendesk_jobs_api_token: Jeton API pour l'authentification Zendesk
zendesk_jobs_email: E-mail à utiliser pour l'authentification Zendesk
zendesk_job_push_all_posts: Transférer tous les messages d'un sujet en tant que commentaires Zendesk ? Si ce paramètre est désactivé, seul le premier message sera envoyé à Zendesk.
zendesk_job_push_only_author_posts: Envoyer uniquement les messages de l'auteur du sujet d'origine à zendesk. S'applique uniquement si « zendesk_job_push_all_posts » est activé
sync_comments_from_zendesk: Publier automatiquement les commentaires de Zendesk sur Discourse. Ne s'applique que pour les sujets présents dans « zendesk_autogenerate_categories ».
zendesk_incoming_webhook_token: Jeton envoyé dans les données depuis le webhook sortant de Zendesk. Obligatoire uniquement si « sync_comments_from_zendesk » est activé.
zendesk_tags: Liste des étiquettes à ajouter à chaque ticket
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
gl:
js:
zendesk:
general_error: Algo foi mal.
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
he:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "יצירת כרטיס ב־Zendesk"
view_zendesk_issue: "הצגה ב־Zendesk"
zendesk:
credentials_not_setup: לא הגדרת את פרטי הגישה שלך ל־Zendeks.
url_not_set: כתובת ה־Zendesk שלך לא מוגדרת כרגע.
general_error: משהו השתבש.
site_settings:
zendesk_url: 'כתובת ה־Zendesk שלך. למשל: https://YOUR_SUBDOMAIN.zendesk.com/api/v2'
zendesk_enabled: הפעלת תוסף Zendesk
zendesk_autogenerate_all_categories: ליצור אוטומטית בקשות לכל הקטגוריות. אם האפשרות פעיל, אז `zendesk_autogenerate_categories` לא תקף.
zendesk_autogenerate_categories: רשימת קטגוריות שייצרו אוטומטית בקשות ב־Zendesk.
zendesk_jobs_api_token: אסימון API לאימות Zendesk
zendesk_jobs_email: דוא״ל לשימוש לאימות Zendesk
zendesk_job_push_all_posts: לדחוף את כל הפוסטים בנושא כהערות ל־Zendesk? אם האפשרות מושבתת רק הפוסט הראשון שלך יידחף ל־Zendesk.
zendesk_job_push_only_author_posts: לדחוף רק פוסטים מהיוצר המקורי ל־Zendesk. תקף רק אם `zendesk_job_push_all_posts` פעיל.
sync_comments_from_zendesk: לפרסם תגובות מ־Zendesk ל־Discourse באופן אוטומטי. תקף רק לנושאים תחת `zendesk_autogenerate_categories`.
zendesk_incoming_webhook_token: אסימון נשלח במטען מההתלייה היוצאת מ־Zendesk. נחוץ רק אם `sync_comments_from_zendesk` פעיל.
zendesk_tags: רשימת תגיות להוספה לכל כרטיס
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
hr:
js:
zendesk:
general_error: Nešto je pošlo krivo.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
hu:
js:
zendesk:
general_error: Valami rosszul sült el.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
hy:
js:
zendesk:
general_error: 'Ինչ-որ բան այն չէ:'
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
id:
js:
zendesk:
general_error: Terjadi kesalahan
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
it:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "Crea ticket Zendesk"
view_zendesk_issue: "Visualizza su Zendesk"
zendesk:
credentials_not_setup: Non hai configurato le tue credenziali Zendesk.
url_not_set: Il tuo URL Zendesk non è attualmente configurato.
general_error: Qualcosa è andato storto.
site_settings:
zendesk_url: Il tuo URL Zendesk. Ad esempio, https://TUO_SOTTODOMINIO.zendesk.com/api/v2
zendesk_enabled: Abilita plug-in Zendesk
zendesk_autogenerate_all_categories: Crea automaticamente ticket per tutte le categorie. Se abilitato, "zendesk_autogenerate_categories" viene ignorato.
zendesk_autogenerate_categories: Elenco di categorie che genereranno automaticamente i ticket Zendesk.
zendesk_jobs_api_token: Token API per l'autenticazione Zendesk
zendesk_jobs_email: E-mail da utilizzare per l'autenticazione Zendesk
zendesk_job_push_all_posts: Inviare tutti i messaggi in un argomento come commenti Zendesk? Se l'opzione è disabilitata, solo il primo messaggio verrà inviato a Zendesk.
zendesk_job_push_only_author_posts: Invia solo i messaggi dell'autore originale dell'argomento su zendesk. L'opzione si applica solo se l'impostazione `zendesk_job_push_all_posts` è abilitata
sync_comments_from_zendesk: Invia automaticamente i commenti da Zendesk a Discourse. L'opzione si applica solo agli argomenti nelle categorie definite da "zendesk_autogenerate_categories".
zendesk_incoming_webhook_token: Token inviato nel payload dal webhook in uscita di Zendesk. Impostazione richiesta solo se l'opzione `sync_comments_from_zendesk` è abilitata.
zendesk_tags: Elenco di etichette da aggiungere a ogni ticket
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
ja:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "Zendesk チケットを作成"
view_zendesk_issue: "Zendesk で表示"
zendesk:
credentials_not_setup: Zendesk の資格情報がセットアップされていません。
url_not_set: あなたの Zendesk URL は現在設定されていません。
general_error: エラーが発生しました。
site_settings:
zendesk_url: 'あなたの Zendesk URL。例: https://YOUR_SUBDOMAIN.zendesk.com/api/v2'
zendesk_enabled: Zendesk プラグインを有効にする
zendesk_autogenerate_all_categories: すべてのカテゴリのチケットを自動的に作成します。有効にすると、`zendesk_autogenerate_categories` は無視されます。
zendesk_autogenerate_categories: Zendesk チケットが自動生成されるカテゴリのリスト。
zendesk_jobs_api_token: Zendesk 認証用の API トークン
zendesk_jobs_email: Zendesk 認証用のメールアドレス
zendesk_job_push_all_posts: トピック内のすべての投稿を Zendesk コメントとしてプッシュしますか?無効にすると、最初の投稿のみが Zendesk にプッシュされます。
zendesk_job_push_only_author_posts: 元のトピック作成者による投稿のみを Zendesk にプッシュしますか?`zendesk_job_push_all_posts` が有効である場合にのみ適用されます。
sync_comments_from_zendesk: Zendesk から Discourse にコメントを自動投稿します。`zendesk_autogenerate_categories` のトピックのみに適用されます。
zendesk_incoming_webhook_token: Zendesk の発信 Webhook からペイロードで送信されるトークン。`sync_comments_from_zendesk` が有効である場合にのみ必要です。
zendesk_tags: 各チケットに追加されるタグのリスト
@@ -0,0 +1,27 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
ko:
js:
topic:
create_zendesk_issue: "Zendesk 티켓 만들기"
view_zendesk_issue: "Zendesk에서 보기"
zendesk:
credentials_not_setup: Zendesk 자격 증명을 설정하지 않았습니다.
url_not_set: Zendesk URL이 설정되지 않았습니다.
general_error: 문제가 발생했습니다.
site_settings:
zendesk_url: 'Zendesk URL. 예: https://YOUR_SUBDOMAIN.zendesk.com/api/v2'
zendesk_enabled: Zendesk 플러그인 활성화
zendesk_autogenerate_all_categories: 모든 카테고리에 대한 티켓을 자동으로 생성합니다. 활성화된 경우 `zendesk_autogenerate_categories`는 무시됩니다.
zendesk_autogenerate_categories: Zendesk 티켓을 자동으로 생성하는 카테고리 목록입니다.
zendesk_jobs_api_token: Zendesk 인증을 위한 API 토큰
zendesk_jobs_email: Zendesk 인증에 사용할 이메일
zendesk_job_push_all_posts: 토픽의 모든 게시물을 Zendesk 댓글로 푸시할까요? 비활성화하면 첫 번째 게시물만 Zendesk로 푸시됩니다.
zendesk_job_push_only_author_posts: 원본 주제 작성자의 게시물만 zendesk로 푸시합니다. `zendesk_job_push_all_posts`가 활성화된 경우에만 적용됩니다.
sync_comments_from_zendesk: Zendesk에서 Discourse로 댓글을 자동 게시합니다. zendesk_autogenerate_categories`의 주제에만 적용됩니다.
zendesk_incoming_webhook_token: Zendesk 발신 웹훅에서 페이로드로 전송된 토큰입니다. `sync_comments_from_zendesk`가 활성화된 경우에만 필요합니다.
zendesk_tags: 각 티켓에 추가할 태그 목록
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
lt:
js:
zendesk:
general_error: Kažkas blogai nutiko.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
lv:
js:
zendesk:
general_error: Kaut kas nogāja greizi.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
nb_NO:
js:
zendesk:
general_error: Noe gikk galt.
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
nl:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "Zendesk-ticket maken"
view_zendesk_issue: "Weergeven op Zendesk"
zendesk:
credentials_not_setup: Je hebt je Zendesk-aanmeldgegevens niet ingesteld.
url_not_set: Je Zendesk-URL is momenteel niet ingesteld.
general_error: Er is iets misgegaan.
site_settings:
zendesk_url: Je Zendesk URL, bijvoorbeeld https://JOUW_SUBDOMEIN.zendesk.com/api/v2
zendesk_enabled: Zendesk-plug-in inschakelen
zendesk_autogenerate_all_categories: Maak automatisch tickets voor alle categorieën. Indien ingeschakeld, wordt 'zendesk_enabled_categories' genegeerd.
zendesk_autogenerate_categories: Lijst van categorieën die automatisch Zendesk-tickets maken.
zendesk_jobs_api_token: API-token voor Zendesk-verificatie
zendesk_jobs_email: Te gebruiken e-mailadres voor Zendesk-verificatie
zendesk_job_push_all_posts: Alle berichten in een topic pushen als Zendesk-opmerkingen? Indien uitgeschakeld, wordt alleen het eerste bericht naar Zendesk gepusht.
zendesk_job_push_only_author_posts: Push alleen berichten van de oorspronkelijke topicauteur naar Zendesk. Alleen van toepassing als `zendesk_job_push_all_posts` is ingeschakeld
sync_comments_from_zendesk: Reacties van Zendesk automatisch op Discourse plaatsen. Alleen van toepassing op topics in `zendesk_autogenerate_categories`.
zendesk_incoming_webhook_token: Token verzonden in de payload van de uitgaande Zendesk-webhook. Alleen vereist als `sync_comments_from_zendesk` is ingeschakeld.
zendesk_tags: Lijst van tags om toe te voegen aan elk ticket
@@ -0,0 +1,27 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
pl_PL:
js:
topic:
create_zendesk_issue: "Utwórz zgłoszenie Zendesk"
view_zendesk_issue: "Zobacz w Zendesk"
zendesk:
credentials_not_setup: Nie skonfigurowałeś swoich danych uwierzytelniających Zendesk.
url_not_set: Twój adres URL Zendesk nie jest obecnie ustawiony.
general_error: Coś poszło nie tak.
site_settings:
zendesk_url: Twój adres URL Zendesk. np. https://TWOJA_SUBDOMENA.zendesk.com/api/v2
zendesk_enabled: Włącz wtyczkę Zendesk
zendesk_autogenerate_all_categories: Automatycznie twórz zgłoszenia dla wszystkich kategorii. Jeśli włączone, `zendesk_autogenerate_categories` jest ignorowane.
zendesk_autogenerate_categories: Lista kategorii, które będą automatycznie tworzyć zgłoszenia Zendesk.
zendesk_jobs_api_token: Token API do uwierzytelniania Zendesk
zendesk_jobs_email: E-mail używany do uwierzytelniania Zendesk
zendesk_job_push_all_posts: Przesłać wszystkie posty w temacie jako komentarze Zendesk? Jeśli wyłączone, tylko pierwszy post zostanie wysłany do Zendesk.
zendesk_job_push_only_author_posts: Wysyłaj do zendesk tylko posty oryginalnego autora tematu. Dotyczy tylko sytuacji, gdy włączona jest opcja `zendesk_job_push_all_posts`.
sync_comments_from_zendesk: Autopostuj komentarze z Zendesk do Discourse. Dotyczy tylko tematów w `zendesk_autogenerate_categories`.
zendesk_incoming_webhook_token: Token wysłany w zapytaniu z wychodzącego webhooka Zendesk. Wymagane tylko wtedy, gdy włączone jest `sync_comments_from_zendesk`.
zendesk_tags: Lista tagów do dodania do każdego zgłoszenia
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
pt:
js:
zendesk:
general_error: Correu algo de errado.
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
pt_BR:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "Criar tíquete da Zendesk"
view_zendesk_issue: "Ver na Zendesk"
zendesk:
credentials_not_setup: Você não configurou suas credenciais da Zendesk.
url_not_set: Sua URL da Zendesk ainda não foi configurada.
general_error: Algo deu errado.
site_settings:
zendesk_url: 'Sua URL da Zendesk, por exemplo: https://YOUR_SUBDOMAIN.zendesk.com/api/v2'
zendesk_enabled: Ativar plugin da Zendesk
zendesk_autogenerate_all_categories: Crie tíquetes automaticamente para todas as categorias. Se estiver ativado, "zendesk_autogenerate_categories" será ignorado.
zendesk_autogenerate_categories: Lista de categorias que criarão automaticamente tíquetes da Zendesk.
zendesk_jobs_api_token: Token de API para autenticação da Zendesk
zendesk_jobs_email: E-mail para usar na autenticação da Zendesk
zendesk_job_push_all_posts: Enviar todas as publicações em um tópico como comentários da Zendesk. Senão só a primeira postagem será enviada para a Zendesk.
zendesk_job_push_only_author_posts: Enviar apenas postagens do(a) autor(a) do tópico original para a Zendesk. Aplicado apenas se "zendesk_job_push_all_posts" estiver ativado
sync_comments_from_zendesk: Poste automaticamente comentários da Zendesk no Discourse. Aplicado apenas para tópicos em "zendesk_autogenerate_categories".
zendesk_incoming_webhook_token: Token enviado no conteúdo do wekhook de saúda da Zendesk. Necessário apenas se "sync_comments_from_zendesk" estiver ativado.
zendesk_tags: Lista de etiquetas para adicionar a cada tíquete
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
ro:
js:
zendesk:
general_error: Ceva nu a funcționat.
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
ru:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Zendesk для Discourse"
js:
topic:
create_zendesk_issue: "Создать тикет в Zendesk"
view_zendesk_issue: "Посмотреть на Zendesk"
zendesk:
credentials_not_setup: Вы не настроили учётные данные Zendesk.
url_not_set: URL-адрес Zendesk не установлен.
general_error: Ошибка.
site_settings:
zendesk_url: URL-адрес Zendesk. Например, https://ВАШ_ПОДДОМЕН.zendesk.com/api/v2
zendesk_enabled: Включить плагин Zendesk
zendesk_autogenerate_all_categories: Автоматическое создание тикетов для всех категорий. Если включено, `zendesk_autogenerate_categories` игнорируется.
zendesk_autogenerate_categories: Список категорий, в которых будут автоматически создаваться тикеты Zendesk.
zendesk_jobs_api_token: Токен API для аутентификации Zendesk
zendesk_jobs_email: Электронная почта для аутентификации Zendesk
zendesk_job_push_all_posts: Отправлять все записи в теме как комментарии Zendesk? Если отключено, в Zendesk будет отправлена только первая запись.
zendesk_job_push_only_author_posts: Отправлять в Zendesk только записи исходного автора темы. Применяется, только если включен параметр `zendesk_job_push_all_posts`.
sync_comments_from_zendesk: Автопубликация комментариев из Zendesk в Discourse. Относится только к темам в `zendesk_autogenerate_categories`.
zendesk_incoming_webhook_token: Токен, отправляемый в сопровождение из исходящего вебхука Zendesk. Требуется, только если включен параметр `sync_comments_from_zendesk`.
zendesk_tags: Список тегов, которые нужно добавить к каждому тикету
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
sk:
js:
zendesk:
general_error: Niečo sa pokazilo.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
sl:
js:
zendesk:
general_error: Nekaj je šlo narobe.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
sq:
js:
zendesk:
general_error: Diçka shkoi keq.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
sr:
js:
zendesk:
general_error: Nešto nije bilo u redu.
@@ -0,0 +1,24 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
sv:
js:
topic:
create_zendesk_issue: "Skapa Zendesk-ärende"
view_zendesk_issue: "Visa på Zendesk"
zendesk:
credentials_not_setup: Du har inte konfigurerat dina Zendesk-autentiseringsuppgifter.
url_not_set: Din Zendesk-URL har för tillfället inte ställts in.
general_error: Något gick fel.
site_settings:
zendesk_url: Din Zendesk-URL, t.ex. https://YOUR_SUBDOMAIN.zendesk.com/api/v2
zendesk_enabled: Aktivera Zendesk-tillägget
zendesk_jobs_api_token: API-token för Zendesk-autentisering
zendesk_jobs_email: E-postadress som ska användas för Zendesk-autentisering
zendesk_job_push_all_posts: Gör alla inlägg i ett ämne till Zendesk-kommentarer? Om detta inaktiveras kommer endast det första inlägget att flyttas till Zendesk.
zendesk_job_push_only_author_posts: Flytta bara inlägg av den ursprungliga ämnesförfattaren till Zendesk. Gäller endast om `zendesk_job_push_all_posts` har aktiverats
zendesk_incoming_webhook_token: Token som skickas i nyttolasten från Zendesks utgående webhook. Krävs endast om `sync_comments_from_zendesk` har aktiverats.
zendesk_tags: Lista över taggar att lägga till i varje ärende
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
sw:
js:
zendesk:
general_error: Kitu kimeenda vibaya.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
te:
js:
zendesk:
general_error: ఏదో తేడా జరిగింది.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
th:
js:
zendesk:
general_error: มีบางอย่างผิดปกติ
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
tr_TR:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "Zendesk Bileti Oluştur"
view_zendesk_issue: "Zendesk'te görüntüle"
zendesk:
credentials_not_setup: Zendesk giriş bilgilerinizi ayarlamadınız.
url_not_set: Zendesk URL'niz şu anda ayarlı değil.
general_error: Bir şeyler ters gitti.
site_settings:
zendesk_url: Zendesk URL'niz. ör. https://YOUR_SUBDOMAIN.zendesk.com/api/v2
zendesk_enabled: Zendesk eklentisini etkinleştirin
zendesk_autogenerate_all_categories: Tüm kategoriler için otomatik olarak bilet oluştur. Etkinleştirilirse `zendesk_autogenerate_categories` yok sayılır.
zendesk_autogenerate_categories: Otomatik olarak Zendesk biletleri oluşturacak kategorilerin listesi.
zendesk_jobs_api_token: Zendesk kimlik doğrulaması için API token'ı
zendesk_jobs_email: Zendesk kimlik doğrulaması için kullanılacak e-posta
zendesk_job_push_all_posts: Bir konudaki tüm gönderiler Zendesk yorumları olarak itilsin mi? Devre dışı bırakılırsa yalnızca ilk gönderi Zendesk'e gönderilir.
zendesk_job_push_only_author_posts: Yalnızca asıl konu yazarının gönderilerini zendesk'e itin. Yalnızca "zendesk_job_push_all_posts" etkinleştirilmişse geçerlidir
sync_comments_from_zendesk: Zendesk'ten Discourse'a otomatik yorum gönderin. Yalnızca `zendesk_autogenerate_categories` içindeki konular için geçerlidir.
zendesk_incoming_webhook_token: Zendesk giden web kancasından gelen yükte gönderilen token. Yalnızca "sync_comments_from_zendesk" etkinleştirilmişse gereklidir.
zendesk_tags: Her bir bilete eklenecek etiketlerin listesi
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
ug:
js:
zendesk:
general_error: چاتاق چىقتى.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
uk:
js:
zendesk:
general_error: Щось пішло не так.
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
ur:
js:
zendesk:
general_error: کچھ غلط ہو گیا۔
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
vi:
js:
zendesk:
general_error: Có một lỗi gì đó đang xảy ra
@@ -0,0 +1,32 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
zh_CN:
admin_js:
admin:
site_settings:
categories:
discourse_zendesk: "Discourse Zendesk"
js:
topic:
create_zendesk_issue: "创建 Zendesk 工单"
view_zendesk_issue: "在 Zendesk 上查看"
zendesk:
credentials_not_setup: 您尚未设置 Zendesk 凭据。
url_not_set: 您的 Zendesk URL 当前未设置。
general_error: 出了点问题。
site_settings:
zendesk_url: 您的 Zendesk URL,例如 https://YOUR_SUBDOMAIN.zendesk.com/api/v2
zendesk_enabled: 启用 Zendesk 插件
zendesk_autogenerate_all_categories: 自动为所有类别创建工单。如果启用,则忽略 `zendesk_autogenerate_categories`。
zendesk_autogenerate_categories: 将自动创建 Zendesk 工单的类别列表。
zendesk_jobs_api_token: Zendesk 身份验证的 API 令牌
zendesk_jobs_email: Zendesk 身份验证的电子邮件
zendesk_job_push_all_posts: 将话题中的所有帖子作为 Zendesk 评论推送?如果禁用,则只有第一个帖子将被推送到 Zendesk。
zendesk_job_push_only_author_posts: 仅将原始话题作者的帖子推送到 Zendesk。仅在启用 `zendesk_job_push_all_posts` 时适用
sync_comments_from_zendesk: 将 Zendesk 的评论自动发布到 Discourse。仅适用于 `zendesk_autogenerate_categories` 中的话题。
zendesk_incoming_webhook_token: Zendesk 传出网络钩子在有效负载中发送的令牌。仅在启用 `sync_comments_from_zendesk` 时才需要。
zendesk_tags: 添加到每张工单的标签列表
@@ -0,0 +1,10 @@
# WARNING: Never edit this file.
# It will be overwritten when translations are pulled from Crowdin.
#
# To work with us on translations, join this project:
# https://translate.discourse.org/
zh_TW:
js:
zendesk:
general_error: 發生錯誤。
@@ -0,0 +1,30 @@
discourse_zendesk:
zendesk_url:
default: https://your-url.zendesk.com/api/v2
client: true
zendesk_enabled:
default: false
client: true
zendesk_jobs_api_token:
default: ""
secret: true
zendesk_jobs_email:
default: ""
zendesk_autogenerate_all_categories:
default: false
zendesk_autogenerate_categories:
type: category_list
client: false
default: ""
zendesk_job_push_all_posts:
default: true
zendesk_job_push_only_author_posts:
default: false
sync_comments_from_zendesk:
default: false
zendesk_incoming_webhook_token:
default: ""
zendesk_tags:
type: list
client: false
default: ""
@@ -0,0 +1,12 @@
# frozen_string_literal: true
class RemoveZendeskSyncSiteSetting < ActiveRecord::Migration[6.0]
def up
execute "DELETE FROM site_settings WHERE name = 'zendesk_sync_enabled'"
execute "DELETE FROM site_settings WHERE name = 'zendesk_signature_regex'"
end
def down
raise ActiveRecord::IrreversibleMigration
end
end
@@ -0,0 +1,17 @@
# frozen_string_literal: true
class DisableZendeskPluginByDefault < ActiveRecord::Migration[6.0]
def change
# enable Zendesk plugin for sites that have configured Zendesk API token
zendesk_email =
DB.query_single("SELECT value FROM site_settings WHERE name = 'zendesk_jobs_email'").first
zendesk_api_token =
DB.query_single("SELECT value FROM site_settings WHERE name = 'zendesk_jobs_api_token'").first
DB.exec(<<~SQL) if zendesk_email.present? && zendesk_api_token.present?
INSERT INTO site_settings (name, data_type, value, created_at, updated_at)
VALUES ('zendesk_enabled', 5, 't', now(), now())
ON CONFLICT (name)
DO NOTHING
SQL
end
end
@@ -0,0 +1,17 @@
# frozen_string_literal: true
class RenameEnableCategoriesSiteSettings < ActiveRecord::Migration[7.0]
def setting(old, new)
execute "UPDATE site_settings SET name='#{new}' where name='#{old}'"
end
def up
setting :zendesk_enable_all_categories, :zendesk_autogenerate_all_categories
setting :zendesk_enabled_categories, :zendesk_autogenerate_categories
end
def down
setting :zendesk_autogenerate_all_categories, :zendesk_enable_all_categories
setting :zendesk_autogenerate_categories, :zendesk_enabled_categories
end
end
@@ -0,0 +1,16 @@
# frozen_string_literal: true
module DiscourseZendeskPlugin
class Engine < ::Rails::Engine
engine_name "discourse-zendesk-plugin"
isolate_namespace DiscourseZendeskPlugin
config.after_initialize do
Discourse::Application.routes.append do
post "/zendesk-plugin/issues" => "discourse_zendesk_plugin/issues#create",
:constraints => StaffConstraint.new
put "/zendesk-plugin/sync" => "discourse_zendesk_plugin/sync#webhook"
end
end
end
end
@@ -0,0 +1,115 @@
# frozen_string_literal: true
module DiscourseZendeskPlugin
module Helper
def zendesk_client
::ZendeskAPI::Client.new do |config|
config.url = SiteSetting.zendesk_url
config.username = SiteSetting.zendesk_jobs_email
config.token = SiteSetting.zendesk_jobs_api_token
end
end
def self.autogeneration_category?(category_id)
return false if category_id.blank?
if SiteSetting.zendesk_autogenerate_all_categories?
true
else
SiteSetting.zendesk_autogenerate_categories.split("|").include?(category_id.to_s)
end
end
def create_ticket(post)
zendesk_user_id = fetch_submitter(post.user)&.id
if zendesk_user_id.present?
ticket =
zendesk_client.tickets.create(
subject: post.topic.title,
comment: {
html_body: get_post_content(post),
},
requester_id: zendesk_user_id,
submitter_id: zendesk_user_id,
priority: "normal",
tags: SiteSetting.zendesk_tags.split("|"),
external_id: post.topic.id,
custom_fields: [
imported_from: ::Discourse.current_hostname,
external_id: post.topic.id,
imported_by: "discourse_zendesk_plugin",
],
)
if ticket.present?
update_topic_custom_fields(post.topic, ticket)
update_post_custom_fields(post, ticket.comments.first)
end
end
end
def comment_eligible_for_sync?(post)
if SiteSetting.zendesk_job_push_only_author_posts?
return false if post.blank? || post.user.blank?
return false if post.topic.blank? || post.topic.user.blank?
post.user.id == post.topic.user.id
else
true
end
end
def add_comment(post, ticket_id)
return if post.blank? || post.user.blank?
zendesk_user_id = fetch_submitter(post.user)&.id
if zendesk_user_id.present?
ticket = ZendeskAPI::Ticket.new(zendesk_client, id: ticket_id)
ticket.comment = { html_body: get_post_content(post), author_id: zendesk_user_id }
ticket.save
update_post_custom_fields(post, ticket.comments.last)
end
end
def get_latest_comment(ticket_id)
ticket = ZendeskAPI::Ticket.new(zendesk_client, id: ticket_id)
last_public_comment = nil
ticket.comments.all! { |comment| last_public_comment = comment if comment.public }
last_public_comment
end
def update_topic_custom_fields(topic, ticket)
topic.custom_fields[::DiscourseZendeskPlugin::ZENDESK_ID_FIELD] = ticket["id"]
topic.custom_fields[::DiscourseZendeskPlugin::ZENDESK_API_URL_FIELD] = ticket["url"]
topic.save_custom_fields
end
def update_post_custom_fields(post, comment)
return if comment.blank?
post.custom_fields[::DiscourseZendeskPlugin::ZENDESK_ID_FIELD] = comment["id"]
post.save_custom_fields
end
def fetch_submitter(user)
result = zendesk_client.users.search(query: user.email)
return result.first if result.present? && result.size == 1
zendesk_client.users.create(
name: (user.name.present? ? user.name : user.username),
email: user.email,
verified: true,
role: "end-user",
)
end
def get_post_content(post)
style = Email::Styles.new(post.cooked)
style.format_basic
style.format_html
html = style.to_html
"#{html} \n\n [<a href='#{post.full_url}'>Discourse post</a>]"
end
end
end
@@ -0,0 +1,17 @@
# frozen_string_literal: true
module DiscourseZendeskPlugin
module PostExtension
def self.prepended(base)
base.after_commit :generate_zendesk_ticket, on: [:create]
end
private
def generate_zendesk_ticket
return unless SiteSetting.zendesk_enabled?
return unless DiscourseZendeskPlugin::Helper.autogeneration_category?(topic.category_id)
Jobs.enqueue_in(5.seconds, :zendesk_job, post_id: id)
end
end
end
@@ -0,0 +1,30 @@
# frozen_string_literal: true
module DiscourseZendeskPlugin
module TopicExtension
def self.prepended(base)
base.after_update :publish_to_zendesk
end
private
def publish_to_zendesk
return if saved_changes[:category_id].blank?
old_category = Category.find_by(id: saved_changes[:category_id].first)
new_category = Category.find_by(id: saved_changes[:category_id].last)
old_cat_enabled = DiscourseZendeskPlugin::Helper.autogeneration_category?(old_category&.id)
new_cat_enabled = DiscourseZendeskPlugin::Helper.autogeneration_category?(new_category&.id)
# Do nothing if neither old or new category are enabled
return nil if !old_cat_enabled && !new_cat_enabled
# Do nothing if both categories are enabled
return nil if old_cat_enabled && new_cat_enabled
# enqueue job in future since after commit does not maintain changes hash
Jobs.enqueue_in(5.seconds, :zendesk_job, topic_id: id)
end
end
end
@@ -0,0 +1,59 @@
# frozen_string_literal: true
# name: discourse-zendesk-plugin
# about: Allows the creation of Zendesk tickets from Discourse topics.
# meta_topic_id: 68005
# version: 1.0.1
# authors: Yana Agun Siswanto, Arpit Jalan
# url: https://github.com/discourse/discourse/tree/main/plugins/discourse-zendesk-plugin
require "inflection"
require "net/http/post/multipart"
require "faraday/multipart"
require "zendesk_api"
enabled_site_setting :zendesk_enabled
module ::DiscourseZendeskPlugin
PLUGIN_NAME = "discourse-zendesk-plugin"
ZENDESK_ID_FIELD = "discourse_zendesk_plugin_zendesk_id"
ZENDESK_URL_FIELD = "discourse_zendesk_plugin_zendesk_url"
ZENDESK_API_URL_FIELD = "discourse_zendesk_plugin_zendesk_api_url"
end
require_relative "lib/discourse_zendesk_plugin/engine"
require_relative "lib/discourse_zendesk_plugin/helper"
after_initialize do
require_relative "app/jobs/onceoff/migrate_zendesk_autogenerate_categories_site_settings"
require_relative "app/jobs/regular/zendesk_job"
require_relative "lib/discourse_zendesk_plugin/post_extension"
require_relative "lib/discourse_zendesk_plugin/topic_extension"
reloadable_patch do |plugin|
Post.prepend DiscourseZendeskPlugin::PostExtension
Topic.prepend DiscourseZendeskPlugin::TopicExtension
end
add_to_serializer(
:topic_view,
::DiscourseZendeskPlugin::ZENDESK_ID_FIELD.to_sym,
respect_plugin_enabled: false,
) { object.topic.custom_fields[::DiscourseZendeskPlugin::ZENDESK_ID_FIELD] }
add_to_serializer(
:topic_view,
::DiscourseZendeskPlugin::ZENDESK_URL_FIELD.to_sym,
respect_plugin_enabled: false,
) do
id = object.topic.custom_fields[::DiscourseZendeskPlugin::ZENDESK_ID_FIELD]
uri = URI.parse(SiteSetting.zendesk_url)
"#{uri.scheme}://#{uri.host}/agent/tickets/#{id}"
end
add_to_serializer(:current_user, :discourse_zendesk_plugin_status) do
SiteSetting.zendesk_jobs_email.present? && SiteSetting.zendesk_jobs_api_token.present? &&
SiteSetting.zendesk_url
end
end
@@ -0,0 +1,49 @@
# frozen_string_literal: true
require "rails_helper"
describe "TopicExtensions" do
before { freeze_time }
fab!(:user_1) { Fabricate(:user, admin: true) }
fab!(:topic_1) { Fabricate(:topic, user: user_1) }
context "when an enabled category is set on the topic" do
fab!(:category_1) { Fabricate(:category) }
before { SiteSetting.zendesk_autogenerate_categories = "#{category_1.id}" }
it "queues a sync job" do
expect_enqueued_with(
job: :zendesk_job,
args: {
topic_id: topic_1.id,
},
at: Time.zone.now + 5.seconds,
) do
topic_1.category = category_1
topic_1.save!
end
end
context "when the category is removed" do
before do
topic_1.category = category_1
topic_1.save!
end
it "queues a sync job" do
expect_enqueued_with(
job: :zendesk_job,
args: {
topic_id: topic_1.id,
},
at: Time.zone.now + 5.seconds,
) do
topic_1.category = nil
topic_1.save!
end
end
end
end
end
@@ -0,0 +1,87 @@
# frozen_string_literal: true
require "rails_helper"
RSpec.describe "Discourse Zendesk Plugin" do
let(:staff) { Fabricate(:moderator) }
let(:zendesk_url_default) { "https://your-url.zendesk.com/api/v2" }
let(:zendesk_api_ticket_url) { zendesk_url_default + "/tickets" }
let(:ticket_response) { { ticket: { id: "ticket_id", url: "ticket_url" } }.to_json }
before do
default_header = { "Content-Type" => "application/json; charset=UTF-8" }
stub_request(:post, zendesk_api_ticket_url).to_return(
status: 200,
body: ticket_response,
headers: default_header,
)
stub_request(:get, zendesk_url_default + "/users/me").to_return(
status: 200,
body: { user: {} }.to_json,
headers: default_header,
)
end
describe "Plugin Settings" do
describe "Storage Preparation" do
let(:zendesk_enabled_default) { false }
it "has zendesk_url & zendesk_enabled site settings" do
expect(SiteSetting.zendesk_url).to eq(zendesk_url_default)
expect(SiteSetting.zendesk_enabled).to eq(zendesk_enabled_default)
end
end
describe "zendesk_job_push_only_author_posts?" do
it "disabled by default" do
expect(SiteSetting.zendesk_job_push_only_author_posts?).to be_falsey
end
end
end
describe "Zendesk Integration" do
describe "Create ticket" do
let!(:topic) { Fabricate(:topic) }
let!(:p1) { Fabricate(:post, topic: topic) }
let(:zendesk_api_user_search_url) do
zendesk_url_default + "/users/search?query=#{p1.user.email}"
end
let(:zendesk_api_user_create_url) { zendesk_url_default + "/users" }
before do
SiteSetting.zendesk_enabled = true
sign_in staff
default_header = { "Content-Type" => "application/json; charset=UTF-8" }
stub_request(:get, zendesk_api_ticket_url + "/ticket_id/comments").to_return(status: 200)
stub_request(:get, zendesk_api_user_search_url).to_return(
status: 200,
body: { user: {} }.to_json,
headers: default_header,
)
stub_request(:post, zendesk_api_user_create_url).to_return(
status: 200,
body: { user: { id: 24 } }.to_json,
headers: default_header,
)
end
it "creates a new zendesk ticket" do
post "/zendesk-plugin/issues.json", params: { topic_id: topic.id }
expect(WebMock).to have_requested(:post, zendesk_api_ticket_url).with { |req|
body = JSON.parse(req.body)
body["ticket"]["submitter_id"] == 24 && body["ticket"]["priority"] == "normal" &&
body["ticket"]["custom_fields"].find do |field|
field["imported_from"].present? && field["external_id"].present? &&
field["imported_by"] == "discourse_zendesk_plugin"
end
}
custom_fields = topic.reload.custom_fields
expect(custom_fields["discourse_zendesk_plugin_zendesk_api_url"]).to eq("ticket_url")
expect(custom_fields["discourse_zendesk_plugin_zendesk_id"]).to eq("ticket_id")
end
end
end
end
@@ -0,0 +1,23 @@
# frozen_string_literal: true
require "rails_helper"
RSpec.describe Jobs::MigrateZendeskAutogenerateCategoriesSiteSettings do
it "should migrate the site settings correctly" do
category = Fabricate(:category)
category_2 = Fabricate(:category)
site_setting =
SiteSetting.create!(
name: "zendesk_autogenerate_categories",
data_type: SiteSettings::TypeSupervisor.types[:list],
value: "#{category.name}|#{category_2.name}|some random name",
)
described_class.new.execute_onceoff({})
expect(site_setting.reload.data_type).to eq(SiteSettings::TypeSupervisor.types[:category_list])
expect(site_setting.value.split("|").map(&:to_i)).to contain_exactly(category.id, category_2.id)
end
end
@@ -0,0 +1,98 @@
# frozen_string_literal: true
require "rails_helper"
RSpec.describe Jobs::ZendeskJob do
subject(:execute) { job.execute(job_args) }
let(:job) { described_class.new }
let(:topic_user) { Fabricate(:user) }
let(:other_user) { Fabricate(:user) }
let(:post_user) { topic_user }
let(:topic) do
Fabricate(:topic, user: topic_user).tap do |topic|
topic.custom_fields[::DiscourseZendeskPlugin::ZENDESK_ID_FIELD] = ticket_id
topic.custom_fields[::DiscourseZendeskPlugin::ZENDESK_API_URL_FIELD] = ticket_url
topic.save_custom_fields
end
end
let(:ticket_id) { "1234" }
let(:ticket_url) { "http://example.com/ticket/#{ticket_id}" }
let(:post) { Fabricate(:post, topic: topic, user: post_user, post_number: 2) }
let(:zendesk_job_push_only_author_posts) { false }
let(:zendesk_job_push_all_posts) { true }
let(:zendesk_enabled) { false }
let(:zendesk_jobs_email) { "test@example.com" }
let(:zendesk_jobs_api_token) { "1234567890" }
let(:job_args) { { post_id: post.id } }
before do
SiteSetting.zendesk_job_push_only_author_posts = zendesk_job_push_only_author_posts
SiteSetting.zendesk_enabled = zendesk_enabled
SiteSetting.zendesk_jobs_email = zendesk_jobs_email
SiteSetting.zendesk_jobs_api_token = zendesk_jobs_api_token
SiteSetting.zendesk_job_push_all_posts = zendesk_job_push_all_posts
end
context "with zendesk disabled" do
it "does nothing" do
Topic.expects(:find_by).never
Post.expects(:find_by).never
execute
end
end
context "with zendesk enabled" do
let(:zendesk_enabled) { true }
before(:each) do
DiscourseZendeskPlugin::Helper
.expects(:autogeneration_category?)
.with(post.topic.category_id)
.returns(true)
.at_least(0)
end
context "with post_id" do
before(:each) do
Topic.expects(:find_by).never
Post.expects(:find_by).with(id: post.id).returns(post).times(1)
job.expects(:create_ticket).never
end
context "with zendesk_job_push_only_author_posts disabled" do
it "adds the comment once" do
job.expects(:add_comment).with(post, ticket_id).times(1)
execute
end
context "when post not from topic author" do
let(:post_user) { other_user }
it "adds the comment once" do
job.expects(:add_comment).with(post, ticket_id).times(1)
execute
end
end
end
context "with zendesk_job_push_only_author_posts enabled" do
let(:zendesk_job_push_only_author_posts) { true }
context "with post from topic author" do
it "adds the comment once" do
job.expects(:add_comment).with(post, ticket_id).times(1)
execute
end
end
context "with post not from topic author" do
let(:post_user) { other_user }
it "does not adds the comment" do
job.expects(:add_comment).never
execute
end
end
end
end
end
end
@@ -0,0 +1,58 @@
# frozen_string_literal: true
require "rails_helper"
describe DiscourseZendeskPlugin::Helper do
subject(:dummy) { Class.new { extend DiscourseZendeskPlugin::Helper } }
it "Instantiates" do
expect(dummy).to be_present
end
describe "comment_eligible_for_sync?" do
subject(:eligible) { dummy.comment_eligible_for_sync?(post) }
let!(:topic_user) { Fabricate(:user) }
let!(:other_user) { Fabricate(:user) }
let(:post_user) { topic_user }
let!(:topic) { Fabricate(:topic, user: topic_user) }
let!(:post) { Fabricate(:post, topic: topic, user: post_user) }
let(:zendesk_job_push_only_author_posts) { true }
before { SiteSetting.zendesk_job_push_only_author_posts = zendesk_job_push_only_author_posts }
context "with zendesk_job_push_only_author_posts disabled" do
let(:zendesk_job_push_only_author_posts) { false }
context "with same author" do
it "should be true" do
expect(eligible).to be_truthy
end
end
context "with different author" do
let(:post_user) { other_user }
it "should be true" do
expect(eligible).to be_truthy
end
end
end
context "with zendesk_job_push_only_author_posts enabled" do
let(:zendesk_job_push_only_author_posts) { true }
context "with same author" do
it "should be true" do
expect(eligible).to be_truthy
end
end
context "with different author" do
let(:post_user) { other_user }
it "should be false" do
expect(eligible).to be_falsey
end
end
end
end
end
@@ -0,0 +1,54 @@
# frozen_string_literal: true
require "rails_helper"
RSpec.describe DiscourseZendeskPlugin::SyncController do
describe "#webhook" do
let!(:token) { "secret-token" }
let!(:topic) { Fabricate(:topic) }
before do
SiteSetting.zendesk_enabled = true
SiteSetting.sync_comments_from_zendesk = true
SiteSetting.zendesk_incoming_webhook_token = token
end
it "raises an error when the token is missing" do
put "/zendesk-plugin/sync.json"
expect(response.status).to eq(400)
end
it "raises an error when the token is invalid" do
put "/zendesk-plugin/sync.json", params: { token: "token" }
expect(response.status).to eq(403)
end
it "raises an error if the plugin is disabled" do
SiteSetting.zendesk_enabled = false
put "/zendesk-plugin/sync.json", params: { token: token }
expect(response.status).to eq(404)
end
it "raises an error if `sync_comments_from_zendesk` is disabled" do
SiteSetting.sync_comments_from_zendesk = false
put "/zendesk-plugin/sync.json", params: { token: token }
expect(response.status).to eq(422)
end
it "raises an error if required parameters are missing" do
put "/zendesk-plugin/sync.json", params: { token: token, topic_id: topic.id }
expect(response.status).to eq(400)
end
it "raises an error when topic is not present" do
topic.destroy!
put "/zendesk-plugin/sync.json", params: { token: token, topic_id: topic.id, ticket_id: 12 }
expect(response.status).to eq(400)
end
it "returns 204 when the request succeeds" do
put "/zendesk-plugin/sync.json", params: { token: token, topic_id: topic.id, ticket_id: 12 }
expect(response.status).to eq(204)
end
end
end
@@ -0,0 +1,7 @@
# frozen_string_literal: true
RSpec.describe "Core features", type: :system do
before { enable_current_plugin }
it_behaves_like "having working core features"
end
+7
View File
@@ -157,3 +157,10 @@ files:
- source_path: plugins/discourse-openid-connect/config/locales/server.en.yml
destination_path: plugins/openid-connect/server.yml
label: openid-connect
- source_path: plugins/discourse-zendesk-plugin/config/locales/client.en.yml
destination_path: plugins/zendesk-plugin/client.yml
label: zendesk-plugin
- source_path: plugins/discourse-zendesk-plugin/config/locales/server.en.yml
destination_path: plugins/zendesk-plugin/server.yml
label: zendesk-plugin