diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7fe6c3c78..be9eb66cb 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,7 @@
[Full Changelog](https://github.com/zammad/zammad/compare/5.0.2...5.0.3)
+
**Implemented enhancements:**
- Possibility to specify the order of objects [294](https://github.com/zammad/zammad/issues/294) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[UX/UI](https://github.com/zammad/zammad/labels/UX/UI)] [[object manager attribute](https://github.com/zammad/zammad/labels/object manager attribute)]
diff --git a/Gemfile.lock b/Gemfile.lock
index 98ee0ecd6..bc11ccdb9 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -21,50 +21,50 @@ GEM
specs:
aasm (5.2.0)
concurrent-ruby (~> 1.0)
- actioncable (6.0.4.4)
- actionpack (= 6.0.4.4)
+ actioncable (6.0.4.7)
+ actionpack (= 6.0.4.7)
nio4r (~> 2.0)
websocket-driver (>= 0.6.1)
- actionmailbox (6.0.4.4)
- actionpack (= 6.0.4.4)
- activejob (= 6.0.4.4)
- activerecord (= 6.0.4.4)
- activestorage (= 6.0.4.4)
- activesupport (= 6.0.4.4)
+ actionmailbox (6.0.4.7)
+ actionpack (= 6.0.4.7)
+ activejob (= 6.0.4.7)
+ activerecord (= 6.0.4.7)
+ activestorage (= 6.0.4.7)
+ activesupport (= 6.0.4.7)
mail (>= 2.7.1)
- actionmailer (6.0.4.4)
- actionpack (= 6.0.4.4)
- actionview (= 6.0.4.4)
- activejob (= 6.0.4.4)
+ actionmailer (6.0.4.7)
+ actionpack (= 6.0.4.7)
+ actionview (= 6.0.4.7)
+ activejob (= 6.0.4.7)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
- actionpack (6.0.4.4)
- actionview (= 6.0.4.4)
- activesupport (= 6.0.4.4)
+ actionpack (6.0.4.7)
+ actionview (= 6.0.4.7)
+ activesupport (= 6.0.4.7)
rack (~> 2.0, >= 2.0.8)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
- actiontext (6.0.4.4)
- actionpack (= 6.0.4.4)
- activerecord (= 6.0.4.4)
- activestorage (= 6.0.4.4)
- activesupport (= 6.0.4.4)
+ actiontext (6.0.4.7)
+ actionpack (= 6.0.4.7)
+ activerecord (= 6.0.4.7)
+ activestorage (= 6.0.4.7)
+ activesupport (= 6.0.4.7)
nokogiri (>= 1.8.5)
- actionview (6.0.4.4)
- activesupport (= 6.0.4.4)
+ actionview (6.0.4.7)
+ activesupport (= 6.0.4.7)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.1, >= 1.2.0)
- activejob (6.0.4.4)
- activesupport (= 6.0.4.4)
+ activejob (6.0.4.7)
+ activesupport (= 6.0.4.7)
globalid (>= 0.3.6)
- activemodel (6.0.4.4)
- activesupport (= 6.0.4.4)
- activerecord (6.0.4.4)
- activemodel (= 6.0.4.4)
- activesupport (= 6.0.4.4)
+ activemodel (6.0.4.7)
+ activesupport (= 6.0.4.7)
+ activerecord (6.0.4.7)
+ activemodel (= 6.0.4.7)
+ activesupport (= 6.0.4.7)
activerecord-import (1.2.0)
activerecord (>= 3.2)
activerecord-nulldb-adapter (0.7.0)
@@ -75,12 +75,12 @@ GEM
multi_json (~> 1.11, >= 1.11.2)
rack (>= 2.0.8, < 3)
railties (>= 5.2.4.1)
- activestorage (6.0.4.4)
- actionpack (= 6.0.4.4)
- activejob (= 6.0.4.4)
- activerecord (= 6.0.4.4)
+ activestorage (6.0.4.7)
+ actionpack (= 6.0.4.7)
+ activejob (= 6.0.4.7)
+ activerecord (= 6.0.4.7)
marcel (~> 1.0.0)
- activesupport (6.0.4.4)
+ activesupport (6.0.4.7)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
@@ -291,7 +291,7 @@ GEM
http_parser.rb (0.6.0)
http_parser.rb (0.6.0-x86_64-linux-musl)
httpclient (2.8.3)
- i18n (1.8.10)
+ i18n (1.10.0)
concurrent-ruby (~> 1.0)
icalendar (2.7.1)
ice_cube (~> 0.16)
@@ -319,11 +319,11 @@ GEM
logging (2.3.0)
little-plugger (~> 1.1)
multi_json (~> 1.14)
- loofah (2.13.0)
+ loofah (2.14.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
lumberjack (1.2.8)
- marcel (1.0.1)
+ marcel (1.0.2)
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
messagebird-rest (3.0.0)
@@ -331,8 +331,8 @@ GEM
mime-types (3.3.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2021.0225)
- mini_mime (1.1.1)
- mini_portile2 (2.6.1)
+ mini_mime (1.1.2)
+ mini_portile2 (2.8.0)
mini_racer (0.2.9)
libv8 (>= 6.9.411)
minitest (5.15.0)
@@ -349,9 +349,8 @@ GEM
net-ldap (0.17.0)
netrc (0.11.0)
nio4r (2.5.8)
- nio4r (2.5.8-x86_64-linux-musl)
- nokogiri (1.12.5)
- mini_portile2 (~> 2.6.1)
+ nokogiri (1.13.3)
+ mini_portile2 (~> 2.8.0)
racc (~> 1.4)
nokogiri (1.12.5-x86_64-linux-musl)
mini_portile2 (~> 2.6.1)
@@ -443,7 +442,7 @@ GEM
binding_of_caller (~> 1.0)
pry (~> 0.13)
public_suffix (4.0.6)
- puma (4.3.10)
+ puma (4.3.11)
nio4r (~> 2.0)
puma (4.3.8-x86_64-linux-musl)
nio4r (~> 2.0)
@@ -451,27 +450,26 @@ GEM
activesupport (>= 3.0.0)
pundit-matchers (1.7.0)
rspec-rails (>= 3.0.0)
- racc (1.5.2)
- racc (1.5.2-x86_64-linux-musl)
+ racc (1.6.0)
rack (2.2.3)
rack-livereload (0.3.17)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
- rails (6.0.4.4)
- actioncable (= 6.0.4.4)
- actionmailbox (= 6.0.4.4)
- actionmailer (= 6.0.4.4)
- actionpack (= 6.0.4.4)
- actiontext (= 6.0.4.4)
- actionview (= 6.0.4.4)
- activejob (= 6.0.4.4)
- activemodel (= 6.0.4.4)
- activerecord (= 6.0.4.4)
- activestorage (= 6.0.4.4)
- activesupport (= 6.0.4.4)
+ rails (6.0.4.7)
+ actioncable (= 6.0.4.7)
+ actionmailbox (= 6.0.4.7)
+ actionmailer (= 6.0.4.7)
+ actionpack (= 6.0.4.7)
+ actiontext (= 6.0.4.7)
+ actionview (= 6.0.4.7)
+ activejob (= 6.0.4.7)
+ activemodel (= 6.0.4.7)
+ activerecord (= 6.0.4.7)
+ activestorage (= 6.0.4.7)
+ activesupport (= 6.0.4.7)
bundler (>= 1.3.0)
- railties (= 6.0.4.4)
+ railties (= 6.0.4.7)
sprockets-rails (>= 2.0.0)
rails-controller-testing (1.0.5)
actionpack (>= 5.0.1.rc1)
@@ -480,11 +478,11 @@ GEM
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
- rails-html-sanitizer (1.4.1)
+ rails-html-sanitizer (1.4.2)
loofah (~> 2.3)
- railties (6.0.4.4)
- actionpack (= 6.0.4.4)
- activesupport (= 6.0.4.4)
+ railties (6.0.4.7)
+ actionpack (= 6.0.4.7)
+ activesupport (= 6.0.4.7)
method_source
rake (>= 0.8.7)
thor (>= 0.20.3, < 2.0)
@@ -610,7 +608,7 @@ GEM
tins (~> 1.0)
test-unit (3.4.7)
power_assert
- thor (1.1.0)
+ thor (1.2.1)
thread_safe (0.3.6)
tilt (2.0.10)
timers (4.3.3)
@@ -666,7 +664,7 @@ GEM
writeexcel (1.0.5)
xpath (3.2.0)
nokogiri (~> 1.8)
- zeitwerk (2.4.2)
+ zeitwerk (2.5.4)
zendesk_api (1.33.0)
faraday (>= 0.9.0, < 2.0.0)
hashie (>= 3.5.2, < 5.0.0)
diff --git a/app/assets/javascripts/app/controllers/_application_controller/observer.coffee b/app/assets/javascripts/app/controllers/_application_controller/observer.coffee
index 293c02528..a50b3915f 100644
--- a/app/assets/javascripts/app/controllers/_application_controller/observer.coffee
+++ b/app/assets/javascripts/app/controllers/_application_controller/observer.coffee
@@ -2,6 +2,7 @@ class App.ControllerObserver extends App.Controller
model: 'Ticket'
template: 'tba'
globalRerender: true
+ lastAttributes: undefined
###
observe:
@@ -25,7 +26,7 @@ class App.ControllerObserver extends App.Controller
# rerender, e. g. on language change
if @globalRerender
@controllerBind('ui:rerender', =>
- @lastAttributres = undefined
+ @lastAttributes = undefined
@maybeRender(App[@model].fullLocal(@object_id))
)
@@ -43,32 +44,40 @@ class App.ControllerObserver extends App.Controller
if !@subscribeId
@subscribeId = object.subscribe(@subscribe)
- # remember current attributes
+ return if !@hasChanged(object)
+
+ @render(object)
+
+ hasChanged: (object) =>
currentAttributes = {}
+
+ objectCloned = $.extend(true, {}, object)
if @observe
for key, active of @observe
- if active
- currentAttributes[key] = object[key]
+ if active && !_.isFunction(value)
+ currentAttributes[key] = objectCloned[key]
+
if @observeNot
- for key, value of object
- if key isnt 'cid' && !@observeNot[key] && !_.isFunction(value) && !_.isObject(value)
+ for key, value of objectCloned
+ if key isnt 'cid' && !@observeNot[key] && !_.isFunction(value)
currentAttributes[key] = value
- if !@lastAttributres
- @lastAttributres = {}
- else
- diff = difference(currentAttributes, @lastAttributres)
- if _.isEmpty(diff)
- @log 'debug', 'maybeRender no diff, no rerender'
- return
+ if !@lastAttributes
+ @lastAttributes = currentAttributes
+ return true
+
+ diff = difference(currentAttributes, @lastAttributes)
+ if _.isEmpty(diff)
+ @log 'debug', 'maybeRender no diff, no rerender'
+ return false
@log 'debug', 'maybeRender.diff', diff, @observe, @model
- @lastAttributres = currentAttributes
+ @lastAttributes = currentAttributes
- @render(object, diff)
+ true
- render: (object, diff) =>
- @log 'debug', 'render', @template, object, diff
+ render: (object) =>
+ @log 'debug', 'render', @template, object
@html App.view(@template)(
object: object
)
diff --git a/app/assets/javascripts/app/controllers/organization_profile.coffee b/app/assets/javascripts/app/controllers/organization_profile.coffee
index ad7890c68..4aefe61b3 100644
--- a/app/assets/javascripts/app/controllers/organization_profile.coffee
+++ b/app/assets/javascripts/app/controllers/organization_profile.coffee
@@ -202,7 +202,7 @@ class Object extends App.ControllerObserver
value = $(e.target).html()
org = App.Organization.find(@object_id)
if org[name] isnt value
- @lastAttributres[name] = value
+ @lastAttributes[name] = value
data = {}
data[name] = value
org.updateAttributes(data)
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee
index f7bcf3867..91857781c 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/email_reply.coffee
@@ -257,7 +257,7 @@ class EmailReply extends App.Controller
quote_header = App.FullQuoteHeader.fullQuoteHeaderForward(article)
- body = "
---Begin forwarded message:---
"
+ body = "
---#{App.i18n.translateInline('Begin forwarded message')}:---
"
articleNew = {}
articleNew.body = body
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/internal.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/internal.coffee
index b748be467..667ea1ad5 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/article_action/internal.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_action/internal.coffee
@@ -24,7 +24,7 @@ class Internal
internal = true
if article.internal == true
internal = false
- ui.lastAttributres.internal = internal
+ ui.lastAttributes.internal = internal
article.updateAttributes(internal: internal)
# runtime update
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee
index 66a6a5e87..18234a14f 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/article_view.coffee
@@ -218,11 +218,11 @@ class ArticleViewItem extends App.ControllerObserver
)
@articleActions = new App.TicketZoomArticleActions(
- el: @$('.js-article-actions')
- ticket: @ticket
- article: article
- lastAttributres: @lastAttributres
- form_id: @form_id
+ el: @$('.js-article-actions')
+ ticket: @ticket
+ article: article
+ lastAttributes: @lastAttributes
+ form_id: @form_id
)
# set see more
@@ -305,34 +305,38 @@ class ArticleViewItem extends App.ControllerObserver
e.stopPropagation()
article_id = $(e.target).closest('.ticket-article-item').data('id')
+ article = App.TicketArticle.find(article_id)
@ajax(
id: 'retrySecurityProcess'
type: 'POST'
url: "#{@apiPath}/ticket_articles/#{article_id}/retry_security_process"
processData: true
- success: (data, status, xhr) =>
- if data.sign.success
- @notify
- type: 'success'
- msg: App.i18n.translateContent('Verify sign success!')
- else if data.sign.comment
- comment = App.i18n.translateContent('Verify sign failed!') + ' ' + App.i18n.translateContent(data.sign.comment || '')
- @notify
- type: 'error'
- msg: comment
- timeout: 2000
+ success: (encryption_data, status, xhr) =>
+ for data in encryption_data
+ continue if article.preferences.security.type isnt data.type
- if data.encryption.success
- @notify
- type: 'success'
- msg: App.i18n.translateContent('Decryption success!')
- else if data.encryption.comment
- comment = App.i18n.translateContent('Decryption failed!') + ' ' + App.i18n.translateContent(data.encryption.comment || '')
- @notify
- type: 'error'
- msg: comment
- timeout: 2000
+ if data.sign.success
+ @notify
+ type: 'success'
+ msg: App.i18n.translateContent('Verify sign success!')
+ else if data.sign.comment
+ comment = App.i18n.translateContent('Verify sign failed!') + ' ' + App.i18n.translateContent(data.sign.comment || '')
+ @notify
+ type: 'error'
+ msg: comment
+ timeout: 2000
+
+ if data.encryption.success
+ @notify
+ type: 'success'
+ msg: App.i18n.translateContent('Decryption success!')
+ else if data.encryption.comment
+ comment = App.i18n.translateContent('Decryption failed!') + ' ' + App.i18n.translateContent(data.encryption.comment || '')
+ @notify
+ type: 'error'
+ msg: comment
+ timeout: 2000
error: (xhr) =>
@notify
diff --git a/app/assets/javascripts/app/controllers/ticket_zoom/title.coffee b/app/assets/javascripts/app/controllers/ticket_zoom/title.coffee
index a9acea2ea..3555967a5 100644
--- a/app/assets/javascripts/app/controllers/ticket_zoom/title.coffee
+++ b/app/assets/javascripts/app/controllers/ticket_zoom/title.coffee
@@ -19,7 +19,7 @@ class App.TicketZoomTitle extends App.ControllerObserver
title = $(e.target).ceg() || ''
# update title
- return if title is @lastAttributres.title
+ return if title is @lastAttributes.title
ticket = App.Ticket.find(@object_id)
ticket.title = title
diff --git a/app/assets/javascripts/app/controllers/user_profile.coffee b/app/assets/javascripts/app/controllers/user_profile.coffee
index 43f11effb..2ec790d05 100644
--- a/app/assets/javascripts/app/controllers/user_profile.coffee
+++ b/app/assets/javascripts/app/controllers/user_profile.coffee
@@ -220,7 +220,7 @@ class Object extends App.ControllerObserver
value = $(e.target).html()
user = App.User.find(@object_id)
if user[name] isnt value
- @lastAttributres[name] = value
+ @lastAttributes[name] = value
data = {}
data[name] = value
user.updateAttributes(data)
diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js
index 4e4974fce..45ebcbd50 100644
--- a/app/assets/javascripts/application.js
+++ b/app/assets/javascripts/application.js
@@ -65,9 +65,9 @@ Date.prototype.getWeek = function() {
function difference(object1, object2) {
var changes = {};
- for (var name in object1) {
- if (name in object2) {
- if (_.isObject(object2[name]) && !_.isArray(object2[name])) {
+ _.uniq(Object.keys(object1).concat(Object.keys(object2))).forEach(function(name) {
+ if (name in object1 && name in object2) {
+ if (_.isObject(object1[name]) && !_.isArray(object1[name]) && _.isObject(object2[name]) && !_.isArray(object2[name])) {
var diff = difference(object1[name], object2[name]);
if (!_.isEmpty(diff)) {
changes[name] = diff;
@@ -75,8 +75,10 @@ function difference(object1, object2) {
} else if (!_.isEqual(object1[name], object2[name])) {
changes[name] = object2[name];
}
+ } else {
+ changes[name] = object2[name]
}
- }
+ })
return changes;
}
diff --git a/config/initializers/db_preferences.rb b/config/initializers/db_preferences.rb
index 265b0d552..26aeccf0a 100644
--- a/config/initializers/db_preferences.rb
+++ b/config/initializers/db_preferences.rb
@@ -10,7 +10,7 @@ when 'mysql2'
# Because of missing ticket updates in high load environments
# we changed the transaction isolation level equally to postgres
# to READ COMMITTED which fixed the problem entirely #3877
- ActiveRecord::ConnectionAdapters::Mysql2Adapter.set_callback :checkout, :before do |conn|
+ ActiveRecord::ConnectionAdapters::Mysql2Adapter.set_callback :checkout, :after do |conn|
conn.execute('SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED')
end
when 'postgresql'
diff --git a/contrib/backup/zammad_db_user_helper.sh b/contrib/backup/zammad_db_user_helper.sh
old mode 100644
new mode 100755
diff --git a/lib/secure_mailing.rb b/lib/secure_mailing.rb
index d28236784..96ada9c01 100644
--- a/lib/secure_mailing.rb
+++ b/lib/secure_mailing.rb
@@ -10,9 +10,11 @@ class SecureMailing
end
def self.retry(article)
+ result = []
active_backends.each do |backend|
- "#{backend}::Retry".constantize.process(article)
+ result << "#{backend}::Retry".constantize.process(article)
end
+ result
end
def self.outgoing(mail, security)
diff --git a/public/assets/tests/core.js b/public/assets/tests/core.js
index 765594dfe..8f2e35819 100644
--- a/public/assets/tests/core.js
+++ b/public/assets/tests/core.js
@@ -536,7 +536,9 @@ test('difference', function() {
object2 = {
key1: 123,
}
- result = {}
+ result = {
+ key2: undefined
+ }
item = difference(object1, object2)
deepEqual(item, result)
@@ -547,38 +549,106 @@ test('difference', function() {
key1: 123,
key2: 124
}
+ result = {
+ key2: 124
+ }
+ item = difference(object1, object2)
+ deepEqual(item, result)
+
+ object1 = {
+ customer_id: 1,
+ organization_id: 2,
+ }
+ object2 = {
+ customer_id: 1,
+ organization_id: null,
+ }
+ result = {
+ organization_id: null,
+ }
+ item = difference(object1, object2)
+ deepEqual(item, result)
+
+ object1 = {
+ customer_id: 1,
+ organization_id: null,
+ }
+ object2 = {
+ customer_id: 1,
+ organization_id: 2,
+ }
+ result = {
+ organization_id: 2,
+ }
+ item = difference(object1, object2)
+ deepEqual(item, result)
+
+ object1 = {
+ customer_id: 1,
+ preferences: { resolved: true },
+ }
+ object2 = {
+ customer_id: 1,
+ preferences: {},
+ }
+ result = {
+ preferences: { resolved: undefined }
+ }
+ item = difference(object1, object2)
+ deepEqual(item, result)
+
+ object1 = {
+ customer_id: 1,
+ }
+ object2 = {
+ customer_id: 1,
+ preferences: { resolved: true },
+ }
+ result = {
+ preferences: { resolved: true }
+ }
+ item = difference(object1, object2)
+ deepEqual(item, result)
+
+ object1 = {
+ customer_id: 1,
+ preferences: {},
+ }
+ object2 = {
+ customer_id: 1,
+ preferences: { resolved: true },
+ }
+ result = {
+ preferences: { resolved: true }
+ }
+ item = difference(object1, object2)
+ deepEqual(item, result)
+
+ object1 = {
+ customer_id: 1,
+ preferences: { resolved: false },
+ }
+ object2 = {
+ customer_id: 1,
+ preferences: { resolved: true },
+ }
+ result = {
+ preferences: { resolved: true }
+ }
+ item = difference(object1, object2)
+ deepEqual(item, result)
+
+ object1 = {
+ customer_id: 1,
+ preferences: { resolved: true },
+ }
+ object2 = {
+ customer_id: 1,
+ preferences: { resolved: true },
+ }
result = {}
item = difference(object1, object2)
deepEqual(item, result)
-
- object1 = {
- customer_id: 1,
- organization_id: 2,
- }
- object2 = {
- customer_id: 1,
- organization_id: null,
- }
- result = {
- organization_id: null,
- }
- item = difference(object1, object2)
- deepEqual(item, result)
-
- object1 = {
- customer_id: 1,
- organization_id: null,
- }
- object2 = {
- customer_id: 1,
- organization_id: 2,
- }
- result = {
- organization_id: 2,
- }
- item = difference(object1, object2)
- deepEqual(item, result)
-
});
test('auth - not existing user', function(assert) {
diff --git a/public/assets/tests/qunit/controller_observer.js b/public/assets/tests/qunit/controller_observer.js
new file mode 100644
index 000000000..1f9b4878a
--- /dev/null
+++ b/public/assets/tests/qunit/controller_observer.js
@@ -0,0 +1,202 @@
+QUnit.test( "controller observer tests - observe", assert => {
+
+ App.Ticket.refresh([{
+ id: 1,
+ title: 'ticket',
+ state_id: 1,
+ customer_id: 33,
+ organization_id: 1,
+ owner_id: 1,
+ preferences: { a: 1, b: 2 },
+ }])
+
+ var observer1 = new App.ControllerObserver({
+ object_id: 1,
+ template: 'version',
+ observe: {
+ title: true,
+ preferences: true,
+ },
+ })
+
+ var ticket = App.Ticket.find(1)
+
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track title changes
+ ticket.title = 'title 2'
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.title = undefined
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.title = 'title 3'
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track no owner_id changes
+ ticket.owner_id = 2
+
+ assert.equal(false, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track preferences changes
+ ticket.preferences['a'] = 3
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.preferences['c'] = 3
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track no new_attribute1 changes
+ ticket.new_attribute1 = 'na 3'
+
+ assert.equal(false, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.new_attribute2 = function() { console.log(1) }
+
+ assert.equal(false, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.new_attribute2 = function() { console.log(2) }
+
+ assert.equal(false, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track title changes
+ ticket.title = function() { console.log(1) }
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.title = function() { console.log(2) }
+
+ assert.equal(false, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.title = 1
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+});
+
+QUnit.test( "controller observer tests - observeNot", assert => {
+
+ App.Ticket.refresh([{
+ id: 2,
+ title: 'ticket',
+ state_id: 1,
+ customer_id: 33,
+ organization_id: 1,
+ owner_id: 1,
+ preferences: { a: 1, b: 2 },
+ }])
+
+ var observer1 = new App.ControllerObserver({
+ object_id: 2,
+ template: 'version',
+ observeNot: {
+ title: true,
+ preferences: true,
+ },
+ })
+
+ var ticket = App.Ticket.find(2)
+
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track no title changes
+ ticket.title = 'title 2'
+
+ assert.equal(false, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track owner_id changes
+ ticket.owner_id = 2
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.owner_id = undefined
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.owner_id = 3
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track no preferences changes
+ ticket.preferences['a'] = 3
+
+ assert.equal(false, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.preferences['c'] = 3
+ assert.equal(false, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track preferences2 changes
+ ticket.preferences2 = {}
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.preferences2['a'] = 3
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.preferences2['a'] = 2
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.preferences2['c'] = 3
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track new_attribute1 changes
+ ticket.new_attribute1 = 'na 3'
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track no new_attribute2 changes (because of function content)
+ ticket.new_attribute2 = function() { console.log(1) }
+
+ assert.equal(false, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.new_attribute2 = function() { console.log(2) }
+
+ assert.equal(false, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ // track owner_id changes (pnly if content has no function content)
+ ticket.owner_id = function() { console.log(1) }
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.owner_id = function() { console.log(2) }
+
+ assert.equal(false, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+ ticket.owner_id = 1
+
+ assert.equal(true, observer1.hasChanged(ticket))
+ assert.equal(false, observer1.hasChanged(ticket))
+
+});
diff --git a/spec/system/ticket/zoom_spec.rb b/spec/system/ticket/zoom_spec.rb
index f7e988c95..3fd9ec3cf 100644
--- a/spec/system/ticket/zoom_spec.rb
+++ b/spec/system/ticket/zoom_spec.rb
@@ -588,8 +588,7 @@ RSpec.describe 'Ticket zoom', type: :system do
end
context 'certificate not present at time of arrival' do
-
- it 'retry' do
+ let(:mail) do
smime1 = create(:smime_certificate, :with_private, fixture: system_email_address)
smime2 = create(:smime_certificate, :with_private, fixture: sender_email_address)
@@ -612,6 +611,10 @@ RSpec.describe 'Ticket zoom', type: :system do
smime1.destroy
smime2.destroy
+ mail
+ end
+
+ it 'does retry successfully' do
parsed_mail = Channel::EmailParser.new.parse(mail.to_s)
ticket, article, _user, _mail = Channel::EmailParser.new.process({ group_id: group.id }, parsed_mail['raw'])
expect(Ticket::Article.find(article.id).body).to eq('no visible content')
@@ -624,6 +627,17 @@ RSpec.describe 'Ticket zoom', type: :system do
click '.js-securityRetryProcess'
expect(page).to have_css('.article-content', text: 'somebody with some text')
end
+
+ it 'does fail on retry (S/MIME function buttons no longer working in tickets #3957)' do
+ parsed_mail = Channel::EmailParser.new.parse(mail.to_s)
+ ticket, article, _user, _mail = Channel::EmailParser.new.process({ group_id: group.id }, parsed_mail['raw'])
+ expect(Ticket::Article.find(article.id).body).to eq('no visible content')
+
+ visit "#ticket/zoom/#{ticket.id}"
+ expect(page).to have_no_css('.article-content', text: 'somebody with some text')
+ click '.js-securityRetryProcess'
+ expect(page).to have_css('#notify', text: 'Decryption failed! Unable to find private key to decrypt')
+ end
end
end
diff --git a/test/integration/clearbit_test.rb b/test/integration/clearbit_test.rb
index fb4381aff..aa7a37879 100644
--- a/test/integration/clearbit_test.rb
+++ b/test/integration/clearbit_test.rb
@@ -282,7 +282,7 @@ class ClearbitTest < ActiveSupport::TestCase
organization6 = Organization.find_by('name LIKE ?', 'APIHub Inc%')
assert(ExternalSync.find_by(source: 'clearbit', object: 'Organization', o_id: organization6.id))
assert_equal(false, organization6.shared)
- assert_equal('The marketing data engine to deeply understand your customers, identify future prospects, & personalize every single marketing & sales interaction.', organization6.note)
+ assert_equal('The Clearbit Data Activation Platform helps B2B teams understand customers, identify prospects, & personalize interactions with real-time intelligence.', organization6.note)
end