Compare commits
297 Commits
develop
...
stable-2.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
238784d13e | ||
|
|
46c61e84b6 | ||
|
|
fdc0abbe7f | ||
|
|
e0daa409ab | ||
|
|
89d4fe19f8 | ||
|
|
5aa751efcf | ||
|
|
3ced341ec4 | ||
|
|
f7fb992fa1 | ||
|
|
d8f5663404 | ||
|
|
3c1eb43b8d | ||
|
|
9fe5c82d7e | ||
|
|
76c24c0d47 | ||
|
|
69357d1d4f | ||
|
|
8684b1e4b5 | ||
|
|
73199b9b6b | ||
|
|
f2e54de705 | ||
|
|
58c2874f4a | ||
|
|
9566acacd3 | ||
|
|
5b344e1bb8 | ||
|
|
1dac03be16 | ||
|
|
5589b9cb53 | ||
|
|
42432ba5f3 | ||
|
|
0554a91442 | ||
|
|
32f17a3fb8 | ||
|
|
f02a3f4cfb | ||
|
|
aa7a28c4dc | ||
|
|
cb963ada6b | ||
|
|
ea50d0c06f | ||
|
|
db5d4de8ad | ||
|
|
efd4c38f99 | ||
|
|
d13ff15956 | ||
|
|
d4c5d81373 | ||
|
|
66c0975877 | ||
|
|
76efb008a8 | ||
|
|
abc0541244 | ||
|
|
c9f8022f83 | ||
|
|
dfc757968e | ||
|
|
52bc45c0f8 | ||
|
|
cbc8ba5467 | ||
|
|
5f071e7d7f | ||
|
|
1dcd6a243c | ||
|
|
679deb1cf3 | ||
|
|
6f6ac44978 | ||
|
|
0bb341cb7e | ||
|
|
6c122e046b | ||
|
|
57c2dad0a3 | ||
|
|
faefd529b4 | ||
|
|
1481a12035 | ||
|
|
2bf0635e0d | ||
|
|
2211274bc5 | ||
|
|
c229c42838 | ||
|
|
a3c71f6558 | ||
|
|
db8b85f767 | ||
|
|
f1664c3841 | ||
|
|
151c298056 | ||
|
|
38f51ce6b2 | ||
|
|
434f3e963e | ||
|
|
b853dd1597 | ||
|
|
3b5b6f612f | ||
|
|
962043c520 | ||
|
|
8394be87ed | ||
|
|
5b547ceb3c | ||
|
|
789ee08485 | ||
|
|
490937859a | ||
|
|
dfc306a2ac | ||
|
|
dea06015a1 | ||
|
|
2711e3392d | ||
|
|
f5e1fe0c2f | ||
|
|
dbbb4ac7a1 | ||
|
|
8ec2ffdde1 | ||
|
|
b76664e7ae | ||
|
|
704c537749 | ||
|
|
633c99bb72 | ||
|
|
44051d8023 | ||
|
|
50dc143c1b | ||
|
|
6d44275869 | ||
|
|
b1b3bf6d3c | ||
|
|
77081ecd4d | ||
|
|
b823b960d8 | ||
|
|
e08f634125 | ||
|
|
ab5e8d9338 | ||
|
|
9a29ea8f14 | ||
|
|
cf87e00b21 | ||
|
|
6233b0a9ec | ||
|
|
04b1bc638c | ||
|
|
a78938f7c2 | ||
|
|
1d23308454 | ||
|
|
6bc9c00ab8 | ||
|
|
bc131742be | ||
|
|
5a12aa0167 | ||
|
|
b3ab9d0055 | ||
|
|
1bde8f91bc | ||
|
|
47ef1b7e5d | ||
|
|
88c7816f5c | ||
|
|
82339c6c18 | ||
|
|
04a609c3a8 | ||
|
|
60430139aa | ||
|
|
7d1c655ee3 | ||
|
|
e34c1c9b79 | ||
|
|
3c430b35ef | ||
|
|
7ad3c70311 | ||
|
|
c270bc1e67 | ||
|
|
3d19bfdcf7 | ||
|
|
dc4a55cc5c | ||
|
|
6e8886277d | ||
|
|
74e96e92b2 | ||
|
|
287b1f0d01 | ||
|
|
feee46e29b | ||
|
|
991efe36e4 | ||
|
|
a2aacb20fa | ||
|
|
592e978062 | ||
|
|
a4769c8bc7 | ||
|
|
d1378d53f1 | ||
|
|
f0b91d3269 | ||
|
|
48c77dd688 | ||
|
|
d86d904395 | ||
|
|
5efc455f0c | ||
|
|
be3bbeba20 | ||
|
|
31ab1b614c | ||
|
|
4bc5fa4693 | ||
|
|
418a64f401 | ||
|
|
abe46270a6 | ||
|
|
1249a77150 | ||
|
|
cfa6b9ed16 | ||
|
|
aa2303f999 | ||
|
|
d5616684f8 | ||
|
|
0f75ba57bd | ||
|
|
c83675bbba | ||
|
|
17d16d405c | ||
|
|
76795ca302 | ||
|
|
5d145bd09f | ||
|
|
82471552a8 | ||
|
|
dc60574129 | ||
|
|
d33a96dee2 | ||
|
|
0098d4ab82 | ||
|
|
bb03b5eab8 | ||
|
|
17eb0f84ec | ||
|
|
56d0523c1f | ||
|
|
9fa18758bc | ||
|
|
d2f2c55b06 | ||
|
|
f4a409bd6e | ||
|
|
971b724d4c | ||
|
|
3263c6f2ba | ||
|
|
359b026535 | ||
|
|
c63518fd3e | ||
|
|
24ba3cff44 | ||
|
|
f7066e1995 | ||
|
|
6844499309 | ||
|
|
afa3e47eab | ||
|
|
5f3e9298f1 | ||
|
|
e4dd303357 | ||
|
|
2fa06eee3d | ||
|
|
dc0ac03334 | ||
|
|
c5a1d69ec5 | ||
|
|
9891981f92 | ||
|
|
2c721f71e7 | ||
|
|
0b4a4be0b7 | ||
|
|
b13bb2fcaf | ||
|
|
d9ba369fcf | ||
|
|
3adece0db5 | ||
|
|
7101ffc277 | ||
|
|
19a7a439b8 | ||
|
|
e728320241 | ||
|
|
1bc17afc53 | ||
|
|
ee5c58f53a | ||
|
|
9bdf6d7b81 | ||
|
|
5754fdccdd | ||
|
|
4901050d57 | ||
|
|
7980c8cb93 | ||
|
|
7e7088388d | ||
|
|
2f6e52d63d | ||
|
|
bde8babb43 | ||
|
|
d6d68fb363 | ||
|
|
814ffed0f0 | ||
|
|
b013fb8cbc | ||
|
|
fbd8e63592 | ||
|
|
e8ad3965d7 | ||
|
|
e00981ee23 | ||
|
|
4e74c6beda | ||
|
|
2d09e556d7 | ||
|
|
8cd39398d6 | ||
|
|
94c616ffe3 | ||
|
|
57649bb888 | ||
|
|
7e9442ec4a | ||
|
|
521e6265fd | ||
|
|
a42a9689fc | ||
|
|
d9ffb8001d | ||
|
|
ec86d26ae6 | ||
|
|
e00efc821a | ||
|
|
f04be8ca93 | ||
|
|
c7ff6a323a | ||
|
|
34833416bc | ||
|
|
d7a6e28d81 | ||
|
|
c13531d720 | ||
|
|
4a40cced7d | ||
|
|
450de10cc7 | ||
|
|
5e587a455c | ||
|
|
04aef9b258 | ||
|
|
9b72557d13 | ||
|
|
a5e0bc30c1 | ||
|
|
458c166e9f | ||
|
|
3373e5d141 | ||
|
|
8f6b8de617 | ||
|
|
22b21a82e7 | ||
|
|
b4151b299f | ||
|
|
e969fca8c4 | ||
|
|
e59993a5d6 | ||
|
|
3adc9d4cf1 | ||
|
|
c1153250cb | ||
|
|
7718dc28d3 | ||
|
|
1894580ae6 | ||
|
|
11df714bbf | ||
|
|
72adee37a8 | ||
|
|
0e8f460d73 | ||
|
|
4e62d5d0d2 | ||
|
|
004e5ba457 | ||
|
|
f1a8a8da6f | ||
|
|
bfb44d1189 | ||
|
|
d64afd8d97 | ||
|
|
97cfdb9c4c | ||
|
|
bb336f63f1 | ||
|
|
80da08f447 | ||
|
|
a6db2b7c90 | ||
|
|
e1c3f83324 | ||
|
|
8545a44ad1 | ||
|
|
cfbe7510a2 | ||
|
|
1479c32edb | ||
|
|
a9d428bf5a | ||
|
|
3a62eb11da | ||
|
|
2df5f81029 | ||
|
|
b88c23bc92 | ||
|
|
4144fbaf5b | ||
|
|
86ddc93f52 | ||
|
|
8a1b583535 | ||
|
|
7623628b86 | ||
|
|
f753bc203f | ||
|
|
ff9ba10705 | ||
|
|
fdc25bdc26 | ||
|
|
d154a587ad | ||
|
|
a9cc4f037b | ||
|
|
50d6679189 | ||
|
|
b82cf4e1d6 | ||
|
|
fa6eaa6710 | ||
|
|
2ca17ac1bd | ||
|
|
862ecd7d36 | ||
|
|
e38b72593b | ||
|
|
81883cae8f | ||
|
|
63770c9cbf | ||
|
|
aaf5da55a0 | ||
|
|
8455d9ae17 | ||
|
|
839a8e8eb4 | ||
|
|
7aa3f6eaee | ||
|
|
219abc69a3 | ||
|
|
595822c928 | ||
|
|
32112937b1 | ||
|
|
a0889c5b99 | ||
|
|
4bc281bfb0 | ||
|
|
e12ec607d7 | ||
|
|
545f393293 | ||
|
|
4efa152e93 | ||
|
|
0ebda4f32a | ||
|
|
b94f54799f | ||
|
|
99f0b4e2e2 | ||
|
|
53cb906733 | ||
|
|
2c31fe8a84 | ||
|
|
6c5e673a2c | ||
|
|
574b891a33 | ||
|
|
9ef1d3f58b | ||
|
|
8b3f432746 | ||
|
|
14a9df261e | ||
|
|
5620a2847b | ||
|
|
13aaae3835 | ||
|
|
2d4fcd3a4f | ||
|
|
f4f70b0bc2 | ||
|
|
1d279bb88f | ||
|
|
fe4757cbf9 | ||
|
|
1d476f163e | ||
|
|
513701b6d2 | ||
|
|
1a1b661714 | ||
|
|
6081a98279 | ||
|
|
157991c33d | ||
|
|
ef67be9170 | ||
|
|
39f3819303 | ||
|
|
7a676bd563 | ||
|
|
80c54daa03 | ||
|
|
99c88cde62 | ||
|
|
17d113ca20 | ||
|
|
2fbf4324a7 | ||
|
|
b46c390d30 | ||
|
|
3c3651bc52 | ||
|
|
abeeb5e66d | ||
|
|
09d61ce4c8 | ||
|
|
cc1c4495b2 | ||
|
|
7b1ec4d17f | ||
|
|
99b3201ccf | ||
|
|
d4205d9ba6 | ||
|
|
8d57633390 |
@@ -259,6 +259,7 @@ test:integration:clearbit:
|
||||
- rake db:migrate
|
||||
- ruby -I test test/integration/clearbit_test.rb
|
||||
- rake db:drop
|
||||
allow_failure: true
|
||||
|
||||
test:integration:sipgate:
|
||||
stage: test
|
||||
|
||||
49
CHANGELOG.md
49
CHANGELOG.md
@@ -1,16 +1,51 @@
|
||||
# Change Log
|
||||
|
||||
## [2.3.0](https://github.com/zammad/zammad/tree/2.3.0) (2018-xx-xx)
|
||||
## [2.3.1](https://github.com/zammad/zammad/tree/2.3.1) (2018-03-29)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/2.3.0...2.3.1)
|
||||
|
||||
**Fixed bugs:**
|
||||
- Direct access to organization tickets possible even though shared is deactivated [\#1857](https://github.com/zammad/zammad/issues/1857) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Can't create email-account with local MTA as outgoing server [\#1852](https://github.com/zammad/zammad/issues/1852) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Issues in the rights-management [\#1810](https://github.com/zammad/zammad/issues/1810) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Reporting: profile condition is ignored [\#1809](https://github.com/zammad/zammad/issues/1809) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Taskbar item race condition causes JS exception [\#1841](https://github.com/zammad/zammad/issues/1841) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- The column widths of a table are shifted after manual change and use of pagination. [\#1829](https://github.com/zammad/zammad/issues/1829) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- JS error on creating new customer [\#1813](https://github.com/zammad/zammad/issues/1813) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Customer response via note does not trigger escalation [\#1322](https://github.com/zammad/zammad/issues/1322) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- LDAP authentication doen't work in 2.3.x [\#1795](https://github.com/zammad/zammad/issues/1795) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- XSS issue in ticket overview [\#1869](https://github.com/zammad/zammad/issues/1869) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
|
||||
## [2.3.0](https://github.com/zammad/zammad/tree/2.3.0) (2018-01-30)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/2.2.0...2.3.0)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
|
||||
|
||||
- Convert Chat into Ticket [\#422](https://github.com/zammad/zammad/issues/422)
|
||||
- Added support of blocking IPs and/or countries for chat.
|
||||
- Added support to search and reopen already finised chat sessions.
|
||||
- LDAP User uid attribute is not reliable [\#1709](https://github.com/zammad/zammad/issues/1709) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
- Add article.body support for triggers [\#1745](https://github.com/zammad/zammad/issues/1745) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
|
||||
|
||||
- Do not allow roles as default signup with admin, admin.\* and ticket.agent permissions [\#1758](https://github.com/zammad/zammad/issues/1758) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
- Attachments with content-id header but not shown as inline part are note taken for forward action [\#1778](https://github.com/zammad/zammad/issues/1778) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Need data\_option\[:null\] - Ticket Object Manager [\#1742](https://github.com/zammad/zammad/issues/1742) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- LDAP login not possible since change to objectguid [\#1764](https://github.com/zammad/zammad/issues/1764) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Generated excel report fails to create for special strings in ticket titles \(also: CSV formula injection possible\) [\#1756](https://github.com/zammad/zammad/issues/1756) [[bug](https://github.com/zammad/zammad/labels/bug)] [[reporting](https://github.com/zammad/zammad/labels/reporting)]
|
||||
- Loss of LDAP group assignment is not reflected in Zammad role assignment [\#1751](https://github.com/zammad/zammad/issues/1751) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Ticket search fails for limit exceeding 100 with internal server error [\#1753](https://github.com/zammad/zammad/issues/1753) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Trigger ignoring tag condition [\#1683](https://github.com/zammad/zammad/issues/1683) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Unable to send auto reply if from contains 2 or more senders with invalid email address [\#1749](https://github.com/zammad/zammad/issues/1749) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Report for Created tickets should not have "merged" tickets [\#1741](https://github.com/zammad/zammad/issues/1741) [[bug](https://github.com/zammad/zammad/labels/bug)] [[reporting](https://github.com/zammad/zammad/labels/reporting)]
|
||||
- Exchange integration process stuck at 1000 users [\#1740](https://github.com/zammad/zammad/issues/1740) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Telegram bot error when exit and delete telegram group [\#1732](https://github.com/zammad/zammad/issues/1732) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Exchange integration tries to import user twice and fails [\#1663](https://github.com/zammad/zammad/issues/1663) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- LDAP - missing support for groupOfUniqueNames / uniquemember [\#1664](https://github.com/zammad/zammad/issues/1664) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Removed LDAP attributes aren't reflected on the user [\#1665](https://github.com/zammad/zammad/issues/1665) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Wrong ticket number count in preview [\#1723](https://github.com/zammad/zammad/issues/1723) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Zammad Api for idoit.object\_ids broken [\#1711](https://github.com/zammad/zammad/issues/1711) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Unable to login with Office365 [\#1710](https://github.com/zammad/zammad/issues/1710) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- No user preference for out-of-office available [\#1699](https://github.com/zammad/zammad/issues/1699) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- SipgateController - undefined method `each' for nil:NilClass \(NoMethodError\) [\#1698](https://github.com/zammad/zammad/issues/1698) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Agent ticket overview broken [\#789](https://github.com/zammad/zammad/issues/789) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
|
||||
\* *This Change Log was automatically generated by [github_changelog_generator](https://github.com/skywinder/Github-Changelog-Generator)*
|
||||
@@ -213,7 +213,7 @@ GEM
|
||||
logging (2.2.2)
|
||||
little-plugger (~> 1.1)
|
||||
multi_json (~> 1.10)
|
||||
loofah (2.1.1)
|
||||
loofah (2.2.2)
|
||||
crass (~> 1.0.2)
|
||||
nokogiri (>= 1.5.9)
|
||||
lumberjack (1.0.12)
|
||||
@@ -235,7 +235,7 @@ GEM
|
||||
net-ldap (0.16.1)
|
||||
netrc (0.11.0)
|
||||
nio4r (2.1.0)
|
||||
nokogiri (1.8.1)
|
||||
nokogiri (1.8.2)
|
||||
mini_portile2 (~> 2.3.0)
|
||||
nori (2.6.0)
|
||||
notiffany (0.1.1)
|
||||
@@ -318,8 +318,8 @@ GEM
|
||||
rails-dom-testing (2.0.3)
|
||||
activesupport (>= 4.2.0)
|
||||
nokogiri (>= 1.6)
|
||||
rails-html-sanitizer (1.0.3)
|
||||
loofah (~> 2.0)
|
||||
rails-html-sanitizer (1.0.4)
|
||||
loofah (~> 2.2, >= 2.2.2)
|
||||
rails-observers (0.1.5)
|
||||
activemodel (>= 4.0)
|
||||
railties (5.1.4)
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
Zammad is a web based open source helpdesk/customer support system with many
|
||||
features to manage customer communication via several channels like telephone,
|
||||
facebook, twitter, chat and e-mails. It is distributed under the GNU AFFERO
|
||||
General Public License (AGPL) and tested on Linux, Solaris, AIX, FreeBSD,
|
||||
OpenBSD and Mac OS 10.x. Do you receive many e-mails and want to answer them
|
||||
with a team of agents?
|
||||
General Public License (AGPL).
|
||||
|
||||
Do you receive many e-mails and want to answer them with a team of agents?
|
||||
|
||||
You're going to love Zammad!
|
||||
|
||||
|
||||
@@ -195,8 +195,8 @@ class App.ControllerTable extends App.Controller
|
||||
el.filter('.js-pager').html('')
|
||||
return
|
||||
pager = App.view('generic/table_pager')(
|
||||
page: @shownPage
|
||||
pages: pages
|
||||
page: @shownPage
|
||||
pages: pages
|
||||
)
|
||||
if find
|
||||
el.find('.js-pager').html(pager)
|
||||
@@ -851,13 +851,21 @@ class App.ControllerTable extends App.Controller
|
||||
# update store and runtime @headerWidth
|
||||
@preferencesStore('headerWidth', leftColumnKey, leftWidth)
|
||||
@headerWidth[leftColumnKey] = leftWidth
|
||||
_.find(@headers, (column) -> column.name is leftColumnKey).displayWidth = leftWidth
|
||||
|
||||
# set header at runtime
|
||||
for header in @headers
|
||||
if header.name is leftColumnKey
|
||||
header.displayWidth = @resizeTargetLeft.outerWidth()
|
||||
|
||||
# update store and runtime @headerWidth
|
||||
if rightColumnKey
|
||||
@preferencesStore('headerWidth', rightColumnKey, rightWidth)
|
||||
@headerWidth[rightColumnKey] = rightWidth
|
||||
_.find(@headers, (column) -> column.name is rightColumnKey).displayWidth = rightWidth
|
||||
|
||||
# set header at runtime
|
||||
for header in @headers
|
||||
if header.name is rightColumnKey
|
||||
header.displayWidth = @resizeTargetRight.outerWidth()
|
||||
|
||||
sortByColumn: (event) =>
|
||||
column = $(event.currentTarget).closest('[data-column-key]').attr('data-column-key')
|
||||
|
||||
@@ -722,7 +722,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||
# get params
|
||||
params = @formParam(e.target)
|
||||
|
||||
if params.options.password is @passwordPlaceholder
|
||||
if params.options && params.options.password is @passwordPlaceholder
|
||||
params.options.password = @inboundPassword
|
||||
|
||||
# let backend know about the channel
|
||||
@@ -784,7 +784,7 @@ class App.ChannelEmailAccountWizard extends App.WizardModal
|
||||
params = @formParam(e.target)
|
||||
params['email'] = @account['meta']['email']
|
||||
|
||||
if params.options.password is @passwordPlaceholder
|
||||
if params.options && params.options.password is @passwordPlaceholder
|
||||
params.options.password = @outboundPassword
|
||||
|
||||
if !params['email'] && @channel
|
||||
|
||||
@@ -358,7 +358,6 @@ class ConnectionWizard extends App.WizardModal
|
||||
# remember payload
|
||||
user_attributes = {}
|
||||
for key, value of App.User.attributesGet()
|
||||
continue if key == 'login'
|
||||
if (value.tag is 'input' || value.tag is 'richtext' || value.tag is 'textarea') && value.type isnt 'password'
|
||||
user_attributes[key] = value.display || key
|
||||
roles = {}
|
||||
@@ -394,6 +393,7 @@ class ConnectionWizard extends App.WizardModal
|
||||
givenname: 'firstname'
|
||||
sn: 'lastname'
|
||||
mail: 'email'
|
||||
samaccountname: 'login'
|
||||
telephonenumber: 'phone'
|
||||
|
||||
@userMappingForm.find('tbody tr.js-entry').remove()
|
||||
@@ -417,14 +417,23 @@ class ConnectionWizard extends App.WizardModal
|
||||
for key in ['source', 'dest']
|
||||
if !_.isArray(user_attributes[key])
|
||||
user_attributes[key] = [user_attributes[key]]
|
||||
user_attributes_local =
|
||||
'samaccountname': 'login'
|
||||
user_attributes_local = {}
|
||||
length = user_attributes.source.length-1
|
||||
for count in [0..length]
|
||||
if user_attributes.source[count] && user_attributes.dest[count]
|
||||
user_attributes_local[user_attributes.source[count]] = user_attributes.dest[count]
|
||||
|
||||
requiredAttribute = Object.keys(user_attributes_local).some( (local_attribute) ->
|
||||
return user_attributes_local[local_attribute] == 'login'
|
||||
)
|
||||
|
||||
@wizardConfig.user_attributes = user_attributes_local
|
||||
|
||||
if !requiredAttribute
|
||||
@showSlide('js-mapping')
|
||||
@showAlert('js-mapping', App.i18n.translatePlain("Attribute '%s' is required in the mapping", 'login'))
|
||||
return
|
||||
|
||||
# group role map
|
||||
group_role_map = @formParam(@groupRoleForm)
|
||||
for key in ['source', 'dest']
|
||||
@@ -448,17 +457,8 @@ class ConnectionWizard extends App.WizardModal
|
||||
|
||||
buildRowsUserMap: (user_attribute_map) =>
|
||||
|
||||
# show static login row
|
||||
userUidDisplayValue = @wizardConfig.wizardData.backend_user_attributes['samaccountname']
|
||||
|
||||
el = [
|
||||
$(App.view('integration/ldap_user_attribute_row_read_only')(
|
||||
key: userUidDisplayValue,
|
||||
value: 'Login'
|
||||
))
|
||||
]
|
||||
el = []
|
||||
for source, dest of user_attribute_map
|
||||
continue if source == 'samaccountname'
|
||||
continue if !(source of @wizardConfig.wizardData.backend_user_attributes)
|
||||
el.push @buildRowUserAttribute(source, dest)
|
||||
el
|
||||
|
||||
@@ -127,7 +127,7 @@ class Create extends App.ControllerModal
|
||||
App.view('profile/token_access_created')(
|
||||
name: ui.newToken.name
|
||||
)
|
||||
post: ->
|
||||
onShown: ->
|
||||
@$('.js-select').on('click', ui.selectAll)
|
||||
onCancel: ->
|
||||
@close()
|
||||
|
||||
@@ -775,10 +775,19 @@ class ChatWindow extends App.Controller
|
||||
# cleanup params
|
||||
fqdn = App.Config.get('fqdn')
|
||||
http_type = App.Config.get('http_type')
|
||||
url = ''
|
||||
session = @session
|
||||
|
||||
# in case we do not have a model, create one
|
||||
if session && !session.uiUrl
|
||||
session = new App.ChatSession(session)
|
||||
if session && session.uiUrl
|
||||
url = session.uiUrl()
|
||||
|
||||
clean_params =
|
||||
id: id
|
||||
prefilledParams:
|
||||
body: "#{http_type}://#{fqdn}#{@session.uiUrl()}"
|
||||
body: "#{http_type}://#{fqdn}/#{url}"
|
||||
title: 'Chat'
|
||||
|
||||
App.TaskManager.execute(
|
||||
|
||||
@@ -558,6 +558,10 @@ class App.TicketZoom extends App.Controller
|
||||
# update changes in ui
|
||||
currentStore = @currentStore()
|
||||
modelDiff = @formDiff(currentParams, currentStore)
|
||||
|
||||
# set followup state if needed
|
||||
@setDefaultFollowUpState(modelDiff, currentStore)
|
||||
|
||||
@markFormDiff(modelDiff)
|
||||
@taskUpdateAll(modelDiff)
|
||||
|
||||
@@ -582,6 +586,43 @@ class App.TicketZoom extends App.Controller
|
||||
|
||||
currentStore
|
||||
|
||||
setDefaultFollowUpState: (modelDiff, currentStore) ->
|
||||
|
||||
# if the default state is set
|
||||
# and the body get changed to empty
|
||||
# then we want to reset the state
|
||||
if @isDefaultFollowUpStateSet && !modelDiff.article.body
|
||||
@$('.sidebar select[name=state_id]').val(currentStore.ticket.state_id).trigger('change')
|
||||
@isDefaultFollowUpStateSet = false
|
||||
return
|
||||
|
||||
# set default if body is filled
|
||||
return if !modelDiff.article.body
|
||||
|
||||
# and state got not changed
|
||||
return if modelDiff.ticket.state_id
|
||||
|
||||
# and we are in the customer interface
|
||||
return if !@permissionCheck('ticket.customer')
|
||||
|
||||
# and the default is was not set before
|
||||
return if @isDefaultFollowUpStateSet
|
||||
|
||||
# prevent multiple changes for the default follow up state
|
||||
@isDefaultFollowUpStateSet = true
|
||||
|
||||
# get state
|
||||
state = App.TicketState.findByAttribute('default_follow_up', true)
|
||||
|
||||
# change ui and trigger change
|
||||
if state
|
||||
@$('.sidebar[data-tab=ticket] select[name=state_id]').val(state.id).trigger('change')
|
||||
|
||||
true
|
||||
|
||||
resetDefaultFollowUpState: ->
|
||||
@isDefaultFollowUpStateSet = false
|
||||
|
||||
formCurrent: =>
|
||||
currentParams =
|
||||
ticket: @formParam(@el.find('.edit'))
|
||||
@@ -596,6 +637,10 @@ class App.TicketZoom extends App.Controller
|
||||
|
||||
# remove not needed attributes
|
||||
delete currentParams.article.form_id
|
||||
|
||||
if @permissionCheck('ticket.customer')
|
||||
currentParams.article.internal = ''
|
||||
|
||||
currentParams
|
||||
|
||||
formDiff: (currentParams, currentStore) ->
|
||||
@@ -867,6 +912,9 @@ class App.TicketZoom extends App.Controller
|
||||
# reset task
|
||||
@taskReset()
|
||||
|
||||
# reset default follow up state
|
||||
@resetDefaultFollowUpState()
|
||||
|
||||
# reset/delete uploaded attachments
|
||||
App.Ajax.request(
|
||||
type: 'DELETE'
|
||||
|
||||
@@ -37,8 +37,11 @@ class UserNew extends App.ControllerModal
|
||||
|
||||
# find role_id
|
||||
if !params.role_ids || _.isEmpty(params.role_ids)
|
||||
role = App.Role.findByAttribute('name', 'Customer')
|
||||
params.role_ids = role.id
|
||||
role_ids = []
|
||||
for role of App.Role.all()
|
||||
if role && role.active is true && role.default_at_signup is true
|
||||
role_ids.push role.id
|
||||
params.role_ids = role_ids
|
||||
@log 'notice', 'updateAttributes', params
|
||||
|
||||
user = new App.User
|
||||
|
||||
@@ -890,6 +890,29 @@ class App.Utils
|
||||
text = text.replace(/http(s|):\/\/[-A-Za-z0-9+&@#\/%?=~_\|!:,.;]+[-A-Za-z0-9+&@#\/%=~_|]/img, placeholder)
|
||||
text.length
|
||||
|
||||
@parseAddressListLocal: (line) ->
|
||||
recipients = emailAddresses.parseAddressList(line)
|
||||
result = []
|
||||
if !_.isEmpty(recipients)
|
||||
for recipient in recipients
|
||||
if recipient && recipient.address
|
||||
result.push recipient.address
|
||||
return result
|
||||
|
||||
# workaround for email-addresses.js issue with this kind of
|
||||
# mail headers "From: invalid sender, realname <sender@example.com>"
|
||||
# email-addresses.js is returning null because it can't parse the
|
||||
# whole header
|
||||
if _.isEmpty(recipients) && line.match('@')
|
||||
recipients = line.split(',')
|
||||
re = /(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))/
|
||||
for recipient in recipients
|
||||
if recipient && recipient.match('@')
|
||||
localResult = recipient.match(re)
|
||||
if localResult && localResult[0]
|
||||
result.push localResult[0]
|
||||
result
|
||||
|
||||
@getRecipientArticle: (ticket, article, article_created_by, type, email_addresses = [], all) ->
|
||||
|
||||
# empty form
|
||||
@@ -938,16 +961,18 @@ class App.Utils
|
||||
# check if article sender is local
|
||||
senderIsLocal = false
|
||||
if !_.isEmpty(article.from)
|
||||
senders = emailAddresses.parseAddressList(article.from)
|
||||
if senders && senders[0] && senders[0].address
|
||||
senderIsLocal = isLocalAddress(senders[0].address)
|
||||
senders = App.Utils.parseAddressListLocal(article.from)
|
||||
if senders
|
||||
for sender in senders
|
||||
if sender && sender.match('@')
|
||||
senderIsLocal = isLocalAddress(sender)
|
||||
|
||||
# check if article recipient is local
|
||||
recipientIsLocal = false
|
||||
if !_.isEmpty(article.to)
|
||||
recipients = emailAddresses.parseAddressList(article.to)
|
||||
if recipients && recipients[0] && recipients[0].address
|
||||
recipientIsLocal = isLocalAddress(recipients[0].address)
|
||||
recipients = App.Utils.parseAddressListLocal(article.to)
|
||||
if recipients && recipients[0]
|
||||
recipientIsLocal = isLocalAddress(recipients[0])
|
||||
|
||||
# sender is local
|
||||
if senderIsLocal
|
||||
@@ -971,14 +996,14 @@ class App.Utils
|
||||
|
||||
# filter for uniq recipients
|
||||
recipientAddresses = {}
|
||||
|
||||
addAddresses = (addressLine, line) ->
|
||||
lineNew = ''
|
||||
recipients = emailAddresses.parseAddressList(addressLine)
|
||||
recipients = App.Utils.parseAddressListLocal(addressLine)
|
||||
|
||||
if !_.isEmpty(recipients)
|
||||
for recipient in recipients
|
||||
if !_.isEmpty(recipient.address)
|
||||
localRecipientAddress = recipient.address.toString().toLowerCase()
|
||||
if !_.isEmpty(recipient)
|
||||
localRecipientAddress = recipient.toString().toLowerCase()
|
||||
|
||||
# check if address is not local
|
||||
if !isLocalAddress(localRecipientAddress)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// email-addresses.js - RFC 5322 email address parser
|
||||
// v 2.0.1
|
||||
// v 3.0.1
|
||||
//
|
||||
// http://tools.ietf.org/html/rfc5322
|
||||
//
|
||||
@@ -186,27 +186,7 @@ function parse5322(opts) {
|
||||
// "First Last" -> "First Last"
|
||||
// "First Last" -> "First Last"
|
||||
function collapseWhitespace(s) {
|
||||
function isWhitespace(c) {
|
||||
return c === ' ' ||
|
||||
c === '\t' ||
|
||||
c === '\r' ||
|
||||
c === '\n';
|
||||
}
|
||||
var i, str;
|
||||
str = "";
|
||||
for (i = 0; i < s.length; i += 1) {
|
||||
if (!isWhitespace(s[i]) || !isWhitespace(s[i + 1])) {
|
||||
str += s[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (isWhitespace(str[0])) {
|
||||
str = str.substring(1);
|
||||
}
|
||||
if (isWhitespace(str[str.length - 1])) {
|
||||
str = str.substring(0, str.length - 1);
|
||||
}
|
||||
return str;
|
||||
return s.replace(/([ \t]|\r\n)+/g, ' ').replace(/^\s*/, '').replace(/\s*$/, '');
|
||||
}
|
||||
|
||||
// UTF-8 pseudo-production (RFC 6532)
|
||||
@@ -597,10 +577,14 @@ function parse5322(opts) {
|
||||
return wrap('domain', function domainCheckTLD() {
|
||||
var result = or(obsDomain, dotAtom, domainLiteral)();
|
||||
if (opts.rejectTLD) {
|
||||
if (result.semantic.indexOf('.') < 0) {
|
||||
if (result && result.semantic && result.semantic.indexOf('.') < 0) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// strip all whitespace from domains
|
||||
if (result) {
|
||||
result.semantic = result.semantic.replace(/\s+/g, '');
|
||||
}
|
||||
return result;
|
||||
}());
|
||||
}
|
||||
@@ -612,6 +596,36 @@ function parse5322(opts) {
|
||||
)());
|
||||
}
|
||||
|
||||
// 3.6.2 Originator Fields
|
||||
// Below we only parse the field body, not the name of the field
|
||||
// like "From:", "Sender:", or "Reply-To:". Other libraries that
|
||||
// parse email headers can parse those and defer to these productions
|
||||
// for the "RFC 5322" part.
|
||||
|
||||
// RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields
|
||||
// from = "From:" (mailbox-list / address-list) CRLF
|
||||
function fromSpec() {
|
||||
return wrap('from', or(
|
||||
mailboxList,
|
||||
addressList
|
||||
)());
|
||||
}
|
||||
|
||||
// RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields
|
||||
// sender = "Sender:" (mailbox / address) CRLF
|
||||
function senderSpec() {
|
||||
return wrap('sender', or(
|
||||
mailbox,
|
||||
address
|
||||
)());
|
||||
}
|
||||
|
||||
// RFC 6854 2.1. Replacement of RFC 5322, Section 3.6.2. Originator Fields
|
||||
// reply-to = "Reply-To:" address-list CRLF
|
||||
function replyToSpec() {
|
||||
return wrap('reply-to', addressList());
|
||||
}
|
||||
|
||||
// 4.1. Miscellaneous Obsolete Tokens
|
||||
|
||||
// obs-NO-WS-CTL = %d1-8 / ; US-ASCII control
|
||||
@@ -766,92 +780,186 @@ function parse5322(opts) {
|
||||
// ast analysis
|
||||
|
||||
function findNode(name, root) {
|
||||
var i, queue, node;
|
||||
var i, stack, node;
|
||||
if (root === null || root === undefined) { return null; }
|
||||
queue = [root];
|
||||
while (queue.length > 0) {
|
||||
node = queue.shift();
|
||||
stack = [root];
|
||||
while (stack.length > 0) {
|
||||
node = stack.pop();
|
||||
if (node.name === name) {
|
||||
return node;
|
||||
}
|
||||
for (i = 0; i < node.children.length; i += 1) {
|
||||
queue.push(node.children[i]);
|
||||
for (i = node.children.length - 1; i >= 0; i -= 1) {
|
||||
stack.push(node.children[i]);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function findAllNodes(name, root) {
|
||||
var i, queue, node, result;
|
||||
var i, stack, node, result;
|
||||
if (root === null || root === undefined) { return null; }
|
||||
queue = [root];
|
||||
stack = [root];
|
||||
result = [];
|
||||
while (queue.length > 0) {
|
||||
node = queue.shift();
|
||||
while (stack.length > 0) {
|
||||
node = stack.pop();
|
||||
if (node.name === name) {
|
||||
result.push(node);
|
||||
}
|
||||
for (i = 0; i < node.children.length; i += 1) {
|
||||
queue.push(node.children[i]);
|
||||
for (i = node.children.length - 1; i >= 0; i -= 1) {
|
||||
stack.push(node.children[i]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function findAllNodesNoChildren(names, root) {
|
||||
var i, stack, node, result, namesLookup;
|
||||
if (root === null || root === undefined) { return null; }
|
||||
stack = [root];
|
||||
result = [];
|
||||
namesLookup = {};
|
||||
for (i = 0; i < names.length; i += 1) {
|
||||
namesLookup[names[i]] = true;
|
||||
}
|
||||
|
||||
while (stack.length > 0) {
|
||||
node = stack.pop();
|
||||
if (node.name in namesLookup) {
|
||||
result.push(node);
|
||||
// don't look at children (hence findAllNodesNoChildren)
|
||||
} else {
|
||||
for (i = node.children.length - 1; i >= 0; i -= 1) {
|
||||
stack.push(node.children[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function giveResult(ast) {
|
||||
function grabSemantic(n) {
|
||||
return n !== null ? n.semantic : null;
|
||||
}
|
||||
var i, ret, addresses, addr, name, aspec, local, domain;
|
||||
var addresses, groupsAndMailboxes, i, groupOrMailbox, result;
|
||||
if (ast === null) {
|
||||
return null;
|
||||
}
|
||||
ret = { ast: ast };
|
||||
addresses = findAllNodes('address', ast);
|
||||
ret.addresses = [];
|
||||
for (i = 0; i < addresses.length; i += 1) {
|
||||
addr = addresses[i];
|
||||
name = findNode('display-name', addr);
|
||||
aspec = findNode('addr-spec', addr);
|
||||
local = findNode('local-part', aspec);
|
||||
domain = findNode('domain', aspec);
|
||||
ret.addresses.push({
|
||||
node: addr,
|
||||
parts: {
|
||||
name: name,
|
||||
address: aspec,
|
||||
local: local,
|
||||
domain: domain
|
||||
},
|
||||
name: grabSemantic(name),
|
||||
address: grabSemantic(aspec),
|
||||
local: grabSemantic(local),
|
||||
domain: grabSemantic(domain)
|
||||
});
|
||||
}
|
||||
addresses = [];
|
||||
|
||||
if (opts.simple) {
|
||||
ret = ret.addresses;
|
||||
for (i = 0; i < ret.length; i += 1) {
|
||||
delete ret[i].node;
|
||||
// An address is a 'group' (i.e. a list of mailboxes) or a 'mailbox'.
|
||||
groupsAndMailboxes = findAllNodesNoChildren(['group', 'mailbox'], ast);
|
||||
for (i = 0; i < groupsAndMailboxes.length; i += 1) {
|
||||
groupOrMailbox = groupsAndMailboxes[i];
|
||||
if (groupOrMailbox.name === 'group') {
|
||||
addresses.push(giveResultGroup(groupOrMailbox));
|
||||
} else if (groupOrMailbox.name === 'mailbox') {
|
||||
addresses.push(giveResultMailbox(groupOrMailbox));
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
|
||||
result = {
|
||||
ast: ast,
|
||||
addresses: addresses,
|
||||
};
|
||||
if (opts.simple) {
|
||||
result = simplifyResult(result);
|
||||
}
|
||||
if (opts.oneResult) {
|
||||
return oneResult(result);
|
||||
}
|
||||
if (opts.simple) {
|
||||
return result && result.addresses;
|
||||
} else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function giveResultGroup(group) {
|
||||
var i;
|
||||
var groupName = findNode('display-name', group);
|
||||
var groupResultMailboxes = [];
|
||||
var mailboxes = findAllNodesNoChildren(['mailbox'], group);
|
||||
for (i = 0; i < mailboxes.length; i += 1) {
|
||||
groupResultMailboxes.push(giveResultMailbox(mailboxes[i]));
|
||||
}
|
||||
return {
|
||||
node: group,
|
||||
parts: {
|
||||
name: groupName,
|
||||
},
|
||||
type: group.name, // 'group'
|
||||
name: grabSemantic(groupName),
|
||||
addresses: groupResultMailboxes,
|
||||
};
|
||||
}
|
||||
|
||||
function giveResultMailbox(mailbox) {
|
||||
var name = findNode('display-name', mailbox);
|
||||
var aspec = findNode('addr-spec', mailbox);
|
||||
var comments = findAllNodes('cfws', mailbox);
|
||||
|
||||
var local = findNode('local-part', aspec);
|
||||
var domain = findNode('domain', aspec);
|
||||
return {
|
||||
node: mailbox,
|
||||
parts: {
|
||||
name: name,
|
||||
address: aspec,
|
||||
local: local,
|
||||
domain: domain,
|
||||
comments: comments
|
||||
},
|
||||
type: mailbox.name, // 'mailbox'
|
||||
name: grabSemantic(name),
|
||||
address: grabSemantic(aspec),
|
||||
local: grabSemantic(local),
|
||||
domain: grabSemantic(domain),
|
||||
groupName: grabSemantic(mailbox.groupName),
|
||||
};
|
||||
}
|
||||
|
||||
function grabSemantic(n) {
|
||||
return n !== null && n !== undefined ? n.semantic : null;
|
||||
}
|
||||
|
||||
function simplifyResult(result) {
|
||||
var i;
|
||||
if (result && result.addresses) {
|
||||
for (i = 0; i < result.addresses.length; i += 1) {
|
||||
delete result.addresses[i].node;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function oneResult(result) {
|
||||
if (!result) { return null; }
|
||||
if (!opts.partial && result.addresses.length > 1) { return null; }
|
||||
return result.addresses && result.addresses[0];
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
|
||||
var parseString, pos, len, parsed;
|
||||
var parseString, pos, len, parsed, startProduction;
|
||||
|
||||
opts = handleOpts(opts, {});
|
||||
if (opts === null) { return null; }
|
||||
|
||||
parseString = opts.input;
|
||||
|
||||
startProduction = {
|
||||
'address': address,
|
||||
'address-list': addressList,
|
||||
'angle-addr': angleAddr,
|
||||
'from': fromSpec,
|
||||
'group': group,
|
||||
'mailbox': mailbox,
|
||||
'mailbox-list': mailboxList,
|
||||
'reply-to': replyToSpec,
|
||||
'sender': senderSpec,
|
||||
}[opts.startAt] || addressList;
|
||||
|
||||
if (!opts.strict) {
|
||||
initialize();
|
||||
opts.strict = true;
|
||||
parsed = addressList(parseString);
|
||||
parsed = startProduction(parseString);
|
||||
if (opts.partial || !inStr()) {
|
||||
return giveResult(parsed);
|
||||
}
|
||||
@@ -859,46 +967,51 @@ function parse5322(opts) {
|
||||
}
|
||||
|
||||
initialize();
|
||||
parsed = addressList(parseString);
|
||||
parsed = startProduction(parseString);
|
||||
if (!opts.partial && inStr()) { return null; }
|
||||
return giveResult(parsed);
|
||||
}
|
||||
|
||||
function parseOneAddressSimple(opts) {
|
||||
var result;
|
||||
|
||||
opts = handleOpts(opts, {
|
||||
return parse5322(handleOpts(opts, {
|
||||
oneResult: true,
|
||||
rfc6532: true,
|
||||
simple: true
|
||||
});
|
||||
if (opts === null) { return null; }
|
||||
|
||||
result = parse5322(opts);
|
||||
|
||||
if ((!result) ||
|
||||
(!opts.partial &&
|
||||
(opts.simple && result.length > 1) ||
|
||||
(!opts.simple && result.addresses.length > 1))) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return opts.simple ?
|
||||
result && result[0] :
|
||||
result && result.addresses && result.addresses[0];
|
||||
simple: true,
|
||||
startAt: 'address-list',
|
||||
}));
|
||||
}
|
||||
|
||||
function parseAddressListSimple(opts) {
|
||||
var result;
|
||||
|
||||
opts = handleOpts(opts, {
|
||||
return parse5322(handleOpts(opts, {
|
||||
rfc6532: true,
|
||||
simple: true
|
||||
});
|
||||
if (opts === null) { return null; }
|
||||
simple: true,
|
||||
startAt: 'address-list',
|
||||
}));
|
||||
}
|
||||
|
||||
result = parse5322(opts);
|
||||
function parseFromSimple(opts) {
|
||||
return parse5322(handleOpts(opts, {
|
||||
rfc6532: true,
|
||||
simple: true,
|
||||
startAt: 'from',
|
||||
}));
|
||||
}
|
||||
|
||||
return opts.simple ? result : result.addresses;
|
||||
function parseSenderSimple(opts) {
|
||||
return parse5322(handleOpts(opts, {
|
||||
oneResult: true,
|
||||
rfc6532: true,
|
||||
simple: true,
|
||||
startAt: 'sender',
|
||||
}));
|
||||
}
|
||||
|
||||
function parseReplyToSimple(opts) {
|
||||
return parse5322(handleOpts(opts, {
|
||||
rfc6532: true,
|
||||
simple: true,
|
||||
startAt: 'reply-to',
|
||||
}));
|
||||
}
|
||||
|
||||
function handleOpts(opts, defs) {
|
||||
@@ -926,24 +1039,28 @@ function handleOpts(opts, defs) {
|
||||
if (!defs) { return null; }
|
||||
|
||||
defaults = {
|
||||
rfc6532: false,
|
||||
oneResult: false,
|
||||
partial: false,
|
||||
rejectTLD: false,
|
||||
rfc6532: false,
|
||||
simple: false,
|
||||
startAt: 'address-list',
|
||||
strict: false,
|
||||
rejectTLD: false
|
||||
};
|
||||
|
||||
for (o in defaults) {
|
||||
if (isNullUndef(opts[o])) {
|
||||
opts[o] = !isNullUndef(defs[o]) ? defs[o] : defaults[o];
|
||||
}
|
||||
opts[o] = !!opts[o];
|
||||
}
|
||||
return opts;
|
||||
}
|
||||
|
||||
parse5322.parseOneAddress = parseOneAddressSimple;
|
||||
parse5322.parseAddressList = parseAddressListSimple;
|
||||
parse5322.parseFrom = parseFromSimple;
|
||||
parse5322.parseSender = parseSenderSimple;
|
||||
parse5322.parseReplyTo = parseReplyToSimple;
|
||||
|
||||
// in Zammad context, go back to non CommonJS
|
||||
// if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
|
||||
|
||||
@@ -152,8 +152,10 @@
|
||||
$(window).on('keydown.dismiss.bs.modal', $.proxy(function (e) {
|
||||
e.which == 27 && this.hide()
|
||||
// 2016-08-21: added event to capture esc for cancel
|
||||
e = $.Event('dismiss.bs.modal')
|
||||
this.$element.trigger(e)
|
||||
if (e.which == 27) {
|
||||
e = $.Event('dismiss.bs.modal')
|
||||
this.$element.trigger(e)
|
||||
}
|
||||
// -
|
||||
}, this))
|
||||
} else if (!this.isShown) {
|
||||
|
||||
@@ -417,6 +417,15 @@ class Model extends Module
|
||||
# ID change, need to do some shifting
|
||||
if atts.id and @id isnt atts.id
|
||||
@changeID(atts.id)
|
||||
|
||||
# temporary debugging of a possible race condition
|
||||
if !@constructor.irecords[@id]
|
||||
model = @constructor.className
|
||||
atts_json = JSON.stringify(atts)
|
||||
console.log "Can't refresh not exisint %s instance with ID %s and attributes %s. Possible race condition?", model, @id, atts_json
|
||||
# prevent exception
|
||||
return
|
||||
|
||||
# go to the source and load attributes
|
||||
@constructor.irecords[@id].load(atts)
|
||||
@trigger('refresh', this)
|
||||
|
||||
@@ -250,7 +250,7 @@ class App.Chat extends App.Model
|
||||
{ name: 'note', display: 'Note', tag: 'textarea', limit: 250, null: true },
|
||||
{ name: 'max_queue', display: 'Max. clients in waitlist', tag: 'input', default: 2 },
|
||||
{ name: 'block_ip', display: 'Blocked IPs (separated by ;)', tag: 'input', default: '', null: true },
|
||||
{ name: 'block_country', display: 'Blocked contries', tag: 'column_select', multiple: true, null: true, default: '', options: @countries, seperator: ';' },
|
||||
{ name: 'block_country', display: 'Blocked countries', tag: 'column_select', multiple: true, null: true, default: '', options: @countries, seperator: ';' },
|
||||
{ name: 'active', display: 'Active', tag: 'active', default: true },
|
||||
{ name: 'created_by_id', display: 'Created by', relation: 'User', readonly: 1 },
|
||||
{ name: 'created_at', display: 'Created', tag: 'datetime', readonly: 1 },
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="js-pager"></div>
|
||||
<table class="table table-hover<%- " #{@class}" if @class %>">
|
||||
<table class="table table-hover<% if @class: %> <%= @class %><% end %>">
|
||||
<thead>
|
||||
<tr>
|
||||
<% if @sortable: %>
|
||||
@@ -19,14 +19,10 @@
|
||||
<th style="width: 40px" class="table-radio"></th>
|
||||
<% end %>
|
||||
<% for header, i in @headers: %>
|
||||
<th class="js-tableHead<%= " #{ header.className }" if header.className %><%= " align-#{ header.align }" if header.align %>" style="<% if header.displayWidth: %>width:<%= header.displayWidth %>px<% end %>" data-column-key="<%= header.name %>">
|
||||
<th class="js-tableHead<% if header.className: %> <%= header.className %><% end %><% if header.align: %> align-<%= header.align %><% end %>" style="<% if header.displayWidth: %>width:<%= header.displayWidth %>px<% end %>" data-column-key="<%= header.name %>">
|
||||
<div class="table-column-head<%= ' js-sort' if @tableId %>">
|
||||
<div class="table-column-title"><%- @T(header.display) %></div>
|
||||
<div class="table-column-sortIcon">
|
||||
<% if header.sortOrderIcon: %>
|
||||
<%- @Icon(header.sortOrderIcon[0], header.sortOrderIcon[1]) %>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="table-column-sortIcon"><% if header.sortOrderIcon: %><%- @Icon(header.sortOrderIcon[0], header.sortOrderIcon[1]) %><% end %></div>
|
||||
</div>
|
||||
<% if @tableId && !header.unresizable && i < @headers.length - 1: %>
|
||||
<div class="table-col-resize js-col-resize"></div>
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<% end %>
|
||||
<% end %>
|
||||
<% end %>
|
||||
<td<%- " class='#{ header.parentClass }'" if header.parentClass %><%- " title='#{ header.title }'" if header.title %><%- " style='text-align:#{ header.align }'" if header.align %>>
|
||||
<td<% if header.parentClass: %> class="<%= header.parentClass %>"<% end %><% if header.title: %> title="<%= header.title %>"<% end %><% if header.align: %> style="text-align:<%= header.align %>"<% end %>>
|
||||
<% if header.name is 'icon': %>
|
||||
<%- @Icon('task-state', header.class) %>
|
||||
<% else if header.icon: %>
|
||||
|
||||
@@ -295,7 +295,7 @@ check if country is blocked for chat
|
||||
|
||||
def blocked_country?(ip)
|
||||
return false if ip.blank?
|
||||
retunn false if block_country.blank?
|
||||
return false if block_country.blank?
|
||||
geo_ip = Service::GeoIp.location(ip)
|
||||
return false if geo_ip.blank?
|
||||
return false if geo_ip['country_code'].blank?
|
||||
|
||||
@@ -21,13 +21,7 @@ class Report
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
adapter: Report::TicketGenericTime,
|
||||
params: { field: 'created_at' },
|
||||
condition: {
|
||||
'state' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
params: { field: 'created_at' }
|
||||
},
|
||||
{
|
||||
name: 'closed',
|
||||
@@ -35,52 +29,28 @@ class Report
|
||||
selected: true,
|
||||
dataDownload: true,
|
||||
adapter: Report::TicketGenericTime,
|
||||
params: { field: 'close_at' },
|
||||
condition: {
|
||||
'state' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
params: { field: 'close_at' }
|
||||
},
|
||||
{
|
||||
name: 'backlog',
|
||||
display: 'Backlog',
|
||||
selected: true,
|
||||
dataDownload: false,
|
||||
adapter: Report::TicketBacklog,
|
||||
condition: {
|
||||
'state' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
adapter: Report::TicketBacklog
|
||||
},
|
||||
{
|
||||
name: 'first_solution',
|
||||
display: 'First Solution',
|
||||
selected: false,
|
||||
dataDownload: true,
|
||||
adapter: Report::TicketFirstSolution,
|
||||
condition: {
|
||||
'ticket_state.name' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
adapter: Report::TicketFirstSolution
|
||||
},
|
||||
{
|
||||
name: 'reopened',
|
||||
display: 'Reopened',
|
||||
selected: false,
|
||||
dataDownload: true,
|
||||
adapter: Report::TicketReopened,
|
||||
condition: {
|
||||
'ticket_state.name' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
adapter: Report::TicketReopened
|
||||
},
|
||||
{
|
||||
name: 'movedin',
|
||||
@@ -88,13 +58,7 @@ class Report
|
||||
selected: false,
|
||||
dataDownload: true,
|
||||
adapter: Report::TicketMoved,
|
||||
params: { type: 'in' },
|
||||
condition: {
|
||||
'ticket_state.name' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
params: { type: 'in' }
|
||||
},
|
||||
{
|
||||
name: 'movedout',
|
||||
@@ -102,13 +66,7 @@ class Report
|
||||
selected: false,
|
||||
dataDownload: true,
|
||||
adapter: Report::TicketMoved,
|
||||
params: { type: 'out' },
|
||||
condition: {
|
||||
'ticket_state.name' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
params: { type: 'out' }
|
||||
},
|
||||
]
|
||||
config[:metric][:count][:backend] = backend
|
||||
|
||||
@@ -36,6 +36,7 @@ returns
|
||||
data[ app_model ][ id ] = local_attributes
|
||||
|
||||
local_attributes['group_ids'].each_key do |group_id|
|
||||
next if data[:Group] && data[:Group][group_id]
|
||||
group = Group.lookup(id: group_id)
|
||||
next if !group
|
||||
data = group.assets(data)
|
||||
|
||||
@@ -21,13 +21,11 @@ class Ticket
|
||||
# access ok if its own ticket
|
||||
return true if customer_id == user.id
|
||||
|
||||
# access ok if its organization ticket
|
||||
if user.organization_id && organization_id
|
||||
return true if organization_id == user.organization_id
|
||||
end
|
||||
|
||||
# no access
|
||||
return false
|
||||
# check organization ticket access
|
||||
return false if organization_id.blank?
|
||||
return false if user.organization_id.blank?
|
||||
return false if organization_id != user.organization_id
|
||||
return organization.shared?
|
||||
end
|
||||
|
||||
# check agent
|
||||
|
||||
@@ -98,11 +98,7 @@ returns
|
||||
|
||||
filter[:group_id] = []
|
||||
groups = if params[:current_user].permissions?('ticket.agent')
|
||||
if params[:ticket].present?
|
||||
params[:current_user].groups_access(%w[change])
|
||||
else
|
||||
params[:current_user].groups_access(%w[create])
|
||||
end
|
||||
params[:current_user].groups_access(%w[create change])
|
||||
else
|
||||
Group.where(active: true)
|
||||
end
|
||||
|
||||
48
db/migrate/20180202000002_custom_ldap_login_attribute.rb
Normal file
48
db/migrate/20180202000002_custom_ldap_login_attribute.rb
Normal file
@@ -0,0 +1,48 @@
|
||||
class CustomLdapLoginAttribute < ActiveRecord::Migration[5.1]
|
||||
def up
|
||||
|
||||
# return if it's a new setup
|
||||
return if !Setting.find_by(name: 'system_init_done')
|
||||
return if no_change_needed?
|
||||
|
||||
perform_changes
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def perform_changes
|
||||
delete_spared
|
||||
update_config
|
||||
end
|
||||
|
||||
def delete_spared
|
||||
# remove samaccountname which is always wrong if there is more than
|
||||
# one other login attribute since it's automatically added
|
||||
ldap_config[:user_attributes].delete('samaccountname')
|
||||
|
||||
# this should not happen but remove any other duplicate that
|
||||
# maps to login and keep the "first" in the list
|
||||
# - which is more or less random
|
||||
login_attributes.reject { |e| e == 'samaccountname' }.drop(1).each do |spared|
|
||||
ldap_config[:user_attributes].delete(spared)
|
||||
end
|
||||
end
|
||||
|
||||
def update_config
|
||||
Import::Ldap.config = ldap_config
|
||||
end
|
||||
|
||||
def login_attributes
|
||||
@login_attributes ||= ldap_config[:user_attributes].select { |_local, remote| remote == 'login' }.keys
|
||||
end
|
||||
|
||||
def no_change_needed?
|
||||
return true if ldap_config.blank?
|
||||
return true if ldap_config[:user_attributes].blank?
|
||||
ldap_config[:user_attributes].values.count('login') < 2
|
||||
end
|
||||
|
||||
def ldap_config
|
||||
@ldap_config ||= Import::Ldap.config
|
||||
end
|
||||
end
|
||||
@@ -374,7 +374,7 @@ cleanup html string:
|
||||
|
||||
def self.cleanup_target(string)
|
||||
string = CGI.unescape(string).encode('utf-8', 'binary', invalid: :replace, undef: :replace, replace: '?')
|
||||
string.gsub(/[[:space:]]|\t|\n|\r/, '').gsub(%r{/\*.*?\*/}, '').gsub(/<!--.*?-->/, '').gsub(/\[.+?\]/, '')
|
||||
string.gsub(/[[:space:]]|\t|\n|\r/, '').gsub(%r{/\*.*?\*/}, '').gsub(/<!--.*?-->/, '').gsub(/\[.+?\]/, '').delete("\u0000")
|
||||
end
|
||||
|
||||
def self.url_same?(url_new, url_old)
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
module Import
|
||||
class Base
|
||||
|
||||
# Checks if the backend is active.
|
||||
#
|
||||
# @example
|
||||
# Import::ExampleBackend.active?
|
||||
# #=> true
|
||||
#
|
||||
# return [Boolean]
|
||||
def self.active?
|
||||
true
|
||||
end
|
||||
|
||||
# Checks if the backend is able to get queued by the Scheduler.
|
||||
#
|
||||
# @example
|
||||
|
||||
@@ -50,6 +50,14 @@ returns
|
||||
elsif params[:interval] == 'minute'
|
||||
stop = start + 1.minute
|
||||
end
|
||||
|
||||
without_merged_tickets = {
|
||||
'ticket_state.name' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
params[:selector].merge!(without_merged_tickets)
|
||||
query, bind_params, tables = Ticket.selector2sql(params[:selector])
|
||||
ticket_list = Ticket.select('tickets.id, tickets.close_at, tickets.created_at').where(
|
||||
'tickets.close_at IS NOT NULL AND tickets.close_at >= ? AND tickets.close_at < ?',
|
||||
@@ -89,7 +97,15 @@ returns
|
||||
=end
|
||||
|
||||
def self.items(params)
|
||||
query, bind_params, tables = Ticket.selector2sql(params[:selector])
|
||||
without_merged_tickets = {
|
||||
'ticket_state.name' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
|
||||
selector = params[:selector].merge!(without_merged_tickets)
|
||||
query, bind_params, tables = Ticket.selector2sql(selector)
|
||||
ticket_list = Ticket.select('tickets.id, tickets.close_at, tickets.created_at').where(
|
||||
'tickets.close_at IS NOT NULL AND tickets.close_at >= ? AND tickets.close_at < ?',
|
||||
params[:range_start],
|
||||
|
||||
@@ -29,10 +29,18 @@ returns
|
||||
field: params[:params][:field],
|
||||
}
|
||||
|
||||
without_merged_tickets = {
|
||||
'state' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
|
||||
selector = params[:selector].clone
|
||||
if params[:params].present? && params[:params][:selector].present?
|
||||
selector = selector.merge(params[:params][:selector])
|
||||
end
|
||||
selector.merge!(without_merged_tickets) # do not show merged tickets in reports
|
||||
|
||||
result_es = SearchIndexBackend.selectors(['Ticket'], selector, nil, nil, aggs_interval)
|
||||
|
||||
@@ -140,10 +148,18 @@ returns
|
||||
limit = 100
|
||||
end
|
||||
|
||||
without_merged_tickets = {
|
||||
'state' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
|
||||
selector = params[:selector].clone
|
||||
if params[:params] && params[:params][:selector]
|
||||
selector = selector.merge(params[:params][:selector])
|
||||
end
|
||||
selector.merge!(without_merged_tickets) # do not show merged tickets in reports
|
||||
|
||||
result = SearchIndexBackend.selectors(['Ticket'], selector, limit, nil, aggs_interval)
|
||||
return result if params[:sheet].present?
|
||||
|
||||
@@ -60,6 +60,13 @@ returns
|
||||
end
|
||||
local_params = group_attributes(selector, params)
|
||||
local_selector = params[:selector].clone
|
||||
without_merged_tickets = {
|
||||
'ticket_state.name' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
local_selector.merge!(without_merged_tickets) # do not show merged tickets in reports
|
||||
if params[:params][:type] == 'out'
|
||||
local_selector.delete('ticket.group_id')
|
||||
end
|
||||
@@ -110,6 +117,13 @@ returns
|
||||
end
|
||||
local_params = group_attributes(selector, params)
|
||||
local_selector = params[:selector].clone
|
||||
without_merged_tickets = {
|
||||
'ticket_state.name' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
local_selector = params[:selector].merge!(without_merged_tickets) # do not show merged tickets in reports
|
||||
if params[:params][:type] == 'out'
|
||||
local_selector.delete('ticket.group_id')
|
||||
end
|
||||
|
||||
@@ -52,6 +52,14 @@ returns
|
||||
elsif params[:interval] == 'minute'
|
||||
stop = start + 1.minute
|
||||
end
|
||||
|
||||
without_merged_tickets = {
|
||||
'ticket_state.name' => {
|
||||
'operator' => 'is not',
|
||||
'value' => 'merged'
|
||||
}
|
||||
}
|
||||
params[:selector].merge!(without_merged_tickets) # do not show merged tickets in reports
|
||||
count = history_count(
|
||||
object: 'Ticket',
|
||||
type: 'updated',
|
||||
|
||||
@@ -16,7 +16,7 @@ class Sequencer
|
||||
'Import::Common::Model::Associations::Extract',
|
||||
'Import::Common::User::Attributes::Downcase',
|
||||
'Import::Common::User::Email::CheckValidity',
|
||||
'Import::Ldap::User::Lookup::Attributes',
|
||||
'Import::Common::Model::FindBy::UserAttributes',
|
||||
'Import::Common::Model::Attributes::AddByIds',
|
||||
'Import::Common::Model::Update',
|
||||
'Import::Common::Model::Create',
|
||||
|
||||
@@ -9,13 +9,7 @@ class Sequencer
|
||||
private
|
||||
|
||||
def mapping
|
||||
ldap_config[:user_attributes].dup.tap do |config|
|
||||
# fallback to samaccountname as login
|
||||
# if no login is given via mapping
|
||||
if !config.values.include?('login')
|
||||
config['samaccountname'] = 'login'
|
||||
end
|
||||
end
|
||||
ldap_config[:user_attributes]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -13,18 +13,20 @@ class Sessions::Event::ChatStatusCustomer < Sessions::Event::ChatBase
|
||||
|
||||
# update recipients of existing sessions
|
||||
chat_session = Chat::Session.find_by(session_id: session_id)
|
||||
chat_session.add_recipient(@client_id, true)
|
||||
if chat_session
|
||||
chat_session.add_recipient(@client_id, true)
|
||||
|
||||
# sent url update to agent
|
||||
if @payload['data']['url']
|
||||
message = {
|
||||
event: 'chat_session_notice',
|
||||
data: {
|
||||
session_id: chat_session.session_id,
|
||||
message: @payload['data']['url'],
|
||||
},
|
||||
}
|
||||
chat_session.send_to_recipients(message, @client_id)
|
||||
# sent url update to agent
|
||||
if @payload['data']['url']
|
||||
message = {
|
||||
event: 'chat_session_notice',
|
||||
data: {
|
||||
session_id: chat_session.session_id,
|
||||
message: @payload['data']['url'],
|
||||
},
|
||||
}
|
||||
chat_session.send_to_recipients(message, @client_id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1982,34 +1982,106 @@ test('check getRecipientArticle format', function() {
|
||||
lastname: 'lastname',
|
||||
email: 'customer@example.com',
|
||||
}
|
||||
agent = {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'agent@example.com',
|
||||
}
|
||||
ticket = {
|
||||
customer: customer,
|
||||
}
|
||||
article = {
|
||||
message_id: 'message_id7',
|
||||
created_by: agent,
|
||||
type: {
|
||||
name: 'email',
|
||||
},
|
||||
sender: {
|
||||
name: 'Agent',
|
||||
name: 'Customer',
|
||||
},
|
||||
from: 'customer2@example.com',
|
||||
to: 'customer@example.com',
|
||||
from: 'some other invalid part, ' + customer.email,
|
||||
to: 'some group',
|
||||
created_by: {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'article_created_by@example.com',
|
||||
}
|
||||
}
|
||||
result = {
|
||||
to: 'customer2@example.com',
|
||||
to: 'customer@example.com',
|
||||
cc: '',
|
||||
body: '',
|
||||
in_reply_to: 'message_id7',
|
||||
}
|
||||
verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type)
|
||||
console.log(verify)
|
||||
deepEqual(verify, result)
|
||||
|
||||
customer = {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'customer@example.com',
|
||||
}
|
||||
ticket = {
|
||||
customer: customer,
|
||||
}
|
||||
article = {
|
||||
message_id: 'message_id7.1',
|
||||
type: {
|
||||
name: 'email',
|
||||
},
|
||||
sender: {
|
||||
name: 'Customer',
|
||||
},
|
||||
from: 'some other invalid part, Some Realname ' + customer.email,
|
||||
to: 'some group',
|
||||
created_by: {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'article_created_by@example.com',
|
||||
}
|
||||
}
|
||||
result = {
|
||||
to: 'customer@example.com',
|
||||
cc: '',
|
||||
body: '',
|
||||
in_reply_to: 'message_id7.1',
|
||||
}
|
||||
verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type)
|
||||
console.log(verify)
|
||||
deepEqual(verify, result)
|
||||
|
||||
customer = {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'customer@example.com',
|
||||
}
|
||||
ticket = {
|
||||
customer: customer,
|
||||
}
|
||||
article = {
|
||||
message_id: 'message_id7.2',
|
||||
type: {
|
||||
name: 'email',
|
||||
},
|
||||
sender: {
|
||||
name: 'Customer',
|
||||
},
|
||||
from: 'some other invalid part, Some Realname ' + customer.email + ' , abc',
|
||||
to: 'some group',
|
||||
created_by: {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'article_created_by@example.com',
|
||||
}
|
||||
}
|
||||
result = {
|
||||
to: 'customer@example.com',
|
||||
cc: '',
|
||||
body: '',
|
||||
in_reply_to: 'message_id7.2',
|
||||
}
|
||||
verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type)
|
||||
console.log(verify)
|
||||
deepEqual(verify, result)
|
||||
|
||||
customer = {
|
||||
@@ -2036,11 +2108,11 @@ test('check getRecipientArticle format', function() {
|
||||
sender: {
|
||||
name: 'Agent',
|
||||
},
|
||||
from: 'agent@example.com',
|
||||
from: 'customer2@example.com',
|
||||
to: 'customer@example.com',
|
||||
}
|
||||
result = {
|
||||
to: 'customer@example.com',
|
||||
to: 'customer2@example.com',
|
||||
cc: '',
|
||||
body: '',
|
||||
in_reply_to: 'message_id8',
|
||||
@@ -2072,9 +2144,8 @@ test('check getRecipientArticle format', function() {
|
||||
sender: {
|
||||
name: 'Agent',
|
||||
},
|
||||
from: 'Agent@Example.com',
|
||||
from: 'agent@example.com',
|
||||
to: 'customer@example.com',
|
||||
cc: 'zammad@example.com',
|
||||
}
|
||||
result = {
|
||||
to: 'customer@example.com',
|
||||
@@ -2110,16 +2181,16 @@ test('check getRecipientArticle format', function() {
|
||||
name: 'Agent',
|
||||
},
|
||||
from: 'Agent@Example.com',
|
||||
to: 'customer@example.com, agent@example.com',
|
||||
to: 'customer@example.com',
|
||||
cc: 'zammad@example.com',
|
||||
}
|
||||
result = {
|
||||
to: 'customer@example.com, agent@example.com',
|
||||
cc: 'zammad@example.com',
|
||||
to: 'customer@example.com',
|
||||
cc: '',
|
||||
body: '',
|
||||
in_reply_to: 'message_id10',
|
||||
}
|
||||
verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type, [], true)
|
||||
verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type)
|
||||
deepEqual(verify, result)
|
||||
|
||||
customer = {
|
||||
@@ -2147,8 +2218,8 @@ test('check getRecipientArticle format', function() {
|
||||
name: 'Agent',
|
||||
},
|
||||
from: 'Agent@Example.com',
|
||||
to: 'customeR@EXAMPLE.com, agent@example.com',
|
||||
cc: 'zammad@example.com, customer@example.com',
|
||||
to: 'customer@example.com, agent@example.com',
|
||||
cc: 'zammad@example.com',
|
||||
}
|
||||
result = {
|
||||
to: 'customer@example.com, agent@example.com',
|
||||
@@ -2156,7 +2227,7 @@ test('check getRecipientArticle format', function() {
|
||||
body: '',
|
||||
in_reply_to: 'message_id11',
|
||||
}
|
||||
verify = App.Utils.getRecipientArticle(ticket, article, agent, article.type, [], true)
|
||||
verify = App.Utils.getRecipientArticle(ticket, article, article.created_by, article.type, [], true)
|
||||
deepEqual(verify, result)
|
||||
|
||||
customer = {
|
||||
@@ -2184,24 +2255,16 @@ test('check getRecipientArticle format', function() {
|
||||
name: 'Agent',
|
||||
},
|
||||
from: 'Agent@Example.com',
|
||||
to: 'customeR@EXAMPLE.com, agent@example.com, zammad2@EXAMPLE.com',
|
||||
cc: 'zammad@example.com, customer2@example.com',
|
||||
to: 'customeR@EXAMPLE.com, agent@example.com',
|
||||
cc: 'zammad@example.com, customer@example.com',
|
||||
}
|
||||
result = {
|
||||
to: 'customer@example.com, agent@example.com',
|
||||
cc: 'customer2@example.com',
|
||||
cc: 'zammad@example.com',
|
||||
body: '',
|
||||
in_reply_to: 'message_id12',
|
||||
}
|
||||
email_addresses = [
|
||||
{
|
||||
email: 'zammad@example.com',
|
||||
},
|
||||
{
|
||||
email: 'zammad2@example.com',
|
||||
}
|
||||
]
|
||||
verify = App.Utils.getRecipientArticle(ticket, article, agent, article.type, email_addresses, true)
|
||||
verify = App.Utils.getRecipientArticle(ticket, article, agent, article.type, [], true)
|
||||
deepEqual(verify, result)
|
||||
|
||||
customer = {
|
||||
@@ -2214,7 +2277,7 @@ test('check getRecipientArticle format', function() {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'AGENT@example.com',
|
||||
email: 'agent@example.com',
|
||||
}
|
||||
ticket = {
|
||||
customer: customer,
|
||||
@@ -2253,21 +2316,27 @@ test('check getRecipientArticle format', function() {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'zammad@example.com',
|
||||
email: 'customer@example.com',
|
||||
}
|
||||
agent = {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'AGENT@example.com',
|
||||
}
|
||||
ticket = {
|
||||
customer: customer,
|
||||
}
|
||||
article = {
|
||||
message_id: 'message_id14',
|
||||
created_by: customer,
|
||||
created_by: agent,
|
||||
type: {
|
||||
name: 'email',
|
||||
},
|
||||
sender: {
|
||||
name: 'Agent',
|
||||
},
|
||||
from: 'zammad@EXAMPLE.com',
|
||||
from: 'Agent@Example.com',
|
||||
to: 'customeR@EXAMPLE.com, agent@example.com, zammad2@EXAMPLE.com',
|
||||
cc: 'zammad@example.com, customer2@example.com',
|
||||
}
|
||||
@@ -2292,7 +2361,7 @@ test('check getRecipientArticle format', function() {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'customer@example.com',
|
||||
email: 'zammad@example.com',
|
||||
}
|
||||
ticket = {
|
||||
customer: customer,
|
||||
@@ -2306,13 +2375,13 @@ test('check getRecipientArticle format', function() {
|
||||
sender: {
|
||||
name: 'Agent',
|
||||
},
|
||||
from: 'customer@example.com',
|
||||
to: 'customer1@example.com, customer2@example.com, zammad@example.com',
|
||||
cc: '',
|
||||
from: 'zammad@EXAMPLE.com',
|
||||
to: 'customeR@EXAMPLE.com, agent@example.com, zammad2@EXAMPLE.com',
|
||||
cc: 'zammad@example.com, customer2@example.com',
|
||||
}
|
||||
result = {
|
||||
to: 'customer1@example.com, customer2@example.com, customer@example.com',
|
||||
cc: '',
|
||||
to: 'customer@example.com, agent@example.com',
|
||||
cc: 'customer2@example.com',
|
||||
body: '',
|
||||
in_reply_to: 'message_id15',
|
||||
}
|
||||
@@ -2346,11 +2415,11 @@ test('check getRecipientArticle format', function() {
|
||||
name: 'Agent',
|
||||
},
|
||||
from: 'customer@example.com',
|
||||
to: 'customer1@example.com, customer2@example.com, zammad@example.com, customer2+2@example.com',
|
||||
to: 'customer1@example.com, customer2@example.com, zammad@example.com',
|
||||
cc: '',
|
||||
}
|
||||
result = {
|
||||
to: 'customer1@example.com, customer2@example.com, customer2+2@example.com, customer@example.com',
|
||||
to: 'customer1@example.com, customer2@example.com, customer@example.com',
|
||||
cc: '',
|
||||
body: '',
|
||||
in_reply_to: 'message_id16',
|
||||
@@ -2372,30 +2441,24 @@ test('check getRecipientArticle format', function() {
|
||||
lastname: 'lastname',
|
||||
email: 'customer@example.com',
|
||||
}
|
||||
agent = {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'zammad@example.com',
|
||||
}
|
||||
ticket = {
|
||||
customer: customer,
|
||||
}
|
||||
article = {
|
||||
message_id: 'message_id17',
|
||||
created_by: agent,
|
||||
created_by: customer,
|
||||
type: {
|
||||
name: 'email',
|
||||
},
|
||||
sender: {
|
||||
name: 'Agent',
|
||||
},
|
||||
from: 'zammad@example.com',
|
||||
to: 'customer@example.com',
|
||||
from: 'customer@example.com',
|
||||
to: 'customer1@example.com, customer2@example.com, zammad@example.com, customer2+2@example.com',
|
||||
cc: '',
|
||||
}
|
||||
result = {
|
||||
to: 'customer@example.com',
|
||||
to: 'customer1@example.com, customer2@example.com, customer2+2@example.com, customer@example.com',
|
||||
cc: '',
|
||||
body: '',
|
||||
in_reply_to: 'message_id17',
|
||||
@@ -2435,6 +2498,51 @@ test('check getRecipientArticle format', function() {
|
||||
sender: {
|
||||
name: 'Agent',
|
||||
},
|
||||
from: 'zammad@example.com',
|
||||
to: 'customer@example.com',
|
||||
cc: '',
|
||||
}
|
||||
result = {
|
||||
to: 'customer@example.com',
|
||||
cc: '',
|
||||
body: '',
|
||||
in_reply_to: 'message_id18',
|
||||
}
|
||||
email_addresses = [
|
||||
{
|
||||
email: 'zammad@example.com',
|
||||
},
|
||||
{
|
||||
email: 'zammad2@example.com',
|
||||
}
|
||||
]
|
||||
verify = App.Utils.getRecipientArticle(ticket, article, agent, article.type, email_addresses, true)
|
||||
deepEqual(verify, result)
|
||||
|
||||
customer = {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'customer@example.com',
|
||||
}
|
||||
agent = {
|
||||
login: 'login',
|
||||
firstname: 'firstname',
|
||||
lastname: 'lastname',
|
||||
email: 'zammad@example.com',
|
||||
}
|
||||
ticket = {
|
||||
customer: customer,
|
||||
}
|
||||
article = {
|
||||
message_id: 'message_id19',
|
||||
created_by: agent,
|
||||
type: {
|
||||
name: 'email',
|
||||
},
|
||||
sender: {
|
||||
name: 'Agent',
|
||||
},
|
||||
from: 'Sender <zammad@example.com>',
|
||||
to: 'Customer <customer@example.com>',
|
||||
cc: '',
|
||||
@@ -2443,7 +2551,7 @@ test('check getRecipientArticle format', function() {
|
||||
to: 'customer@example.com',
|
||||
cc: '',
|
||||
body: '',
|
||||
in_reply_to: 'message_id18',
|
||||
in_reply_to: 'message_id19',
|
||||
}
|
||||
email_addresses = [
|
||||
{
|
||||
@@ -2466,7 +2574,7 @@ test('check getRecipientArticle format', function() {
|
||||
customer: agent,
|
||||
}
|
||||
article = {
|
||||
message_id: 'message_id19',
|
||||
message_id: 'message_id20',
|
||||
created_by: agent,
|
||||
type: {
|
||||
name: 'email',
|
||||
@@ -2482,7 +2590,7 @@ test('check getRecipientArticle format', function() {
|
||||
to: 'agent@example.com',
|
||||
cc: '',
|
||||
body: '',
|
||||
in_reply_to: 'message_id19',
|
||||
in_reply_to: 'message_id20',
|
||||
}
|
||||
email_addresses = [
|
||||
{
|
||||
|
||||
@@ -4,6 +4,13 @@ require 'lib/import/import_job_backend_examples'
|
||||
RSpec.describe Import::Base do
|
||||
it_behaves_like 'ImportJob backend'
|
||||
|
||||
describe '#active?' do
|
||||
|
||||
it 'returns true by default' do
|
||||
expect(described_class.active?).to be true
|
||||
end
|
||||
end
|
||||
|
||||
describe '#queueable?' do
|
||||
|
||||
it 'returns true by default' do
|
||||
|
||||
@@ -64,5 +64,92 @@ class CustomerTicketCreateTest < TestCase
|
||||
css: '.content.active div.ticket-article',
|
||||
value: 'some body 1234 äöüß',
|
||||
)
|
||||
|
||||
# now we want to verify the default followup state
|
||||
# for this case we close the ticket first and then
|
||||
# write a new article. If the content is written
|
||||
# then the state should change initially to open
|
||||
|
||||
# close the ticket
|
||||
select(
|
||||
css: '.content.active [name="state_id"]',
|
||||
value: 'closed',
|
||||
)
|
||||
|
||||
set(
|
||||
css: '.content.active [data-name="body"]',
|
||||
value: 'close #1',
|
||||
no_click: true,
|
||||
)
|
||||
|
||||
click(css: '.content.active .js-submit')
|
||||
watch_for(
|
||||
css: '.content.active div.ticket-article',
|
||||
value: 'close #1',
|
||||
)
|
||||
|
||||
# check if the ticket is closed
|
||||
match(
|
||||
css: '.content.active .sidebar [name="state_id"]',
|
||||
value: 'closed',
|
||||
)
|
||||
|
||||
# type in new content into rte to trigger the default follow up state
|
||||
set(
|
||||
css: '.content.active [data-name="body"]',
|
||||
value: 'some body blublub default followup for reopen check',
|
||||
no_click: true,
|
||||
)
|
||||
|
||||
# verify if the state has changed to open
|
||||
watch_for(
|
||||
css: '.content.active .sidebar [name="state_id"]',
|
||||
value: 'open',
|
||||
)
|
||||
|
||||
# no we verify the reverse way:
|
||||
# if the body get changed to empty again then
|
||||
# the default follow up state should get unset and
|
||||
# will change to the the default ticket state.
|
||||
|
||||
# remove content from rte
|
||||
set(
|
||||
css: '.content.active [data-name="body"]',
|
||||
value: '',
|
||||
no_click: true,
|
||||
)
|
||||
|
||||
# check if state changed to closed again
|
||||
watch_for(
|
||||
css: '.content.active .sidebar [name="state_id"]',
|
||||
value: 'closed',
|
||||
)
|
||||
|
||||
# type in new content into rte to trigger the default follow up state
|
||||
set(
|
||||
css: '.content.active [data-name="body"]',
|
||||
value: 'some body blublub default followup for reopen check',
|
||||
no_click: true,
|
||||
)
|
||||
|
||||
# verify if the state has changed to open
|
||||
watch_for(
|
||||
css: '.content.active .sidebar [name="state_id"]',
|
||||
value: 'open',
|
||||
)
|
||||
|
||||
# submit and reload to check if the new state is set
|
||||
click(css: '.content.active .js-submit')
|
||||
|
||||
watch_for(
|
||||
css: '.content.active div.ticket-article',
|
||||
value: 'some body blublub default followup for reopen check',
|
||||
)
|
||||
|
||||
# verify if the state has changed to open
|
||||
match(
|
||||
css: '.content.active .sidebar [name="state_id"]',
|
||||
value: 'open',
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
1047
test/fixtures/mail66.box
vendored
Normal file
1047
test/fixtures/mail66.box
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@@ -304,7 +304,7 @@ class ReportTest < ActiveSupport::TestCase
|
||||
assert_equal(0, result[7])
|
||||
assert_equal(0, result[8])
|
||||
assert_equal(2, result[9])
|
||||
assert_equal(2, result[10])
|
||||
assert_equal(1, result[10])
|
||||
assert_equal(0, result[11])
|
||||
assert_nil(result[12])
|
||||
|
||||
@@ -317,8 +317,7 @@ class ReportTest < ActiveSupport::TestCase
|
||||
assert_equal(@ticket5.id, result[:ticket_ids][0])
|
||||
assert_equal(@ticket6.id, result[:ticket_ids][1])
|
||||
assert_equal(@ticket7.id, result[:ticket_ids][2])
|
||||
assert_equal(@ticket8.id, result[:ticket_ids][3])
|
||||
assert_nil(result[:ticket_ids][4])
|
||||
assert_nil(result[:ticket_ids][3])
|
||||
|
||||
# month - with selector #1
|
||||
result = Report::TicketFirstSolution.aggs(
|
||||
@@ -425,7 +424,7 @@ class ReportTest < ActiveSupport::TestCase
|
||||
assert_equal(0, result[7])
|
||||
assert_equal(0, result[8])
|
||||
assert_equal(1, result[9])
|
||||
assert_equal(2, result[10])
|
||||
assert_equal(1, result[10])
|
||||
assert_equal(0, result[11])
|
||||
assert_nil(result[12])
|
||||
|
||||
@@ -442,8 +441,7 @@ class ReportTest < ActiveSupport::TestCase
|
||||
assert(result)
|
||||
assert_equal(@ticket6.id, result[:ticket_ids][0])
|
||||
assert_equal(@ticket7.id, result[:ticket_ids][1])
|
||||
assert_equal(@ticket8.id, result[:ticket_ids][2])
|
||||
assert_nil(result[:ticket_ids][3])
|
||||
assert_nil(result[:ticket_ids][2])
|
||||
|
||||
# week
|
||||
result = Report::TicketFirstSolution.aggs(
|
||||
@@ -929,7 +927,7 @@ class ReportTest < ActiveSupport::TestCase
|
||||
assert_equal(0, result[7])
|
||||
assert_equal(0, result[8])
|
||||
assert_equal(6, result[9])
|
||||
assert_equal(2, result[10])
|
||||
assert_equal(1, result[10])
|
||||
assert_equal(0, result[11])
|
||||
assert_nil(result[12])
|
||||
|
||||
@@ -940,15 +938,14 @@ class ReportTest < ActiveSupport::TestCase
|
||||
params: { field: 'created_at' },
|
||||
)
|
||||
assert(result)
|
||||
assert_equal(@ticket8.id, result[:ticket_ids][0].to_i)
|
||||
assert_equal(@ticket7.id, result[:ticket_ids][1].to_i)
|
||||
assert_equal(@ticket6.id, result[:ticket_ids][2].to_i)
|
||||
assert_equal(@ticket5.id, result[:ticket_ids][3].to_i)
|
||||
assert_equal(@ticket4.id, result[:ticket_ids][4].to_i)
|
||||
assert_equal(@ticket3.id, result[:ticket_ids][5].to_i)
|
||||
assert_equal(@ticket2.id, result[:ticket_ids][6].to_i)
|
||||
assert_equal(@ticket1.id, result[:ticket_ids][7].to_i)
|
||||
assert_nil(result[:ticket_ids][8])
|
||||
assert_equal(@ticket7.id, result[:ticket_ids][0].to_i)
|
||||
assert_equal(@ticket6.id, result[:ticket_ids][1].to_i)
|
||||
assert_equal(@ticket5.id, result[:ticket_ids][2].to_i)
|
||||
assert_equal(@ticket4.id, result[:ticket_ids][3].to_i)
|
||||
assert_equal(@ticket3.id, result[:ticket_ids][4].to_i)
|
||||
assert_equal(@ticket2.id, result[:ticket_ids][5].to_i)
|
||||
assert_equal(@ticket1.id, result[:ticket_ids][6].to_i)
|
||||
assert_nil(result[:ticket_ids][7])
|
||||
|
||||
# create at - selector with merge
|
||||
result = Report::TicketGenericTime.aggs(
|
||||
|
||||
@@ -1285,6 +1285,35 @@ delete your own text from the attached returned message.
|
||||
",
|
||||
},
|
||||
},
|
||||
{
|
||||
data: IO.binread('test/fixtures/mail66.box'),
|
||||
body_md5: '346effdbc86ef1f5ea263102fba2e542',
|
||||
attachments: [
|
||||
{
|
||||
md5: '9e56d72f98bbc339c180329e61e21bdf',
|
||||
filename: 'message.html',
|
||||
},
|
||||
{
|
||||
md5: 'ddbdf67aa2f5c60c294008a54d57082b',
|
||||
filename: 'FF_Geburtstagsmail.jpg',
|
||||
},
|
||||
{
|
||||
md5: 'a618d671348735744d4c9a4005b56799',
|
||||
filename: 'team.jpg',
|
||||
},
|
||||
],
|
||||
params: {
|
||||
from: 'ABC GmbH <info@example.com>',
|
||||
from_email: 'info@example.com',
|
||||
from_display_name: 'ABC GmbH',
|
||||
subject: 'ABC gratuliert!',
|
||||
content_type: 'text/html',
|
||||
body: 'Glückwunschkarte <p>Wenn diese Mail nicht richtig dargestellt wird, dann klicken Sie bitte <a href="http://www.example.com/wlabel/geburtstag/?id=0umjv6klh0skcp4j57kl3ro8jymo4c134rcbh31ezc3bk1wv&xz=d???NvnDNoP???!??a?qH@>+?DI?&nv=1337" rel="nofollow noreferrer noopener" target="_blank" title="http://www.example.com/wlabel/geburtstag/?id=0umjv6klh0skcp4j57kl3ro8jymo4c134rcbh31ezc3bk1wv&xz=d???NvnDNoP???!??a?qH@>+?DI?&nv=1337"><u>hier</u></a>.</p><table border="0" cellpadding="0" cellspacing="0" align="center" style="border:2px solid #ebebeb;"> <tr style="background-color:#ffffff;"> <td> <img src="FF_Geburtstagsmail.jpg" alt="Herzlichen Glückwunsch !"> </td> </tr> <tr> <td style="background-color:#ffffff; padding:30px 30px 0 30px;"> <h1>Sehr geehrte Damen und Herren,</h1> <p>zu Ihrem Geburtstag schicken wir Ihnen ein großes Paket mit guten Wünschen:<br> Viel Erfolg, Energie und ein gutes Gespür für die richtigen Entscheidungen!</p><p>Ihr Ehrentag ist ein guter Anlass zurückzublicken und sich an Erreichtem zu erfreuen. Doch er ist auch Anlass, den Blick nach vorne zu richten. Sich kurz zu orientieren und neue Ziele zu stecken. Unsere besten Wünsche begleiten Sie auf Ihrem zukünftigen Weg und wir freuen uns darauf, Ihnen auch dabei zur Seite zu stehen!</p><p>Heute wünschen wir Ihnen einen schönen Tag im Kreise Ihrer Freunde und Familie.</p><p>Herzliche Grüße</p><p>Ihre ABC</p></td> </tr> <tr> <td style="background-color:#ffffff; padding-left: 30px; font-size: 0.75em;"> <br>
|
||||
<br> ABC GmbH<br> Einestraße 23<br> 99999 München<br>
|
||||
<br> Telefon.: +49 (0)11 11 11 11-1<br> Fax: +49 (0)11 11 11 11-1<br> <br> <a href="https://www.example.com/" rel="nofollow noreferrer noopener" target="_blank">www.example.com</a><br> <p> </p>Geschäftszeiten: Mo-Do 08:00-18:00 Uhr Fr 08:00-17:00 Uhr<br> Sitz der Gesellschaft: München<br> Registergericht: Amtsgericht München, HRB AAAA<br> Geschäftsführer: AAAA, BBBB<br><br></td> </tr>
|
||||
</table>',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
count = 0
|
||||
|
||||
@@ -140,10 +140,10 @@ class TicketScreenOptionsTest < ActiveSupport::TestCase
|
||||
assert(result[:form_meta][:filter][:type_id])
|
||||
assert_equal([], result[:form_meta][:filter][:type_id].sort)
|
||||
assert(result[:form_meta][:filter][:group_id])
|
||||
assert_equal([group1.id, group3.id], result[:form_meta][:filter][:group_id].sort)
|
||||
assert_equal([group1.id, group2.id, group3.id], result[:form_meta][:filter][:group_id].sort)
|
||||
assert(result[:form_meta][:dependencies])
|
||||
assert(result[:form_meta][:dependencies][:group_id])
|
||||
assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
|
||||
assert_equal(4, result[:form_meta][:dependencies][:group_id].count)
|
||||
assert(result[:form_meta][:dependencies][:group_id][''])
|
||||
assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
|
||||
assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
|
||||
@@ -182,10 +182,10 @@ class TicketScreenOptionsTest < ActiveSupport::TestCase
|
||||
assert(result[:form_meta][:filter][:type_id])
|
||||
assert_equal([], result[:form_meta][:filter][:type_id].sort)
|
||||
assert(result[:form_meta][:filter][:group_id])
|
||||
assert_equal([group1.id, group3.id], result[:form_meta][:filter][:group_id].sort)
|
||||
assert_equal([group1.id, group2.id, group3.id], result[:form_meta][:filter][:group_id].sort)
|
||||
assert(result[:form_meta][:dependencies])
|
||||
assert(result[:form_meta][:dependencies][:group_id])
|
||||
assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
|
||||
assert_equal(4, result[:form_meta][:dependencies][:group_id].count)
|
||||
assert(result[:form_meta][:dependencies][:group_id][''])
|
||||
assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
|
||||
assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
|
||||
@@ -467,10 +467,10 @@ class TicketScreenOptionsTest < ActiveSupport::TestCase
|
||||
Ticket::Article::Type.lookup(name: 'note').id,
|
||||
], result[:form_meta][:filter][:type_id].sort)
|
||||
assert(result[:form_meta][:filter][:group_id])
|
||||
assert_equal([group1.id, group2.id], result[:form_meta][:filter][:group_id].sort)
|
||||
assert_equal([group1.id, group2.id, group3.id], result[:form_meta][:filter][:group_id].sort)
|
||||
assert(result[:form_meta][:dependencies])
|
||||
assert(result[:form_meta][:dependencies][:group_id])
|
||||
assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
|
||||
assert_equal(4, result[:form_meta][:dependencies][:group_id].count)
|
||||
assert(result[:form_meta][:dependencies][:group_id][''])
|
||||
assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
|
||||
assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
|
||||
@@ -513,10 +513,10 @@ class TicketScreenOptionsTest < ActiveSupport::TestCase
|
||||
Ticket::Article::Type.lookup(name: 'note').id,
|
||||
], result[:form_meta][:filter][:type_id].sort)
|
||||
assert(result[:form_meta][:filter][:group_id])
|
||||
assert_equal([group1.id, group2.id], result[:form_meta][:filter][:group_id].sort)
|
||||
assert_equal([group1.id, group2.id, group3.id], result[:form_meta][:filter][:group_id].sort)
|
||||
assert(result[:form_meta][:dependencies])
|
||||
assert(result[:form_meta][:dependencies][:group_id])
|
||||
assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
|
||||
assert_equal(4, result[:form_meta][:dependencies][:group_id].count)
|
||||
assert(result[:form_meta][:dependencies][:group_id][''])
|
||||
assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
|
||||
assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
|
||||
|
||||
Reference in New Issue
Block a user