From 5e86f2c21fd4de60d1cf4bc899b604a8839b8f5b Mon Sep 17 00:00:00 2001 From: Jarek Radosz Date: Fri, 11 Jul 2025 15:55:36 +0200 Subject: [PATCH] DEV: Move discourse-zendesk-plugin to core (#33570) https://meta.discourse.org/t/373574 Internal `/t/-/156778` --- .github/labeler.yml | 4 + .gitignore | 1 + Gemfile | 6 + Gemfile.lock | 19 +++ plugins/discourse-zendesk-plugin/README.md | 5 + .../issues_controller.rb | 22 ++++ .../sync_controller.rb | 57 +++++++++ ...k_autogenerate_categories_site_settings.rb | 22 ++++ .../app/jobs/regular/zendesk_job.rb | 45 +++++++ .../zendesk-topic-actions.gjs | 69 +++++++++++ .../config/locales/client.ar.yml | 32 +++++ .../config/locales/client.be.yml | 10 ++ .../config/locales/client.bg.yml | 10 ++ .../config/locales/client.bs_BA.yml | 10 ++ .../config/locales/client.ca.yml | 10 ++ .../config/locales/client.cs.yml | 10 ++ .../config/locales/client.da.yml | 10 ++ .../config/locales/client.de.yml | 32 +++++ .../config/locales/client.el.yml | 10 ++ .../config/locales/client.en.yml | 26 ++++ .../config/locales/client.en_GB.yml | 7 ++ .../config/locales/client.es.yml | 32 +++++ .../config/locales/client.et.yml | 10 ++ .../config/locales/client.fa_IR.yml | 10 ++ .../config/locales/client.fi.yml | 32 +++++ .../config/locales/client.fr.yml | 32 +++++ .../config/locales/client.gl.yml | 10 ++ .../config/locales/client.he.yml | 32 +++++ .../config/locales/client.hr.yml | 10 ++ .../config/locales/client.hu.yml | 10 ++ .../config/locales/client.hy.yml | 10 ++ .../config/locales/client.id.yml | 10 ++ .../config/locales/client.it.yml | 32 +++++ .../config/locales/client.ja.yml | 32 +++++ .../config/locales/client.ko.yml | 27 ++++ .../config/locales/client.lt.yml | 10 ++ .../config/locales/client.lv.yml | 10 ++ .../config/locales/client.nb_NO.yml | 10 ++ .../config/locales/client.nl.yml | 32 +++++ .../config/locales/client.pl_PL.yml | 27 ++++ .../config/locales/client.pt.yml | 10 ++ .../config/locales/client.pt_BR.yml | 32 +++++ .../config/locales/client.ro.yml | 10 ++ .../config/locales/client.ru.yml | 32 +++++ .../config/locales/client.sk.yml | 10 ++ .../config/locales/client.sl.yml | 10 ++ .../config/locales/client.sq.yml | 10 ++ .../config/locales/client.sr.yml | 10 ++ .../config/locales/client.sv.yml | 24 ++++ .../config/locales/client.sw.yml | 10 ++ .../config/locales/client.te.yml | 10 ++ .../config/locales/client.th.yml | 10 ++ .../config/locales/client.tr_TR.yml | 32 +++++ .../config/locales/client.ug.yml | 10 ++ .../config/locales/client.uk.yml | 10 ++ .../config/locales/client.ur.yml | 10 ++ .../config/locales/client.vi.yml | 10 ++ .../config/locales/client.zh_CN.yml | 32 +++++ .../config/locales/client.zh_TW.yml | 10 ++ .../config/settings.yml | 30 +++++ ...122325_remove_zendesk_sync_site_setting.rb | 12 ++ ...41108_disable_zendesk_plugin_by_default.rb | 17 +++ ..._rename_enable_categories_site_settings.rb | 17 +++ .../lib/discourse_zendesk_plugin/engine.rb | 16 +++ .../lib/discourse_zendesk_plugin/helper.rb | 115 ++++++++++++++++++ .../post_extension.rb | 17 +++ .../topic_extension.rb | 30 +++++ plugins/discourse-zendesk-plugin/plugin.rb | 59 +++++++++ .../spec/integration/topic_extensions_spec.rb | 49 ++++++++ .../spec/integration/zendesk_plugin_spec.rb | 87 +++++++++++++ ...ogenerate_categories_site_settings_spec.rb | 23 ++++ .../spec/jobs/regular/zendesk_job_spec.rb | 98 +++++++++++++++ .../discourse_zendesk_plugin/helper_spec.rb | 58 +++++++++ .../spec/requests/sync_controller_spec.rb | 54 ++++++++ .../spec/system/core_features_spec.rb | 7 ++ translator.yml | 7 ++ 76 files changed, 1783 insertions(+) create mode 100644 plugins/discourse-zendesk-plugin/README.md create mode 100644 plugins/discourse-zendesk-plugin/app/controllers/discourse_zendesk_plugin/issues_controller.rb create mode 100644 plugins/discourse-zendesk-plugin/app/controllers/discourse_zendesk_plugin/sync_controller.rb create mode 100644 plugins/discourse-zendesk-plugin/app/jobs/onceoff/migrate_zendesk_autogenerate_categories_site_settings.rb create mode 100644 plugins/discourse-zendesk-plugin/app/jobs/regular/zendesk_job.rb create mode 100644 plugins/discourse-zendesk-plugin/assets/javascripts/discourse-zendesk-plugin/connectors/after-topic-footer-buttons/zendesk-topic-actions.gjs create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.ar.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.be.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.bg.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.bs_BA.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.ca.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.cs.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.da.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.de.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.el.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.en.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.en_GB.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.es.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.et.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.fa_IR.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.fi.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.fr.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.gl.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.he.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.hr.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.hu.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.hy.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.id.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.it.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.ja.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.ko.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.lt.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.lv.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.nb_NO.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.nl.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.pl_PL.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.pt.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.pt_BR.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.ro.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.ru.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.sk.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.sl.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.sq.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.sr.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.sv.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.sw.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.te.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.th.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.tr_TR.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.ug.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.uk.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.ur.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.vi.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.zh_CN.yml create mode 100644 plugins/discourse-zendesk-plugin/config/locales/client.zh_TW.yml create mode 100644 plugins/discourse-zendesk-plugin/config/settings.yml create mode 100644 plugins/discourse-zendesk-plugin/db/migrate/20200707122325_remove_zendesk_sync_site_setting.rb create mode 100644 plugins/discourse-zendesk-plugin/db/migrate/20200917041108_disable_zendesk_plugin_by_default.rb create mode 100644 plugins/discourse-zendesk-plugin/db/migrate/20230113110559_rename_enable_categories_site_settings.rb create mode 100644 plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/engine.rb create mode 100644 plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/helper.rb create mode 100644 plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/post_extension.rb create mode 100644 plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/topic_extension.rb create mode 100644 plugins/discourse-zendesk-plugin/plugin.rb create mode 100644 plugins/discourse-zendesk-plugin/spec/integration/topic_extensions_spec.rb create mode 100644 plugins/discourse-zendesk-plugin/spec/integration/zendesk_plugin_spec.rb create mode 100644 plugins/discourse-zendesk-plugin/spec/jobs/onceoff/migrate_zendesk_autogenerate_categories_site_settings_spec.rb create mode 100644 plugins/discourse-zendesk-plugin/spec/jobs/regular/zendesk_job_spec.rb create mode 100644 plugins/discourse-zendesk-plugin/spec/lib/discourse_zendesk_plugin/helper_spec.rb create mode 100644 plugins/discourse-zendesk-plugin/spec/requests/sync_controller_spec.rb create mode 100644 plugins/discourse-zendesk-plugin/spec/system/core_features_spec.rb diff --git a/.github/labeler.yml b/.github/labeler.yml index d1721837871..fb33a0ae6dc 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -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/**/* diff --git a/.gitignore b/.gitignore index a870e90b556..88de60ad250 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/Gemfile b/Gemfile index c4917e9557d..284e2565222 100644 --- a/Gemfile +++ b/Gemfile @@ -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 diff --git a/Gemfile.lock b/Gemfile.lock index f85aed8cb11..9949c4b518a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -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 diff --git a/plugins/discourse-zendesk-plugin/README.md b/plugins/discourse-zendesk-plugin/README.md new file mode 100644 index 00000000000..e8cec92938d --- /dev/null +++ b/plugins/discourse-zendesk-plugin/README.md @@ -0,0 +1,5 @@ +# Discourse Zendesk Plugin + +Zendesk for Discourse + +For more information, please see: https://meta.discourse.org/t/discourse-zendesk-plugin/68005 diff --git a/plugins/discourse-zendesk-plugin/app/controllers/discourse_zendesk_plugin/issues_controller.rb b/plugins/discourse-zendesk-plugin/app/controllers/discourse_zendesk_plugin/issues_controller.rb new file mode 100644 index 00000000000..fd1f32f6886 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/app/controllers/discourse_zendesk_plugin/issues_controller.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/app/controllers/discourse_zendesk_plugin/sync_controller.rb b/plugins/discourse-zendesk-plugin/app/controllers/discourse_zendesk_plugin/sync_controller.rb new file mode 100644 index 00000000000..4d9570b9b6c --- /dev/null +++ b/plugins/discourse-zendesk-plugin/app/controllers/discourse_zendesk_plugin/sync_controller.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/app/jobs/onceoff/migrate_zendesk_autogenerate_categories_site_settings.rb b/plugins/discourse-zendesk-plugin/app/jobs/onceoff/migrate_zendesk_autogenerate_categories_site_settings.rb new file mode 100644 index 00000000000..11416065f87 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/app/jobs/onceoff/migrate_zendesk_autogenerate_categories_site_settings.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/app/jobs/regular/zendesk_job.rb b/plugins/discourse-zendesk-plugin/app/jobs/regular/zendesk_job.rb new file mode 100644 index 00000000000..4ec994a3415 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/app/jobs/regular/zendesk_job.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/assets/javascripts/discourse-zendesk-plugin/connectors/after-topic-footer-buttons/zendesk-topic-actions.gjs b/plugins/discourse-zendesk-plugin/assets/javascripts/discourse-zendesk-plugin/connectors/after-topic-footer-buttons/zendesk-topic-actions.gjs new file mode 100644 index 00000000000..71130749917 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/assets/javascripts/discourse-zendesk-plugin/connectors/after-topic-footer-buttons/zendesk-topic-actions.gjs @@ -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, + }); + }); + } + + +} diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.ar.yml b/plugins/discourse-zendesk-plugin/config/locales/client.ar.yml new file mode 100644 index 00000000000..a24d5bb15e2 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.ar.yml @@ -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: قائمة الوسوم التي سيتم إضافتها إلى كل تذكرة diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.be.yml b/plugins/discourse-zendesk-plugin/config/locales/client.be.yml new file mode 100644 index 00000000000..e303d5fdaf9 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.be.yml @@ -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: Нешта пайшло не так. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.bg.yml b/plugins/discourse-zendesk-plugin/config/locales/client.bg.yml new file mode 100644 index 00000000000..b2ded898c61 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.bg.yml @@ -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: Нещо се обърка. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.bs_BA.yml b/plugins/discourse-zendesk-plugin/config/locales/client.bs_BA.yml new file mode 100644 index 00000000000..711c1db541f --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.bs_BA.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.ca.yml b/plugins/discourse-zendesk-plugin/config/locales/client.ca.yml new file mode 100644 index 00000000000..3e105b826af --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.ca.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.cs.yml b/plugins/discourse-zendesk-plugin/config/locales/client.cs.yml new file mode 100644 index 00000000000..6910ccd7a6a --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.cs.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.da.yml b/plugins/discourse-zendesk-plugin/config/locales/client.da.yml new file mode 100644 index 00000000000..3c76b797f26 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.da.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.de.yml b/plugins/discourse-zendesk-plugin/config/locales/client.de.yml new file mode 100644 index 00000000000..47622129146 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.de.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.el.yml b/plugins/discourse-zendesk-plugin/config/locales/client.el.yml new file mode 100644 index 00000000000..fbe6c3f7c32 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.el.yml @@ -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: Κάτι δεν πήγε καλά. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.en.yml b/plugins/discourse-zendesk-plugin/config/locales/client.en.yml new file mode 100644 index 00000000000..9a9c82c772d --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.en.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.en_GB.yml b/plugins/discourse-zendesk-plugin/config/locales/client.en_GB.yml new file mode 100644 index 00000000000..2d4fa180ec7 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.en_GB.yml @@ -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: diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.es.yml b/plugins/discourse-zendesk-plugin/config/locales/client.es.yml new file mode 100644 index 00000000000..ba15aa70745 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.es.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.et.yml b/plugins/discourse-zendesk-plugin/config/locales/client.et.yml new file mode 100644 index 00000000000..9a4c165878e --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.et.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.fa_IR.yml b/plugins/discourse-zendesk-plugin/config/locales/client.fa_IR.yml new file mode 100644 index 00000000000..77f1644ea35 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.fa_IR.yml @@ -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: اشتباهی روی داد. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.fi.yml b/plugins/discourse-zendesk-plugin/config/locales/client.fi.yml new file mode 100644 index 00000000000..fe708235778 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.fi.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.fr.yml b/plugins/discourse-zendesk-plugin/config/locales/client.fr.yml new file mode 100644 index 00000000000..52bb3c7842b --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.fr.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.gl.yml b/plugins/discourse-zendesk-plugin/config/locales/client.gl.yml new file mode 100644 index 00000000000..f36a311410a --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.gl.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.he.yml b/plugins/discourse-zendesk-plugin/config/locales/client.he.yml new file mode 100644 index 00000000000..5bd87e44cae --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.he.yml @@ -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: רשימת תגיות להוספה לכל כרטיס diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.hr.yml b/plugins/discourse-zendesk-plugin/config/locales/client.hr.yml new file mode 100644 index 00000000000..71fc9d02591 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.hr.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.hu.yml b/plugins/discourse-zendesk-plugin/config/locales/client.hu.yml new file mode 100644 index 00000000000..933ed87bc3b --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.hu.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.hy.yml b/plugins/discourse-zendesk-plugin/config/locales/client.hy.yml new file mode 100644 index 00000000000..3bee3ddf6fb --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.hy.yml @@ -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: 'Ինչ-որ բան այն չէ:' diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.id.yml b/plugins/discourse-zendesk-plugin/config/locales/client.id.yml new file mode 100644 index 00000000000..10ecbb5099f --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.id.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.it.yml b/plugins/discourse-zendesk-plugin/config/locales/client.it.yml new file mode 100644 index 00000000000..ad3cd1ee003 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.it.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.ja.yml b/plugins/discourse-zendesk-plugin/config/locales/client.ja.yml new file mode 100644 index 00000000000..bc660411095 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.ja.yml @@ -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: 各チケットに追加されるタグのリスト diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.ko.yml b/plugins/discourse-zendesk-plugin/config/locales/client.ko.yml new file mode 100644 index 00000000000..05cc6a215a4 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.ko.yml @@ -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: 각 티켓에 추가할 태그 목록 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.lt.yml b/plugins/discourse-zendesk-plugin/config/locales/client.lt.yml new file mode 100644 index 00000000000..edbaa1ef77e --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.lt.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.lv.yml b/plugins/discourse-zendesk-plugin/config/locales/client.lv.yml new file mode 100644 index 00000000000..85b245e7879 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.lv.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.nb_NO.yml b/plugins/discourse-zendesk-plugin/config/locales/client.nb_NO.yml new file mode 100644 index 00000000000..cb4fe8b02e8 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.nb_NO.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.nl.yml b/plugins/discourse-zendesk-plugin/config/locales/client.nl.yml new file mode 100644 index 00000000000..282bb0f23cd --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.nl.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.pl_PL.yml b/plugins/discourse-zendesk-plugin/config/locales/client.pl_PL.yml new file mode 100644 index 00000000000..a28e932207f --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.pl_PL.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.pt.yml b/plugins/discourse-zendesk-plugin/config/locales/client.pt.yml new file mode 100644 index 00000000000..3a03e66c268 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.pt.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.pt_BR.yml b/plugins/discourse-zendesk-plugin/config/locales/client.pt_BR.yml new file mode 100644 index 00000000000..8fe35b9bfd5 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.pt_BR.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.ro.yml b/plugins/discourse-zendesk-plugin/config/locales/client.ro.yml new file mode 100644 index 00000000000..e9e2b5eb477 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.ro.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.ru.yml b/plugins/discourse-zendesk-plugin/config/locales/client.ru.yml new file mode 100644 index 00000000000..342e31ed69f --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.ru.yml @@ -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: Список тегов, которые нужно добавить к каждому тикету diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.sk.yml b/plugins/discourse-zendesk-plugin/config/locales/client.sk.yml new file mode 100644 index 00000000000..519c01a9dba --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.sk.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.sl.yml b/plugins/discourse-zendesk-plugin/config/locales/client.sl.yml new file mode 100644 index 00000000000..5227878deb3 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.sl.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.sq.yml b/plugins/discourse-zendesk-plugin/config/locales/client.sq.yml new file mode 100644 index 00000000000..cff332c66d2 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.sq.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.sr.yml b/plugins/discourse-zendesk-plugin/config/locales/client.sr.yml new file mode 100644 index 00000000000..8637372cd0c --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.sr.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.sv.yml b/plugins/discourse-zendesk-plugin/config/locales/client.sv.yml new file mode 100644 index 00000000000..a1ad28987c8 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.sv.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.sw.yml b/plugins/discourse-zendesk-plugin/config/locales/client.sw.yml new file mode 100644 index 00000000000..cd3d13ee4e7 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.sw.yml @@ -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. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.te.yml b/plugins/discourse-zendesk-plugin/config/locales/client.te.yml new file mode 100644 index 00000000000..8cf68f6d068 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.te.yml @@ -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: ఏదో తేడా జరిగింది. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.th.yml b/plugins/discourse-zendesk-plugin/config/locales/client.th.yml new file mode 100644 index 00000000000..e82d3cd2765 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.th.yml @@ -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: มีบางอย่างผิดปกติ diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.tr_TR.yml b/plugins/discourse-zendesk-plugin/config/locales/client.tr_TR.yml new file mode 100644 index 00000000000..d1bbdd6fadf --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.tr_TR.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.ug.yml b/plugins/discourse-zendesk-plugin/config/locales/client.ug.yml new file mode 100644 index 00000000000..f965580e8da --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.ug.yml @@ -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: چاتاق چىقتى. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.uk.yml b/plugins/discourse-zendesk-plugin/config/locales/client.uk.yml new file mode 100644 index 00000000000..86382c0ce58 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.uk.yml @@ -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: Щось пішло не так. diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.ur.yml b/plugins/discourse-zendesk-plugin/config/locales/client.ur.yml new file mode 100644 index 00000000000..e3ea9fd312b --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.ur.yml @@ -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: کچھ غلط ہو گیا۔ diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.vi.yml b/plugins/discourse-zendesk-plugin/config/locales/client.vi.yml new file mode 100644 index 00000000000..4d901ac266a --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.vi.yml @@ -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 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.zh_CN.yml b/plugins/discourse-zendesk-plugin/config/locales/client.zh_CN.yml new file mode 100644 index 00000000000..41cac822a16 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.zh_CN.yml @@ -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: 添加到每张工单的标签列表 diff --git a/plugins/discourse-zendesk-plugin/config/locales/client.zh_TW.yml b/plugins/discourse-zendesk-plugin/config/locales/client.zh_TW.yml new file mode 100644 index 00000000000..ed60b0a2771 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/locales/client.zh_TW.yml @@ -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: 發生錯誤。 diff --git a/plugins/discourse-zendesk-plugin/config/settings.yml b/plugins/discourse-zendesk-plugin/config/settings.yml new file mode 100644 index 00000000000..b059d18ae32 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/config/settings.yml @@ -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: "" diff --git a/plugins/discourse-zendesk-plugin/db/migrate/20200707122325_remove_zendesk_sync_site_setting.rb b/plugins/discourse-zendesk-plugin/db/migrate/20200707122325_remove_zendesk_sync_site_setting.rb new file mode 100644 index 00000000000..abf61da6a55 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/db/migrate/20200707122325_remove_zendesk_sync_site_setting.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/db/migrate/20200917041108_disable_zendesk_plugin_by_default.rb b/plugins/discourse-zendesk-plugin/db/migrate/20200917041108_disable_zendesk_plugin_by_default.rb new file mode 100644 index 00000000000..26d4a0714aa --- /dev/null +++ b/plugins/discourse-zendesk-plugin/db/migrate/20200917041108_disable_zendesk_plugin_by_default.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/db/migrate/20230113110559_rename_enable_categories_site_settings.rb b/plugins/discourse-zendesk-plugin/db/migrate/20230113110559_rename_enable_categories_site_settings.rb new file mode 100644 index 00000000000..c9b67f61127 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/db/migrate/20230113110559_rename_enable_categories_site_settings.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/engine.rb b/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/engine.rb new file mode 100644 index 00000000000..67817b56c64 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/engine.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/helper.rb b/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/helper.rb new file mode 100644 index 00000000000..9bce6df2c17 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/helper.rb @@ -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 [Discourse post]" + end + end +end diff --git a/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/post_extension.rb b/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/post_extension.rb new file mode 100644 index 00000000000..e8f68c3d270 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/post_extension.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/topic_extension.rb b/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/topic_extension.rb new file mode 100644 index 00000000000..4766d6e8ae2 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/lib/discourse_zendesk_plugin/topic_extension.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/plugin.rb b/plugins/discourse-zendesk-plugin/plugin.rb new file mode 100644 index 00000000000..972aa901948 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/plugin.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/spec/integration/topic_extensions_spec.rb b/plugins/discourse-zendesk-plugin/spec/integration/topic_extensions_spec.rb new file mode 100644 index 00000000000..71d8fe80df0 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/spec/integration/topic_extensions_spec.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/spec/integration/zendesk_plugin_spec.rb b/plugins/discourse-zendesk-plugin/spec/integration/zendesk_plugin_spec.rb new file mode 100644 index 00000000000..2557a609cd3 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/spec/integration/zendesk_plugin_spec.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/spec/jobs/onceoff/migrate_zendesk_autogenerate_categories_site_settings_spec.rb b/plugins/discourse-zendesk-plugin/spec/jobs/onceoff/migrate_zendesk_autogenerate_categories_site_settings_spec.rb new file mode 100644 index 00000000000..f3ebcf53218 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/spec/jobs/onceoff/migrate_zendesk_autogenerate_categories_site_settings_spec.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/spec/jobs/regular/zendesk_job_spec.rb b/plugins/discourse-zendesk-plugin/spec/jobs/regular/zendesk_job_spec.rb new file mode 100644 index 00000000000..c3f25cd24aa --- /dev/null +++ b/plugins/discourse-zendesk-plugin/spec/jobs/regular/zendesk_job_spec.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/spec/lib/discourse_zendesk_plugin/helper_spec.rb b/plugins/discourse-zendesk-plugin/spec/lib/discourse_zendesk_plugin/helper_spec.rb new file mode 100644 index 00000000000..687c9e99d2f --- /dev/null +++ b/plugins/discourse-zendesk-plugin/spec/lib/discourse_zendesk_plugin/helper_spec.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/spec/requests/sync_controller_spec.rb b/plugins/discourse-zendesk-plugin/spec/requests/sync_controller_spec.rb new file mode 100644 index 00000000000..acc227f1395 --- /dev/null +++ b/plugins/discourse-zendesk-plugin/spec/requests/sync_controller_spec.rb @@ -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 diff --git a/plugins/discourse-zendesk-plugin/spec/system/core_features_spec.rb b/plugins/discourse-zendesk-plugin/spec/system/core_features_spec.rb new file mode 100644 index 00000000000..db86db283bd --- /dev/null +++ b/plugins/discourse-zendesk-plugin/spec/system/core_features_spec.rb @@ -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 diff --git a/translator.yml b/translator.yml index 66358ea14b7..4da67d79b7e 100644 --- a/translator.yml +++ b/translator.yml @@ -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