Compare commits

...

285 Commits

Author SHA1 Message Date
Martin Edenhofer
1fb556c483 Updated CHANES. 2017-12-06 11:31:47 +01:00
Martin Edenhofer
b993a3efd1 Fixed issue #1604 - Webform isn´t available | 401 Unauthorized. 2017-12-04 16:36:59 +01:00
Martin Edenhofer
215d9df0fb Improved issue #1591 - Improved js snipped for form channel (use div, not button for non modal forms). 2017-12-04 16:36:47 +01:00
Martin Edenhofer
2f8acf4f51 Removed debug log. 2017-11-30 11:34:11 +01:00
Martin Edenhofer
ca45fb39e5 Fixed issue #1571 - Improve i-doit filtering (without type). 2017-11-30 11:13:43 +01:00
Martin Edenhofer
0000c3d2fd Fixed issue #1513 - TimeAccounting ticket condition prevents submit of Zoom. 2017-11-30 09:32:40 +01:00
Martin Edenhofer
dbbb4c08d9 Applied rubocop. 2017-11-27 12:48:33 +01:00
Martin Edenhofer
bef233d0ae Fixed issue #1681 - Unable to re-order overviews in admin interface with over 100 overviews. 2017-11-27 12:46:15 +01:00
Martin Edenhofer
e5f3aa77be Fixed issue #1670 - Reset customer selection in ticket create screen if input field cleared. 2017-11-24 16:56:04 +01:00
Martin Edenhofer
5548c3c7ec Fixed issue #1671 - Add config option for intelligent customer selection of incoming emails of agents. 2017-11-23 21:13:43 +01:00
Martin Edenhofer
524d1fe407 Applied rubocop. 2017-11-23 09:29:12 +01:00
Martin Edenhofer
e71dc0cb13 Applied rubocop. 2017-11-23 09:28:12 +01:00
Martin Edenhofer
f39861a6ab Fixed issue #1666 - Unable to open trigger in admin interface. 2017-11-23 09:25:26 +01:00
Martin Edenhofer
29f0a03a3f Fixed issue #1661 - Users mail_delivery_failed is not removed after changing the email address. 2017-11-21 11:01:52 +01:00
Martin Edenhofer
e725aed6f7 Fixed issue #1649 - Tickets are deleted but database is still the same size. 2017-11-20 12:20:11 +01:00
Martin Edenhofer
44070687d3 Implemented issue #1623 - Translation for form widget in Dutch. 2017-11-15 13:14:11 +01:00
Martin Edenhofer
ec0c3c874e Fixed this binding/proxy in callback. 2017-11-14 23:34:00 +01:00
Thorsten Eckel
86d5b8823e Fixed issue #1628 - Added support for new Twitter tweet length limit of 280 chars. 2017-11-08 17:15:13 +01:00
Martin Edenhofer
0192619979 Fixed issue #1618 - Chat language setting or behaviour in dutch. 2017-11-07 15:01:01 +01:00
Martin Edenhofer
b8f9873041 Improved test. 2017-11-06 03:41:33 +01:00
Martin Edenhofer
09ba66ed1e Stabilised tests. 2017-11-06 03:03:31 +01:00
Thorsten Eckel
ae39d0b189 Updated autodiscover dependency to fix an issue with not reachable redirected HTTP URLs in Exchange autodiscovery process - see https://github.com/WinRb/autodiscover/issues/10 . 2017-11-03 14:49:37 +01:00
Thorsten Eckel
d4b12f4650 Exchange changes:
- Fixed bug: Not possible to disable SSL certificate check for import but only for autodiscover.
- Improved SSL certificate error message to show domain of affected domain to prevent users from thinking that there is an issue with their Zammad installation.
2017-11-03 14:49:34 +01:00
Thorsten Eckel
5412c0b02c Added placeholder for better usability. 2017-11-03 14:49:28 +01:00
Martin Edenhofer
4ab133075a Fixed issue #1606 - Ignore Twitter search key with only #. 2017-11-03 08:14:51 +01:00
Martin Edenhofer
763fbd63d2 Improved error handling for strange/invalid email addresses. 2017-11-02 14:47:08 +01:00
Martin Edenhofer
aa4e8b2c8f Fixed issue #1375 - Improved handling assignment_timeout. 2017-11-02 10:30:40 +01:00
Thorsten Eckel
620384476b Fixed issue #1442 - IBM bluepages searches fail. 2017-11-01 15:48:49 +01:00
Thorsten Eckel
686bb74fea Follow up: Fixed issue #1442 - SSL certificate verification for certificate not matching hostnames fail. 2017-11-01 15:48:08 +01:00
Martin Edenhofer
b73085525f Fixed issue #1595 - Unable to sort overview by priority. 2017-10-30 13:51:41 +01:00
Martin Edenhofer
c6ca66c3e0 Updated CHANGES. 2017-10-25 14:10:46 +02:00
Martin Edenhofer
0bb341cb7e Merge branch 'develop' 2017-10-25 14:05:59 +02:00
Martin Edenhofer
6c122e046b Merge branch 'develop' 2017-10-25 10:15:04 +02:00
Martin Edenhofer
57c2dad0a3 Merge branch 'develop' 2017-10-23 03:19:56 +02:00
Martin Edenhofer
faefd529b4 Merge branch 'develop' 2017-10-09 02:27:20 +02:00
Martin Edenhofer
1481a12035 Merge branch 'develop' 2017-10-09 01:37:42 +02:00
Martin Edenhofer
2bf0635e0d Merge branch 'develop' 2017-09-27 11:02:30 +02:00
Martin Edenhofer
2211274bc5 Merge branch 'develop' 2017-09-12 16:39:39 +02:00
Martin Edenhofer
c229c42838 Merge branch 'develop' 2017-09-11 06:45:49 +02:00
Martin Edenhofer
a3c71f6558 Merge branch 'develop' 2017-09-10 19:43:13 +02:00
Thorsten Eckel
db8b85f767 Merge branch 'develop' 2017-09-06 15:01:15 +02:00
Martin Edenhofer
f1664c3841 Merge branch 'develop' 2017-09-05 21:54:52 +02:00
Martin Edenhofer
151c298056 Merge branch 'develop' 2017-08-31 09:05:09 +02:00
Martin Edenhofer
38f51ce6b2 Merge branch 'develop' 2017-08-28 11:44:51 +02:00
Martin Edenhofer
434f3e963e Merge branch 'develop' 2017-08-25 05:38:22 +02:00
Martin Edenhofer
b853dd1597 Merge branch 'develop' 2017-08-24 01:00:34 +02:00
Martin Edenhofer
3b5b6f612f Merge branch 'develop' 2017-08-23 17:16:20 +02:00
Martin Edenhofer
962043c520 Merge branch 'develop' 2017-08-22 14:58:32 +02:00
Martin Edenhofer
8394be87ed Merge branch 'develop' 2017-08-14 11:32:42 +02:00
Martin Edenhofer
5b547ceb3c Merge branch 'develop' 2017-08-13 11:55:41 +02:00
Martin Edenhofer
789ee08485 Merge branch 'develop' 2017-08-11 12:08:58 +02:00
Martin Edenhofer
490937859a Merge branch 'develop' 2017-07-29 13:03:58 +02:00
Martin Edenhofer
dfc306a2ac Merge branch 'develop' 2017-07-28 13:57:37 +02:00
Martin Edenhofer
dea06015a1 Merge branch 'develop' 2017-07-28 11:48:50 +02:00
Martin Edenhofer
2711e3392d Merge branch 'develop' 2017-07-27 06:38:29 +02:00
Martin Edenhofer
f5e1fe0c2f Merge branch 'develop' 2017-07-24 15:26:00 +02:00
Martin Edenhofer
dbbb4ac7a1 Merge branch 'develop' 2017-07-21 15:09:34 +02:00
Martin Edenhofer
8ec2ffdde1 Merge branch 'develop' 2017-07-20 17:22:54 +02:00
Martin Edenhofer
b76664e7ae Merge branch 'develop' 2017-07-20 15:58:47 +02:00
Martin Edenhofer
704c537749 Merge branch 'develop' 2017-07-20 15:00:37 +02:00
Martin Edenhofer
633c99bb72 Merge branch 'develop' 2017-07-19 11:07:56 +02:00
Martin Edenhofer
44051d8023 Merge branch 'develop' 2017-07-16 18:15:24 +02:00
Martin Edenhofer
50dc143c1b Merge branch 'develop' 2017-07-14 15:58:16 +02:00
Martin Edenhofer
6d44275869 Merge branch 'develop' 2017-07-13 20:53:59 +02:00
Martin Edenhofer
b1b3bf6d3c Merge branch 'develop' 2017-07-12 13:30:01 +02:00
Martin Edenhofer
77081ecd4d Merge branch 'develop' 2017-07-04 16:05:04 +02:00
Martin Edenhofer
b823b960d8 Merge branch 'develop' 2017-06-30 08:32:40 +02:00
Martin Edenhofer
e08f634125 Merge branch 'develop' 2017-06-21 09:10:41 +02:00
Martin Edenhofer
ab5e8d9338 Merge branch 'develop' 2017-06-19 20:01:15 +02:00
Martin Edenhofer
9a29ea8f14 Merge branch 'develop' 2017-06-13 02:40:32 +02:00
Martin Edenhofer
cf87e00b21 Merge branch 'develop' 2017-06-13 01:57:29 +02:00
Martin Edenhofer
6233b0a9ec Merge branch 'develop' 2017-06-01 18:32:42 +02:00
Martin Edenhofer
04b1bc638c Merge branch 'develop' 2017-05-29 06:57:52 +02:00
Martin Edenhofer
a78938f7c2 Merge branch 'develop' 2017-05-23 11:05:51 +02:00
Martin Edenhofer
1d23308454 Merge branch 'develop' 2017-05-23 10:30:03 +02:00
Martin Edenhofer
6bc9c00ab8 Merge branch 'develop' 2017-05-16 15:41:06 +02:00
Martin Edenhofer
bc131742be Merge branch 'develop' 2017-05-16 14:22:22 +02:00
Martin Edenhofer
5a12aa0167 Merge branch 'develop' 2017-05-16 01:47:49 +02:00
Martin Edenhofer
b3ab9d0055 Merge branch 'develop' 2017-05-16 00:57:14 +02:00
Martin Edenhofer
1bde8f91bc Merge branch 'develop' 2017-05-15 15:31:15 +02:00
Martin Edenhofer
47ef1b7e5d Merge branch 'develop' 2017-05-11 23:54:32 +02:00
Martin Edenhofer
88c7816f5c Merge branch 'develop' 2017-05-08 17:09:55 +02:00
Martin Edenhofer
82339c6c18 Merge branch 'develop' 2017-05-08 16:56:10 +02:00
Martin Edenhofer
04a609c3a8 Merge branch 'develop' 2017-05-05 15:23:04 +02:00
Martin Edenhofer
60430139aa Merge branch 'develop' 2017-05-02 10:45:06 +02:00
Martin Edenhofer
7d1c655ee3 Merge branch 'develop' 2017-04-28 16:50:31 +02:00
Martin Edenhofer
e34c1c9b79 Merge branch 'develop' 2017-04-28 12:48:40 +02:00
Thorsten Eckel
3c430b35ef Fixed issue #906 - Doorkeeper tokens should be refreshable but aren't. 2017-04-24 13:58:03 +02:00
Rolf Schmidt
7ad3c70311 Fixed issue #975 - Exception in OTRS Import. 2017-04-24 11:58:07 +02:00
Martin Edenhofer
c270bc1e67 Merge branch 'develop' 2017-04-21 14:36:50 +02:00
Thorsten Eckel
3d19bfdcf7 Fixed issue #912 - Long Twitter direct messages are shown as link after 140 chars. 2017-04-21 13:58:33 +02:00
Martin Edenhofer
dc4a55cc5c Merge branch 'develop' 2017-04-21 12:38:25 +02:00
Martin Edenhofer
6e8886277d Merge branch 'develop' 2017-04-21 06:17:09 +02:00
Martin Edenhofer
74e96e92b2 Merge branch 'develop' 2017-04-20 00:22:13 +02:00
Martin Edenhofer
287b1f0d01 Merge branch 'develop' 2017-04-18 09:57:19 +02:00
Martin Edenhofer
feee46e29b Merge branch 'develop' 2017-04-08 08:32:45 +02:00
Martin Edenhofer
991efe36e4 Merge branch 'develop' 2017-04-05 22:23:05 +02:00
Martin Edenhofer
a2aacb20fa Merge branch 'develop' 2017-03-31 16:20:21 +02:00
Martin Edenhofer
592e978062 Merge branch 'develop' 2017-03-31 14:01:20 +02:00
Martin Edenhofer
a4769c8bc7 Merge branch 'develop' 2017-03-27 14:49:54 +02:00
Martin Edenhofer
d1378d53f1 Merge branch 'develop' 2017-03-25 14:44:10 +01:00
Martin Edenhofer
f0b91d3269 Merge branch 'develop' 2017-03-23 21:10:03 +01:00
Martin Edenhofer
48c77dd688 Merge branch 'develop' 2017-03-21 16:06:51 +01:00
Martin Edenhofer
d86d904395 Merge branch 'develop' 2017-03-21 10:05:58 +01:00
Martin Edenhofer
5efc455f0c Merge branch 'develop' 2017-03-18 23:16:57 +01:00
Martin Edenhofer
be3bbeba20 Merged develop into master. 2017-03-18 13:45:42 +01:00
Martin Edenhofer
31ab1b614c Merge branch 'develop' 2017-03-17 08:09:20 +01:00
Martin Edenhofer
4bc5fa4693 Merge branch 'develop' 2017-03-14 19:24:36 +01:00
Martin Edenhofer
418a64f401 Merge branch 'develop' 2017-03-14 13:33:37 +01:00
Martin Edenhofer
abe46270a6 Merge branch 'develop' 2017-03-03 10:54:22 +01:00
Martin Edenhofer
1249a77150 Merge branch 'develop' 2017-03-03 09:46:01 +01:00
Martin Edenhofer
cfa6b9ed16 Merge branch 'develop' 2017-02-24 23:19:06 +01:00
Rolf Schmidt
aa2303f999 Merge branch 'develop' 2017-02-24 09:27:43 +01:00
Martin Edenhofer
d5616684f8 Merge branch 'develop' 2017-02-22 07:12:36 +01:00
Martin Edenhofer
0f75ba57bd Merge branch 'develop' 2017-02-15 17:42:20 +01:00
Martin Edenhofer
c83675bbba Merge branch 'develop' 2017-02-15 13:39:29 +01:00
Martin Edenhofer
17d16d405c Merge branch 'develop' 2017-02-06 11:48:59 +01:00
Martin Edenhofer
76795ca302 Merge branch 'develop' 2017-02-06 00:16:24 +01:00
Martin Edenhofer
5d145bd09f Merge branch 'develop' 2017-02-05 19:26:16 +01:00
Martin Edenhofer
82471552a8 Merge branch 'develop' 2017-02-01 23:24:18 +01:00
Rolf Schmidt
dc60574129 Merge branch 'develop' 2017-01-23 15:05:52 +01:00
Martin Edenhofer
d33a96dee2 Merge branch 'develop' 2017-01-19 06:18:19 +01:00
Martin Edenhofer
0098d4ab82 Merge branch 'develop' 2017-01-17 15:57:42 +01:00
Martin Edenhofer
bb03b5eab8 Merge branch 'develop' 2017-01-17 12:41:03 +01:00
Martin Edenhofer
17eb0f84ec Merge branch 'develop' 2017-01-17 08:56:18 +01:00
Martin Edenhofer
56d0523c1f Merge branch 'develop' 2017-01-04 15:21:24 +01:00
Martin Edenhofer
9fa18758bc Merge branch 'develop' 2016-12-21 14:12:06 +01:00
Martin Edenhofer
d2f2c55b06 Merge branch 'develop' 2016-12-21 08:50:52 +01:00
Martin Edenhofer
f4a409bd6e Merge branch 'develop' 2016-12-21 00:13:59 +01:00
Martin Edenhofer
971b724d4c Merge branch 'develop' 2016-12-18 12:45:13 +01:00
Martin Edenhofer
3263c6f2ba Merge branch 'develop' 2016-12-16 15:49:33 +01:00
Martin Edenhofer
359b026535 Merge branch 'develop' 2016-12-15 17:16:38 +01:00
Martin Edenhofer
c63518fd3e Merge branch 'develop' 2016-12-14 16:06:09 +01:00
Martin Edenhofer
24ba3cff44 Merge branch 'develop' 2016-12-06 13:29:23 +01:00
Martin Edenhofer
f7066e1995 Merge branch 'develop' 2016-12-06 12:23:13 +01:00
Martin Edenhofer
6844499309 Merge branch 'develop' 2016-11-25 16:59:16 +01:00
Martin Edenhofer
afa3e47eab Merge branch 'develop' 2016-11-25 14:22:00 +01:00
Martin Edenhofer
5f3e9298f1 Merge branch 'develop' 2016-11-24 16:03:45 +01:00
Martin Edenhofer
e4dd303357 Merge branch 'develop' 2016-11-21 17:07:30 +01:00
Martin Edenhofer
2fa06eee3d Merge branch 'develop' 2016-11-21 08:58:54 +01:00
Martin Edenhofer
dc0ac03334 Merge branch 'develop' 2016-11-19 16:42:10 +01:00
Martin Edenhofer
c5a1d69ec5 Merge branch 'develop' 2016-11-19 16:35:07 +01:00
Martin Edenhofer
9891981f92 Merge branch 'develop' 2016-11-17 15:12:22 +01:00
Martin Edenhofer
2c721f71e7 Merge branch 'develop' 2016-11-17 10:03:34 +01:00
Martin Edenhofer
0b4a4be0b7 Merge branch 'develop' 2016-11-16 23:21:05 +01:00
Martin Edenhofer
b13bb2fcaf Added change log. 2016-11-14 08:37:51 +01:00
Martin Edenhofer
d9ba369fcf Merge branch 'develop' 2016-11-14 08:36:58 +01:00
Martin Edenhofer
3adece0db5 Merge branch 'develop' 2016-11-14 00:03:57 +01:00
Martin Edenhofer
7101ffc277 Merge branch 'develop' 2016-11-12 16:44:43 +01:00
Martin Edenhofer
19a7a439b8 Merge branch 'develop' 2016-11-11 19:29:56 +01:00
Martin Edenhofer
e728320241 Merge branch 'develop' 2016-10-30 07:08:08 +01:00
Martin Edenhofer
1bc17afc53 Merge branch 'master' of git.znuny.com:zammad/zammad 2016-10-30 07:07:39 +01:00
Thorsten Eckel
ee5c58f53a Fixed bug: Zip archive doesn't contain sub folder content. 2016-10-19 08:25:51 +02:00
Martin Edenhofer
9bdf6d7b81 Merge branch 'develop' 2016-10-19 07:50:08 +02:00
Thorsten Eckel
5754fdccdd Working on CI tag/branch pushing, syncing, deployment issue. 2016-10-19 07:32:05 +02:00
Thorsten Eckel
4901050d57 Working on issue not syncing to github correctly. 2016-10-19 07:25:18 +02:00
Martin Edenhofer
7980c8cb93 Merge branch 'develop' 2016-10-19 07:21:10 +02:00
Martin Edenhofer
7e7088388d Merge branch 'develop' 2016-10-17 16:43:54 +02:00
Martin Edenhofer
2f6e52d63d Merge branch 'develop' 2016-09-28 16:08:28 +02:00
Martin Edenhofer
bde8babb43 Merge branch 'develop' 2016-09-28 08:53:02 +02:00
Martin Edenhofer
d6d68fb363 Merge branch 'develop' 2016-09-19 07:47:06 +02:00
Martin Edenhofer
814ffed0f0 Merge branch 'develop' 2016-09-15 22:11:57 +02:00
Thorsten Eckel
b013fb8cbc Merge branch 'private-otrs_import_df' 2016-09-13 12:06:56 +02:00
Martin Edenhofer
fbd8e63592 Merge branch 'develop' 2016-09-13 08:55:38 +02:00
Martin Edenhofer
e8ad3965d7 Removed build badged. 2016-09-10 16:47:33 +02:00
Martin Edenhofer
e00981ee23 Merge branch 'master' of git.znuny.com:zammad/zammad 2016-09-10 00:05:18 +02:00
Martin Edenhofer
4e74c6beda Merge branch 'develop' 2016-09-10 00:04:28 +02:00
Thorsten Eckel
2d09e556d7 Added deployment of archives. 2016-09-07 15:31:28 +02:00
Martin Edenhofer
8cd39398d6 Merge branch 'develop' 2016-09-06 16:07:33 +02:00
Martin Edenhofer
94c616ffe3 Merge branch 'develop' 2016-08-25 10:00:36 +02:00
Martin Edenhofer
57649bb888 Merge branch 'develop' 2016-08-23 09:49:40 +02:00
Martin Edenhofer
7e9442ec4a Merge branch 'develop' 2016-08-21 21:38:00 +02:00
Martin Edenhofer
521e6265fd Merge branch 'develop' 2016-08-19 13:58:26 +02:00
Martin Edenhofer
a42a9689fc Merge branch 'develop' 2016-08-19 13:48:46 +02:00
Martin Edenhofer
d9ffb8001d Merge branch 'develop' 2016-07-28 13:39:08 +02:00
Martin Edenhofer
ec86d26ae6 Merge branch 'develop' 2016-07-24 23:52:04 +02:00
Martin Edenhofer
e00efc821a Merge branch 'develop' 2016-07-18 19:35:51 +02:00
Martin Edenhofer
f04be8ca93 Merge branch 'develop' 2016-07-12 20:50:32 +02:00
Martin Edenhofer
c7ff6a323a Merge branch 'develop' 2016-07-08 11:28:43 +02:00
Martin Edenhofer
34833416bc Merge branch 'develop' 2016-06-30 09:50:09 +02:00
Martin Edenhofer
d7a6e28d81 Merge branch 'develop' 2016-06-29 00:18:44 +02:00
Martin Edenhofer
c13531d720 Merge branch 'develop' 2016-06-27 11:28:22 +02:00
Martin Edenhofer
4a40cced7d Merge branch 'develop' 2016-06-26 08:07:04 +02:00
Martin Edenhofer
450de10cc7 Merge branch 'develop' 2016-06-23 08:24:56 +02:00
Martin Edenhofer
5e587a455c Merge branch 'develop' 2016-06-22 08:54:24 +02:00
Martin Edenhofer
04aef9b258 Merge branch 'develop' 2016-06-20 15:52:43 +02:00
Martin Edenhofer
9b72557d13 Merge branch 'develop' 2016-06-15 06:58:36 +02:00
Martin Edenhofer
a5e0bc30c1 Merge branch 'develop' 2016-06-09 13:40:27 +02:00
Martin Edenhofer
458c166e9f Merge branch 'develop' 2016-06-08 16:43:29 +02:00
Martin Edenhofer
3373e5d141 Merge branch 'develop' 2016-06-08 10:48:12 +02:00
Martin Edenhofer
8f6b8de617 Merge branch 'develop' 2016-06-08 07:42:19 +02:00
Martin Edenhofer
22b21a82e7 Merge branch 'develop' 2016-06-07 07:02:25 +02:00
Martin Edenhofer
b4151b299f Merge branch 'develop' 2016-06-04 02:23:14 +02:00
Martin Edenhofer
e969fca8c4 Merge branch 'develop' 2016-06-03 07:08:59 +02:00
Martin Edenhofer
e59993a5d6 Merge branch 'develop' 2016-05-31 08:31:56 +02:00
Martin Edenhofer
3adc9d4cf1 Merge branch 'develop' 2016-05-30 13:21:46 +02:00
Martin Edenhofer
c1153250cb Merge branch 'develop' 2016-05-30 00:00:52 +02:00
Martin Edenhofer
7718dc28d3 Merge branch 'develop'
# Conflicts:
#	README.md
2016-05-27 17:30:22 +02:00
Martin Edenhofer
1894580ae6 Updated badge url. 2016-05-27 17:28:26 +02:00
Martin Edenhofer
11df714bbf Merge branch 'develop' 2016-05-20 15:18:36 +02:00
Martin Edenhofer
72adee37a8 Merge branch 'develop' 2016-05-20 06:10:19 +02:00
Martin Edenhofer
0e8f460d73 Merge branch 'develop' 2016-05-06 16:25:09 +02:00
Martin Edenhofer
4e62d5d0d2 Merge branch 'develop' 2016-05-06 09:40:16 +02:00
Martin Edenhofer
004e5ba457 Merge branch 'develop' 2016-05-04 12:13:34 +02:00
Martin Edenhofer
f1a8a8da6f Merge branch 'develop' 2016-05-03 16:01:03 +02:00
Martin Edenhofer
bfb44d1189 Merge branch 'develop' 2016-05-01 14:18:26 +02:00
Martin Edenhofer
d64afd8d97 Merge branch 'develop' 2016-04-14 17:47:03 +02:00
Martin Edenhofer
97cfdb9c4c Merge branch 'develop' 2016-04-12 08:25:06 +02:00
Martin Edenhofer
bb336f63f1 Merge branch 'develop' 2016-03-25 18:23:12 +01:00
Martin Edenhofer
80da08f447 Merge branch 'develop' 2016-03-23 09:31:02 +01:00
Martin Edenhofer
a6db2b7c90 Merge branch 'develop' 2016-03-17 17:45:04 +01:00
Martin Edenhofer
e1c3f83324 Merge branch 'develop' 2016-03-17 10:41:20 +01:00
Martin Edenhofer
8545a44ad1 Merge branch 'develop' 2016-03-16 11:17:22 +01:00
Martin Edenhofer
cfbe7510a2 Merge branch 'develop' 2016-03-16 09:10:05 +01:00
Martin Edenhofer
1479c32edb Merge branch 'develop' 2016-03-15 00:34:36 +01:00
Martin Edenhofer
a9d428bf5a Merge branch 'develop' 2016-03-11 10:38:15 +01:00
Martin Edenhofer
3a62eb11da Merge branch 'develop' 2016-03-04 07:07:55 +01:00
Martin Edenhofer
2df5f81029 Merge branch 'develop' 2016-03-03 03:42:27 +01:00
Martin Edenhofer
b88c23bc92 Merge branch 'develop' 2016-02-28 00:16:49 +01:00
Martin Edenhofer
4144fbaf5b Merge branch 'develop' 2016-02-25 23:46:10 +01:00
Martin Edenhofer
86ddc93f52 Merge branch 'develop' 2016-02-23 14:29:01 +01:00
Martin Edenhofer
8a1b583535 Merge branch 'develop' 2016-02-23 01:38:39 +01:00
Martin Edenhofer
7623628b86 Merge branch 'develop' 2016-02-12 08:53:57 +01:00
Martin Edenhofer
f753bc203f Merge branch 'develop' 2016-02-11 13:25:39 +01:00
Martin Edenhofer
ff9ba10705 Merge branch 'develop' 2016-02-11 02:11:06 +01:00
Martin Edenhofer
fdc25bdc26 Merge branch 'develop' 2016-02-09 01:36:03 +01:00
Martin Edenhofer
d154a587ad Merge branch 'develop' 2016-02-04 12:55:30 +01:00
Martin Edenhofer
a9cc4f037b Merge branch 'develop' 2016-02-04 10:41:41 +01:00
Martin Edenhofer
50d6679189 Merge branch 'develop' 2016-02-03 13:19:51 +01:00
Martin Edenhofer
b82cf4e1d6 Merge branch 'develop' 2016-01-29 15:19:23 +01:00
Martin Edenhofer
fa6eaa6710 Merge branch 'develop'
# Conflicts:
#	README.md
2016-01-26 19:59:34 +01:00
Martin Edenhofer
2ca17ac1bd Updated build status url. 2016-01-26 13:57:24 +01:00
Martin Edenhofer
862ecd7d36 Merge branch 'develop' 2016-01-22 14:47:53 +01:00
Martin Edenhofer
e38b72593b Merge branch 'develop' 2016-01-12 11:14:24 +01:00
Martin Edenhofer
81883cae8f Revert "update terminal start script"
This reverts commit 63770c9cbf.
2016-01-12 11:13:40 +01:00
Felix Niklas
63770c9cbf update terminal start script 2016-01-12 10:58:46 +01:00
Martin Edenhofer
aaf5da55a0 Merge branch 'develop' 2015-12-28 11:33:58 +01:00
Martin Edenhofer
8455d9ae17 Merge branch 'develop' 2015-12-21 16:03:31 +01:00
Martin Edenhofer
839a8e8eb4 Merge branch 'develop' 2015-12-13 15:26:35 +01:00
Martin Edenhofer
7aa3f6eaee Updated build url. 2015-12-10 09:44:16 +01:00
Martin Edenhofer
219abc69a3 Merge branch 'develop' 2015-12-10 09:21:59 +01:00
Martin Edenhofer
595822c928 Merge branch 'develop' 2015-12-02 02:27:40 +01:00
Martin Edenhofer
32112937b1 Merge branch 'develop' 2015-12-02 01:41:10 +01:00
Martin Edenhofer
a0889c5b99 Merge branch 'develop' 2015-12-01 22:03:52 +01:00
Martin Edenhofer
4bc281bfb0 Merge branch 'develop' 2015-12-01 20:04:51 +01:00
Martin Edenhofer
e12ec607d7 Merge branch 'develop' 2015-11-30 15:11:25 +01:00
Martin Edenhofer
545f393293 Merge branch 'develop' 2015-11-30 01:24:11 +01:00
Martin Edenhofer
4efa152e93 Merge branch 'master' of github.com:martini/zammad 2015-11-24 03:39:17 +01:00
Martin Edenhofer
0ebda4f32a Merge branch 'develop'
Conflicts:
	README.md
	script/websocket-server.rb
2015-11-24 03:38:55 +01:00
Martin Edenhofer
b94f54799f Merge branch 'develop' of http://ci.lab.zammad.com/core/zammad 2015-11-24 03:07:38 +01:00
Martin Edenhofer
99f0b4e2e2 Merge branch 'develop' 2015-11-19 14:27:39 +01:00
Martin Edenhofer
53cb906733 Merge branch 'develop' 2015-11-01 01:49:02 +01:00
Martin Edenhofer
2c31fe8a84 Merge branch 'develop' 2015-10-31 23:40:10 +01:00
Martin Edenhofer
6c5e673a2c Merge branch 'develop' 2015-10-02 15:31:54 +02:00
Martin Edenhofer
574b891a33 Merge branch 'develop' 2015-09-28 02:12:31 +02:00
Martin Edenhofer
9ef1d3f58b Merge branch 'develop'
Conflicts:
	extras/zammad.spec
2015-09-28 01:24:03 +02:00
Martin Edenhofer
8b3f432746 Merge branch 'develop' 2015-09-01 03:15:03 +02:00
Martin Edenhofer
14a9df261e Merge branch 'develop' 2015-08-31 15:11:27 +02:00
Martin Edenhofer
5620a2847b Merge branch 'develop' 2015-08-31 12:42:04 +02:00
Martin Edenhofer
13aaae3835 Merge branch 'develop' 2015-08-30 09:19:02 +02:00
Martin Edenhofer
2d4fcd3a4f Merge branch 'develop' 2015-08-30 08:22:27 +02:00
Martin Edenhofer
f4f70b0bc2 Merge branch 'develop' 2015-08-30 01:36:18 +02:00
Martin Edenhofer
1d279bb88f Merge branch 'develop' 2015-08-30 01:32:10 +02:00
Martin Edenhofer
fe4757cbf9 Merge branch 'develop' 2015-08-21 17:03:28 +02:00
me
1d476f163e Use also mysql on test. 2015-08-21 16:53:38 +02:00
Martin Edenhofer
513701b6d2 Merge branch 'develop'
Conflicts:
	README.md
	script/websocket-server.rb
2015-08-11 15:17:14 +02:00
Thorsten Eckel
1a1b661714 Fixed typo. 2015-07-16 09:50:18 +02:00
Roy Kaldung
6081a98279 Update README.md 2015-01-12 12:39:26 +01:00
Roy Kaldung
157991c33d Update README.md 2015-01-12 12:38:11 +01:00
Roy Kaldung
ef67be9170 We like to know if it's starting or stopping 2014-11-06 17:24:45 +01:00
Martin Edenhofer
39f3819303 Merge branch 'develop' 2014-11-06 16:13:39 +01:00
Martin Edenhofer
7a676bd563 Merge branch 'develop' into 'master', goto next level.
Conflicts:
	Gemfile
	README.md
	extras/zammad.spec
2014-10-05 20:42:39 +02:00
Roy Kaldung
80c54daa03 Delete httpd.spec 2014-05-02 12:47:51 +02:00
Roy Kaldung
99c88cde62 Delete apr.spec 2014-05-02 12:47:41 +02:00
Roy Kaldung
17d113ca20 removed old file 2014-05-02 12:47:18 +02:00
Martin Edenhofer
2fbf4324a7 Update Gemfile 2014-02-22 14:46:25 +01:00
Roy Kaldung
b46c390d30 minor change to test GitHub hook (automatic deploy) 2013-12-04 18:22:21 +01:00
Martin Edenhofer
3c3651bc52 Merge branch 'develop'
Conflicts:
	app/controllers/tickets_controller.rb
2013-09-20 13:52:53 +02:00
Roy Kaldung
abeeb5e66d Updated Build Status image URL 2013-08-23 21:00:55 +02:00
rkaldung
09d61ce4c8 added dependency 2013-08-14 20:38:09 +02:00
rkaldung
cc1c4495b2 Merge branch 'master' of github.com:martini/zammad 2013-08-14 20:27:15 +02:00
rkaldung
7b1ec4d17f modified install section 2013-08-14 20:26:25 +02:00
rkaldung
99b3201ccf added initial spec for rpm 2013-08-14 20:20:55 +02:00
Roy Kaldung
d4205d9ba6 removed Windows ;-) 2013-08-14 20:08:23 +02:00
Roy Kaldung
8d57633390 minor changes on comments 2013-08-05 19:18:52 +02:00
88 changed files with 2892 additions and 1034 deletions

View File

@@ -79,6 +79,8 @@ test:unit:mysql:
- rake db:seed
- rake test:units
- rake test:controllers
- ruby -I test/ test/integration/object_manager_test.rb
- ruby -I test/ test/integration/package_test.rb
- rake db:drop
test:unit:postgresql:
@@ -93,6 +95,8 @@ test:unit:postgresql:
- rake db:seed
- rake test:units
- rake test:controllers
- ruby -I test/ test/integration/object_manager_test.rb
- ruby -I test/ test/integration/package_test.rb
- rake db:drop
test:integration:autowizard:

View File

@@ -18,7 +18,7 @@ targets:
dependencies:
- elasticsearch
- nginx|apache2
- postgresql|mariadb-server|sqlite
- postgresql|mariadb-server|sqlite
ubuntu-16.04:
dependencies:
- elasticsearch

View File

@@ -41,6 +41,8 @@ script:
- rake db:seed
- rake test:units
- rake test:controllers
- ruby -I test/ test/integration/object_manager_test.rb
- ruby -I test/ test/integration/package_test.rb
- rake assets:precompile
- rake db:drop
- rake db:create

View File

@@ -1,16 +1,58 @@
# Change Log
## [2.1.0](https://github.com/zammad/zammad/tree/2.1.0) (2017-xx-xx)
[Full Changelog](https://github.com/zammad/zammad/compare/2.0.0...2.1.0)
## [2.1.1](https://github.com/zammad/zammad/tree/2.1.1) (2017-12-06)
[Full Changelog](https://github.com/zammad/zammad/compare/2.1.0...2.1.1)
**Implemented enhancements:**
- Improve i-doit filtering \(without type\) [\#1571](https://github.com/zammad/zammad/issues/1571) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
- Reset customer selection in ticket create screen if input field cleared [\#1670](https://github.com/zammad/zammad/issues/1670) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
- Add config option for intelligent customer selection of incoming emails of agents [\#1671](https://github.com/zammad/zammad/issues/1671) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
- Translation for form widget in Dutch [\#1623](https://github.com/zammad/zammad/issues/1623) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
- Twitter: Allow tweet articles to be 280 chars long [\#1628](https://github.com/zammad/zammad/issues/1628) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
- Chat language setting or behaviour in dutch [\#1618](https://github.com/zammad/zammad/issues/1618) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
**Fixed bugs:**
- Webform isn´t available | 401 Unauthorized [\#1604](https://github.com/zammad/zammad/issues/1604) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Unable to re-order overviews in admin interface with over 100 overviews [\#1681](https://github.com/zammad/zammad/issues/1681) [[bug](https://github.com/zammad/zammad/labels/bug)]
- TimeAccounting ticket condition prevents submit of Zoom [\#1513](https://github.com/zammad/zammad/issues/1513) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Unable to open trigger in admin interface [\#1666](https://github.com/zammad/zammad/issues/1666) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Users mail\_delivery\_failed is not removed after changing the email address [\#1661](https://github.com/zammad/zammad/issues/1661) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Tickets are deleted but database is still the same size [\#1649](https://github.com/zammad/zammad/issues/1649) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Ignore Twitter search key with only \# [\#1606](https://github.com/zammad/zammad/issues/1606) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Unable to sort overview by priority [\#1595](https://github.com/zammad/zammad/issues/1595) [[bug](https://github.com/zammad/zammad/labels/bug)]
## [2.1.0](https://github.com/zammad/zammad/tree/2.1.0) (2017-10-25)
[Full Changelog](https://github.com/zammad/zammad/compare/2.0.0...2.1.0)
**Implemented enhancements:**
- Added reporting feature.
- Added Minit support.
- Added Check_MK support.
- Moved to Ruby on Rails 5.1.
- leading and tailing utf8 spaces are not removed for email addresses are not removed [\#1579](https://github.com/zammad/zammad/issues/1579) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
- Import emails with same message\_id but target was different channels [\#1578](https://github.com/zammad/zammad/issues/1578) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
- Allow cti log entries to check done \(also if no hangup state is available\) [\#1478](https://github.com/zammad/zammad/issues/1478) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
- Selecting specific users for overviews [\#1418](https://github.com/zammad/zammad/issues/1418) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)] [[UX/UI](https://github.com/zammad/zammad/labels/UX/UI)]
- support Weibo OAuth2 login [\#1465](https://github.com/zammad/zammad/issues/1465) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
**Fixed bugs:**
- prevent admin from locking out [\#1563](https://github.com/zammad/zammad/issues/1563) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Unable to reindex tickets / elasticsearch error "MapperParsingException\[failed to parse \[article.ticket\]\]; nested: JsonParseException\[Current token \(START\_OBJECT\) not of boolean type" [\#1538](https://github.com/zammad/zammad/issues/1538) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Unable to show overview if selected order by attribute is not show in header [\#1528](https://github.com/zammad/zammad/issues/1528) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Cannot update notification preferences when nothing is selected [\#1276](https://github.com/zammad/zammad/issues/1276) [[bug](https://github.com/zammad/zammad/labels/bug)] [[notification](https://github.com/zammad/zammad/labels/notification)]
- ReplyAll - moves recipients from "To" to "CC" [\#1303](https://github.com/zammad/zammad/issues/1303) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Zammad sends reply to itself [\#986](https://github.com/zammad/zammad/issues/986) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Exchange Integration SSL Error with self-signed root certificate authority [\#1442](https://github.com/zammad/zammad/issues/1442) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Exchange Feature - URL? [\#1406](https://github.com/zammad/zammad/issues/1406) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Tickets sent by agent via email into Zammad have state open \(not new\) [\#1482](https://github.com/zammad/zammad/issues/1482) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Scheduler not running because of Bad file descriptor in PGConsumeInput\(\) [\#1405](https://github.com/zammad/zammad/issues/1405) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Icinga/Nagios Integration: No longer accepts regex in "Sender" [\#1439](https://github.com/zammad/zammad/issues/1439) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Invalidate cache when switching users [\#1280](https://github.com/zammad/zammad/issues/1280) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Job BackgroundJobSearchIndex NoMethodError: undefined method `lookup' for User::Permission:Module [\#1424](https://github.com/zammad/zammad/issues/1424) [[bug](https://github.com/zammad/zammad/labels/bug)]
- Profile not clickable on browsers with touch events or on some Chrome for Windows [\#1398](https://github.com/zammad/zammad/issues/1398) [[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)*

View File

@@ -1,6 +1,6 @@
GIT
remote: https://github.com/thorsteneckel/autodiscover.git
revision: 29d713ee0c8c25fcf74c4292ff13fe1fa4d0d827
revision: ee9b53dfa797ce6d4f970b82beea7fbdd2df56bb
specs:
autodiscover (1.0.2)
httpclient
@@ -221,7 +221,7 @@ GEM
mime-types (2.99.3)
mini_portile2 (2.3.0)
minitest (5.10.3)
multi_json (1.12.1)
multi_json (1.12.2)
multi_xml (0.6.0)
multipart-post (2.0.0)
mysql2 (0.4.9)

View File

@@ -148,24 +148,26 @@ class App.ControllerGenericIndex extends App.Controller
return item
)
# show description button, only if content exists
showDescription = false
if App[ @genericObject ].description && !_.isEmpty(objects)
showDescription = true
if !@table
@html App.view('generic/admin/index')(
head: @pageData.objects
notes: @pageData.notes
buttons: @pageData.buttons
menus: @pageData.menus
showDescription: showDescription
)
# show description button, only if content exists
showDescription = false
if App[ @genericObject ].description && !_.isEmpty(objects)
showDescription = true
# show description in content if no no content exists
if _.isEmpty(objects) && App[ @genericObject ].description
description = marked(App[ @genericObject ].description)
@$('.table-overview').html(description)
return
@html App.view('generic/admin/index')(
head: @pageData.objects
notes: @pageData.notes
buttons: @pageData.buttons
menus: @pageData.menus
showDescription: showDescription
)
# show description in content if no no content exists
if _.isEmpty(objects) && App[ @genericObject ].description
description = marked(App[ @genericObject ].description)
@$('.table-overview').html(description)
return
# append content table
params = _.extend(
@@ -184,7 +186,10 @@ class App.ControllerGenericIndex extends App.Controller
},
@pageData.tableExtend
)
new App.ControllerTable(params)
if !@table
@table = new App.ControllerTable(params)
else
@table.update(objects: objects)
edit: (id, e) =>
e.preventDefault()
@@ -1170,7 +1175,6 @@ class App.ObserverController extends App.Controller
if @globalRerender
@bind('ui:rerender', =>
@lastAttributres = undefined
console.log('aaaa', @model, @template)
@maybeRender(App[@model].fullLocal(@object_id))
)

View File

@@ -499,7 +499,6 @@ class App.ControllerTable extends App.Controller
orderBy = @customOrderBy || @orderBy
orderDirection = @customOrderDirection || @orderDirection
#console.log('LLL', @lastOrderBy, @orderBy, @lastOrderDirection, @orderDirection, @overviewAttributes, @lastOverview)
if @headers && @lastOrderBy is orderBy && @lastOrderDirection is orderDirection && !@tableHeadersHasChanged()
#console.log('tableHeaders: same overviewAttributes just return headers', @headers)
return ['headers are the same', @headers]
@@ -609,9 +608,10 @@ class App.ControllerTable extends App.Controller
@lastOrderDirection = orderDirection
@lastOrderBy = orderBy
localObjects is undefined
if orderBy
for header in @headers
if header.name is orderBy || "#{header.name}_id" is orderBy
if header.name is orderBy || "#{header.name}_id" is orderBy || header.name is "#{orderBy}_id"
localObjects = _.sortBy(
@objects
(item) ->
@@ -649,7 +649,7 @@ class App.ControllerTable extends App.Controller
# in case order by is not in show column, use orderBy attribute
if !localObjects
for attributeName, attribute of @attributesList
if attributeName is orderBy || "#{attributeName}_id" is orderBy
if attributeName is orderBy || "#{attributeName}_id" is orderBy || attributeName is "#{orderBy}_id"
# order by
localObjects = _.sortBy(
@@ -722,6 +722,7 @@ class App.ControllerTable extends App.Controller
localObjects = localObjects.concat groupObjects[group]
groupObjects[group] = [] # release old array
return if localObjects is undefined
@objects = localObjects
@lastSortedobjects = localObjects

View File

@@ -67,11 +67,15 @@ class App.ChannelForm extends App.ControllerSubContent
# rebuild preview
params.test = true
if params.modal
@$('.js-modal').removeClass('hide')
@$('.js-inlineForm').addClass('hide')
@$('.js-formInline').addClass('hide')
@$('.js-formBtn').removeClass('hide')
@$('.js-formBtn').ZammadForm(params)
@$('.js-formBtn').text('Feedback')
else
@$('.js-modal').addClass('hide')
@$('.js-inlineForm').removeClass('hide')
@$('.js-formBtn').addClass('hide')
@$('.js-formInline').removeClass('hide')
@$('.js-formInline').ZammadForm(params)

View File

@@ -174,17 +174,18 @@ class ConnectionWizard extends App.WizardModal
'js-mapping': 'mappingShow'
events:
'submit form.js-discover': 'discover'
'submit form.js-discoverSsl': 'discover'
'submit form.js-bind': 'folders'
'submit form.js-folders': 'mapping'
'click .js-cancelSsl': 'showSlideDiscover'
'click .js-mapping .js-submitTry': 'mappingChange'
'click .js-try .js-submitSave': 'save'
'click .js-close': 'hide'
'click .js-remove': 'removeRow'
'click .js-userMappingForm .js-add': 'addUserMapping'
'click .js-goToSlide': 'goToSlide'
'submit form.js-discover': 'discover'
'submit form.js-discoverCertificateIssue': 'discover'
'submit form.js-bind': 'folders'
'submit form.js-bindCertificateIssue': 'folders'
'submit form.js-folders': 'mapping'
'click .js-cancelSsl': 'showSlideDiscover'
'click .js-mapping .js-submitTry': 'mappingChange'
'click .js-try .js-submitSave': 'save'
'click .js-close': 'hide'
'click .js-remove': 'removeRow'
'click .js-userMappingForm .js-add': 'addUserMapping'
'click .js-goToSlide': 'goToSlide'
elements:
'.modal-body': 'body'
@@ -261,20 +262,17 @@ class ConnectionWizard extends App.WizardModal
processData: true
success: (data, status, xhr) =>
if data.result isnt 'ok'
if data.message.indexOf('certificate verify failed') is -1
@showSlide('js-discover')
@showAlert('js-discover', data.message)
else
@$('.js-discoverSsl input[name="user"]').val(params.user)
@$('.js-discoverSsl input[name="password"]').val(params.password)
@showSlide('js-discoverSsl')
@handleCertificateIssue(
message: data.message
wizardClass: 'js-discover'
user: params.user
password: params.password
)
return
@wizardConfig.endpoint = data.endpoint
@wizardConfig.user = params.user
@wizardConfig.password = params.password
@wizardConfig.disable_ssl_verify = params.disable_ssl_verify
@wizardConfig.user = params.user
@wizardConfig.password = params.password
@showSlide('js-bind')
@showBindDetails()
@@ -300,13 +298,19 @@ class ConnectionWizard extends App.WizardModal
processData: true
success: (data, status, xhr) =>
if data.result isnt 'ok'
@showSlide('js-bind')
@showAlert('js-bind', data.message)
@handleCertificateIssue(
message: data.message
wizardClass: 'js-bind'
endpoint: params.endpoint
user: params.user
password: params.password
)
return
@wizardConfig.endpoint = params.endpoint
@wizardConfig.user = params.user
@wizardConfig.password = params.password
@wizardConfig.disable_ssl_verify = params.disable_ssl_verify
@wizardConfig.endpoint = params.endpoint
@wizardConfig.user = params.user
@wizardConfig.password = params.password
# update wizard data
@wizardConfig.wizardData = {}
@@ -341,6 +345,45 @@ class ConnectionWizard extends App.WizardModal
@foldersSelectSubmit.addClass('is-disabled')
)
handleCertificateIssue: (params) =>
if params.message.indexOf('certificate') is -1
@showSlide(params.wizardClass)
@showAlert(params.wizardClass, params.message)
else
wizardClass = "#{params.wizardClass}CertificateIssue"
domain = @domainFromMessageOrEmail(
message: params.message
user: params.user
)
wizardSlide = App.view('integration/exchange_certificate_issue')(
wizardClass: wizardClass
endpoint: params.endpoint
user: params.user
password: params.password
domain: domain
)
@$('.js-certificateIssuePlaceholder').html(wizardSlide)
@showSlide(wizardClass)
domainFromMessageOrEmail: (params) ->
# try to extract the hostname from the error message
hostname = params.message.match(/hostname[ ]\"([^\"]+)"/i)
if hostname
return hostname[1]
# try to extract it from the given user
emailDomain = params.user.match(/@(.*)$/)
if emailDomain
return emailDomain[1]
# fallback to user - better than no value?!
return user
mapping: (e) =>
e.preventDefault()
@showSlide('js-analyze')

View File

@@ -1,7 +1,7 @@
class SidebarCustomer extends App.Controller
sidebarItem: =>
return if !@permissionCheck('ticket.agent')
return if !@params.customer_id
return if _.isEmpty(@params.customer_id)
{
head: 'Customer'
name: 'customer'
@@ -18,6 +18,7 @@ class SidebarCustomer extends App.Controller
showCustomer: (el) =>
@el = el
return if _.isEmpty(@params.customer_id)
new App.WidgetUser(
el: @el
user_id: @params.customer_id

View File

@@ -44,6 +44,8 @@ class App.IdoitObjectSelector extends App.ControllerModal
''
search: (filter) =>
if _.isEmpty(filter.type)
delete filter.type
if _.isEmpty(filter.title)
delete filter.title
else

View File

@@ -2121,7 +2121,7 @@ class TwitterConversationRef extends App.ControllerContent
open: 88
closed: 20
maxTextLength: 140
maxTextLength: 280
warningTextLength: 10
constructor: ->

View File

@@ -23,17 +23,22 @@ class Index extends App.ControllerSubContent
]
container: @el.closest('.content')
large: true
dndCallback: =>
dndCallback: (e, item) =>
items = @el.find('table > tbody > tr')
order = []
prios = []
prio = 0
for item in items
prio += 1
id = $(item).data('id')
overview = App.Overview.find(id)
if overview.prio isnt prio
overview.prio = prio
overview.save()
prios.push [id, prio]
@ajax(
id: 'overview_prio'
type: 'POST'
url: "#{@apiPath}/overviews_prio"
processData: true
data: JSON.stringify(prios: prios)
)
)
App.Config.set('Overview', { prio: 2300, name: 'Overviews', parent: '#manage', target: '#manage/overviews', controller: Index, permission: ['admin.overview'] }, 'NavBarAdmin')

View File

@@ -18,8 +18,19 @@ class App.TicketCustomer extends App.ControllerModal
onSubmit: (e) =>
params = @formParam(e.target)
@customer_id = params['customer_id']
ticket = App.Ticket.find(@ticket_id)
ticket.customer_id = params['customer_id']
errors = ticket.validate()
if !_.isEmpty(errors)
@log 'error', errors
@formValidate(
form: e.target
errors: errors
)
return
@customer_id = params['customer_id']
callback = =>
# close modal

View File

@@ -144,7 +144,7 @@ class App.TicketZoomArticleNew extends App.Controller
attributes: []
internal: false,
features: ['body:limit', 'body:initials']
maxTextLength: 140
maxTextLength: 280
warningTextLength: 30
}
if possibleArticleType['twitter direct-message']

View File

@@ -77,7 +77,7 @@ class App._CollectionSingletonBase
callback: (data) =>
for counter, attr of @callbacks
callback = ->
callback = =>
attr.callback(data)
if attr.one
delete @callbacks[counter]

View File

@@ -71,7 +71,7 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
@open()
focusInput: =>
@objectSelect.focus() if not @formControl.hasClass 'focus'
@objectSelect.focus() if not @formControl.hasClass('focus')
onBlur: =>
selectObject = @objectSelect.val()
@@ -85,6 +85,9 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
@objectId.val("guess:#{selectObject}")
@formControl.removeClass 'focus'
resetObjectSelection: =>
@objectId.val('').trigger('change')
onObjectClick: (e) =>
objectId = $(e.currentTarget).data('object-id')
@selectObject(objectId)
@@ -103,23 +106,23 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
# Only work with the last one since its the newest one
objectId = @objectId.val().split(',').pop()
return if !objectId
return if !App[@objectSingle].exists(objectId)
object = App[@objectSingle].find(objectId)
name = object.displayName()
if objectId && App[@objectSingle].exists(objectId)
object = App[@objectSingle].find(objectId)
name = object.displayName()
if @attribute.multiple
# create token
@createToken name, objectId
else
if object.email
if @attribute.multiple
# quote name for special character
if name.match(/\@|,|;|\^|\+|#|§|\$|%|&|\/|\(|\)|=|\?|!|\*|\[|\]/)
name = "\"#{name}\""
name += " <#{object.email}>"
# create token
@createToken(name, objectId)
else
if object.email
@objectSelect.val(name)
# quote name for special character
if name.match(/\@|,|;|\^|\+|#|§|\$|%|&|\/|\(|\)|=|\?|!|\*|\[|\]/)
name = "\"#{name}\""
name += " <#{object.email}>"
@objectSelect.val(name)
if @callback
@callback(objectId)
@@ -321,12 +324,16 @@ class App.ObjectOrganizationAutocompletion extends App.Controller
@hideOrganizationMembers()
# hide dropdown
if !query
if _.isEmpty(query)
@emptyResultList()
if !@attribute.disableCreateObject
@recipientList.append(@buildObjectNew())
# reset object selection
@resetObjectSelection()
return
# show dropdown
if query && ( !@attribute.minLengt || @attribute.minLengt <= query.length )
@lazySearch(query)

View File

@@ -196,7 +196,7 @@ set new attributes of model (remove already available attributes)
for attribute in attributes
App[@.className].attributes.push attribute.name
attributesNew.push attribute
App[ @.className ].configure_attributes = attributesNew
App[@.className].configure_attributes = attributesNew
###
@@ -226,7 +226,7 @@ set new attributes of model (remove already available attributes)
@attributesGet: (screen = undefined, attributes = false, noDefaultAttributes = false) ->
if !attributes
attributes = clone(App[ @.className ].configure_attributes, true)
attributes = clone(App[@.className].configure_attributes, true)
else
attributes = clone(attributes, true)
@@ -387,15 +387,17 @@ set new attributes of model (remove already available attributes)
=>
return if _.isEmpty(@SUBSCRIPTION_COLLECTION)
App.Log.debug('Model', "server notify collection change #{@className}")
@fetchFull(
->
clear: true
)
callback = =>
@fetchFull(
->
clear: true
)
App.Delay.set(callback, 200, "full-#{@className}")
"Collection::Subscribe::#{@className}"
)
key = @className + '-' + Math.floor( Math.random() * 99999 )
key = "#{@className}-#{Math.floor(Math.random() * 99999)}"
@SUBSCRIPTION_COLLECTION[key] = callback
# fetch init collection

View File

@@ -1,5 +1,5 @@
class App.Overview extends App.Model
@configure 'Overview', 'name', 'prio', 'condition', 'order', 'group_by', 'view', 'user_ids', 'organization_shared', 'role_ids', 'order', 'group_by', 'active', 'updated_at'
@configure 'Overview', 'name', 'prio', 'condition', 'order', 'group_by', 'view', 'user_ids', 'organization_shared', 'role_ids', 'active'
@extend Spine.Model.Ajax
@url: @apiPath + '/overviews'
@configure_attributes = [

View File

@@ -200,6 +200,26 @@ class App.Ticket extends App.Model
result = true if objectValue.toString().match(contains_regex)
else if condition.operator == 'contains not'
result = true if !objectValue.toString().match(contains_regex)
else if condition.operator == 'contains all'
result = true
for loopConditionValue in conditionValue
if !_.contains(objectValue, loopConditionValue)
result = false
else if condition.operator == 'contains one'
result = false
for loopConditionValue in conditionValue
if _.contains(objectValue, loopConditionValue)
result = true
else if condition.operator == 'contains all not'
result = true
for loopObjectValue in objectValue
if _.contains(conditionValue, loopObjectValue)
result = false
else if condition.operator == 'contains one not'
result = false
for loopObjectValue in objectValue
if !_.contains(conditionValue, loopObjectValue)
result = true
else if condition.operator == 'is'
result = true if objectValue.toString().trim().toLowerCase() is loopConditionValue.toString().trim().toLowerCase()
else if condition.operator == 'is not'

View File

@@ -132,7 +132,7 @@
<p><%- @T('You need to add the following Javascript code snippet to your web page') %>:</p>
<pre><code class="language-html js-paramsBlock">&lt;button id="feedback-form"&gt;Feedback&lt;/button&gt;
<pre class="js-modal"><code class="language-html js-code js-paramsBlock">&lt;button id="feedback-form"&gt;Feedback&lt;/button&gt;
&lt;script id="zammad_form_script" src="<%= @baseurl %>/assets/form/form.js"&gt;&lt;/script&gt;
@@ -144,3 +144,16 @@ $(function() {
});
&lt;/script&gt;</code></pre>
</div>
<pre class="js-inlineForm"><code class="language-html js-code js-paramsBlock">&lt;div id="feedback-form"&gt;form will be placed in here&lt;/div&gt;
&lt;script id="zammad_form_script" src="<%= @baseurl %>/assets/form/form.js"&gt;&lt;/script&gt;
&lt;script&gt;
$(function() {
$('#feedback-form').ZammadForm({
<span class="js-modal-params"></span>
});
});
&lt;/script&gt;</code></pre>
</div>

View File

@@ -0,0 +1,25 @@
<form class="modal-content setup wizard hide <%= @wizardClass %>">
<input type="hidden" name="disable_ssl_verify" value="1">
<input type="hidden" name="endpoint" value="<%= @endpoint %>">
<input type="hidden" name="user" value="<%= @user %>">
<input type="hidden" name="password" value="<%= @password %>">
<div class="modal-header">
<div class="modal-close js-close">
<%- @Icon('diagonal-cross') %>
</div>
<h1 class="modal-title"><%- @T('Your connection is not private') %></h1>
</div>
<div class="modal-body">
<div class="wizard-body vertical">
<p><%- @T('The certificate of the domain |%s| could not be verified. This may allow hackers to steal your credentials. If you are sure that you are using a self-signed certificate, you can press "Proceed". Otherwise, please "Cancel".', @domain) %></p>
</div>
</div>
<div class="modal-footer">
<div class="modal-leftFooter">
<button class="btn btn--text btn--danger btn--secondary js-submit"><%- @T('Proceed') %></button>
</div>
<div class="modal-rightFooter">
<a class="btn btn--primary align-right js-cancelSsl"><%- @T('Cancel') %></a>
</div>
</div>
</form>

View File

@@ -19,7 +19,7 @@
<tbody>
<tr>
<td class="settings-list-row-control"><%- @T('User') %>
<td class="settings-list-control-cell"><input type="text" name="user" class="form-control form-control--small js-user" value="" placeholder="" autocomplete="off" required>
<td class="settings-list-control-cell"><input type="text" name="user" class="form-control form-control--small js-user" value="" placeholder="user@your-exchange.tld" autocomplete="off" required>
<tr>
<td class="settings-list-row-control"><%- @T('Password') %>
<td class="settings-list-control-cell"><input type="password" name="password" class="form-control form-control--small js-password" value="" placeholder="" autocomplete="new-password" required>
@@ -34,30 +34,7 @@
</div>
</form>
<form class="modal-content setup wizard hide js-discoverSsl">
<input type="hidden" name="disable_ssl_verify" value="1">
<input type="hidden" name="user" value="">
<input type="hidden" name="password" value="">
<div class="modal-header">
<div class="modal-close js-close">
<%- @Icon('diagonal-cross') %>
</div>
<h1 class="modal-title"><%- @T('Your connection is not private') %></h1>
</div>
<div class="modal-body">
<div class="wizard-body vertical">
<p><%- @T('The certificate of the domain could not be verified. Hackers could steal the credentials or redirect the connection. Or maybe you are using a self-signed certificate.') %></p>
</div>
</div>
<div class="modal-footer">
<div class="modal-leftFooter">
<button class="btn btn--text btn--danger btn--secondary js-submit"><%- @T('Proceed') %></button>
</div>
<div class="modal-rightFooter">
<a class="btn btn--primary align-right js-cancelSsl"><%- @T('Cancel') %></a>
</div>
</div>
</form>
<div class="js-certificateIssuePlaceholder"></div>
<form class="modal-content setup wizard hide js-connect">
<div class="modal-header">

View File

@@ -440,7 +440,7 @@
</div>
<div class="textBubble-footer">
<div class="textBubble-signatur"><span class="js-signature">/je</span></div>
<div class="textBubble-letterCount js-letterCount">140</div>
<div class="textBubble-letterCount js-letterCount">280</div>
</div>
</div>
</div>

View File

@@ -241,7 +241,7 @@ class FormController < ApplicationController
def enabled?
return true if params[:test] && current_user && current_user.permissions?('admin.channel_formular')
return true if Setting.get('form_ticket_create') && Setting.get('customer_ticket_create')
return true if Setting.get('form_ticket_create')
response_access_deny
false
end

View File

@@ -26,11 +26,7 @@ class Integration::ExchangeController < ApplicationController
answer_with do
Sequencer.process('Import::Exchange::AvailableFolders',
parameters: {
ews_config: {
endpoint: params[:endpoint],
user: params[:user],
password: params[:password],
}
ews_config: ews_config
})
end
end
@@ -42,11 +38,7 @@ class Integration::ExchangeController < ApplicationController
examples = Sequencer.process('Import::Exchange::AttributesExamples',
parameters: {
ews_folder_ids: params[:folders],
ews_config: {
endpoint: params[:endpoint],
user: params[:user],
password: params[:password],
}
ews_config: ews_config
})
examples.tap do |result|
raise 'No entries found in selected folder(s).' if result[:attributes].blank?
@@ -61,15 +53,20 @@ class Integration::ExchangeController < ApplicationController
{
ews_attributes: params[:attributes].permit!.to_h,
ews_folder_ids: params[:folders],
ews_config: {
endpoint: params[:endpoint],
user: params[:user],
password: params[:password],
}
ews_config: ews_config
}
end
def payload_import
nil
end
def ews_config
{
disable_ssl_verify: params[:disable_ssl_verify],
endpoint: params[:endpoint],
user: params[:user],
password: params[:password],
}
end
end

View File

@@ -30,7 +30,7 @@ Example:
=begin
Resource:
GET /api/v1/overviews.json
GET /api/v1/overviews
Response:
[
@@ -47,7 +47,7 @@ Response:
]
Test:
curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password}
curl http://localhost/api/v1/overviews -v -u #{login}:#{password}
=end
@@ -58,7 +58,7 @@ curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password}
=begin
Resource:
GET /api/v1/overviews/#{id}.json
GET /api/v1/overviews/#{id}
Response:
{
@@ -68,7 +68,7 @@ Response:
}
Test:
curl http://localhost/api/v1/overviews/#{id}.json -v -u #{login}:#{password}
curl http://localhost/api/v1/overviews/#{id} -v -u #{login}:#{password}
=end
@@ -79,7 +79,7 @@ curl http://localhost/api/v1/overviews/#{id}.json -v -u #{login}:#{password}
=begin
Resource:
POST /api/v1/overviews.json
POST /api/v1/overviews
Payload:
{
@@ -101,7 +101,7 @@ Response:
}
Test:
curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X POST -d '{"name": "some_name","active": true, "note": "some note"}'
curl http://localhost/api/v1/overviews -v -u #{login}:#{password} -H "Content-Type: application/json" -X POST -d '{"name": "some_name","active": true, "note": "some note"}'
=end
@@ -112,7 +112,7 @@ curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password} -H "Conte
=begin
Resource:
PUT /api/v1/overviews/{id}.json
PUT /api/v1/overviews/{id}
Payload:
{
@@ -134,7 +134,7 @@ Response:
}
Test:
curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X PUT -d '{"name": "some_name","active": true, "note": "some note"}'
curl http://localhost/api/v1/overviews -v -u #{login}:#{password} -H "Content-Type: application/json" -X PUT -d '{"name": "some_name","active": true, "note": "some note"}'
=end
@@ -145,17 +145,55 @@ curl http://localhost/api/v1/overviews.json -v -u #{login}:#{password} -H "Conte
=begin
Resource:
DELETE /api/v1/overviews/{id}.json
DELETE /api/v1/overviews/{id}
Response:
{}
Test:
curl http://localhost/api/v1/overviews/#{id}.json -v -u #{login}:#{password} -H "Content-Type: application/json" -X DELETE
curl http://localhost/api/v1/overviews/#{id} -v -u #{login}:#{password} -H "Content-Type: application/json" -X DELETE
=end
def destroy
model_destroy_render(Overview, params)
end
=begin
Resource:
POST /api/v1/overviews_prio
Payload:
{
"prios": [
[overview_id, prio],
[overview_id, prio],
[overview_id, prio],
[overview_id, prio],
[overview_id, prio]
]
}
Response:
{
"success": true,
}
Test:
curl http://localhost/api/v1/overviews_prio -v -u #{login}:#{password} -H "Content-Type: application/json" -X POST -d '{"prios": [ [1,1], [44,2] ]}'
=end
def prio
Overview.without_callback(:update, :before, :rearrangement) do
params[:prios].each do |overview_prio|
overview = Overview.find(overview_prio[0])
next if overview.prio == overview_prio[1]
overview.prio = overview_prio[1]
overview.save!
end
end
render json: { success: true }, status: :ok
end
end

View File

@@ -75,12 +75,12 @@ get assets and record_ids of selector
attribute_ref_class = models[attribute_class][:reflections][reflection].klass
if content['value'].instance_of?(Array)
content['value'].each do |item_id|
attribute_object = attribute_ref_class.find_by(id: item_id)
if attribute_object
assets = attribute_object.assets(assets)
end
next if item_id.blank?
attribute_object = attribute_ref_class.lookup(id: item_id)
next if !attribute_object
assets = attribute_object.assets(assets)
end
else
elsif content['value'].present?
attribute_object = attribute_ref_class.find_by(id: content['value'])
if attribute_object
assets = attribute_object.assets(assets)
@@ -138,11 +138,11 @@ get assets of object list
require item['object'].to_filename
record = Kernel.const_get(item['object']).find(item['o_id'])
assets = record.assets(assets)
if item['created_by_id']
if item['created_by_id'].present?
user = User.find(item['created_by_id'])
assets = user.assets(assets)
end
if item['updated_by_id']
if item['updated_by_id'].present?
user = User.find(item['updated_by_id'])
assets = user.assets(assets)
end

View File

@@ -223,6 +223,7 @@ returns
hashtags = []
sync['search'].each do |item|
next if item['term'].blank?
next if item['term'] == '#'
next if item['group_id'].blank?
hashtags.push item['term']
end
@@ -275,6 +276,7 @@ returns
hit = false
sync['search'].each do |item|
next if item['term'].blank?
next if item['term'] == '#'
next if item['group_id'].blank?
tweet.hashtags.each do |hashtag|
next if item['term'] !~ /^#/
@@ -295,6 +297,7 @@ returns
body = tweet.text
sync['search'].each do |item|
next if item['term'].blank?
next if item['term'] == '#'
next if item['group_id'].blank?
if body =~ /#{item['term']}/
hit = item
@@ -314,6 +317,7 @@ returns
return if @sync[:search].blank?
@sync[:search].each do |search|
next if search[:term].blank?
next if search[:term] == '#'
next if search[:group_id].blank?
result_type = search[:type] || 'mixed'
Rails.logger.debug " - searching for '#{search[:term]}'"

View File

@@ -22,9 +22,9 @@ module Channel::Filter::IdentifySender
if !customer_user && mail[ 'x-zammad-customer-email'.to_sym ].present?
customer_user = User.find_by(email: mail[ 'x-zammad-customer-email'.to_sym ])
end
if !customer_user
# get correct customer
# get correct customer
if !customer_user && Setting.get('postmaster_sender_is_agent_search_for_customer') == true
if mail[ 'x-zammad-ticket-create-article-sender'.to_sym ] == 'Agent'
# get first recipient and set customer
@@ -46,18 +46,21 @@ module Channel::Filter::IdentifySender
end
end
rescue => e
Rails.logger.error 'ERROR: SenderIsSystemAddress: ' + e.inspect
Rails.logger.error "SenderIsSystemAddress: ##{e.inspect}"
end
end
if !customer_user
customer_user = user_create(
login: mail[ 'x-zammad-customer-login'.to_sym ] || mail[ 'x-zammad-customer-email'.to_sym ] || mail[:from_email],
firstname: mail[ 'x-zammad-customer-firstname'.to_sym ] || mail[:from_display_name],
lastname: mail[ 'x-zammad-customer-lastname'.to_sym ],
email: mail[ 'x-zammad-customer-email'.to_sym ] || mail[:from_email],
)
end
end
# take regular from as customer
if !customer_user
customer_user = user_create(
login: mail[ 'x-zammad-customer-login'.to_sym ] || mail[ 'x-zammad-customer-email'.to_sym ] || mail[:from_email],
firstname: mail[ 'x-zammad-customer-firstname'.to_sym ] || mail[:from_display_name],
lastname: mail[ 'x-zammad-customer-lastname'.to_sym ],
email: mail[ 'x-zammad-customer-email'.to_sym ] || mail[:from_email],
)
end
create_recipients(mail)
mail[ 'x-zammad-ticket-customer_id'.to_sym ] = customer_user.id

View File

@@ -4,31 +4,48 @@ class Observer::Ticket::LastOwnerUpdate < ActiveRecord::Observer
observe 'ticket'
def before_create(record)
_check('create', record)
_check(record)
end
def before_update(record)
_check('update', record)
_check(record)
end
private
def _check(type, record)
def _check(record)
# return if we run import mode
return true if Setting.get('import_mode')
# check if owner has changed
if type == 'update'
return true if record.changes_to_save['owner_id'].blank?
end
# check if owner, state or group has changed
return true if record.changes_to_save['owner_id'].blank? && record.changes_to_save['state_id'].blank? && record.changes_to_save['group_id'].blank? && record.changes_to_save['last_contact_agent_at'].blank?
# check if owner is nobody
if record.owner_id.blank? || record.owner_id == 1
if record.changes_to_save['owner_id'].present? && record.changes_to_save['owner_id'][1] == 1
record.last_owner_update_at = nil
return true
end
# check if group is change
if record.changes_to_save['group_id'].present?
group = Group.lookup(id: record.changes_to_save['group_id'][1])
return true if !group
if group.assignment_timeout.blank? || group.assignment_timeout.zero?
record.last_owner_update_at = nil
return true
end
end
# check if state is not new/open
if record.changes_to_save['state_id'].present?
state_ids = Ticket::State.by_category(:work_on).pluck(:id)
if !state_ids.include?(record.changes_to_save['state_id'][1])
record.last_owner_update_at = nil
return true
end
end
record.last_owner_update_at = Time.zone.now
end
end

View File

@@ -17,26 +17,47 @@ class Overview < ApplicationModel
validates :name, presence: true
before_create :fill_link_on_create, :fill_prio
before_update :fill_link_on_update
before_update :fill_link_on_update, :rearrangement
private
def rearrangement
return true if !changes['prio']
prio = 0
Overview.all.order(prio: :asc, updated_at: :desc).pluck(:id).each do |overview_id|
prio += 1
next if id == overview_id
Overview.without_callback(:update, :before, :rearrangement) do
overview = Overview.find(overview_id)
next if overview.prio == prio
overview.prio = prio
overview.save!
end
end
end
def fill_prio
return true if prio
self.prio = 9999
return true if prio.present?
self.prio = Overview.count + 1
true
end
def fill_link_on_create
return true if link.present?
self.link = link_name(name)
self.link = if link.present?
link_name(link)
else
link_name(name)
end
true
end
def fill_link_on_update
return true if !changes['name']
return true if changes['link']
self.link = link_name(name)
return true if !changes['name'] && !changes['link']
self.link = if link.present?
link_name(link)
else
link_name(name)
end
true
end
@@ -50,12 +71,16 @@ class Overview < ApplicationModel
local_link = id || rand(999)
end
check = true
count = 0
local_lookup_link = local_link
while check
exists = Overview.find_by(link: local_link)
count += 1
exists = Overview.find_by(link: local_lookup_link)
if exists && exists.id != id
local_link = "#{local_link}_#{rand(999)}"
local_lookup_link = "#{local_link}_#{count}"
else
check = false
local_link = local_lookup_link
end
end
local_link

View File

@@ -42,9 +42,7 @@ returns
data = user.assets(data)
end
end
data = assets_of_selector('condition', data)
end
%w(created_by_id updated_by_id).each do |local_user_id|
next if !self[ local_user_id ]

View File

@@ -47,7 +47,7 @@ returns
data.delete('object')
# store meta data
store = Store.create(data)
store = Store.create!(data)
store
end
@@ -123,17 +123,18 @@ remove one attachment from storage
=end
def self.remove_item(store_id)
store = Store.find(store_id)
file_id = store.store_file_id
store.destroy
# check backend for references
files = Store.where(store_file_id: file_id)
return if files.count != 1
return if files.first.id != store.id
if files.count > 1 || files.first.id != store.id
store.destroy!
return true
end
Store::File.find(file_id).destroy
store.destroy!
Store::File.find(file_id).destroy!
end
=begin

View File

@@ -249,7 +249,7 @@ returns
return [] if groups.blank?
groups.each do |group|
next if group.assignment_timeout.blank?
ticket_ids = Ticket.where('state_id IN (?) AND owner_id != 1 AND group_id = ?', state_ids, group.id).limit(600).pluck(:id)
ticket_ids = Ticket.where('state_id IN (?) AND owner_id != 1 AND group_id = ? AND last_owner_update_at IS NOT NULL', state_ids, group.id).limit(600).pluck(:id)
ticket_ids.each do |ticket_id|
ticket = Ticket.find_by(id: ticket_id)
next if !ticket
@@ -922,7 +922,7 @@ perform changes on ticket
ticket_id: id,
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'email'),
).where("ticket_articles.created_at > ? AND ticket_articles.to LIKE '%#{recipient_email.strip}%'", Time.zone.now - minutes.minutes).count
).where('ticket_articles.created_at > ? AND ticket_articles.to LIKE ?', Time.zone.now - minutes.minutes, "%#{recipient_email.strip}%").count
next if already_sent < count
logger.info "Send no trigger based notification to #{recipient_email} because already sent #{count} for this ticket within last #{minutes} minutes (loop protection)"
skip = true
@@ -941,7 +941,7 @@ perform changes on ticket
already_sent = Ticket::Article.where(
sender: Ticket::Article::Sender.find_by(name: 'System'),
type: Ticket::Article::Type.find_by(name: 'email'),
).where("ticket_articles.created_at > ? AND ticket_articles.to LIKE '%#{recipient_email.strip}%'", Time.zone.now - minutes.minutes).count
).where('ticket_articles.created_at > ? AND ticket_articles.to LIKE ?', Time.zone.now - minutes.minutes, "%#{recipient_email.strip}%").count
next if already_sent < count
logger.info "Send no trigger based notification to #{recipient_email} because already sent #{count} in total within last #{minutes} minutes (loop protection)"
skip = true

View File

@@ -18,6 +18,7 @@ class Ticket::Article < ApplicationModel
store :preferences
before_create :check_subject, :check_body, :check_message_id_md5
before_update :check_subject, :check_body, :check_message_id_md5
after_destroy :store_delete
sanitized_html :body
@@ -316,6 +317,18 @@ returns
}
end
# delete attachments and mails of article
def store_delete
Store.remove(
object: 'Ticket::Article',
o_id: id,
)
Store.remove(
object: 'Ticket::Article::Mail',
o_id: id,
)
end
class Flag < ApplicationModel
end

View File

@@ -4,6 +4,9 @@ class Trigger < ApplicationModel
include ChecksConditionValidation
include CanSeed
load 'trigger/assets.rb'
include Trigger::Assets
store :condition
store :perform
validates :name, presence: true

View File

@@ -0,0 +1,50 @@
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
class Trigger
module Assets
=begin
get all assets / related models for this trigger
trigger = Trigger.find(123)
result = trigger.assets(assets_if_exists)
returns
result = {
:triggers => {
123 => trigger_model_123,
1234 => trigger_model_1234,
}
}
=end
def assets(data)
app_model_overview = Trigger.to_app_model
app_model_user = User.to_app_model
if !data[ app_model_overview ]
data[ app_model_overview ] = {}
end
if !data[ app_model_user ]
data[ app_model_user ] = {}
end
if !data[ app_model_overview ][ id ]
data[ app_model_overview ][ id ] = attributes_with_association_ids
data = assets_of_selector('condition', data)
data = assets_of_selector('perform', data)
end
%w(created_by_id updated_by_id).each do |local_user_id|
next if !self[ local_user_id ]
next if data[ app_model_user ][ self[ local_user_id ] ]
user = User.lookup(id: self[ local_user_id ])
next if !user
data = user.assets(data)
end
data
end
end
end

View File

@@ -38,7 +38,7 @@ class User < ApplicationModel
load 'user/search_index.rb'
include User::SearchIndex
before_validation :check_name, :check_email, :check_login, :ensure_uniq_email, :ensure_password, :ensure_roles, :ensure_identifier
before_validation :check_name, :check_email, :check_login, :check_mail_delivery_failed, :ensure_uniq_email, :ensure_password, :ensure_roles, :ensure_identifier
before_create :check_preferences_default, :validate_ooo, :domain_based_assignment, :set_locale
before_update :check_preferences_default, :validate_ooo, :reset_login_failed, :validate_agent_limit_by_attributes, :last_admin_check_by_attribute
after_create :avatar_for_email_check
@@ -945,6 +945,12 @@ returns
true
end
def check_mail_delivery_failed
return true if !changes || !changes['email']
preferences.delete(:mail_delivery_failed)
true
end
def ensure_roles
return true if role_ids.present?
self.role_ids = Role.signup_role_ids

View File

@@ -7,5 +7,6 @@ Zammad::Application.routes.draw do
match api_path + '/overviews', to: 'overviews#create', via: :post
match api_path + '/overviews/:id', to: 'overviews#update', via: :put
match api_path + '/overviews/:id', to: 'overviews#destroy', via: :delete
match api_path + '/overviews_prio', to: 'overviews#prio', via: :post
end

View File

@@ -1,57 +0,0 @@
class LastOwnerUpdate < ActiveRecord::Migration[4.2]
def up
# return if it's a new setup
return if !Setting.find_by(name: 'system_init_done')
# reset assignment_timeout to prevent unwanted things happen
Group.all.each do |group|
group.assignment_timeout = nil
group.save!
end
add_column :tickets, :last_owner_update_at, :timestamp, limit: 3, null: true
add_index :tickets, [:last_owner_update_at]
Ticket.reset_column_information
Scheduler.create_if_not_exists(
name: 'Process auto unassign tickets',
method: 'Ticket.process_auto_unassign',
period: 10.minutes,
prio: 1,
active: true,
updated_by_id: 1,
created_by_id: 1,
)
state_ids = Ticket::State.by_category(:work_on).pluck(:id)
if state_ids.present?
ticket_ids = Ticket.where('tickets.state_id IN (?) AND tickets.owner_id != 1', state_ids).order(created_at: :desc).limit(1000).pluck(:id)
ticket_ids.each do |ticket_id|
ticket = Ticket.find_by(id: ticket_id)
next if !ticket
ticket.last_owner_update_at = last_owner_update_at(ticket)
ticket.save!
end
end
end
def last_owner_update_at(ticket)
type = History::Type.lookup(name: 'updated')
if type
object = History::Object.lookup(name: 'Ticket')
if object
attribute = History::Attribute.lookup(name: 'owner')
if attribute
history = History.where(o_id: ticket.id, history_type_id: type.id, history_object_id: object.id, history_attribute_id: attribute.id).where.not(id_to: 1).order(created_at: :desc).limit(1)
if history.present?
return history.first.created_at
end
end
end
end
return nil if ticket.owner_id == 1
ticket.created_at
end
end

View File

@@ -0,0 +1,32 @@
class LastOwnerUpdate2 < ActiveRecord::Migration[5.1]
def up
# return if it's a new setup
return if !Setting.find_by(name: 'system_init_done')
# reset assignment_timeout to prevent unwanted things happen
Group.all.each do |group|
group.assignment_timeout = nil
group.save!
end
# check if column already exists
if !ActiveRecord::Base.connection.column_exists?(:tickets, :last_owner_update_at)
add_column :tickets, :last_owner_update_at, :timestamp, limit: 3, null: true
add_index :tickets, [:last_owner_update_at]
Ticket.reset_column_information
end
Scheduler.create_if_not_exists(
name: 'Process auto unassign tickets',
method: 'Ticket.process_auto_unassign',
period: 10.minutes,
prio: 1,
active: true,
updated_by_id: 1,
created_by_id: 1,
)
Cache.clear
end
end

View File

@@ -0,0 +1,34 @@
class EmailProcessCustomerSelectionBasedOnSenderRecipient < ActiveRecord::Migration[4.2]
def up
# return if it's a new setup
return if !Setting.find_by(name: 'system_init_done')
Setting.create_if_not_exists(
title: 'Customer selection based on sender and receiver list',
name: 'postmaster_sender_is_agent_search_for_customer',
area: 'Email::Base',
description: 'If the sender is an agent, set the first user in the recipient list as a customer.',
options: {
form: [
{
display: '',
null: true,
name: 'postmaster_sender_is_agent_search_for_customer',
tag: 'boolean',
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: true,
preferences: {
permission: ['admin.channel_email'],
},
frontend: false
)
end
end

View File

@@ -2022,6 +2022,32 @@ Setting.create_if_not_exists(
frontend: false
)
Setting.create_if_not_exists(
title: 'Customer selection based on sender and receiver list',
name: 'postmaster_sender_is_agent_search_for_customer',
area: 'Email::Base',
description: 'If the sender is an agent, set the first user in the recipient list as a customer.',
options: {
form: [
{
display: '',
null: true,
name: 'postmaster_sender_is_agent_search_for_customer',
tag: 'boolean',
options: {
true => 'yes',
false => 'no',
},
},
],
},
state: true,
preferences: {
permission: ['admin.channel_email'],
},
frontend: false
)
Setting.create_if_not_exists(
title: 'Notification Sender',
name: 'notification_sender',

View File

@@ -10,7 +10,8 @@ fill your database with demo records
customers: 1000,
groups: 20,
organizations: 40,
tickets: 100
overviews: 5,
tickets: 100,
)
or if you only want to create 100 tickets
@@ -25,6 +26,7 @@ or if you only want to create 100 tickets
customers = params[:customers] || 0
groups = params[:groups] || 0
organizations = params[:organizations] || 0
overviews = params[:overviews] || 0
tickets = params[:tickets] || 0
puts 'load db with:'
@@ -32,6 +34,7 @@ or if you only want to create 100 tickets
puts " customers:#{customers}"
puts " groups:#{groups}"
puts " organizations:#{organizations}"
puts " overviews:#{overviews}"
puts " tickets:#{tickets}"
# set current user
@@ -39,7 +42,7 @@ or if you only want to create 100 tickets
# organizations
organization_pool = []
if organizations && !organizations.zero?
if !organizations.zero?
(1..organizations).each do
ActiveRecord::Base.transaction do
organization = Organization.create!(name: "FillOrganization::#{rand(999_999)}", active: true)
@@ -53,7 +56,7 @@ or if you only want to create 100 tickets
# create agents
agent_pool = []
if agents && !agents.zero?
if !agents.zero?
roles = Role.where(name: [ 'Agent'])
groups_all = Group.all
@@ -81,7 +84,7 @@ or if you only want to create 100 tickets
# create customer
customer_pool = []
if customers && !customers.zero?
if !customers.zero?
roles = Role.where(name: [ 'Customer'])
groups_all = Group.all
@@ -113,7 +116,7 @@ or if you only want to create 100 tickets
# create groups
group_pool = []
if groups && !groups.zero?
if !groups.zero?
(1..groups).each do
ActiveRecord::Base.transaction do
@@ -133,6 +136,35 @@ or if you only want to create 100 tickets
puts " take #{group_pool.length} groups"
end
# create overviews
if !overviews.zero?
(1..overviews).each do
ActiveRecord::Base.transaction do
overview = Overview.create!(
name: "Filloverview::#{rand(999_999)}",
role_ids: [Role.find_by(name: 'Agent').id],
condition: {
'ticket.state_id' => {
operator: 'is',
value: Ticket::State.by_category(:work_on_all).pluck(:id),
},
},
order: {
by: 'created_at',
direction: 'ASC',
},
view: {
d: %w(title customer group state owner created_at),
s: %w(title customer group state owner created_at),
m: %w(number title customer group state owner created_at),
view_mode_default: 's',
},
active: true
)
end
end
end
# create tickets
priority_pool = Ticket::Priority.all
state_pool = Ticket::State.all

View File

@@ -151,6 +151,12 @@ class Ldap
params[:encryption] = @encryption
end
# special workaround for IBM bluepages
# see issue #1422 for more details
if @host == 'bluepages.ibm.com'
params[:force_no_page] = true
end
params
end

View File

@@ -11,12 +11,37 @@ class Sequencer
return if state.provided?(:ews_connection)
state.provide(:ews_connection) do
config = ews_config
config ||= ::Import::Exchange.config
Viewpoint::EWSClient.new(config[:endpoint], config[:user], config[:password])
Viewpoint::EWSClient.new(
config[:endpoint],
config[:user],
config[:password],
additional_opts
)
end
end
private
def config
@config ||= begin
ews_config || ::Import::Exchange.config
end
end
def additional_opts
@additional_opts ||= begin
http_opts
end
end
def http_opts
return {} if config[:disable_ssl_verify].blank?
{
http_opts: {
ssl_verify_mode: OpenSSL::SSL::VERIFY_NONE
}
}
end
end
end
end

View File

@@ -579,7 +579,7 @@ remove all session and spool messages
next if !session_data
next if !session_data[:user]
next if !session_data[:user]['id']
user = User.lookup( id: session_data[:user]['id'] )
user = User.lookup(id: session_data[:user]['id'])
next if !user
# start client thread
@@ -590,7 +590,9 @@ remove all session and spool messages
thread_client(client_id)
@@client_threads[client_id] = nil
log('debug', "close client (#{client_id}) thread")
ActiveRecord::Base.connection.close
if ActiveRecord::Base.connection.owner == Thread.current
ActiveRecord::Base.connection.close
end
end
sleep 0.5
end

View File

@@ -228,6 +228,22 @@ do($ = window.jQuery, window) ->
'Since you didn\'t respond in the last %s minutes your conversation with <strong>%s</strong> got closed.': 'Si vous ne répondez pas dans les <strong>%s</strong> minutes, votre conversation avec %s va être fermée.'
'Since you didn\'t respond in the last %s minutes your conversation got closed.': 'Si vous ne répondez pas dans les %s minutes, votre conversation va être fermée.'
'We are sorry, it takes longer as expected to get an empty slot. Please try again later or send us an email. Thank you!': 'Nous sommes désolés, il faut plus de temps que prévu pour obtenir un emplacement vide. Veuillez réessayer ultérieurement ou nous envoyer un courriel. Je vous remercie!'
'nl':
'<strong>Chat</strong> with us!': '<strong>Chat</strong> met ons!'
'Scroll down to see new messages': 'Scrol naar beneden om nieuwe berichten te zien'
'Online': 'Online'
'Offline': 'Offline'
'Connecting': 'Verbinden'
'Connection re-established': 'Verbinding herstelt'
'Today': 'Vandaag'
'Send': 'Verzenden'
'Compose your message...': 'Typ uw bericht...'
'All colleagues are busy.': 'Alle medewerkers zijn bezet.'
'You are on waiting list position <strong>%s</strong>.': 'U bent <strong>%s</strong> in de wachtrij.'
'Start new conversation': 'Nieuwe conversatie starten'
'Since you didn\'t respond in the last %s minutes your conversation with <strong>%s</strong> got closed.': 'Omdat u in de laatste %s minuten niets geschreven heeft wordt de conversatie met <strong>%s</strong> gesloten.'
'Since you didn\'t respond in the last %s minutes your conversation got closed.': 'Omdat u in de laatste %s minuten niets geschreven heeft is de conversatie gesloten.'
'We are sorry, it takes longer as expected to get an empty slot. Please try again later or send us an email. Thank you!': 'Het spijt ons, het duurt langer dan verwacht om te antwoorden. Alstublieft probeer het later nogmaals of stuur ons een email. Hartelijk dank!'
'zh-cn':
'<strong>Chat</strong> with us!': '发起<strong>即时对话</strong>!'
'Scroll down to see new messages': '向下滚动以查看新消息'

View File

@@ -1,64 +1,3 @@
if (!window.zammadChatTemplates) {
window.zammadChatTemplates = {};
}
window.zammadChatTemplates["agent"] = function (__obj) {
if (!__obj) __obj = {};
var __out = [], __capture = function(callback) {
var out = __out, result;
__out = [];
callback.call(this);
result = __out.join('');
__out = out;
return __safe(result);
}, __sanitize = function(value) {
if (value && value.ecoSafe) {
return value;
} else if (typeof value !== 'undefined' && value != null) {
return __escape(value);
} else {
return '';
}
}, __safe, __objSafe = __obj.safe, __escape = __obj.escape;
__safe = __obj.safe = function(value) {
if (value && value.ecoSafe) {
return value;
} else {
if (!(typeof value !== 'undefined' && value != null)) value = '';
var result = new String(value);
result.ecoSafe = true;
return result;
}
};
if (!__escape) {
__escape = __obj.escape = function(value) {
return ('' + value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
};
}
(function() {
(function() {
if (this.agent.avatar) {
__out.push('\n<img class="zammad-chat-agent-avatar" src="');
__out.push(__sanitize(this.agent.avatar));
__out.push('">\n');
}
__out.push('\n<span class="zammad-chat-agent-sentence">\n <span class="zammad-chat-agent-name">');
__out.push(__sanitize(this.agent.name));
__out.push('</span>\n</span>');
}).call(this);
}).call(__obj);
__obj.safe = __objSafe, __obj.escape = __escape;
return __out.join('');
};
var bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; },
slice = [].slice,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
@@ -418,6 +357,23 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
'Since you didn\'t respond in the last %s minutes your conversation got closed.': 'Si vous ne répondez pas dans les %s minutes, votre conversation va être fermée.',
'We are sorry, it takes longer as expected to get an empty slot. Please try again later or send us an email. Thank you!': 'Nous sommes désolés, il faut plus de temps que prévu pour obtenir un emplacement vide. Veuillez réessayer ultérieurement ou nous envoyer un courriel. Je vous remercie!'
},
'nl': {
'<strong>Chat</strong> with us!': '<strong>Chat</strong> met ons!',
'Scroll down to see new messages': 'Scrol naar beneden om nieuwe berichten te zien',
'Online': 'Online',
'Offline': 'Offline',
'Connecting': 'Verbinden',
'Connection re-established': 'Verbinding herstelt',
'Today': 'Vandaag',
'Send': 'Verzenden',
'Compose your message...': 'Typ uw bericht...',
'All colleagues are busy.': 'Alle medewerkers zijn bezet.',
'You are on waiting list position <strong>%s</strong>.': 'U bent <strong>%s</strong> in de wachtrij.',
'Start new conversation': 'Nieuwe conversatie starten',
'Since you didn\'t respond in the last %s minutes your conversation with <strong>%s</strong> got closed.': 'Omdat u in de laatste %s minuten niets geschreven heeft wordt de conversatie met <strong>%s</strong> gesloten.',
'Since you didn\'t respond in the last %s minutes your conversation got closed.': 'Omdat u in de laatste %s minuten niets geschreven heeft is de conversatie gesloten.',
'We are sorry, it takes longer as expected to get an empty slot. Please try again later or send us an email. Thank you!': 'Het spijt ons, het duurt langer dan verwacht om te antwoorden. Alstublieft probeer het later nogmaals of stuur ons een email. Hartelijk dank!'
},
'zh-cn': {
'<strong>Chat</strong> with us!': '发起<strong>即时对话</strong>!',
'Scroll down to see new messages': '向下滚动以查看新消息',
@@ -666,7 +622,7 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
})(this));
this.input.on('paste', (function(_this) {
return function(e) {
var clipboardData, docType, error, html, htmlTmp, imageFile, imageInserted, item, match, reader, regex, replacementTag, text;
var clipboardData, docType, html, htmlTmp, imageFile, imageInserted, item, match, reader, regex, replacementTag, text;
e.stopPropagation();
e.preventDefault();
clipboardData;
@@ -1818,6 +1774,67 @@ var bind = function(fn, me){ return function(){ return fn.apply(me, arguments);
return window.ZammadChat = ZammadChat;
})(window.jQuery, window);
if (!window.zammadChatTemplates) {
window.zammadChatTemplates = {};
}
window.zammadChatTemplates["agent"] = function (__obj) {
if (!__obj) __obj = {};
var __out = [], __capture = function(callback) {
var out = __out, result;
__out = [];
callback.call(this);
result = __out.join('');
__out = out;
return __safe(result);
}, __sanitize = function(value) {
if (value && value.ecoSafe) {
return value;
} else if (typeof value !== 'undefined' && value != null) {
return __escape(value);
} else {
return '';
}
}, __safe, __objSafe = __obj.safe, __escape = __obj.escape;
__safe = __obj.safe = function(value) {
if (value && value.ecoSafe) {
return value;
} else {
if (!(typeof value !== 'undefined' && value != null)) value = '';
var result = new String(value);
result.ecoSafe = true;
return result;
}
};
if (!__escape) {
__escape = __obj.escape = function(value) {
return ('' + value)
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;');
};
}
(function() {
(function() {
if (this.agent.avatar) {
__out.push('\n<img class="zammad-chat-agent-avatar" src="');
__out.push(__sanitize(this.agent.avatar));
__out.push('">\n');
}
__out.push('\n<span class="zammad-chat-agent-sentence">\n <span class="zammad-chat-agent-name">');
__out.push(__sanitize(this.agent.name));
__out.push('</span>\n</span>');
}).call(this);
}).call(__obj);
__obj.safe = __objSafe, __obj.escape = __escape;
return __out.join('');
};
if (!window.zammadChatTemplates) {
window.zammadChatTemplates = {};
}

File diff suppressed because one or more lines are too long

View File

@@ -124,6 +124,15 @@ $(function() {
'Attachments': 'Pièces jointes',
'Your Message...': 'Votre message...',
},
'nl': {
'Name': 'Naam',
'Your Name': 'Uw naam',
'Email': 'Email adres',
'Your Email': 'Uw Email adres',
'Message': 'Bericht',
'Attachments': 'Bijlage',
'Your Message...': 'Uw bericht.......',
},
'zh-cn': {
'Name': '联系人',
'Your Name': '您的尊姓大名',

View File

@@ -1321,7 +1321,7 @@ test('table new - initial list', function() {
equal(el.find('.js-pager').first().find('.js-page.is-selected').length, 1)
equal(el.find('.js-pager').first().find('.js-page.is-selected').text(), '1')
$('#table').append('<hr><h1>table with data</h1><div id="table-new7"></div>')
$('#table').append('<hr><h1>table with data 7</h1><div id="table-new7"></div>')
var el = $('#table-new7')
App.TicketPriority.refresh([
@@ -1421,4 +1421,229 @@ test('table new - initial list', function() {
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 3')
equal(el.find('tbody > tr:nth-child(4) > td').length, 0, 'check row 3')
$('#table').append('<hr><h1>table with data 8</h1><div id="table-new8"></div>')
var el = $('#table-new8')
App.TicketPriority.refresh([
{
id: 1,
name: '1 low',
note: 'some note',
active: true,
created_at: '2014-06-12T11:17:34.000Z',
},
{
id: 2,
name: '2 normal',
note: 'some note 2',
active: false,
created_at: '2014-06-10T10:17:34.000Z',
},
{
id: 3,
name: '3 high',
note: 'some note 3',
active: false,
created_at: '2014-06-10T10:17:38.000Z',
},
], {clear: true})
var table = new App.ControllerTable({
el: el,
overviewAttributes: ['name', 'created_at', 'active'],
model: App.TicketPriority,
objects: App.TicketPriority.all(),
checkbox: false,
radio: false,
orderBy: 'not_existing',
orderDirection: 'DESC',
})
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '12.06.2014', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2')
equal(el.find('tbody > tr:nth-child(3) > td').length, 3, 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:first').text().trim(), '3 hoch', 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 3')
equal(el.find('tbody > tr:nth-child(4) > td').length, 0, 'check row 3')
result = table.update({sync: true, objects: App.TicketPriority.all(), orderBy: 'not_existing', orderDirection: 'ASC'})
equal(result[0], 'noChanges')
$('#table').append('<hr><h1>table with data 9</h1><div id="table-new9"></div>')
var el = $('#table-new9')
App.TicketPriority.refresh([
{
id: 1,
name: '1 low',
external_id: 3,
note: 'some note',
active: true,
created_at: '2014-06-12T11:17:34.000Z',
},
{
id: 2,
name: '2 normal',
external_id: 2,
note: 'some note 2',
active: false,
created_at: '2014-06-10T10:17:34.000Z',
},
{
id: 3,
name: '3 high',
external_id: 1,
note: 'some note 3',
active: false,
created_at: '2014-06-10T10:17:38.000Z',
},
], {clear: true})
App.TicketPriority.resetAttributes()
App.TicketPriority.updateAttributes([{
name: 'external_id',
display: 'External',
tag: 'input',
readonly: 1,
}])
var table = new App.ControllerTable({
el: el,
overviewAttributes: ['name', 'created_at', 'active'],
model: App.TicketPriority,
objects: App.TicketPriority.all(),
checkbox: false,
radio: false,
orderBy: 'external',
orderDirection: 'DESC',
})
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '12.06.2014', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2')
equal(el.find('tbody > tr:nth-child(3) > td').length, 3, 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:first').text().trim(), '3 hoch', 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 3')
equal(el.find('tbody > tr:nth-child(4) > td').length, 0, 'check row 3')
result = table.update({sync: true, objects: App.TicketPriority.all(), orderBy: 'external', orderDirection: 'ASC'})
equal(result[0], 'fullRender.contentChanged')
equal(result[1], 0)
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 3')
equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '3 hoch', 'check row 3')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 3')
equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2')
equal(el.find('tbody > tr:nth-child(3) > td').length, 3, 'check row 1')
equal(el.find('tbody > tr:nth-child(3) > td:first').text().trim(), '1 niedrig', 'check row 1')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '12.06.2014', 'check row 1')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
equal(el.find('tbody > tr:nth-child(4) > td').length, 0, 'check row 3')
$('#table').append('<hr><h1>table with data 10</h1><div id="table-new10"></div>')
var el = $('#table-new10')
App.TicketPriority.refresh([
{
id: 1,
name: '1 low',
external_id: 3,
note: 'some note',
active: true,
created_at: '2014-06-12T11:17:34.000Z',
},
{
id: 2,
name: '2 normal',
external_id: 2,
note: 'some note 2',
active: false,
created_at: '2014-06-10T10:17:34.000Z',
},
{
id: 3,
name: '3 high',
external_id: 1,
note: 'some note 3',
active: false,
created_at: '2014-06-10T10:17:38.000Z',
},
], {clear: true})
App.TicketPriority.resetAttributes()
App.TicketPriority.updateAttributes([{
name: 'external',
display: 'External',
tag: 'input',
readonly: 1,
}])
var table = new App.ControllerTable({
el: el,
overviewAttributes: ['name', 'created_at', 'active'],
model: App.TicketPriority,
objects: App.TicketPriority.all(),
checkbox: false,
radio: false,
orderBy: 'external',
orderDirection: 'ASC',
})
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '1 niedrig', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '12.06.2014', 'check row 1')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2')
equal(el.find('tbody > tr:nth-child(3) > td').length, 3, 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:first').text().trim(), '3 hoch', 'check row 3')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 3')
equal(el.find('tbody > tr:nth-child(4) > td').length, 0, 'check row 3')
result = table.update({sync: true, objects: App.TicketPriority.all(), orderBy: 'external', orderDirection: 'DESC'})
equal(result[0], 'fullRender.contentChanged')
equal(result[1], 0)
equal(el.find('table > thead > tr').length, 1, 'row count')
equal(el.find('table > thead > tr > th:nth-child(1)').text().trim(), 'Name', 'check header')
equal(el.find('table > thead > tr > th:nth-child(2)').text().trim(), 'Erstellt', 'check header')
equal(el.find('table > thead > tr > th:nth-child(3)').text().trim(), 'Aktiv', 'check header')
equal(el.find('tbody > tr:nth-child(1) > td').length, 3, 'check row 3')
equal(el.find('tbody > tr:nth-child(1) > td:first').text().trim(), '3 hoch', 'check row 3')
equal(el.find('tbody > tr:nth-child(1) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 3')
equal(el.find('tbody > tr:nth-child(2) > td').length, 3, 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:first').text().trim(), '2 normal', 'check row 2')
equal(el.find('tbody > tr:nth-child(2) > td:nth-child(2)').text().trim(), '10.06.2014', 'check row 2')
equal(el.find('tbody > tr:nth-child(3) > td').length, 3, 'check row 1')
equal(el.find('tbody > tr:nth-child(3) > td:first').text().trim(), '1 niedrig', 'check row 1')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(2)').text().trim(), '12.06.2014', 'check row 1')
equal(el.find('tbody > tr:nth-child(3) > td:nth-child(3)').text().trim(), 'true', 'check row 1')
equal(el.find('tbody > tr:nth-child(4) > td').length, 0, 'check row 3')
})

View File

@@ -130,6 +130,7 @@ window.onload = function() {
"vip": false,
"id": 434
},
"tags": ["tag a", "tag b"],
"escalation_at": "2017-02-09T09:16:56.192Z",
"last_contact_agent_at": "2017-02-09T09:16:56.192Z",
"last_contact_agent_at": "2017-02-09T09:16:56.192Z",
@@ -191,7 +192,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
setting = {
@@ -202,7 +203,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
};
@@ -215,7 +216,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
setting = {
@@ -226,7 +227,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
};
@@ -243,7 +244,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
setting = {
@@ -256,7 +257,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
@@ -270,7 +271,7 @@ window.onload = function() {
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
setting = {
@@ -283,7 +284,7 @@ window.onload = function() {
}
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
@@ -296,7 +297,7 @@ window.onload = function() {
}
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
@@ -307,7 +308,7 @@ window.onload = function() {
}
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
@@ -318,7 +319,7 @@ window.onload = function() {
}
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
};
@@ -335,7 +336,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
setting = {
@@ -348,7 +349,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
@@ -362,7 +363,7 @@ window.onload = function() {
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
setting = {
@@ -375,7 +376,7 @@ window.onload = function() {
}
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
@@ -388,7 +389,7 @@ window.onload = function() {
}
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
@@ -399,7 +400,7 @@ window.onload = function() {
}
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
@@ -410,10 +411,148 @@ window.onload = function() {
}
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
};
var testPreConditionTags = function (key, ticket) {
App.Session.set(sessionData);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains one",
"value": "tag a",
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains one",
"value": "tag aa",
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains all",
"value": "tag a",
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains all",
"value": ["tag a", "not existing"],
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains all not",
"value": "tag a",
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains all not",
"value": ["tag a", "tag b"],
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains all not",
"value": ["tag a", "tag b", "tag c"],
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains all not",
"value": ["tag c", "tag d"],
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains one not",
"value": "tag a",
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains one not",
"value": ["tag a", "tag b"],
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains one not",
"value": ["tag a", "tag c"],
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
setting = {
"condition": {
"ticket.tags": {
"operator": "contains one not",
"value": ["tag c"],
},
}
};
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
};
var testTime = function (key, value, ticket) {
valueDate = new Date(value);
compareDate = new Date( valueDate.setHours( valueDate.getHours() - 1 ) ).toISOString();
@@ -425,7 +564,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
valueDate = new Date(value);
@@ -438,7 +577,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
valueDate = new Date(value);
@@ -451,7 +590,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, false, result);
valueDate = new Date(value);
@@ -464,7 +603,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
valueDate = new Date(value);
@@ -478,7 +617,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, true, result);
};
@@ -492,7 +631,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, expectedResult, result);
};
@@ -506,7 +645,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, expectedResult, result);
};
@@ -520,7 +659,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, expectedResult, result);
};
@@ -534,7 +673,7 @@ window.onload = function() {
},
}
};
result = App.Ticket.selector(ticket, setting['condition'] );
result = App.Ticket.selector(ticket, setting['condition']);
equal(result, expectedResult, result);
};
@@ -612,7 +751,7 @@ window.onload = function() {
testTimeBeforeRelative('ticket.pending_time', 1, 'hour', false, ticket);
compareDate = new Date();
compareDate.setTime( compareDate.getTime() - 60 * 60 * 2 * 1000 );
compareDate.setTime( compareDate.getTime() - 60 * 60 * 2 * 1000);
ticket.pending_time = compareDate.toISOString();
testTimeBeforeRelative('ticket.pending_time', 1, 'hour', true, ticket);
@@ -621,7 +760,7 @@ window.onload = function() {
testTimeBeforeRelative('ticket.pending_time', 1, 'day', false, ticket);
compareDate = new Date();
compareDate.setTime( compareDate.getTime() - 60 * 60 * 48 * 1000 );
compareDate.setTime( compareDate.getTime() - 60 * 60 * 48 * 1000);
ticket.pending_time = compareDate.toISOString();
testTimeBeforeRelative('ticket.pending_time', 1, 'day', true, ticket);
@@ -630,7 +769,7 @@ window.onload = function() {
testTimeBeforeRelative('ticket.pending_time', 1, 'year', false, ticket);
compareDate = new Date();
compareDate.setTime( compareDate.getTime() - 60 * 60 * 365 * 2 * 1000 );
compareDate.setTime( compareDate.getTime() - 60 * 60 * 365 * 2 * 1000);
ticket.pending_time = compareDate.toISOString();
testTimeBeforeRelative('ticket.pending_time', 1, 'year', true, ticket);
@@ -643,7 +782,7 @@ window.onload = function() {
testTimeAfterRelative('ticket.pending_time', 1, 'hour', false, ticket);
compareDate = new Date();
compareDate.setTime( compareDate.getTime() + 60 * 60 * 2 * 1000 );
compareDate.setTime( compareDate.getTime() + 60 * 60 * 2 * 1000);
ticket.pending_time = compareDate.toISOString();
testTimeAfterRelative('ticket.pending_time', 1, 'hour', true, ticket);
@@ -652,7 +791,7 @@ window.onload = function() {
testTimeAfterRelative('ticket.pending_time', 1, 'day', false, ticket);
compareDate = new Date();
compareDate.setTime( compareDate.getTime() + 60 * 60 * 48 * 1000 );
compareDate.setTime( compareDate.getTime() + 60 * 60 * 48 * 1000);
ticket.pending_time = compareDate.toISOString();
testTimeAfterRelative('ticket.pending_time', 1, 'day', true, ticket);
@@ -661,7 +800,7 @@ window.onload = function() {
testTimeAfterRelative('ticket.pending_time', 1, 'year', false, ticket);
compareDate = new Date();
compareDate.setTime( compareDate.getTime() + 60 * 60 * 365 * 2 * 1000 );
compareDate.setTime( compareDate.getTime() + 60 * 60 * 365 * 2 * 1000);
ticket.pending_time = compareDate.toISOString();
testTimeAfterRelative('ticket.pending_time', 1, 'year', true, ticket);
@@ -672,12 +811,12 @@ window.onload = function() {
// hour
compareDate = new Date();
compareDate.setTime( compareDate.getTime() - 60 * 60 * 0.5 * 1000 );
compareDate.setTime( compareDate.getTime() - 60 * 60 * 0.5 * 1000);
ticket.pending_time = compareDate.toISOString();
testTimeWithinLastRelative('ticket.pending_time', 1, 'hour', true, ticket);
compareDate = new Date();
compareDate.setTime( compareDate.getTime() - 60 * 60 * 2 * 1000 );
compareDate.setTime( compareDate.getTime() - 60 * 60 * 2 * 1000);
ticket.pending_time = compareDate.toISOString();
testTimeWithinLastRelative('ticket.pending_time', 1, 'hour', false, ticket);
@@ -687,12 +826,12 @@ window.onload = function() {
// hour
compareDate = new Date();
compareDate.setTime( compareDate.getTime() + 60 * 60 * 0.5 * 1000 );
compareDate.setTime( compareDate.getTime() + 60 * 60 * 0.5 * 1000);
ticket.pending_time = compareDate.toISOString();
testTimeWithinNextRelative('ticket.pending_time', 1, 'hour', true, ticket);
compareDate = new Date();
compareDate.setTime( compareDate.getTime() + 60 * 60 * 2 * 1000 );
compareDate.setTime( compareDate.getTime() + 60 * 60 * 2 * 1000);
ticket.pending_time = compareDate.toISOString();
testTimeWithinNextRelative('ticket.pending_time', 1, 'hour', false, ticket);
});
@@ -778,6 +917,13 @@ window.onload = function() {
testPreConditionUser('ticket.updated_by_id', '6', ticket, sessionData);
});
test("ticket tags", function() {
ticket = new App.Ticket();
ticket.load(ticketData);
testPreConditionTags('ticket.tags', ticket);
});
test("article from", function() {
ticket = new App.Ticket();
ticket.load(ticketData);

View File

@@ -20,6 +20,7 @@ if [ "$LEVEL" == '1' ]; then
rm test/browser/admin_role_test.rb
# test/browser/agent_navigation_and_title_test.rb
rm test/browser/agent_ticket_attachment_test.rb
rm test/browser/agent_ticket_create_reset_customer_selection_test.rb
rm test/browser/agent_ticket_email_reply_keep_body_test.rb
rm test/browser/agent_ticket_email_signature_test.rb
rm test/browser/agent_ticket_link_test.rb
@@ -78,6 +79,7 @@ elif [ "$LEVEL" == '2' ]; then
rm test/browser/agent_navigation_and_title_test.rb
rm test/browser/agent_organization_profile_test.rb
rm test/browser/agent_ticket_attachment_test.rb
rm test/browser/agent_ticket_create_reset_customer_selection_test.rb
rm test/browser/agent_ticket_email_reply_keep_body_test.rb
rm test/browser/agent_ticket_email_signature_test.rb
rm test/browser/agent_ticket_link_test.rb
@@ -136,6 +138,7 @@ elif [ "$LEVEL" == '3' ]; then
rm test/browser/agent_navigation_and_title_test.rb
rm test/browser/agent_organization_profile_test.rb
# test/browser/agent_ticket_attachment_test.rb
# test/browser/agent_ticket_create_reset_customer_selection_test.rb
# test/browser/agent_ticket_email_reply_keep_body_test.rb
# test/browser/agent_ticket_email_signature_test.rb
# test/browser/agent_ticket_link_test.rb
@@ -194,6 +197,7 @@ elif [ "$LEVEL" == '4' ]; then
rm test/browser/agent_navigation_and_title_test.rb
rm test/browser/agent_organization_profile_test.rb
rm test/browser/agent_ticket_attachment_test.rb
rm test/browser/agent_ticket_create_reset_customer_selection_test.rb
rm test/browser/agent_ticket_email_reply_keep_body_test.rb
rm test/browser/agent_ticket_email_signature_test.rb
rm test/browser/agent_ticket_link_test.rb
@@ -251,6 +255,7 @@ elif [ "$LEVEL" == '5' ]; then
rm test/browser/agent_navigation_and_title_test.rb
# test/browser/agent_organization_profile_test.rb
rm test/browser/agent_ticket_attachment_test.rb
rm test/browser/agent_ticket_create_reset_customer_selection_test.rb
rm test/browser/agent_ticket_email_reply_keep_body_test.rb
rm test/browser/agent_ticket_email_signature_test.rb
rm test/browser/agent_ticket_link_test.rb
@@ -311,6 +316,7 @@ elif [ "$LEVEL" == '6' ]; then
rm test/browser/agent_navigation_and_title_test.rb
rm test/browser/agent_organization_profile_test.rb
rm test/browser/agent_ticket_attachment_test.rb
rm test/browser/agent_ticket_create_reset_customer_selection_test.rb
rm test/browser/agent_ticket_email_reply_keep_body_test.rb
rm test/browser/agent_ticket_email_signature_test.rb
rm test/browser/agent_ticket_link_test.rb

View File

@@ -0,0 +1,244 @@
require 'browser_test_helper'
class AgentTicketCreateResetCustomerSelectionTest < TestCase
def test_clear_customer
@browser = browser_instance
login(
username: 'master@example.com',
password: 'test',
url: browser_url,
)
tasks_close_all()
click(css: 'a[href="#new"]')
click(css: 'a[href="#ticket/create"]')
sleep 2
exists(css: '.content.active .newTicket')
exists(css: '.content.active .tabsSidebar .sidebar[data-tab="template"]')
exists(css: '.content.active .tabsSidebar .tabsSidebar-tab.active[data-tab="template"]')
exists_not(css: '.content.active .tabsSidebar .sidebar[data-tab="customer"]')
exists_not(css: '.content.active .tabsSidebar .tabsSidebar-tab[data-tab="customer"]')
click(css: '.content.active .newTicket [name="customer_id_completion"]')
# check if pulldown is open, it's not working stable via selenium
@browser.execute_script( "$('.content.active .newTicket .js-recipientDropdown').addClass('open')" )
set(
css: '.content.active .newTicket input[name="customer_id_completion"]',
value: 'nicole',
)
sleep 2
sendkey(value: :enter)
sleep 1
exists(css: '.content.active .newTicket')
exists(css: '.content.active .tabsSidebar .sidebar[data-tab="template"]')
exists(css: '.content.active .tabsSidebar .tabsSidebar-tab.active[data-tab="template"]')
exists(css: '.content.active .tabsSidebar .sidebar[data-tab="customer"]')
exists(css: '.content.active .tabsSidebar .tabsSidebar-tab[data-tab="customer"]')
set(
css: '.content.active .newTicket input[name="customer_id_completion"]',
value: '',
)
sendkey(value: :backspace)
sleep 1
exists(css: '.content.active .newTicket')
exists(css: '.content.active .tabsSidebar .sidebar[data-tab="template"]')
exists(css: '.content.active .tabsSidebar .tabsSidebar-tab.active[data-tab="template"]')
exists_not(css: '.content.active .tabsSidebar .sidebar[data-tab="customer"]')
exists_not(css: '.content.active .tabsSidebar .tabsSidebar-tab[data-tab="customer"]')
set(
css: '.content.active .newTicket input[name="title"]',
value: 'some title',
)
set(
css: '.content.active .newTicket div[data-name="body"]',
value: 'some body',
)
select(
css: '.content.active .newTicket select[name="group_id"]',
value: 'Users',
)
click(css: '.content.active .newTicket .js-submit')
watch_for(
css: '.content.active .newTicket .user_autocompletion.form-group.has-error',
)
# cleanup
tasks_close_all()
end
def test_clear_customer_use_email
@browser = browser_instance
login(
username: 'master@example.com',
password: 'test',
url: browser_url,
)
tasks_close_all()
click(css: 'a[href="#new"]')
click(css: 'a[href="#ticket/create"]')
sleep 2
exists(css: '.content.active .newTicket')
exists(css: '.content.active .tabsSidebar .sidebar[data-tab="template"]')
exists(css: '.content.active .tabsSidebar .tabsSidebar-tab.active[data-tab="template"]')
exists_not(css: '.content.active .tabsSidebar .sidebar[data-tab="customer"]')
exists_not(css: '.content.active .tabsSidebar .tabsSidebar-tab[data-tab="customer"]')
click(css: '.content.active .newTicket [name="customer_id_completion"]')
# check if pulldown is open, it's not working stable via selenium
@browser.execute_script( "$('.content.active .newTicket .js-recipientDropdown').addClass('open')" )
set(
css: '.content.active .newTicket input[name="customer_id_completion"]',
value: 'nicole',
)
sleep 2
sendkey(value: :enter)
sleep 1
exists(css: '.content.active .newTicket')
exists(css: '.content.active .tabsSidebar .sidebar[data-tab="template"]')
exists(css: '.content.active .tabsSidebar .tabsSidebar-tab.active[data-tab="template"]')
exists(css: '.content.active .tabsSidebar .sidebar[data-tab="customer"]')
exists(css: '.content.active .tabsSidebar .tabsSidebar-tab[data-tab="customer"]')
set(
css: '.content.active .newTicket input[name="customer_id_completion"]',
value: '',
)
sendkey(value: :backspace)
sleep 1
exists(css: '.content.active .newTicket')
exists(css: '.content.active .tabsSidebar .sidebar[data-tab="template"]')
exists(css: '.content.active .tabsSidebar .tabsSidebar-tab.active[data-tab="template"]')
exists_not(css: '.content.active .tabsSidebar .sidebar[data-tab="customer"]')
exists_not(css: '.content.active .tabsSidebar .tabsSidebar-tab[data-tab="customer"]')
set(
css: '.content.active .newTicket input[name="customer_id_completion"]',
value: 'somecustomer_not_existing_right_now@example.com',
)
set(
css: '.content.active .newTicket input[name="title"]',
value: 'some title',
)
set(
css: '.content.active .newTicket div[data-name="body"]',
value: 'some body',
)
select(
css: '.content.active .newTicket select[name="group_id"]',
value: 'Users',
)
click(css: '.content.active .newTicket .js-submit')
watch_for(
css: '.content.active .ticketZoom-header .ticket-number',
value: '\d',
)
click(css: '.content.active .tabsSidebar-tabs .tabsSidebar-tab[data-tab="customer"]')
match(
css: '.content.active .tabsSidebar .sidebar[data-tab="customer"]',
value: 'somecustomer_not_existing_right_now@example.com',
)
click(css: '.content.active .tabsSidebar .sidebar[data-tab="customer"] .js-actions')
click(css: '.content.active .tabsSidebar .sidebar[data-tab="customer"] .js-actions li[data-type="customer-change"]')
watch_for(
css: '.content.active .modal',
)
exists_not(
css: '.content.active .modal .user_autocompletion.form-group.has-error',
)
click(css: '.content.active .modal .js-submit')
watch_for(
css: '.content.active .modal .user_autocompletion.form-group.has-error',
)
set(
css: '.content.active .modal input[name="customer_id_completion"]',
value: 'master',
)
click(css: '.content.active .modal .js-submit')
watch_for(
css: '.content.active .modal .user_autocompletion.form-group.has-error',
)
set(
css: '.content.active .modal input[name="customer_id_completion"]',
value: 'master',
)
sendkey(value: :enter)
sleep 1
set(
css: '.content.active .modal input[name="customer_id_completion"]',
value: '',
)
sendkey(value: :backspace)
sleep 1
click(css: '.content.active .modal .js-submit')
watch_for(
css: '.content.active .modal .user_autocompletion.form-group.has-error',
)
set(
css: '.content.active .modal input[name="customer_id_completion"]',
value: 'master',
)
sendkey(value: :enter)
sleep 1
click(css: '.content.active .modal .js-submit')
#click(css: '.content.active .tabsSidebar-tabs .tabsSidebar-tab[data-tab="customer"]')
watch_for(
css: '.content.active .tabsSidebar .sidebar[data-tab="customer"]',
value: 'master@example.com',
)
# cleanup
tasks_close_all()
end
end

View File

@@ -19,17 +19,17 @@ class AgentUserManageTest < TestCase
sleep 1
# create customer
click( css: 'a[href="#new"]' )
click( css: 'a[href="#ticket/create"]' )
click( css: '.active .newTicket [name="customer_id_completion"]' )
click(css: 'a[href="#new"]')
click(css: 'a[href="#ticket/create"]')
click(css: '.active .newTicket [name="customer_id_completion"]')
# check if pulldown is open, it's not working stable via selenium
@browser.execute_script( "$('.active .newTicket .js-recipientDropdown').addClass('open')" )
sleep 1
sendkey( value: :arrow_down )
sendkey(value: :arrow_down)
sleep 0.5
click( css: '.active .newTicket .recipientList-entry.js-objectNew' )
click(css: '.active .newTicket .recipientList-entry.js-objectNew')
sleep 1
set(
@@ -45,7 +45,7 @@ class AgentUserManageTest < TestCase
value: customer_user_email,
)
click( css: '.modal button.js-submit' )
click(css: '.modal button.js-submit')
sleep 4
# check is used to check selected
@@ -75,8 +75,8 @@ class AgentUserManageTest < TestCase
# call new ticket screen again
tasks_close_all()
click( css: 'a[href="#new"]' )
click( css: 'a[href="#ticket/create"]' )
click(css: 'a[href="#new"]')
click(css: 'a[href="#ticket/create"]')
sleep 2
match(
@@ -93,7 +93,7 @@ class AgentUserManageTest < TestCase
)
sleep 3
click( css: '.active .newTicket .recipientList-entry.js-object.is-active' )
click(css: '.active .newTicket .recipientList-entry.js-object.is-active')
sleep 1
# check is used to check selected

View File

@@ -1268,7 +1268,7 @@ set type of task (closeTab, closeNextInOverview, stayOnTab)
sleep 0.5
return true
# match pn attribute
# match an attribute
else
text = if params[:attribute]
element.attribute(params[:attribute])

View File

@@ -245,8 +245,8 @@ class FormControllerTest < ActionDispatch::IntegrationTest
end
test '06 - customer_ticket_create false disables form' do
Setting.set('form_ticket_create', true)
Setting.set('customer_ticket_create', false)
Setting.set('form_ticket_create', false)
Setting.set('customer_ticket_create', true)
fingerprint = SecureRandom.hex(40)

View File

@@ -0,0 +1,179 @@
require 'test_helper'
class OverviewsControllerTest < ActionDispatch::IntegrationTest
setup do
# set accept header
@headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
# create agent
roles = Role.where(name: %w(Admin Agent))
groups = Group.all
UserInfo.current_user_id = 1
@admin = User.create_or_update(
login: 'tickets-admin',
firstname: 'Tickets',
lastname: 'Admin',
email: 'tickets-admin@example.com',
password: 'adminpw',
active: true,
roles: roles,
groups: groups,
)
# create agent
roles = Role.where(name: 'Agent')
@agent = User.create_or_update(
login: 'tickets-agent@example.com',
firstname: 'Tickets',
lastname: 'Agent',
email: 'tickets-agent@example.com',
password: 'agentpw',
active: true,
roles: roles,
groups: Group.all,
)
end
test 'no permissions' do
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-agent', 'agentpw')
params = {
name: 'Overview2',
link: 'my_overview',
condition: {
'ticket.state_id' => {
operator: 'is',
value: [1, 2, 3],
},
},
order: {
by: 'created_at',
direction: 'DESC',
},
view: {
d: %w(title customer state created_at),
s: %w(number title customer state created_at),
m: %w(number title customer state created_at),
view_mode_default: 's',
},
}
post '/api/v1/overviews', params: params.to_json, headers: @headers.merge('Authorization' => credentials)
assert_response(401)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('authentication failed', result['error'])
end
test 'create overviews' do
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin', 'adminpw')
params = {
name: 'Overview2',
link: 'my_overview',
condition: {
'ticket.state_id' => {
operator: 'is',
value: [1, 2, 3],
},
},
order: {
by: 'created_at',
direction: 'DESC',
},
view: {
d: %w(title customer state created_at),
s: %w(number title customer state created_at),
m: %w(number title customer state created_at),
view_mode_default: 's',
},
}
post '/api/v1/overviews', params: params.to_json, headers: @headers.merge('Authorization' => credentials)
assert_response(201)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('Overview2', result['name'])
assert_equal('my_overview', result['link'])
post '/api/v1/overviews', params: params.to_json, headers: @headers.merge('Authorization' => credentials)
assert_response(201)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal('Overview2', result['name'])
assert_equal('my_overview_1', result['link'])
end
test 'set mass prio' do
overview1 = Overview.create!(
name: 'Overview1',
link: 'my_overview',
condition: {
'ticket.state_id' => {
operator: 'is',
value: [1, 2, 3],
},
},
order: {
by: 'created_at',
direction: 'DESC',
},
view: {
d: %w(title customer state created_at),
s: %w(number title customer state created_at),
m: %w(number title customer state created_at),
view_mode_default: 's',
},
prio: 1,
updated_by_id: 1,
created_by_id: 1,
)
overview2 = Overview.create!(
name: 'Overview2',
link: 'my_overview',
condition: {
'ticket.state_id' => {
operator: 'is',
value: [1, 2, 3],
},
},
order: {
by: 'created_at',
direction: 'DESC',
},
view: {
d: %w(title customer state created_at),
s: %w(number title customer state created_at),
m: %w(number title customer state created_at),
view_mode_default: 's',
},
prio: 2,
updated_by_id: 1,
created_by_id: 1,
)
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('tickets-admin', 'adminpw')
params = {
prios: [
[overview2.id, 1],
[overview1.id, 2],
]
}
post '/api/v1/overviews_prio', params: params.to_json, headers: @headers.merge('Authorization' => credentials)
assert_response(200)
result = JSON.parse(@response.body)
assert_equal(Hash, result.class)
assert_equal(true, result['success'])
overview1.reload
overview2.reload
assert_equal(2, overview1.prio)
assert_equal(1, overview2.prio)
end
end

View File

@@ -20,5 +20,17 @@ email_address = EmailAddress.create_or_update(
)
Group.all.each do |group|
group.email_address_id = email_address.id
group.save
group.save!
end
User.create_or_update(
login: 'admin@example.com',
firstname: 'Default',
lastname: 'Admin',
email: 'admin@example.com',
password: 'adminpw',
active: true,
roles: Role.where(name: %w(Admin)),
updated_by_id: 1,
created_by_id: 1,
)

View File

@@ -2,6 +2,7 @@
require 'integration_test_helper'
class ClearbitTest < ActiveSupport::TestCase
self.use_transactional_tests = true
# check
test 'base' do

View File

@@ -2,6 +2,8 @@
require 'integration_test_helper'
class FacebookTest < ActiveSupport::TestCase
self.test_order = :sorted
self.use_transactional_tests = false
# set system mode to done / to activate
Setting.set('system_init_done', true)

View File

@@ -2,6 +2,8 @@
require 'test_helper'
class ObjectManagerTest < ActiveSupport::TestCase
self.use_transactional_tests = false
test 'a object manager' do
list_objects = ObjectManager.list_objects

View File

@@ -2,6 +2,8 @@
require 'test_helper'
class PackageTest < ActiveSupport::TestCase
self.use_transactional_tests = false
test 'packages' do
tests = [

View File

@@ -2,6 +2,8 @@
require 'integration_test_helper'
class TwitterTest < ActiveSupport::TestCase
self.test_order = :sorted
self.use_transactional_tests = false
# set system mode to done / to activate
Setting.set('system_init_done', true)

View File

@@ -2,13 +2,16 @@
require 'test_helper'
class UserDeviceControllerTest < ActionDispatch::IntegrationTest
self.test_order = :sorted
self.use_transactional_tests = false
setup do
# set accept header
@headers = { 'ACCEPT' => 'application/json', 'CONTENT_TYPE' => 'application/json' }
# create agent
roles = Role.where( name: %w(Admin Agent) )
roles = Role.where(name: %w(Admin Agent))
groups = Group.all
UserInfo.current_user_id = 1
@@ -24,7 +27,7 @@ class UserDeviceControllerTest < ActionDispatch::IntegrationTest
)
# create agent
roles = Role.where( name: 'Agent' )
roles = Role.where(name: 'Agent')
@agent = User.create_or_update(
login: 'user-device-agent',
firstname: 'UserDevice',

View File

@@ -2,6 +2,8 @@
require 'integration_test_helper'
class ZendeskImportTest < ActiveSupport::TestCase
self.test_order = :sorted
self.use_transactional_tests = false
if !ENV['IMPORT_ZENDESK_ENDPOINT']
raise "ERROR: Need IMPORT_ZENDESK_ENDPOINT - hint IMPORT_ZENDESK_ENDPOINT='https://example.zendesk.com/api/v2'"
@@ -45,7 +47,7 @@ class ZendeskImportTest < ActiveSupport::TestCase
# check count of imported items
test 'check counts' do
assert_equal(143, User.count, 'users')
assert_equal(144, User.count, 'users')
assert_equal(3, Group.count, 'groups')
assert_equal(3, Role.count, 'roles')
assert_equal(2, Organization.count, 'organizations')
@@ -69,7 +71,7 @@ class ZendeskImportTest < ActiveSupport::TestCase
checks = [
{
id: 4,
id: 5,
data: {
firstname: 'Bob',
lastname: 'Smith',
@@ -83,7 +85,7 @@ class ZendeskImportTest < ActiveSupport::TestCase
groups: [group_support],
},
{
id: 5,
id: 6,
data: {
firstname: 'Hansimerkur',
lastname: '',
@@ -96,7 +98,7 @@ class ZendeskImportTest < ActiveSupport::TestCase
groups: [group_additional_group, group_support],
},
{
id: 6,
id: 7,
data: {
firstname: 'Bernd',
lastname: 'Hofbecker',
@@ -108,7 +110,7 @@ class ZendeskImportTest < ActiveSupport::TestCase
groups: [],
},
{
id: 7,
id: 8,
data: {
firstname: 'Zendesk',
lastname: '',
@@ -120,7 +122,7 @@ class ZendeskImportTest < ActiveSupport::TestCase
groups: [],
},
{
id: 89,
id: 90,
data: {
firstname: 'Hans',
lastname: 'Peter Wurst',
@@ -309,7 +311,7 @@ class ZendeskImportTest < ActiveSupport::TestCase
group_id: 3,
priority_id: 3,
owner_id: 1,
customer_id: 6,
customer_id: 7,
organization_id: 2,
test_checkbox: true,
custom_integer: 999,
@@ -332,7 +334,7 @@ If you\'re reading this message in your email, click the ticket number link that
group_id: 3,
priority_id: 1,
owner_id: 1,
customer_id: 7,
customer_id: 8,
organization_id: nil,
test_checkbox: false,
custom_integer: nil,
@@ -353,7 +355,7 @@ If you\'re reading this message in your email, click the ticket number link that
group_id: 3,
priority_id: 2,
owner_id: 1,
customer_id: 91,
customer_id: 92,
organization_id: nil,
},
},
@@ -369,7 +371,7 @@ If you\'re reading this message in your email, click the ticket number link that
group_id: 1,
priority_id: 2,
owner_id: 1,
customer_id: 143,
customer_id: 144,
organization_id: nil,
},
},

View File

@@ -4,8 +4,9 @@ require 'rails/test_help'
require 'cache'
class ActiveSupport::TestCase
# disable transactions
#self.use_transactional_tests = false
# disable transactions / to work with own database connections for each thread
self.use_transactional_tests = false
ActiveRecord::Base.logger = Rails.logger.clone
ActiveRecord::Base.logger.level = Logger::INFO
@@ -22,15 +23,12 @@ class ActiveSupport::TestCase
# clear cache
Cache.clear
# reload settings
Setting.reload
# remove all session messages
Sessions.cleanup
# remove background jobs
Delayed::Job.destroy_all
Trigger.destroy_all
ActivityStream.destroy_all
PostmasterFilter.destroy_all
# set current user
UserInfo.current_user_id = nil
end

View File

@@ -7,10 +7,7 @@ require 'simplecov-rcov'
require 'coveralls'
Coveralls.wear!
#ActiveSupport::TestCase.test_order = :sorted
class ActiveSupport::TestCase
self.test_order = :sorted
ActiveRecord::Base.logger = Rails.logger.clone
ActiveRecord::Base.logger.level = Logger::INFO
@@ -27,9 +24,6 @@ class ActiveSupport::TestCase
SimpleCov.start
fixtures :all
# disable transactions
self.use_transactional_tests = false
# clear cache
Cache.clear
@@ -52,27 +46,12 @@ class ActiveSupport::TestCase
# clear cache
Cache.clear
# reload settings
Setting.reload
# remove all session messages
Sessions.cleanup
# remove background jobs
Delayed::Job.destroy_all
Trigger.destroy_all
ActivityStream.destroy_all
PostmasterFilter.destroy_all
Ticket.destroy_all
Taskbar.destroy_all
Sla.destroy_all
Calendar.destroy_all
# reset settings
Setting.all.pluck(:name).each do |name|
next if name == 'models_searchable' # skip setting
Setting.reset(name, false)
end
Setting.set('system_init_done', true)
Setting.reload
# set current user
UserInfo.current_user_id = nil

View File

@@ -1,566 +0,0 @@
# encoding: utf-8
require 'test_helper'
class AssetsTest < ActiveSupport::TestCase
test 'user' do
roles = Role.where(name: %w(Agent Admin))
groups = Group.all
org1 = Organization.create_or_update(
name: 'some user org',
updated_by_id: 1,
created_by_id: 1,
)
user1 = User.create_or_update(
login: 'assets1@example.org',
firstname: 'assets1',
lastname: 'assets1',
email: 'assets1@example.org',
password: 'some_pass',
active: true,
updated_by_id: 1,
created_by_id: 1,
organization_id: org1.id,
roles: roles,
groups: groups,
)
user2 = User.create_or_update(
login: 'assets2@example.org',
firstname: 'assets2',
lastname: 'assets2',
email: 'assets2@example.org',
password: 'some_pass',
active: true,
updated_by_id: 1,
created_by_id: 1,
roles: roles,
groups: groups,
)
user3 = User.create_or_update(
login: 'assets3@example.org',
firstname: 'assets3',
lastname: 'assets3',
email: 'assets3@example.org',
password: 'some_pass',
active: true,
updated_by_id: user1.id,
created_by_id: user2.id,
roles: roles,
groups: groups,
)
user3 = User.find(user3.id)
assets = user3.assets({})
org1 = Organization.find(org1.id)
attributes = org1.attributes_with_association_ids
attributes.delete('user_ids')
assert( diff(attributes, assets[:Organization][org1.id]), 'check assets')
user1 = User.find(user1.id)
attributes = user1.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user1.id]), 'check assets' )
user2 = User.find(user2.id)
attributes = user2.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user2.id]), 'check assets' )
user3 = User.find(user3.id)
attributes = user3.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user3.id]), 'check assets' )
# touch org, check if user1 has changed
travel 2.seconds
org2 = Organization.find(org1.id)
org2.note = "some note...#{rand(9_999_999_999_999)}"
org2.save!
attributes = org2.attributes_with_association_ids
attributes.delete('user_ids')
assert( !diff(attributes, assets[:Organization][org2.id]), 'check assets' )
user1_new = User.find(user1.id)
attributes = user1_new.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( !diff(attributes, assets[:User][user1_new.id]), 'check assets' )
# check new assets lookup
assets = user3.assets({})
attributes = org2.attributes_with_association_ids
attributes.delete('user_ids')
assert( diff(attributes, assets[:Organization][org1.id]), 'check assets')
user1 = User.find(user1.id)
attributes = user1.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user1.id]), 'check assets' )
user2 = User.find(user2.id)
attributes = user2.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user2.id]), 'check assets' )
user3 = User.find(user3.id)
attributes = user3.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user3.id]), 'check assets' )
travel_back
user3.destroy!
user2.destroy!
user1.destroy!
org1.destroy!
assert_not(Organization.find_by(id: org2.id))
end
test 'organization' do
roles = Role.where( name: %w(Agent Admin) )
admin1 = User.create_or_update(
login: 'admin1@example.org',
firstname: 'admin1',
lastname: 'admin1',
email: 'admin1@example.org',
password: 'some_pass',
active: true,
updated_by_id: 1,
created_by_id: 1,
roles: roles,
)
roles = Role.where( name: %w(Customer) )
org = Organization.create_or_update(
name: 'some customer org',
updated_by_id: admin1.id,
created_by_id: 1,
)
user1 = User.create_or_update(
login: 'assets1@example.org',
firstname: 'assets1',
lastname: 'assets1',
email: 'assets1@example.org',
password: 'some_pass',
active: true,
updated_by_id: 1,
created_by_id: 1,
organization_id: org.id,
roles: roles,
)
user2 = User.create_or_update(
login: 'assets2@example.org',
firstname: 'assets2',
lastname: 'assets2',
email: 'assets2@example.org',
password: 'some_pass',
active: true,
updated_by_id: 1,
created_by_id: 1,
organization_id: org.id,
roles: roles,
)
user3 = User.create_or_update(
login: 'assets3@example.org',
firstname: 'assets3',
lastname: 'assets3',
email: 'assets3@example.org',
password: 'some_pass',
active: true,
updated_by_id: user1.id,
created_by_id: user2.id,
roles: roles,
)
org = Organization.find(org.id)
assets = org.assets({})
attributes = org.attributes_with_association_ids
attributes.delete('user_ids')
assert( diff(attributes, assets[:Organization][org.id]), 'check assets' )
admin1 = User.find(admin1.id)
attributes = admin1.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][admin1.id]), 'check assets' )
user1 = User.find(user1.id)
attributes = user1.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user1.id]), 'check assets' )
user2 = User.find(user2.id)
attributes = user2.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user2.id]), 'check assets' )
user3 = User.find(user3.id)
attributes = user3.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert_nil( assets[:User][user3.id], 'check assets' )
# touch user 2, check if org has changed
travel 2.seconds
user_new_2 = User.find(user2.id)
user_new_2.lastname = 'assets2'
user_new_2.save!
org_new = Organization.find(org.id)
attributes = org_new.attributes_with_association_ids
attributes.delete('user_ids')
assert( !diff(attributes, assets[:Organization][org_new.id]), 'check assets' )
attributes = user_new_2.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user_new_2.id]), 'check assets' )
# check new assets lookup
assets = org_new.assets({})
attributes = org_new.attributes_with_association_ids
attributes.delete('user_ids')
assert( diff(attributes, assets[:Organization][org_new.id]), 'check assets' )
attributes = user_new_2.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user_new_2.id]), 'check assets' )
travel_back
user3.destroy!
user2.destroy!
user1.destroy!
org.destroy!
assert_not(Organization.find_by(id: org_new.id))
end
def diff(o1, o2)
return true if o1 == o2
%w(updated_at created_at).each do |item|
if o1[item]
o1[item] = o1[item].to_s
end
if o2[item]
o2[item] = o2[item].to_s
end
end
return true if (o1.to_a - o2.to_a).empty?
#puts "ERROR: difference \n1: #{o1.inspect}\n2: #{o2.inspect}\ndiff: #{(o1.to_a - o2.to_a).inspect}"
false
end
test 'overview' do
UserInfo.current_user_id = 1
roles = Role.where(name: %w(Customer))
user1 = User.create_or_update(
login: 'assets_overview1@example.org',
firstname: 'assets_overview1',
lastname: 'assets_overview1',
email: 'assets_overview1@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user2 = User.create_or_update(
login: 'assets_overview2@example.org',
firstname: 'assets_overview2',
lastname: 'assets_overview2',
email: 'assets_overview2@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user3 = User.create_or_update(
login: 'assets_overview3@example.org',
firstname: 'assets_overview3',
lastname: 'assets_overview3',
email: 'assets_overview3@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user4 = User.create_or_update(
login: 'assets_overview4@example.org',
firstname: 'assets_overview4',
lastname: 'assets_overview4',
email: 'assets_overview4@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user5 = User.create_or_update(
login: 'assets_overview5@example.org',
firstname: 'assets_overview5',
lastname: 'assets_overview5',
email: 'assets_overview5@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
ticket_state1 = Ticket::State.find_by(name: 'new')
ticket_state2 = Ticket::State.find_by(name: 'open')
overview_role = Role.find_by(name: 'Agent')
overview = Overview.create_or_update(
name: 'my asset test',
link: 'my_asset_test',
prio: 1000,
role_ids: [overview_role.id],
user_ids: [user4.id, user5.id],
condition: {
'ticket.state_id' => {
operator: 'is',
value: [ ticket_state1.id, ticket_state2.id ],
},
'ticket.owner_id' => {
operator: 'is',
pre_condition: 'specific',
value: user1.id,
value_completion: 'John Smith <john.smith@example.com>'
},
},
order: {
by: 'created_at',
direction: 'ASC',
},
view: {
d: %w(title customer group created_at),
s: %w(title customer group created_at),
m: %w(number title customer group created_at),
view_mode_default: 's',
},
)
assets = overview.assets({})
assert(assets[:User][user1.id], 'check assets')
assert_not(assets[:User][user2.id], 'check assets')
assert_not(assets[:User][user3.id], 'check assets')
assert(assets[:User][user4.id], 'check assets')
assert(assets[:User][user5.id], 'check assets')
assert(assets[:TicketState][ticket_state1.id], 'check assets')
assert(assets[:TicketState][ticket_state2.id], 'check assets')
overview = Overview.create_or_update(
name: 'my asset test',
link: 'my_asset_test',
prio: 1000,
role_ids: [overview_role.id],
user_ids: [user4.id],
condition: {
'ticket.state_id' => {
operator: 'is',
value: ticket_state1.id,
},
'ticket.owner_id' => {
operator: 'is',
pre_condition: 'specific',
value: [user1.id, user2.id],
},
},
order: {
by: 'created_at',
direction: 'ASC',
},
view: {
d: %w(title customer group created_at),
s: %w(title customer group created_at),
m: %w(number title customer group created_at),
view_mode_default: 's',
},
)
assets = overview.assets({})
assert(assets[:User][user1.id], 'check assets')
assert(assets[:User][user2.id], 'check assets')
assert_not(assets[:User][user3.id], 'check assets')
assert(assets[:User][user4.id], 'check assets')
assert_not(assets[:User][user5.id], 'check assets')
assert(assets[:TicketState][ticket_state1.id], 'check assets')
assert_not(assets[:TicketState][ticket_state2.id], 'check assets')
overview.destroy!
end
test 'sla' do
UserInfo.current_user_id = 1
roles = Role.where(name: %w(Customer))
user1 = User.create_or_update(
login: 'assets_sla1@example.org',
firstname: 'assets_sla1',
lastname: 'assets_sla1',
email: 'assets_sla1@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user2 = User.create_or_update(
login: 'assets_sla2@example.org',
firstname: 'assets_sla2',
lastname: 'assets_sla2',
email: 'assets_sla2@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
calendar1 = Calendar.create_or_update(
name: 'US 1',
timezone: 'America/Los_Angeles',
business_hours: {
mon: { '09:00' => '17:00' },
tue: { '09:00' => '17:00' },
wed: { '09:00' => '17:00' },
thu: { '09:00' => '17:00' },
fri: { '09:00' => '17:00' }
},
default: true,
ical_url: nil,
updated_by_id: 1,
created_by_id: 1,
)
ticket_state1 = Ticket::State.find_by(name: 'new')
ticket_state2 = Ticket::State.find_by(name: 'open')
sla = Sla.create_or_update(
name: 'my asset test',
calendar_id: calendar1.id,
condition: {
'ticket.state_id' => {
operator: 'is',
value: [ ticket_state1.id, ticket_state2.id ],
},
'ticket.owner_id' => {
operator: 'is',
pre_condition: 'specific',
value: user1.id,
value_completion: 'John Smith <john.smith@example.com>'
},
},
)
assets = sla.assets({})
assert(assets[:User][user1.id], 'check assets')
assert_not(assets[:User][user2.id], 'check assets')
assert(assets[:TicketState][ticket_state1.id], 'check assets')
assert(assets[:TicketState][ticket_state2.id], 'check assets')
assert(assets[:Calendar][calendar1.id], 'check assets')
end
test 'job' do
UserInfo.current_user_id = 1
roles = Role.where(name: %w(Customer))
user1 = User.create_or_update(
login: 'assets_job1@example.org',
firstname: 'assets_job1',
lastname: 'assets_job1',
email: 'assets_job1@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user2 = User.create_or_update(
login: 'assets_job2@example.org',
firstname: 'assets_job2',
lastname: 'assets_job2',
email: 'assets_job2@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user3 = User.create_or_update(
login: 'assets_job3@example.org',
firstname: 'assets_job3',
lastname: 'assets_job3',
email: 'assets_job3@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
ticket_state1 = Ticket::State.find_by(name: 'new')
ticket_state2 = Ticket::State.find_by(name: 'open')
ticket_priority2 = Ticket::Priority.find_by(name: '2 normal')
job = Job.create_or_update(
name: 'my job',
timeplan: {
mon: true,
},
condition: {
'ticket.state_id' => {
operator: 'is',
value: [ ticket_state1.id, ticket_state2.id ],
},
'ticket.owner_id' => {
operator: 'is',
pre_condition: 'specific',
value: user1.id,
value_completion: 'John Smith <john.smith@example.com>'
},
},
perform: {
'ticket.priority_id' => {
value: ticket_priority2.id,
},
'ticket.owner_id' => {
pre_condition: 'specific',
value: user2.id,
value_completion: 'metest123@znuny.com <metest123@znuny.com>'
},
},
disable_notification: true,
)
assets = job.assets({})
assert(assets[:User][user1.id], 'check assets')
assert(assets[:User][user2.id], 'check assets')
assert_not(assets[:User][user3.id], 'check assets')
assert(assets[:TicketState][ticket_state1.id], 'check assets')
assert(assets[:TicketState][ticket_state2.id], 'check assets')
assert(assets[:TicketPriority][ticket_priority2.id], 'check assets')
end
end

View File

@@ -0,0 +1,79 @@
require 'test_helper'
class EmailProcessCustomerSelectionBasedOnSenderRecipient < ActiveSupport::TestCase
setup do
groups = Group.all
roles = Role.where(name: 'Agent')
@agent1 = User.create_or_update(
login: 'user-customer-selection-agent1@example.com',
firstname: 'UserOutOfOffice',
lastname: 'Agent1',
email: 'user-customer-selection-agent1@example.com',
password: 'agentpw',
active: true,
roles: roles,
groups: groups,
updated_by_id: 1,
created_by_id: 1,
)
roles = Role.where(name: 'Customer')
@customer1 = User.create_or_update(
login: 'user-customer-selection-customer1@example.com',
firstname: 'UserOutOfOffice',
lastname: 'customer1',
email: 'user-customer-selection-customer1@example.com',
password: 'customerpw',
active: true,
roles: roles,
updated_by_id: 1,
created_by_id: 1,
)
end
test 'customer need to be customer' do
email_raw_string = "From: #{@agent1.email}
To: #{@customer1.email}
Subject: test
Some Text"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket = Ticket.find(ticket_p.id)
article = Ticket::Article.find(article_p.id)
assert_equal('test', ticket.title)
assert_equal('new', ticket.state.name)
assert_equal('Agent', ticket.create_article_sender.name)
assert_equal('Agent', article.sender.name)
assert_equal(@customer1.email, ticket.customer.email)
assert_equal(@customer1.firstname, ticket.customer.firstname)
assert_equal(@customer1.lastname, ticket.customer.lastname)
end
test 'agent need to be customer' do
Setting.set('postmaster_sender_is_agent_search_for_customer', false)
email_raw_string = "From: #{@agent1.email}
To: #{@customer1.email}
Subject: test
Some Text"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket = Ticket.find(ticket_p.id)
article = Ticket::Article.find(article_p.id)
assert_equal('test', ticket.title)
assert_equal('new', ticket.state.name)
assert_equal('Agent', ticket.create_article_sender.name)
assert_equal('Agent', article.sender.name)
assert_equal(@agent1.email, ticket.customer.email)
assert_equal(@agent1.firstname, ticket.customer.firstname)
assert_equal(@agent1.lastname, ticket.customer.lastname)
end
end

View File

@@ -5,7 +5,7 @@ class EmailProcessIdentifySenderMax < ActiveSupport::TestCase
test 'text max created recipients per email' do
current_users = User.count
email_raw_string = "From: customer@example.com
email_raw_string = "From: #{generate_recipient(1)}
To: #{generate_recipient(22)}
Cc: #{generate_recipient(22)}
Subject: test max sender identify
@@ -15,8 +15,7 @@ Some Text"
ticket_p, article_p, user_p, mail = Channel::EmailParser.new.process({}, email_raw_string)
ticket = Ticket.find(ticket_p.id)
assert_equal('test max sender identify', ticket.title)
assert_equal(current_users + 40, User.count)
assert_equal(current_users + 41, User.count)
end
def generate_recipient(count)

View File

@@ -69,6 +69,45 @@ Some Textäöü",
},
},
},
{
data: "From: me@exampl'e.com
To: customer@exampl'e.com
Subject: äöü some subject
Some Textäöü",
channel: {
trusted: false,
},
success: true,
result: {
0 => {
priority: '2 normal',
title: 'äöü some subject',
},
1 => {
body: 'Some Textäöü',
sender: 'Customer',
type: 'email',
internal: false,
},
},
verify: {
users: [
{
firstname: '',
lastname: '',
fullname: 'me@exampl\'e.com',
email: 'me@exampl\'e.com',
},
{
firstname: '',
lastname: '',
fullname: 'customer@exampl\'e.com',
email: 'customer@exampl\'e.com',
},
],
},
},
{
data: "From: me@example.com
To: customer@example.com

View File

@@ -0,0 +1,80 @@
require 'test_helper'
class JobAssetsTest < ActiveSupport::TestCase
test 'assets' do
UserInfo.current_user_id = 1
roles = Role.where(name: %w(Customer))
user1 = User.create_or_update(
login: 'assets_job1@example.org',
firstname: 'assets_job1',
lastname: 'assets_job1',
email: 'assets_job1@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user2 = User.create_or_update(
login: 'assets_job2@example.org',
firstname: 'assets_job2',
lastname: 'assets_job2',
email: 'assets_job2@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user3 = User.create_or_update(
login: 'assets_job3@example.org',
firstname: 'assets_job3',
lastname: 'assets_job3',
email: 'assets_job3@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
ticket_state1 = Ticket::State.find_by(name: 'new')
ticket_state2 = Ticket::State.find_by(name: 'open')
ticket_priority2 = Ticket::Priority.find_by(name: '2 normal')
job = Job.create_or_update(
name: 'my job',
timeplan: {
mon: true,
},
condition: {
'ticket.state_id' => {
operator: 'is',
value: [ ticket_state1.id, ticket_state2.id ],
},
'ticket.owner_id' => {
operator: 'is',
pre_condition: 'specific',
value: user1.id,
value_completion: 'John Smith <john.smith@example.com>'
},
},
perform: {
'ticket.priority_id' => {
value: ticket_priority2.id,
},
'ticket.owner_id' => {
pre_condition: 'specific',
value: user2.id,
value_completion: 'metest123@znuny.com <metest123@znuny.com>'
},
},
disable_notification: true,
)
assets = job.assets({})
assert(assets[:User][user1.id])
assert(assets[:User][user2.id])
assert_not(assets[:User][user3.id])
assert(assets[:TicketState][ticket_state1.id])
assert(assets[:TicketState][ticket_state2.id])
assert(assets[:TicketPriority][ticket_priority2.id])
end
end

View File

@@ -0,0 +1,157 @@
require 'test_helper'
class OrganizationAssetsTest < ActiveSupport::TestCase
test 'assets' do
roles = Role.where( name: %w(Agent Admin) )
admin1 = User.create_or_update(
login: 'admin1@example.org',
firstname: 'admin1',
lastname: 'admin1',
email: 'admin1@example.org',
password: 'some_pass',
active: true,
updated_by_id: 1,
created_by_id: 1,
roles: roles,
)
roles = Role.where( name: %w(Customer) )
org = Organization.create_or_update(
name: 'some customer org',
updated_by_id: admin1.id,
created_by_id: 1,
)
user1 = User.create_or_update(
login: 'assets1@example.org',
firstname: 'assets1',
lastname: 'assets1',
email: 'assets1@example.org',
password: 'some_pass',
active: true,
updated_by_id: 1,
created_by_id: 1,
organization_id: org.id,
roles: roles,
)
user2 = User.create_or_update(
login: 'assets2@example.org',
firstname: 'assets2',
lastname: 'assets2',
email: 'assets2@example.org',
password: 'some_pass',
active: true,
updated_by_id: 1,
created_by_id: 1,
organization_id: org.id,
roles: roles,
)
user3 = User.create_or_update(
login: 'assets3@example.org',
firstname: 'assets3',
lastname: 'assets3',
email: 'assets3@example.org',
password: 'some_pass',
active: true,
updated_by_id: user1.id,
created_by_id: user2.id,
roles: roles,
)
org = Organization.find(org.id)
assets = org.assets({})
attributes = org.attributes_with_association_ids
attributes.delete('user_ids')
assert( diff(attributes, assets[:Organization][org.id]), 'check assets' )
admin1 = User.find(admin1.id)
attributes = admin1.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][admin1.id]), 'check assets' )
user1 = User.find(user1.id)
attributes = user1.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user1.id]), 'check assets' )
user2 = User.find(user2.id)
attributes = user2.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user2.id]), 'check assets' )
user3 = User.find(user3.id)
attributes = user3.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert_nil( assets[:User][user3.id], 'check assets' )
# touch user 2, check if org has changed
travel 2.seconds
user_new_2 = User.find(user2.id)
user_new_2.lastname = 'assets2'
user_new_2.save!
org_new = Organization.find(org.id)
attributes = org_new.attributes_with_association_ids
attributes.delete('user_ids')
assert( !diff(attributes, assets[:Organization][org_new.id]), 'check assets' )
attributes = user_new_2.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user_new_2.id]), 'check assets' )
# check new assets lookup
assets = org_new.assets({})
attributes = org_new.attributes_with_association_ids
attributes.delete('user_ids')
assert( diff(attributes, assets[:Organization][org_new.id]), 'check assets' )
attributes = user_new_2.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert( diff(attributes, assets[:User][user_new_2.id]), 'check assets' )
travel_back
user3.destroy!
user2.destroy!
user1.destroy!
org.destroy!
assert_not(Organization.find_by(id: org_new.id))
end
def diff(o1, o2)
return true if o1 == o2
%w(updated_at created_at).each do |item|
if o1[item]
o1[item] = o1[item].to_s
end
if o2[item]
o2[item] = o2[item].to_s
end
end
return true if (o1.to_a - o2.to_a).blank?
#puts "ERROR: difference \n1: #{o1.inspect}\n2: #{o2.inspect}\ndiff: #{(o1.to_a - o2.to_a).inspect}"
false
end
end

View File

@@ -0,0 +1,136 @@
require 'test_helper'
class OverviewAssetsTest < ActiveSupport::TestCase
test 'assets' do
UserInfo.current_user_id = 1
roles = Role.where(name: %w(Customer))
user1 = User.create_or_update(
login: 'assets_overview1@example.org',
firstname: 'assets_overview1',
lastname: 'assets_overview1',
email: 'assets_overview1@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user2 = User.create_or_update(
login: 'assets_overview2@example.org',
firstname: 'assets_overview2',
lastname: 'assets_overview2',
email: 'assets_overview2@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user3 = User.create_or_update(
login: 'assets_overview3@example.org',
firstname: 'assets_overview3',
lastname: 'assets_overview3',
email: 'assets_overview3@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user4 = User.create_or_update(
login: 'assets_overview4@example.org',
firstname: 'assets_overview4',
lastname: 'assets_overview4',
email: 'assets_overview4@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user5 = User.create_or_update(
login: 'assets_overview5@example.org',
firstname: 'assets_overview5',
lastname: 'assets_overview5',
email: 'assets_overview5@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
ticket_state1 = Ticket::State.find_by(name: 'new')
ticket_state2 = Ticket::State.find_by(name: 'open')
overview_role = Role.find_by(name: 'Agent')
overview = Overview.create_or_update(
name: 'my asset test',
link: 'my_asset_test',
prio: 1000,
role_ids: [overview_role.id],
user_ids: [user4.id, user5.id],
condition: {
'ticket.state_id' => {
operator: 'is',
value: [ ticket_state1.id, ticket_state2.id ],
},
'ticket.owner_id' => {
operator: 'is',
pre_condition: 'specific',
value: user1.id,
value_completion: 'John Smith <john.smith@example.com>'
},
},
order: {
by: 'created_at',
direction: 'ASC',
},
view: {
d: %w(title customer group created_at),
s: %w(title customer group created_at),
m: %w(number title customer group created_at),
view_mode_default: 's',
},
)
assets = overview.assets({})
assert(assets[:User][user1.id])
assert_not(assets[:User][user2.id])
assert_not(assets[:User][user3.id])
assert(assets[:User][user4.id])
assert(assets[:User][user5.id])
assert(assets[:TicketState][ticket_state1.id])
assert(assets[:TicketState][ticket_state2.id])
overview = Overview.create_or_update(
name: 'my asset test',
link: 'my_asset_test',
prio: 1000,
role_ids: [overview_role.id],
user_ids: [user4.id],
condition: {
'ticket.state_id' => {
operator: 'is',
value: ticket_state1.id,
},
'ticket.owner_id' => {
operator: 'is',
pre_condition: 'specific',
value: [user1.id, user2.id],
},
},
order: {
by: 'created_at',
direction: 'ASC',
},
view: {
d: %w(title customer group created_at),
s: %w(title customer group created_at),
m: %w(number title customer group created_at),
view_mode_default: 's',
},
)
assets = overview.assets({})
assert(assets[:User][user1.id])
assert(assets[:User][user2.id])
assert_not(assets[:User][user3.id])
assert(assets[:User][user4.id])
assert_not(assets[:User][user5.id])
assert(assets[:TicketState][ticket_state1.id])
assert_not(assets[:TicketState][ticket_state2.id])
overview.destroy!
end
end

View File

@@ -28,7 +28,7 @@ class OverviewTest < ActiveSupport::TestCase
overview.destroy!
overview = Overview.create!(
name: 'My assigned Tickets',
name: 'My assigned Tickets 2',
condition: {
'ticket.state_id' => {
operator: 'is',
@@ -46,7 +46,7 @@ class OverviewTest < ActiveSupport::TestCase
view_mode_default: 's',
},
)
assert_equal(overview.link, 'my_assigned_tickets')
assert_equal(overview.link, 'my_assigned_tickets_2')
overview.destroy!
overview = Overview.create!(
@@ -210,6 +210,158 @@ class OverviewTest < ActiveSupport::TestCase
assert_equal(overview.link, 'my_overview2')
overview.destroy!
end
test 'same url' do
UserInfo.current_user_id = 1
overview1 = Overview.create!(
name: 'My own assigned Tickets',
condition: {
'ticket.state_id' => {
operator: 'is',
value: [1, 2, 3],
},
},
order: {
by: 'created_at',
direction: 'DESC',
},
view: {
d: %w(title customer state created_at),
s: %w(number title customer state created_at),
m: %w(number title customer state created_at),
view_mode_default: 's',
},
)
assert_equal(overview1.link, 'my_own_assigned_tickets')
overview2 = Overview.create!(
name: 'My own assigned Tickets',
condition: {
'ticket.state_id' => {
operator: 'is',
value: [1, 2, 3],
},
},
order: {
by: 'created_at',
direction: 'DESC',
},
view: {
d: %w(title customer state created_at),
s: %w(number title customer state created_at),
m: %w(number title customer state created_at),
view_mode_default: 's',
},
)
assert_equal(overview2.link, 'my_own_assigned_tickets_1')
overview3 = Overview.create!(
name: 'My own assigned Tickets',
condition: {
'ticket.state_id' => {
operator: 'is',
value: [1, 2, 3],
},
},
order: {
by: 'created_at',
direction: 'DESC',
},
view: {
d: %w(title customer state created_at),
s: %w(number title customer state created_at),
m: %w(number title customer state created_at),
view_mode_default: 's',
},
)
assert_equal(overview3.link, 'my_own_assigned_tickets_2')
overview1.destroy!
overview2.destroy!
overview3.destroy!
end
test 'priority rearrangement' do
UserInfo.current_user_id = 1
overview1 = Overview.create!(
name: 'Overview1',
link: 'my_overview',
condition: {
'ticket.state_id' => {
operator: 'is',
value: [1, 2, 3],
},
},
order: {
by: 'created_at',
direction: 'DESC',
},
view: {
d: %w(title customer state created_at),
s: %w(number title customer state created_at),
m: %w(number title customer state created_at),
view_mode_default: 's',
},
prio: 1,
)
overview2 = Overview.create!(
name: 'Overview2',
link: 'my_overview',
condition: {
'ticket.state_id' => {
operator: 'is',
value: [1, 2, 3],
},
},
order: {
by: 'created_at',
direction: 'DESC',
},
view: {
d: %w(title customer state created_at),
s: %w(number title customer state created_at),
m: %w(number title customer state created_at),
view_mode_default: 's',
},
prio: 2,
)
overview3 = Overview.create!(
name: 'Overview3',
link: 'my_overview',
condition: {
'ticket.state_id' => {
operator: 'is',
value: [1, 2, 3],
},
},
order: {
by: 'created_at',
direction: 'DESC',
},
view: {
d: %w(title customer state created_at),
s: %w(number title customer state created_at),
m: %w(number title customer state created_at),
view_mode_default: 's',
},
prio: 3,
)
overview2.prio = 3
overview2.save!
overviews = Overview.all.order(prio: :asc).pluck(:id)
assert_equal(overview1.id, overviews[0])
assert_equal(overview3.id, overviews[1])
assert_equal(overview2.id, overviews[2])
overview1.destroy!
overview2.destroy!
overview3.destroy!
end
end

View File

@@ -2,7 +2,7 @@
require 'test_helper'
class SessionEnhancedTest < ActiveSupport::TestCase
test 'a check clients and send messages' do
test 'check clients and send messages' do
# create users
roles = Role.where(name: ['Agent'])
@@ -172,7 +172,8 @@ class SessionEnhancedTest < ActiveSupport::TestCase
travel_back
end
test 'b check client and backends' do
test 'check client and backends' do
# create users
roles = Role.where(name: ['Agent'])
groups = Group.all

View File

@@ -0,0 +1,71 @@
require 'test_helper'
class SlaAssetsTest < ActiveSupport::TestCase
test 'assets' do
UserInfo.current_user_id = 1
roles = Role.where(name: %w(Customer))
user1 = User.create_or_update(
login: 'assets_sla1@example.org',
firstname: 'assets_sla1',
lastname: 'assets_sla1',
email: 'assets_sla1@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user2 = User.create_or_update(
login: 'assets_sla2@example.org',
firstname: 'assets_sla2',
lastname: 'assets_sla2',
email: 'assets_sla2@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
calendar1 = Calendar.create_or_update(
name: 'US 1',
timezone: 'America/Los_Angeles',
business_hours: {
mon: { '09:00' => '17:00' },
tue: { '09:00' => '17:00' },
wed: { '09:00' => '17:00' },
thu: { '09:00' => '17:00' },
fri: { '09:00' => '17:00' }
},
default: true,
ical_url: nil,
updated_by_id: 1,
created_by_id: 1,
)
ticket_state1 = Ticket::State.find_by(name: 'new')
ticket_state2 = Ticket::State.find_by(name: 'open')
sla = Sla.create_or_update(
name: 'my asset test',
calendar_id: calendar1.id,
condition: {
'ticket.state_id' => {
operator: 'is',
value: [ ticket_state1.id, ticket_state2.id ],
},
'ticket.owner_id' => {
operator: 'is',
pre_condition: 'specific',
value: user1.id,
value_completion: 'John Smith <john.smith@example.com>'
},
},
)
assets = sla.assets({})
assert(assets[:User][user1.id], 'check assets')
assert_not(assets[:User][user2.id], 'check assets')
assert(assets[:TicketState][ticket_state1.id], 'check assets')
assert(assets[:TicketState][ticket_state2.id], 'check assets')
assert(assets[:Calendar][calendar1.id], 'check assets')
end
end

View File

@@ -29,7 +29,7 @@ class StoreTest < ActiveSupport::TestCase
assert(exists)
end
test 'store attachment' do
test 'store attachment and move it between backends' do
files = [
{
data: 'hello world',
@@ -54,7 +54,7 @@ class StoreTest < ActiveSupport::TestCase
]
files.each do |file|
sha = Digest::SHA256.hexdigest( file[:data] )
sha = Digest::SHA256.hexdigest(file[:data])
# add attachments
store = Store.add(
@@ -75,23 +75,23 @@ class StoreTest < ActiveSupport::TestCase
assert attachments
# sha check
sha_new = Digest::SHA256.hexdigest( attachments[0].content )
assert_equal( sha, sha_new, "check file #{file[:filename]}")
sha_new = Digest::SHA256.hexdigest(attachments[0].content)
assert_equal(sha, sha_new, "check file #{file[:filename]}")
# filename check
assert_equal( file[:filename], attachments[0].filename )
assert_equal(file[:filename], attachments[0].filename)
# provider check
assert_equal( 'DB', attachments[0].provider )
assert_equal('DB', attachments[0].provider)
end
success = Store::File.verify
assert success, 'verify ok'
Store::File.move( 'DB', 'File' )
Store::File.move('DB', 'File')
files.each do |file|
sha = Digest::SHA256.hexdigest( file[:data] )
sha = Digest::SHA256.hexdigest(file[:data])
# get list of attachments
attachments = Store.list(
@@ -101,54 +101,55 @@ class StoreTest < ActiveSupport::TestCase
assert attachments
# sha check
sha_new = Digest::SHA256.hexdigest( attachments[0].content )
assert_equal( sha, sha_new, "check file #{file[:filename]}")
sha_new = Digest::SHA256.hexdigest(attachments[0].content)
assert_equal(sha, sha_new, "check file #{file[:filename]}")
# filename check
assert_equal( file[:filename], attachments[0].filename )
assert_equal(file[:filename], attachments[0].filename)
# provider check
assert_equal( 'File', attachments[0].provider )
assert_equal('File', attachments[0].provider)
end
success = Store::File.verify
assert success, 'verify ok'
Store::File.move( 'File', 'DB' )
Store::File.move('File', 'DB')
files.each do |file|
sha = Digest::SHA256.hexdigest( file[:data] )
sha = Digest::SHA256.hexdigest(file[:data])
# get list of attachments
attachments = Store.list(
object: 'Test',
o_id: file[:o_id],
)
assert attachments
assert(attachments)
assert_equal(attachments.count, 1)
# sha check
sha_new = Digest::SHA256.hexdigest( attachments[0].content )
assert_equal( sha, sha_new, "check file #{file[:filename]}")
sha_new = Digest::SHA256.hexdigest(attachments[0].content)
assert_equal(sha, sha_new, "check file #{file[:filename]}")
# filename check
assert_equal( file[:filename], attachments[0].filename )
assert_equal(file[:filename], attachments[0].filename)
# provider check
assert_equal( 'DB', attachments[0].provider )
assert_equal('DB', attachments[0].provider)
# delete attachments
success = Store.remove(
object: 'Test',
o_id: file[:o_id],
)
assert success
assert(success)
# check attachments again
attachments = Store.list(
object: 'Test',
o_id: file[:o_id],
)
assert !attachments[0]
assert_not(attachments[0])
end
end
end

View File

@@ -0,0 +1,75 @@
# encoding: utf-8
require 'test_helper'
class TicketArticleStoreEmpty < ActiveSupport::TestCase
test 'check if attachments are deleted after ticket is deleted' do
current_count = Store.count
current_file_count = Store::File.count
current_backend_count = Store::Provider::DB.count
email_raw_string = IO.binread('test/fixtures/mail1.box')
ticket, article, user, mail = Channel::EmailParser.new.process({}, email_raw_string)
next_count = Store.count
next_file_count = Store::File.count
next_backend_count = Store::Provider::DB.count
assert_equal(current_count, next_count - 2)
assert_equal(current_file_count, next_file_count - 2)
assert_equal(current_backend_count, next_backend_count - 2)
ticket.destroy!
after_count = Store.count
after_file_count = Store::File.count
after_backend_count = Store::Provider::DB.count
assert_equal(current_count, after_count)
assert_equal(current_file_count, after_file_count)
assert_equal(current_backend_count, after_backend_count)
end
test 'check if attachments are deleted after ticket same ticket 2 times is deleted' do
current_count = Store.count
current_file_count = Store::File.count
current_backend_count = Store::Provider::DB.count
email_raw_string = IO.binread('test/fixtures/mail1.box')
ticket1, article1, user1, mail1 = Channel::EmailParser.new.process({}, email_raw_string)
ticket2, article2, user2, mail2 = Channel::EmailParser.new.process({}, email_raw_string)
next_count = Store.count
next_file_count = Store::File.count
next_backend_count = Store::Provider::DB.count
assert_equal(current_count, next_count - 4)
assert_equal(current_file_count, next_file_count - 2)
assert_equal(current_backend_count, next_backend_count - 2)
ticket1.destroy!
next_count = Store.count
next_file_count = Store::File.count
next_backend_count = Store::Provider::DB.count
assert_equal(current_count, next_count - 2)
assert_equal(current_file_count, next_file_count - 2)
assert_equal(current_backend_count, next_backend_count - 2)
ticket2.destroy!
after_count = Store.count
after_file_count = Store::File.count
after_backend_count = Store::Provider::DB.count
assert_equal(current_count, after_count)
assert_equal(current_file_count, after_file_count)
assert_equal(current_backend_count, after_backend_count)
end
end

View File

@@ -6,6 +6,7 @@ class TicketLastOwnerUpdateTest < ActiveSupport::TestCase
setup do
group = Group.create_or_update(
name: 'LastOwnerUpdate',
email_address: EmailAddress.first,
assignment_timeout: 60,
updated_by_id: 1,
created_by_id: 1,
@@ -25,6 +26,95 @@ class TicketLastOwnerUpdateTest < ActiveSupport::TestCase
)
end
test 'last_owner_update_at check by state' do
ticket = Ticket.create!(
title: 'assignment_timeout test by state 1',
group: Group.lookup(name: 'LastOwnerUpdate'),
owner: @agent1,
customer_id: 2,
state: Ticket::State.lookup(name: 'new'),
updated_by_id: 1,
created_by_id: 1,
)
assert_equal(ticket.last_owner_update_at.to_s, ticket.updated_at.to_s)
ticket.state = Ticket::State.lookup(name: 'closed')
ticket.save!
assert_nil(ticket.last_owner_update_at)
ticket = Ticket.create!(
title: 'assignment_timeout test by state 1',
group: Group.lookup(name: 'LastOwnerUpdate'),
owner: @agent1,
customer_id: 2,
state: Ticket::State.lookup(name: 'pending reminder'),
updated_by_id: 1,
created_by_id: 1,
)
assert_nil(ticket.last_owner_update_at)
ticket.state = Ticket::State.lookup(name: 'open')
ticket.save!
assert_equal(ticket.last_owner_update_at.to_s, ticket.updated_at.to_s)
end
test 'last_owner_update_at check with agent reply' do
ticket = Ticket.create!(
title: 'assignment_timeout test by state 1',
group: Group.lookup(name: 'LastOwnerUpdate'),
owner: @agent1,
customer_id: 2,
state: Ticket::State.lookup(name: 'open'),
updated_by_id: 1,
created_by_id: 1,
)
assert_equal(ticket.last_owner_update_at.to_s, ticket.updated_at.to_s)
travel 1.hour
article1 = Ticket::Article.create(
ticket_id: ticket.id,
from: 'some_sender@example.com',
to: 'some_recipient@example.com',
subject: 'some subject',
message_id: 'some@id',
body: 'some message reply by customer email',
internal: false,
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
type: Ticket::Article::Type.find_by(name: 'email'),
updated_by_id: 2,
created_by_id: 2,
)
ticket_last_owner_update_at = ticket.last_owner_update_at
ticket.reload
assert_equal(ticket_last_owner_update_at.to_s, ticket.last_owner_update_at.to_s)
travel 1.hour
article2 = Ticket::Article.create(
ticket_id: ticket.id,
from: 'some_sender@example.com',
to: 'some_recipient@example.com',
subject: 'some subject',
message_id: 'some@id',
body: 'some message reply by agent email',
internal: false,
sender: Ticket::Article::Sender.find_by(name: 'Agent'),
type: Ticket::Article::Type.find_by(name: 'email'),
updated_by_id: @agent1.id,
created_by_id: @agent1.id,
)
ticket_last_owner_update_at = Time.zone.now
ticket.reload
assert_equal(ticket_last_owner_update_at.to_s, ticket.last_owner_update_at.to_s)
end
test 'last_owner_update_at check' do
ticket = Ticket.create!(
@@ -77,7 +167,7 @@ class TicketLastOwnerUpdateTest < ActiveSupport::TestCase
group: Group.lookup(name: 'LastOwnerUpdate'),
owner: @agent1,
customer_id: 2,
state: Ticket::State.lookup(name: 'closed'),
state: Ticket::State.lookup(name: 'open'),
updated_by_id: 1,
created_by_id: 1,
)
@@ -119,7 +209,7 @@ class TicketLastOwnerUpdateTest < ActiveSupport::TestCase
ticket = Ticket.create!(
title: 'assignment_timeout test 2',
group: Group.lookup(name: 'Users'),
group: Group.lookup(name: 'LastOwnerUpdate'),
owner: @agent1,
customer_id: 2,
state: Ticket::State.lookup(name: 'new'),
@@ -141,7 +231,7 @@ class TicketLastOwnerUpdateTest < ActiveSupport::TestCase
updated_by_id: 1,
created_by_id: 1,
)
assert_equal(ticket.last_owner_update_at.to_s, ticket.updated_at.to_s)
assert_nil(ticket.last_owner_update_at)
ticket.owner_id = 1
ticket.save!
@@ -177,7 +267,7 @@ class TicketLastOwnerUpdateTest < ActiveSupport::TestCase
group: Group.lookup(name: 'LastOwnerUpdate'),
owner: @agent1,
customer_id: 2,
state: Ticket::State.lookup(name: 'closed'),
state: Ticket::State.lookup(name: 'open'),
updated_by_id: 1,
created_by_id: 1,
)
@@ -195,7 +285,7 @@ class TicketLastOwnerUpdateTest < ActiveSupport::TestCase
ticket5 = Ticket.create!(
title: 'assignment_timeout test 5',
group: Group.lookup(name: 'Users'),
group: Group.lookup(name: 'LastOwnerUpdate'),
owner: @agent1,
customer_id: 2,
state: Ticket::State.lookup(name: 'new'),
@@ -229,7 +319,7 @@ class TicketLastOwnerUpdateTest < ActiveSupport::TestCase
travel 15.minutes
Ticket.process_auto_unassign
ticket2_updated_at = Time.current
ticket_updated_at = Time.current
ticket1after = Ticket.find(ticket1.id)
assert_nil(ticket1.last_owner_update_at)
@@ -238,20 +328,20 @@ class TicketLastOwnerUpdateTest < ActiveSupport::TestCase
ticket2after = Ticket.find(ticket2.id)
assert_nil(ticket2after.last_owner_update_at)
assert_equal(ticket2after.owner_id, 1)
assert_equal(ticket2_updated_at.to_s, ticket2after.updated_at.to_s)
assert_equal(ticket_updated_at.to_s, ticket2after.updated_at.to_s)
ticket3after = Ticket.find(ticket3.id)
assert_equal(ticket3after.owner_id, @agent1.id)
assert_equal(ticket3.last_owner_update_at.to_s, ticket3after.last_owner_update_at.to_s)
assert_equal(ticket3.updated_at.to_s, ticket3after.updated_at.to_s)
assert_nil(ticket3after.last_owner_update_at)
assert_equal(ticket3after.owner_id, 1)
assert_equal(ticket_updated_at.to_s, ticket3after.updated_at.to_s)
ticket4after = Ticket.find(ticket4.id)
assert_nil(ticket4.last_owner_update_at)
assert_equal(ticket4.updated_at.to_s, ticket4after.updated_at.to_s)
ticket5after = Ticket.find(ticket5.id)
assert_equal(ticket5after.owner_id, @agent1.id)
assert_equal(ticket5.updated_at.to_s, ticket5after.updated_at.to_s)
assert_equal(ticket5after.owner_id, 1)
assert_equal(ticket_updated_at.to_s, ticket5after.updated_at.to_s)
end

View File

@@ -0,0 +1,77 @@
require 'test_helper'
class TriggerAssetsTest < ActiveSupport::TestCase
test 'assets' do
UserInfo.current_user_id = 1
roles = Role.where(name: %w(Customer))
user1 = User.create_or_update(
login: 'assets_trigger1@example.org',
firstname: 'assets_trigger1',
lastname: 'assets_trigger1',
email: 'assets_trigger1@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user2 = User.create_or_update(
login: 'assets_trigger2@example.org',
firstname: 'assets_trigger2',
lastname: 'assets_trigger2',
email: 'assets_trigger2@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
user3 = User.create_or_update(
login: 'assets_trigger3@example.org',
firstname: 'assets_trigger3',
lastname: 'assets_trigger3',
email: 'assets_trigger3@example.org',
password: 'some_pass',
active: true,
roles: roles,
)
group1 = Group.create_or_update(
name: 'group1_trigger',
active: true,
)
ticket_state1 = Ticket::State.find_by(name: 'new')
ticket_state2 = Ticket::State.find_by(name: 'open')
ticket_priority2 = Ticket::Priority.find_by(name: '2 normal')
trigger = Trigger.create_or_update(
name: 'my trigger',
condition: {
'ticket.state_id' => {
operator: 'is',
value: [ ticket_state1.id ],
},
'ticket.owner_id' => {
operator: 'is',
pre_condition: 'specific',
value: user1.id,
value_completion: 'John Smith <john.smith@example.com>'
},
},
perform: {
'ticket.group_id' => {
value: group1.id.to_s,
},
},
disable_notification: true,
)
assets = trigger.assets({})
assert(assets[:User][user1.id])
assert_not(assets[:User][user2.id])
assert_not(assets[:User][user3.id])
assert(assets[:TicketState][ticket_state1.id])
assert_not(assets[:TicketState][ticket_state2.id])
assert_not(assets[:TicketPriority])
assert(assets[:Group][group1.id])
end
end

View File

@@ -0,0 +1,157 @@
require 'test_helper'
class UserAssetsTest < ActiveSupport::TestCase
test 'assets' do
roles = Role.where(name: %w(Agent Admin))
groups = Group.all
org1 = Organization.create_or_update(
name: 'some user org',
updated_by_id: 1,
created_by_id: 1,
)
user1 = User.create_or_update(
login: 'assets1@example.org',
firstname: 'assets1',
lastname: 'assets1',
email: 'assets1@example.org',
password: 'some_pass',
active: true,
updated_by_id: 1,
created_by_id: 1,
organization_id: org1.id,
roles: roles,
groups: groups,
)
user2 = User.create_or_update(
login: 'assets2@example.org',
firstname: 'assets2',
lastname: 'assets2',
email: 'assets2@example.org',
password: 'some_pass',
active: true,
updated_by_id: 1,
created_by_id: 1,
roles: roles,
groups: groups,
)
user3 = User.create_or_update(
login: 'assets3@example.org',
firstname: 'assets3',
lastname: 'assets3',
email: 'assets3@example.org',
password: 'some_pass',
active: true,
updated_by_id: user1.id,
created_by_id: user2.id,
roles: roles,
groups: groups,
)
user3 = User.find(user3.id)
assets = user3.assets({})
org1 = Organization.find(org1.id)
attributes = org1.attributes_with_association_ids
attributes.delete('user_ids')
assert(diff(attributes, assets[:Organization][org1.id]), 'check assets')
user1 = User.find(user1.id)
attributes = user1.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert(diff(attributes, assets[:User][user1.id]), 'check assets')
user2 = User.find(user2.id)
attributes = user2.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert(diff(attributes, assets[:User][user2.id]), 'check assets')
user3 = User.find(user3.id)
attributes = user3.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert(diff(attributes, assets[:User][user3.id]), 'check assets')
# touch org, check if user1 has changed
travel 2.seconds
org2 = Organization.find(org1.id)
org2.note = "some note...#{rand(9_999_999_999_999)}"
org2.save!
attributes = org2.attributes_with_association_ids
attributes.delete('user_ids')
assert_not(diff(attributes, assets[:Organization][org2.id]), 'check assets')
user1_new = User.find(user1.id)
attributes = user1_new.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert_not(diff(attributes, assets[:User][user1_new.id]), 'check assets')
# check new assets lookup
assets = user3.assets({})
attributes = org2.attributes_with_association_ids
attributes.delete('user_ids')
assert(diff(attributes, assets[:Organization][org1.id]), 'check assets')
user1 = User.find(user1.id)
attributes = user1.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert(diff(attributes, assets[:User][user1.id]), 'check assets')
user2 = User.find(user2.id)
attributes = user2.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert(diff(attributes, assets[:User][user2.id]), 'check assets')
user3 = User.find(user3.id)
attributes = user3.attributes_with_association_ids
attributes['accounts'] = {}
attributes.delete('password')
attributes.delete('token_ids')
attributes.delete('authorization_ids')
assert(diff(attributes, assets[:User][user3.id]), 'check assets')
travel_back
user3.destroy!
user2.destroy!
user1.destroy!
org1.destroy!
assert_not(Organization.find_by(id: org2.id))
end
def diff(o1, o2)
return true if o1 == o2
%w(updated_at created_at).each do |item|
if o1[item]
o1[item] = o1[item].to_s
end
if o2[item]
o2[item] = o2[item].to_s
end
end
return true if (o1.to_a - o2.to_a).blank?
#puts "ERROR: difference \n1: #{o1.inspect}\n2: #{o2.inspect}\ndiff: #{(o1.to_a - o2.to_a).inspect}"
false
end
end

View File

@@ -0,0 +1,40 @@
require 'test_helper'
class UserMailDeliveryFailedTest < ActiveSupport::TestCase
setup do
UserInfo.current_user_id = 1
roles = Role.where(name: 'Customer')
@customer1 = User.create_or_update(
login: 'user-mail-delivery-failed-customer1@example.com',
firstname: 'UserOutOfOffice',
lastname: 'Customer1',
email: 'user-mail-delivery-failed-customer1@example.com',
password: 'agentpw',
active: true,
roles: roles,
)
end
test 'check reset of mail_delivery_failed' do
@customer1.preferences[:mail_delivery_failed] = true
@customer1.preferences[:mail_delivery_failed_data] = Time.zone.now
@customer1.save!
@customer1.reload
assert_equal(@customer1.preferences[:mail_delivery_failed], true)
assert(@customer1.preferences[:mail_delivery_failed_data])
@customer1.email = 'new-user-mail-delivery-failed-customer1@example.com'
@customer1.save!
@customer1.reload
assert_not(@customer1.preferences[:mail_delivery_failed], true)
assert(@customer1.preferences[:mail_delivery_failed_data])
end
end

View File

@@ -932,15 +932,9 @@ class UserTest < ActiveSupport::TestCase
end
test 'min admin permission check' do
# workaround:
# - We need to get rid of all admin users but can't delete them
# because we have foreign keys pointing at them since the tests are not isolated yet :(
# - We can't just remove the roles since then our check would take place
# So we need to merge them with the User Nr 1 and destroy them afterwards
User.with_permissions('admin').each do |user|
Models.merge('User', 1, user.id)
user.destroy!
end
# delete inital admin
User.find_by(login: 'admin@example.com').destroy
# store current admin count
admin_count_inital = User.with_permissions('admin').count

View File

@@ -79,7 +79,7 @@ class UserValidateAgentLimit < ActiveSupport::TestCase
permissions: Permission.where(name: 'ticket.agent'),
active: false,
)
user3.roles = [role_agent_limit]
user3.roles = [role_agent_limit]
user3.active = true
user3.save!
@@ -90,6 +90,17 @@ class UserValidateAgentLimit < ActiveSupport::TestCase
assert_equal(User.with_permissions('ticket.agent').count, agent_max)
# set roles of agent again
role_admin = Role.lookup(name: 'Admin')
user2.roles = [role_agent, role_admin]
user2.save!
user2.role_ids = [role_admin.id, role_agent_limit.id]
user2.save!
user2.role_ids = [role_admin.id.to_s, role_agent_limit.id.to_s]
user2.save!
user1.destroy!
user2.destroy!
user3.destroy!