Compare commits
184 Commits
develop
...
stable-1.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1974f9cee0 | ||
|
|
22ca95d5b1 | ||
|
|
8ca3c54ff1 | ||
|
|
f0277013d5 | ||
|
|
d81e13c532 | ||
|
|
8bdff80959 | ||
|
|
b3f1dced52 | ||
|
|
54dbd7efff | ||
|
|
176379dc6d | ||
|
|
0362f240d0 | ||
|
|
c3822f195a | ||
|
|
85b214ea1f | ||
|
|
26dba04436 | ||
|
|
4bdd379a05 | ||
|
|
0d82236e7b | ||
|
|
e68b237c0b | ||
|
|
b6138d2b47 | ||
|
|
677ee5c547 | ||
|
|
b46826145c | ||
|
|
cb1bac8920 | ||
|
|
63ed48ae20 | ||
|
|
99753b22cb | ||
|
|
5eca4ca6a5 | ||
|
|
bd63f10443 | ||
|
|
da760de674 | ||
|
|
37184d6d31 | ||
|
|
df8100679d | ||
|
|
aca15ad056 | ||
|
|
7a39ddb0e5 | ||
|
|
7c5742ab23 | ||
|
|
2aeace8e59 | ||
|
|
7693fefc4d | ||
|
|
5956d4ab28 | ||
|
|
748515b175 | ||
|
|
e56aff3e01 | ||
|
|
f6678e7deb | ||
|
|
9f16d7e557 | ||
|
|
40051c6088 | ||
|
|
29ef36e75a | ||
|
|
0f93f01504 | ||
|
|
50499d667d | ||
|
|
e3ab97b46a | ||
|
|
98bc61591c | ||
|
|
884e6436b7 | ||
|
|
767c8375b2 | ||
|
|
a10edc3eda | ||
|
|
1b42a90233 | ||
|
|
44cd11583c | ||
|
|
19a7a439b8 | ||
|
|
e728320241 | ||
|
|
1bc17afc53 | ||
|
|
ee5c58f53a | ||
|
|
9bdf6d7b81 | ||
|
|
5754fdccdd | ||
|
|
4901050d57 | ||
|
|
7980c8cb93 | ||
|
|
7e7088388d | ||
|
|
2f6e52d63d | ||
|
|
bde8babb43 | ||
|
|
d6d68fb363 | ||
|
|
814ffed0f0 | ||
|
|
b013fb8cbc | ||
|
|
fbd8e63592 | ||
|
|
e8ad3965d7 | ||
|
|
e00981ee23 | ||
|
|
4e74c6beda | ||
|
|
2d09e556d7 | ||
|
|
8cd39398d6 | ||
|
|
94c616ffe3 | ||
|
|
57649bb888 | ||
|
|
7e9442ec4a | ||
|
|
521e6265fd | ||
|
|
a42a9689fc | ||
|
|
d9ffb8001d | ||
|
|
ec86d26ae6 | ||
|
|
e00efc821a | ||
|
|
f04be8ca93 | ||
|
|
c7ff6a323a | ||
|
|
34833416bc | ||
|
|
d7a6e28d81 | ||
|
|
c13531d720 | ||
|
|
4a40cced7d | ||
|
|
450de10cc7 | ||
|
|
5e587a455c | ||
|
|
04aef9b258 | ||
|
|
9b72557d13 | ||
|
|
a5e0bc30c1 | ||
|
|
458c166e9f | ||
|
|
3373e5d141 | ||
|
|
8f6b8de617 | ||
|
|
22b21a82e7 | ||
|
|
b4151b299f | ||
|
|
e969fca8c4 | ||
|
|
e59993a5d6 | ||
|
|
3adc9d4cf1 | ||
|
|
c1153250cb | ||
|
|
7718dc28d3 | ||
|
|
1894580ae6 | ||
|
|
11df714bbf | ||
|
|
72adee37a8 | ||
|
|
0e8f460d73 | ||
|
|
4e62d5d0d2 | ||
|
|
004e5ba457 | ||
|
|
f1a8a8da6f | ||
|
|
bfb44d1189 | ||
|
|
d64afd8d97 | ||
|
|
97cfdb9c4c | ||
|
|
bb336f63f1 | ||
|
|
80da08f447 | ||
|
|
a6db2b7c90 | ||
|
|
e1c3f83324 | ||
|
|
8545a44ad1 | ||
|
|
cfbe7510a2 | ||
|
|
1479c32edb | ||
|
|
a9d428bf5a | ||
|
|
3a62eb11da | ||
|
|
2df5f81029 | ||
|
|
b88c23bc92 | ||
|
|
4144fbaf5b | ||
|
|
86ddc93f52 | ||
|
|
8a1b583535 | ||
|
|
7623628b86 | ||
|
|
f753bc203f | ||
|
|
ff9ba10705 | ||
|
|
fdc25bdc26 | ||
|
|
d154a587ad | ||
|
|
a9cc4f037b | ||
|
|
50d6679189 | ||
|
|
b82cf4e1d6 | ||
|
|
fa6eaa6710 | ||
|
|
2ca17ac1bd | ||
|
|
862ecd7d36 | ||
|
|
e38b72593b | ||
|
|
81883cae8f | ||
|
|
63770c9cbf | ||
|
|
aaf5da55a0 | ||
|
|
8455d9ae17 | ||
|
|
839a8e8eb4 | ||
|
|
7aa3f6eaee | ||
|
|
219abc69a3 | ||
|
|
595822c928 | ||
|
|
32112937b1 | ||
|
|
a0889c5b99 | ||
|
|
4bc281bfb0 | ||
|
|
e12ec607d7 | ||
|
|
545f393293 | ||
|
|
4efa152e93 | ||
|
|
0ebda4f32a | ||
|
|
b94f54799f | ||
|
|
99f0b4e2e2 | ||
|
|
53cb906733 | ||
|
|
2c31fe8a84 | ||
|
|
6c5e673a2c | ||
|
|
574b891a33 | ||
|
|
9ef1d3f58b | ||
|
|
8b3f432746 | ||
|
|
14a9df261e | ||
|
|
5620a2847b | ||
|
|
13aaae3835 | ||
|
|
2d4fcd3a4f | ||
|
|
f4f70b0bc2 | ||
|
|
1d279bb88f | ||
|
|
fe4757cbf9 | ||
|
|
1d476f163e | ||
|
|
513701b6d2 | ||
|
|
1a1b661714 | ||
|
|
6081a98279 | ||
|
|
157991c33d | ||
|
|
ef67be9170 | ||
|
|
39f3819303 | ||
|
|
7a676bd563 | ||
|
|
80c54daa03 | ||
|
|
99c88cde62 | ||
|
|
17d113ca20 | ||
|
|
2fbf4324a7 | ||
|
|
b46c390d30 | ||
|
|
3c3651bc52 | ||
|
|
abeeb5e66d | ||
|
|
09d61ce4c8 | ||
|
|
cc1c4495b2 | ||
|
|
7b1ec4d17f | ||
|
|
99b3201ccf | ||
|
|
d4205d9ba6 | ||
|
|
8d57633390 |
85
CHANGELOG.md
Normal file
85
CHANGELOG.md
Normal file
@@ -0,0 +1,85 @@
|
||||
# Change Log
|
||||
|
||||
## [1.0.4](https://github.com/zammad/zammad/tree/1.0.4) (2017-02-15)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/1.0.3...1.0.4)
|
||||
|
||||
**Fixed bugs:**
|
||||
- Ticket without Subject is blocked - can't do anything with it \("Title needed"\) [\#719](https://github.com/zammad/zammad/issues/719) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
- Unable to process emails with email addresses longer then 140 signs. [\#650](https://github.com/zammad/zammad/issues/650) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Unable to process emails if "Additional follow-up detection" was checked and unchecked again [\#740](https://github.com/zammad/zammad/issues/740) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Prevent attachment preview in browser attachment download [\#617](https://github.com/zammad/zammad/issues/617) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Follow up detection not working if ticket\_hook\_position "none" is used. [\#686](https://github.com/zammad/zammad/issues/686) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
|
||||
## [1.0.3](https://github.com/zammad/zammad/tree/1.0.3) (2017-01-16)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/1.0.2...1.0.3)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Imap sort errors with gmail in production.log [\#568](https://github.com/zammad/zammad/issues/568) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Agent - Group assignment shows "\<br\>" [\#566](https://github.com/zammad/zammad/issues/566) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Overview is not show it organization is used as row and first ticket has no organization \(app is not responding anymore\) [\#554](https://github.com/zammad/zammad/issues/554) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Error message at creation of new overview with not existing specific customer [\#545](https://github.com/zammad/zammad/issues/545) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Renaming standard roles breaks ticket views [\#499](https://github.com/zammad/zammad/issues/499) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- New users won't get initial user group [\#249](https://github.com/zammad/zammad/issues/249) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- add e.g. screenshots form clipboard doesn't work \(FireFox 45.3.0\) [\#235](https://github.com/zammad/zammad/issues/235) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
|
||||
## [1.0.2](https://github.com/zammad/zammad/tree/1.0.2) (2016-12-14)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/1.0.1...1.0.2)
|
||||
|
||||
**Implemented enhancements:**
|
||||
|
||||
- Provide a Debian Package [\#209](https://github.com/zammad/zammad/issues/209) [[enhancement](https://github.com/zammad/zammad/labels/enhancement)]
|
||||
|
||||
**Fixed bugs:**
|
||||
- Wrong recipient on reply to Received call [\#206](https://github.com/zammad/zammad/issues/206) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- New users won't get initial user group [\#249](https://github.com/zammad/zammad/issues/249) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- bugfix: added missing join table [\#541](https://github.com/zammad/zammad/pull/541) [[bug](https://github.com/zammad/zammad/labels/bug)] ([TeaMoe](https://github.com/TeaMoe))
|
||||
- Object manager allows method names as attributes [\#433](https://github.com/zammad/zammad/issues/433) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Max times for escalation 99 hours [\#418](https://github.com/zammad/zammad/issues/418) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Pending event time after 22:59 jumps back to 22:59 [\#329](https://github.com/zammad/zammad/issues/329) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- "Get latest Translations" fails\(?\) without error [\#502](https://github.com/zammad/zammad/issues/502) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Token without expiration timestamp expires "01/01/1970" [\#478](https://github.com/zammad/zammad/issues/478) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- "Password has been changed" email contains unresolved placeholders [\#468](https://github.com/zammad/zammad/issues/468) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Search result won't get updated after focus is lost and new search is started [\#466](https://github.com/zammad/zammad/issues/466) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Missing quotation marks on sender address [\#402](https://github.com/zammad/zammad/issues/402) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- New overview with article conditions not working [\#448](https://github.com/zammad/zammad/issues/448) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Customer should not have the internal attribute to set in customer interface. [\#437](https://github.com/zammad/zammad/issues/437) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Unable to set owner + customer in postmaster/email filter [\#419](https://github.com/zammad/zammad/issues/419) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Can't process email / Error creating ticket with changed Ticket Number Format [\#413](https://github.com/zammad/zammad/issues/413) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- "Ticket will escalate soon" in online notifications is not translated. [\#408](https://github.com/zammad/zammad/issues/408) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
|
||||
|
||||
## [1.0.1](https://github.com/zammad/zammad/tree/1.0.1) (2016-11-14)
|
||||
[Full Changelog](https://github.com/zammad/zammad/compare/1.0.0...1.0.1)
|
||||
|
||||
**Fixed bugs:**
|
||||
|
||||
- Some windows in the config area too wide in firefox [\#392](https://github.com/zammad/zammad/issues/392) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- \[Critical\] Short display of "Setup a new system" on public site while restarting Zammad! [\#389](https://github.com/zammad/zammad/issues/389) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Mailresponse to customer not working at all after editing a "Trigger" event text [\#385](https://github.com/zammad/zammad/issues/385) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Click on "Reports" leads to Error 500 [\#384](https://github.com/zammad/zammad/issues/384) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- TicketSelector in Overview or SLA not working with filter for ticket customer or owner [\#383](https://github.com/zammad/zammad/issues/383) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Changelog generator breaks packager.io builds [\#379](https://github.com/zammad/zammad/issues/379) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- script/scheduler.rb crashes after recreation of Zammad database [\#374](https://github.com/zammad/zammad/issues/374) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- ticket search cache issue [\#349](https://github.com/zammad/zammad/issues/349) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- IMAP mail fetching stops because of broken spam email \(invalid Content-Transfer-Encoding header\) [\#348](https://github.com/zammad/zammad/issues/348) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- IMAP mail fetching stops working on spam mail and invalid email format [\#345](https://github.com/zammad/zammad/issues/345) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Unable to create tickets [\#323](https://github.com/zammad/zammad/issues/323) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Admin -\> Channels -\> Email -\> Filters not shown / no name shown [\#313](https://github.com/zammad/zammad/issues/313) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- In object manager, blank line in object deleted all values for selections [\#312](https://github.com/zammad/zammad/issues/312) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- triggers do not work? [\#306](https://github.com/zammad/zammad/issues/306) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Answers from google mail shows complete quote [\#286](https://github.com/zammad/zammad/issues/286) [[minor bug](https://github.com/zammad/zammad/labels/minor%20bug)]
|
||||
- Avatar in Chat not showing - wrong url [\#275](https://github.com/zammad/zammad/issues/275) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- chat not working / http 404 [\#274](https://github.com/zammad/zammad/issues/274) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Zammad Docker container for rpi/ARM [\#271](https://github.com/zammad/zammad/issues/271) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Zendesk: unknown article type fails import. [\#270](https://github.com/zammad/zammad/issues/270) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- No space at comment on ticket bulk action [\#268](https://github.com/zammad/zammad/issues/268) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- After adding a new attribute - zammad won't start [\#248](https://github.com/zammad/zammad/issues/248) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Images/Avatars blank [\#217](https://github.com/zammad/zammad/issues/217) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Docker/Ubuntu Not starting postgresql-9.6 service [\#213](https://github.com/zammad/zammad/issues/213) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- Can´t choose Organization for Customer [\#211](https://github.com/zammad/zammad/issues/211) [[bug](https://github.com/zammad/zammad/labels/bug)]
|
||||
- CentOS 7 HTTPS Error 404 - Not Found [\#210](https://github.com/zammad/zammad/issues/210) [[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)*
|
||||
@@ -277,7 +277,7 @@ GEM
|
||||
unicode-display_width (~> 1.0, >= 1.0.1)
|
||||
ruby-progressbar (1.8.1)
|
||||
ruby_dep (1.4.0)
|
||||
rubyzip (1.2.0)
|
||||
rubyzip (1.2.1)
|
||||
sass (3.4.22)
|
||||
sass-rails (5.0.6)
|
||||
railties (>= 4.0.0, < 6)
|
||||
|
||||
@@ -11,7 +11,6 @@ class App.UiElement.object_manager_attribute extends App.UiElement.ApplicationUi
|
||||
|
||||
updateDataMap = (localParams, localAttribute, localAttributes, localClassname, localForm, localA) =>
|
||||
localItem = localForm.closest('.js-data')
|
||||
console.log('updateDataMap', attribute, params)
|
||||
element = $(App.view("object_manager/attribute/#{localParams.data_type}")(
|
||||
attribute: attribute
|
||||
params: params
|
||||
@@ -49,7 +48,7 @@ class App.UiElement.object_manager_attribute extends App.UiElement.ApplicationUi
|
||||
objects =
|
||||
Ticket:
|
||||
Customer:
|
||||
create:
|
||||
create_bottom:
|
||||
shown: true
|
||||
required: false
|
||||
edit:
|
||||
|
||||
@@ -16,8 +16,11 @@ class App.UiElement.postmaster_set
|
||||
relation: 'TicketState'
|
||||
},
|
||||
{
|
||||
value: 'x-zammad-ticket-customer'
|
||||
value: 'x-zammad-ticket-customer_id'
|
||||
name: 'Customer'
|
||||
relation: 'User'
|
||||
tag: 'user_autocompletion'
|
||||
disableCreateUser: true,
|
||||
},
|
||||
{
|
||||
|
||||
@@ -26,10 +29,11 @@ class App.UiElement.postmaster_set
|
||||
relation: 'Group'
|
||||
},
|
||||
{
|
||||
value: 'x-zammad-ticket-owner'
|
||||
value: 'x-zammad-ticket-owner_id'
|
||||
name: 'Owner'
|
||||
relation: 'User',
|
||||
tag: 'user_autocompletion',
|
||||
relation: 'User'
|
||||
tag: 'user_autocompletion'
|
||||
disableCreateUser: true,
|
||||
},
|
||||
{
|
||||
value: 'x-zammad-ignore'
|
||||
|
||||
@@ -368,9 +368,11 @@ class App.UiElement.ticket_selector
|
||||
if config.relation is 'User'
|
||||
config.multiple = false
|
||||
config.nulloption = false
|
||||
config.guess = false
|
||||
if config.relation is 'Organization'
|
||||
config.multiple = false
|
||||
config.nulloption = false
|
||||
config.guess = false
|
||||
if config.tag is 'checkbox'
|
||||
config.tag = 'select'
|
||||
tagSearch = "#{config.tag}_search"
|
||||
|
||||
@@ -102,12 +102,20 @@ class App.UiElement.user_permission
|
||||
if !checked
|
||||
if rolesWithGroupPlugin[role_id] is 'group'
|
||||
item.find('.js-groupList').addClass('hidden')
|
||||
|
||||
# select groups if only one is available
|
||||
if hideGroups
|
||||
item.find('.js-groupList [name=group_ids]').prop('checked', false)
|
||||
return
|
||||
|
||||
# if role with groups plugin is selected, show group selection
|
||||
if rolesWithGroupPlugin[role_id] is 'group'
|
||||
item.find('.js-groupList:not(.js-groupListHide)').removeClass('hidden')
|
||||
|
||||
# select groups if only one is available
|
||||
if hideGroups
|
||||
item.find('.js-groupList [name=group_ids]').prop('checked', true)
|
||||
|
||||
for trigger in triggers
|
||||
trigger.trigger('change')
|
||||
)
|
||||
|
||||
@@ -68,17 +68,18 @@ class Index extends App.ControllerContent
|
||||
params: defaults
|
||||
noFieldset: true
|
||||
)
|
||||
#new App.ControllerForm(
|
||||
# el: @el.find('.ticket-form-bottom')
|
||||
# form_id: @form_id
|
||||
# model: App.Ticket
|
||||
# screen: 'create_bottom'#@article_attributes['screen']
|
||||
# handlers: [
|
||||
# formChanges
|
||||
# ]
|
||||
# filter: @formMeta.filter
|
||||
# params: defaults
|
||||
#)
|
||||
if !_.isEmpty(App.Ticket.attributesGet('create_bottom', false, true))
|
||||
new App.ControllerForm(
|
||||
el: @el.find('.ticket-form-bottom')
|
||||
form_id: @form_id
|
||||
model: App.Ticket
|
||||
screen: 'create_bottom'
|
||||
handlers: [
|
||||
@ticketFormChanges
|
||||
]
|
||||
filter: @formMeta.filter
|
||||
params: defaults
|
||||
)
|
||||
|
||||
new App.ControllerDrox(
|
||||
el: @el.find('.sidebar')
|
||||
|
||||
@@ -424,11 +424,13 @@ class Table extends App.Controller
|
||||
attribute.link = object.uiUrl()
|
||||
value
|
||||
callbackUserPopover = (value, object, attribute, attributes, refObject) ->
|
||||
return value if !refObject
|
||||
attribute.class = 'user-popover'
|
||||
attribute.data =
|
||||
id: refObject.id
|
||||
value
|
||||
callbackOrganizationPopover = (value, object, attribute, attributes, refObject) ->
|
||||
return value if !refObject
|
||||
attribute.class = 'organization-popover'
|
||||
attribute.data =
|
||||
id: refObject.id
|
||||
@@ -716,6 +718,11 @@ class BulkForm extends App.Controller
|
||||
return
|
||||
|
||||
ticket.load(ticket_update)
|
||||
|
||||
# if title is empty - ticket can't processed, set ?
|
||||
if _.isEmpty(ticket.title)
|
||||
ticket.title = '-'
|
||||
|
||||
ticket.save(
|
||||
done: (r) =>
|
||||
@bulk_count_index++
|
||||
|
||||
@@ -698,11 +698,9 @@ class App.TicketZoom extends App.Controller
|
||||
if !ticket['owner_id']
|
||||
ticket['owner_id'] = 1
|
||||
|
||||
# check if title exists
|
||||
if !ticket['title']
|
||||
alert( App.i18n.translateContent('Title needed') )
|
||||
@formEnable(e)
|
||||
return
|
||||
# if title is empty - ticket can't processed, set ?
|
||||
if _.isEmpty(ticket.title)
|
||||
ticket.title = '-'
|
||||
|
||||
# stop autosave
|
||||
@autosaveStop()
|
||||
|
||||
@@ -123,6 +123,13 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||
icon: 'reply'
|
||||
href: '#'
|
||||
}
|
||||
if article.sender.name is 'Agent' && article.type.name is 'phone'
|
||||
actions.push {
|
||||
name: 'reply'
|
||||
type: 'emailReply'
|
||||
icon: 'reply'
|
||||
href: '#'
|
||||
}
|
||||
if article.type.name is 'twitter status'
|
||||
actions.push {
|
||||
name: 'reply'
|
||||
@@ -284,6 +291,7 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||
# get reference article
|
||||
article_id = $(e.target).parents('[data-id]').data('id')
|
||||
article = App.TicketArticle.fullLocal(article_id)
|
||||
ticket = App.Ticket.fullLocal(article.ticket_id)
|
||||
type = App.TicketArticleType.find(article.type_id)
|
||||
customer = App.User.find(article.created_by_id)
|
||||
|
||||
@@ -304,15 +312,31 @@ class App.TicketZoomArticleActions extends App.Controller
|
||||
|
||||
if type.name is 'email' || type.name is 'phone' || type.name is 'web'
|
||||
|
||||
if article.sender.name is 'Agent'
|
||||
articleNew.to = article.to
|
||||
else
|
||||
articleNew.to = article.from
|
||||
if type.name is 'phone'
|
||||
|
||||
# inbound call
|
||||
if article.sender.name is 'Agent'
|
||||
articleNew.to = article.to
|
||||
|
||||
# outbound call
|
||||
else
|
||||
articleNew.to = article.to
|
||||
|
||||
# if sender is customer but in article.from is no email, try to get
|
||||
# customers email via customer user
|
||||
if articleNew.to && !articleNew.to.match(/@/)
|
||||
articleNew.to = article.created_by.email
|
||||
articleNew.to = ticket.customer.email
|
||||
|
||||
else
|
||||
if article.sender.name is 'Agent'
|
||||
articleNew.to = article.to
|
||||
else
|
||||
articleNew.to = article.from
|
||||
|
||||
# if sender is customer but in article.from is no email, try to get
|
||||
# customers email via customer user
|
||||
if articleNew.to && !articleNew.to.match(/@/)
|
||||
articleNew.to = article.created_by.email
|
||||
|
||||
# filter for uniq recipients
|
||||
recipientAddresses = {}
|
||||
|
||||
@@ -48,6 +48,7 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||
possibleArticleType['email'] = true
|
||||
|
||||
# gets referenced in @setArticleType
|
||||
@internalSelector = true
|
||||
@type = @defaults['type'] || 'note'
|
||||
@articleTypes = []
|
||||
if possibleArticleType.note
|
||||
@@ -115,6 +116,9 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||
},
|
||||
]
|
||||
|
||||
if @permissionCheck('ticket.customer')
|
||||
@internalSelector = false
|
||||
|
||||
@textareaHeight =
|
||||
open: 148
|
||||
closed: 20
|
||||
@@ -194,11 +198,12 @@ class App.TicketZoomArticleNew extends App.Controller
|
||||
ticket = App.Ticket.fullLocal(@ticket_id)
|
||||
|
||||
@html App.view('ticket_zoom/article_new')(
|
||||
ticket: ticket
|
||||
articleTypes: @articleTypes
|
||||
article: @defaults
|
||||
form_id: @form_id
|
||||
isCustomer: @permissionCheck('ticket.customer')
|
||||
ticket: ticket
|
||||
articleTypes: @articleTypes
|
||||
article: @defaults
|
||||
form_id: @form_id
|
||||
isCustomer: @permissionCheck('ticket.customer')
|
||||
internalSelector: @internalSelector
|
||||
)
|
||||
@setArticleType(@type)
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class App.TicketZoomAttributeBar extends App.Controller
|
||||
if @resetButton.get(0) && !@resetButton.hasClass('hide')
|
||||
resetButtonShown = true
|
||||
|
||||
macros = App.Macro.all()
|
||||
macros = App.Macro.findAllByAttribute('active', true)
|
||||
@macroLastUpdated = App.Macro.lastUpdatedAt()
|
||||
|
||||
if _.isEmpty(macros) || !@permissionCheck('ticket.agent')
|
||||
|
||||
@@ -164,14 +164,16 @@ class Index extends App.ControllerSubContent
|
||||
type: 'GET'
|
||||
url: "#{@apiPath}/translations/sync/#{locale.locale}"
|
||||
processData: false
|
||||
complete: (data, status, xhr) =>
|
||||
success: =>
|
||||
loader.update(locale.name, false)
|
||||
locale = locales.shift()
|
||||
if _.isEmpty(locales)
|
||||
hide()
|
||||
return
|
||||
@_syncChanges(locale, locales, loader, hide)
|
||||
)
|
||||
error: ->
|
||||
hide()
|
||||
)
|
||||
|
||||
updateOnServer: (params, event) =>
|
||||
|
||||
|
||||
@@ -16,11 +16,13 @@ class App.TicketList extends App.Controller
|
||||
attribute.link = object.uiUrl()
|
||||
value
|
||||
callbackUserPopover = (value, object, attribute, attributes, refObject) ->
|
||||
return value if !refObject
|
||||
attribute.class = 'user-popover'
|
||||
attribute.data =
|
||||
id: refObject.id
|
||||
value
|
||||
callbackOrganizationPopover = (value, object, attribute, attributes, refObject) ->
|
||||
return value if !refObject
|
||||
attribute.class = 'organization-popover'
|
||||
attribute.data =
|
||||
id: refObject.id
|
||||
|
||||
@@ -9,7 +9,8 @@ class App.GlobalSearch
|
||||
class _globalSearchSingleton extends Spine.Module
|
||||
|
||||
constructor: ->
|
||||
@searchResultCache = {}
|
||||
@searchResultCache = undefined
|
||||
@searchResultCacheByKey = {}
|
||||
@apiPath = App.Config.get('api_path')
|
||||
|
||||
execute: (params) ->
|
||||
@@ -20,8 +21,8 @@ class _globalSearchSingleton extends Spine.Module
|
||||
|
||||
# use cache for search result
|
||||
currentTime = new Date
|
||||
if @searchResultCache[cacheKey] && @searchResultCache[cacheKey].time > currentTime.setSeconds(currentTime.getSeconds() - 20)
|
||||
render(@searchResultCache[cacheKey].result)
|
||||
if @searchResultCacheByKey[cacheKey] && @searchResultCacheByKey[cacheKey].time > currentTime.setSeconds(currentTime.getSeconds() - 20)
|
||||
@renderTry(render, @searchResultCacheByKey[cacheKey].result, cacheKey)
|
||||
return
|
||||
|
||||
App.Ajax.request(
|
||||
@@ -31,7 +32,7 @@ class _globalSearchSingleton extends Spine.Module
|
||||
data:
|
||||
query: query
|
||||
limit: limit
|
||||
processData: true,
|
||||
processData: true
|
||||
success: (data, status, xhr) =>
|
||||
App.Collection.loadAssets(data.assets)
|
||||
result = {}
|
||||
@@ -48,19 +49,21 @@ class _globalSearchSingleton extends Spine.Module
|
||||
else
|
||||
App.Log.error('_globalSearchSingleton', "No such model App.#{item.type}")
|
||||
|
||||
diff = false
|
||||
if @searchResultCache[cacheKey]
|
||||
diff = difference(@searchResultCache[cacheKey].resultRaw, data.result)
|
||||
|
||||
# cache search result
|
||||
@searchResultCache[cacheKey] =
|
||||
result: result
|
||||
resultRaw: data.result
|
||||
limit: limit
|
||||
time: new Date
|
||||
|
||||
# if result hasn't changed, do not rerender
|
||||
return if diff isnt false && _.isEmpty(diff)
|
||||
|
||||
render(result)
|
||||
@renderTry(render, result, cacheKey)
|
||||
)
|
||||
|
||||
renderTry: (render, result, cacheKey) =>
|
||||
|
||||
# if result hasn't changed, do not rerender
|
||||
diff = false
|
||||
if @searchResultCache
|
||||
diff = difference(@searchResultCache, result)
|
||||
return if diff isnt false && _.isEmpty(diff)
|
||||
|
||||
# cache search result
|
||||
@searchResultCache = result
|
||||
@searchResultCacheByKey[cacheKey] =
|
||||
result: result
|
||||
time: new Date
|
||||
|
||||
render(result)
|
||||
|
||||
@@ -282,15 +282,20 @@ class _i18nSingleton extends Spine.Module
|
||||
notTranslated
|
||||
|
||||
removeNotTranslated: (locale, key) =>
|
||||
return if !@_notTranslated[locale]
|
||||
delete @_notTranslated[locale][key]
|
||||
|
||||
setNotTranslated: (locale, key) =>
|
||||
if !@_notTranslated[locale]
|
||||
@_notTranslated[locale] = {}
|
||||
@_notTranslated[locale][key] = true
|
||||
|
||||
date: (time, offset) =>
|
||||
return time if !time
|
||||
@convert(time, offset, @mapTime['date'] || @dateFormat)
|
||||
|
||||
timestamp: (time, offset) =>
|
||||
return time if !time
|
||||
@convert(time, offset, @mapTime['timestamp'] || @timestampFormat)
|
||||
|
||||
convert: (time, offset, format) ->
|
||||
|
||||
@@ -206,7 +206,7 @@ class App.Utils
|
||||
|
||||
# Replace all x tags with the type of replacementTag
|
||||
html.find('textarea').each( ->
|
||||
outer = @outerHTML;
|
||||
outer = @outerHTML
|
||||
|
||||
# Replace opening tag
|
||||
regex = new RegExp('<' + @tagName, 'i')
|
||||
|
||||
@@ -485,13 +485,21 @@
|
||||
},
|
||||
|
||||
highlightHour: function() {
|
||||
var time = this.$element.val(),
|
||||
timeArray = time.replace(/[^0-9\:]/g, '').split(':'),
|
||||
hour = timeArray[0] ? timeArray[0].toString() : timeArray.toString(),
|
||||
hour_max_length = hour.toString().length
|
||||
this.highlightedUnit = 'hour';
|
||||
this.setSelectionRange(0, 2);
|
||||
this.setSelectionRange(0, hour_max_length);
|
||||
},
|
||||
|
||||
highlightMinute: function() {
|
||||
var time = this.$element.val(),
|
||||
timeArray = time.replace(/[^0-9\:]/g, '').split(':'),
|
||||
hour = timeArray[0] ? timeArray[0].toString() : timeArray.toString(),
|
||||
hour_max_length = hour.toString().length
|
||||
this.highlightedUnit = 'minute';
|
||||
this.setSelectionRange(3, 5);
|
||||
this.setSelectionRange(hour_max_length+1, hour_max_length+3);
|
||||
},
|
||||
|
||||
highlightSecond: function() {
|
||||
@@ -790,7 +798,8 @@
|
||||
|
||||
hour = timeArray[0] ? timeArray[0].toString() : timeArray.toString();
|
||||
|
||||
if(this.explicitMode && hour.length > 2 && (hour.length % 2) !== 0 ) {
|
||||
var hour_max_length = this.maxHours.toString().length
|
||||
if(this.explicitMode && hour.length > hour_max_length && (hour.length % 2) !== 0 ) {
|
||||
this.clear();
|
||||
return;
|
||||
}
|
||||
@@ -804,9 +813,9 @@
|
||||
hour = hour.slice(0, -2);
|
||||
}
|
||||
|
||||
if (hour.length > 2) {
|
||||
minute = hour.slice(-2);
|
||||
hour = hour.slice(0, -2);
|
||||
if (hour.length > hour_max_length) {
|
||||
minute = hour.slice(-hour_max_length);
|
||||
hour = hour.slice(0, -hour_max_length);
|
||||
}
|
||||
|
||||
if (minute.length > 2) {
|
||||
@@ -838,9 +847,9 @@
|
||||
minute = 59;
|
||||
}
|
||||
|
||||
if (hour >= this.maxHours) {
|
||||
if (hour > this.maxHours) {
|
||||
// No day/date handling.
|
||||
hour = this.maxHours - 1;
|
||||
hour = this.maxHours;
|
||||
}
|
||||
|
||||
if (this.showMeridian) {
|
||||
@@ -859,7 +868,7 @@
|
||||
} else if (hour < 12 && timeMode === 2) {
|
||||
hour += 12;
|
||||
} else {
|
||||
if (hour >= this.maxHours) {
|
||||
if (hour > this.maxHours) {
|
||||
hour = this.maxHours - 1;
|
||||
} else if ((hour < 0) || (hour === 12 && timeMode === 1)){
|
||||
hour = 0;
|
||||
|
||||
@@ -184,7 +184,7 @@ class App.Model extends Spine.Model
|
||||
|
||||
###
|
||||
|
||||
@attributesGet: (screen = undefined, attributes = false) ->
|
||||
@attributesGet: (screen = undefined, attributes = false, noDefaultAttributes = false) ->
|
||||
if !attributes
|
||||
attributes = clone(App[ @.className ].configure_attributes, true)
|
||||
else
|
||||
@@ -203,7 +203,7 @@ class App.Model extends Spine.Model
|
||||
attributesNew[ attribute.name ] = attribute
|
||||
|
||||
# if no screen is given or no attribute has this screen - use default attributes
|
||||
if !screen || _.isEmpty(attributesNew)
|
||||
if (!screen || _.isEmpty(attributesNew)) && !noDefaultAttributes
|
||||
for attribute in attributes
|
||||
attributesNew[ attribute.name ] = attribute
|
||||
|
||||
|
||||
@@ -89,4 +89,6 @@ class App.Ticket extends App.Model
|
||||
return App.i18n.translateContent('Pending reminder reached for Ticket |%s|', item.title)
|
||||
else if item.type is 'escalation'
|
||||
return App.i18n.translateContent('Ticket |%s| is escalated!', item.title)
|
||||
else if item.type is 'escalation_warning'
|
||||
return App.i18n.translateContent('Ticket |%s| will escalate soon!', item.title)
|
||||
return "Unknow action for (#{@objectDisplayName()}/#{item.type}), extend activityMessage() of model."
|
||||
|
||||
@@ -108,7 +108,7 @@
|
||||
<% if !_.isEmpty(channel.last_log_out): %>
|
||||
<div class="alert alert--danger">
|
||||
<%= channel.last_log_out %>
|
||||
<div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
<hr>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="newTicket">
|
||||
<div class="box box--newTicket">
|
||||
<div class="page-header">
|
||||
<h1><%- @T( 'New Ticket' ) %></h1>
|
||||
<h1><%- @T('New Ticket') %></h1>
|
||||
</div>
|
||||
|
||||
<div class="page-content">
|
||||
@@ -18,7 +18,6 @@
|
||||
<div class="ticket-form-bottom"></div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-controls">
|
||||
<a class="btn btn--text btn--subtle js-cancel" href="#/"><%- @T( 'Cancel & Go Back' ) %></a>
|
||||
<button type="submit" class="btn btn--success js-submit align-right"><%- @T( 'Create' ) %></button>
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<input type="checkbox" value="<%= group.id %>" name="group_ids" <% if @groupsSelected[group.id]: %>checked<% end %>/>
|
||||
<%- @Icon('checkbox', 'icon-unchecked') %>
|
||||
<%- @Icon('checkbox-checked', 'icon-checked') %>
|
||||
<span class="label-text"><%= group.displayName() %> <% if group.note: %>- <span class="help-text"><%= group.note %></span><% end %></span>
|
||||
<span class="label-text"><%= group.displayName() %> <% if group.note: %>- <span class="help-text"><%- group.note %></span><% end %></span>
|
||||
</label>
|
||||
<% end %>
|
||||
</div>
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
<% if @internalSelector: %>
|
||||
<div class="editControls-item is-hidden js-toggleVisibility js-selectInternalPublic">
|
||||
<div class="editControls-iconHolder">
|
||||
<div class="editControls-icon icon-internal" title="<%- @Ti("set to public") %>">
|
||||
@@ -31,6 +32,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<% end %>
|
||||
</div>
|
||||
<div class="article-content bubble-gap">
|
||||
<div class="internal-border">
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<div class="attachments-title"><%- @article.attachments.length %> <%- @T('Attached Files') %></div>
|
||||
<% for attachment in @article.attachments: %>
|
||||
<div class="attachment">
|
||||
<a class="attachment-name u-highlight" href="<%= App.Config.get('api_path') %>/ticket_attachment/<%= @article.ticket_id %>/<%= @article.id %>/<%= attachment.id %>" target="_blank" data-type="attachment"><%= attachment.filename %></a>
|
||||
<a class="attachment-name u-highlight" href="<%= App.Config.get('api_path') %>/ticket_attachment/<%= @article.ticket_id %>/<%= @article.id %>/<%= attachment.id %>?disposition=attachment" target="_blank" data-type="attachment"><%= attachment.filename %></a>
|
||||
<div class="attachment-size"><%- @humanFileSize(attachment.size) %></div>
|
||||
</div>
|
||||
<% end %>
|
||||
|
||||
@@ -1594,7 +1594,6 @@ input[type=time] {
|
||||
|
||||
input.timeframe,
|
||||
input.time {
|
||||
width: 4.5ch;
|
||||
box-sizing: content-box;
|
||||
padding: 0 6px;
|
||||
line-height: 42px;
|
||||
@@ -1605,6 +1604,13 @@ input.time {
|
||||
}
|
||||
}
|
||||
|
||||
input.timeframe {
|
||||
width: 5.5ch;
|
||||
}
|
||||
input.time {
|
||||
width: 4.5ch;
|
||||
}
|
||||
|
||||
input.time.time--12 {
|
||||
width: 7.5ch;
|
||||
}
|
||||
|
||||
@@ -239,11 +239,14 @@ class TicketArticlesController < ApplicationController
|
||||
|
||||
# find file
|
||||
file = Store.find(params[:id])
|
||||
|
||||
disposition = sanitized_disposition
|
||||
|
||||
send_data(
|
||||
file.content,
|
||||
filename: file.filename,
|
||||
type: file.preferences['Content-Type'] || file.preferences['Mime-Type'],
|
||||
disposition: 'inline'
|
||||
disposition: disposition
|
||||
)
|
||||
end
|
||||
|
||||
@@ -271,4 +274,12 @@ class TicketArticlesController < ApplicationController
|
||||
)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def sanitized_disposition
|
||||
disposition = params.fetch(:disposition, 'inline')
|
||||
valid_disposition = %w(inline attachment)
|
||||
return disposition if valid_disposition.include?(disposition)
|
||||
raise Exceptions::NotAuthorized, "Invalid disposition #{disposition} requested. Only #{valid_disposition.join(', ')} are valid."
|
||||
end
|
||||
end
|
||||
|
||||
@@ -50,11 +50,7 @@ add a new activity entry for an object
|
||||
|
||||
# resturn if old entry is really fresh
|
||||
if result
|
||||
activity_record_delay = if ENV['ZAMMAD_ACTIVITY_RECORD_DELAY']
|
||||
ENV['ZAMMAD_ACTIVITY_RECORD_DELAY'].to_i.seconds
|
||||
else
|
||||
90.seconds
|
||||
end
|
||||
activity_record_delay = 90.seconds
|
||||
return result if result.created_at.to_i >= ( data[:created_at].to_i - activity_record_delay )
|
||||
end
|
||||
|
||||
@@ -97,13 +93,10 @@ return all activity entries of an user
|
||||
=end
|
||||
|
||||
def self.list(user, limit)
|
||||
# do not return an activity stream for custoers
|
||||
# do not return an activity stream for customers
|
||||
return [] if !user.permissions?('ticket.agent') && !user.permissions?('admin')
|
||||
|
||||
permission_ids = []
|
||||
user.roles.each { |role|
|
||||
permission_ids = permission_ids.concat(role.permission_ids)
|
||||
}
|
||||
permission_ids = user.permissions_with_child_ids
|
||||
group_ids = user.group_ids
|
||||
|
||||
stream = if group_ids.empty?
|
||||
|
||||
@@ -201,6 +201,9 @@ returns
|
||||
next if !respond_to?(real_ids)
|
||||
attributes[real_ids] = send(real_ids)
|
||||
}
|
||||
|
||||
filter_attributes(attributes)
|
||||
|
||||
Cache.write(key, attributes)
|
||||
attributes
|
||||
end
|
||||
@@ -260,12 +263,16 @@ returns
|
||||
attributes[destination] = user.login
|
||||
}
|
||||
|
||||
filter_attributes(attributes)
|
||||
|
||||
attributes
|
||||
end
|
||||
|
||||
def filter_attributes(attributes)
|
||||
# remove forbitten attributes
|
||||
%w(password token tokens token_ids).each { |item|
|
||||
attributes.delete(item)
|
||||
}
|
||||
|
||||
attributes
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
@@ -126,6 +126,21 @@ module Channel::EmailBuild
|
||||
mail
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
quoted_in_one_line = Channel::EmailBuild.recipient_line('Somebody @ "Company"', 'some.body@example.com')
|
||||
|
||||
returnes
|
||||
|
||||
'"Somebody @ \"Company\"" <some.body@example.com>'
|
||||
|
||||
=end
|
||||
|
||||
def self.recipient_line(realname, email)
|
||||
return "#{realname} <#{email}>" if realname =~ /^[A-z]+$/i
|
||||
"\"#{realname.gsub('"', '\"')}\" <#{email}>"
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
Check if string is a complete html document. If not, add head and css styles.
|
||||
|
||||
@@ -81,14 +81,14 @@ class Channel::EmailParser
|
||||
data[field.name.to_s.downcase.to_sym] = Encode.conv('utf8', field.to_s)
|
||||
|
||||
# if we need to access the lines by objects later again
|
||||
data[ "raw-#{field.name.downcase}".to_sym ] = field
|
||||
data["raw-#{field.name.downcase}".to_sym] = field
|
||||
}
|
||||
|
||||
# get sender
|
||||
from = nil
|
||||
['from', 'reply-to', 'return-path'].each { |item|
|
||||
next if !mail[ item.to_sym ]
|
||||
from = mail[ item.to_sym ].value
|
||||
next if !mail[item.to_sym]
|
||||
from = mail[item.to_sym].value
|
||||
break if from
|
||||
}
|
||||
|
||||
@@ -371,7 +371,7 @@ returns
|
||||
do not raise an exception - e. g. if used by scheduler
|
||||
|
||||
parser = Channel::EmailParser.new
|
||||
ticket, article, user = parser.process(channel, email_raw_string, fakse)
|
||||
ticket, article, user = parser.process(channel, email_raw_string, false)
|
||||
|
||||
returns
|
||||
|
||||
@@ -424,7 +424,7 @@ returns
|
||||
}
|
||||
|
||||
# check ignore header
|
||||
if mail[ 'x-zammad-ignore'.to_sym ] == 'true' || mail[ 'x-zammad-ignore'.to_sym ] == true
|
||||
if mail['x-zammad-ignore'.to_sym] == 'true' || mail['x-zammad-ignore'.to_sym] == true
|
||||
Rails.logger.info "ignored email with msgid '#{mail[:message_id]}' from '#{mail[:from]}' because of x-zammad-ignore header"
|
||||
return true
|
||||
end
|
||||
@@ -440,7 +440,7 @@ returns
|
||||
Transaction.execute(interface_handle: "#{original_interface_handle}.postmaster") do
|
||||
|
||||
# get sender user
|
||||
session_user_id = mail[ 'x-zammad-session-user-id'.to_sym ]
|
||||
session_user_id = mail['x-zammad-session-user-id'.to_sym]
|
||||
if !session_user_id
|
||||
raise 'No x-zammad-session-user-id, no sender set!'
|
||||
end
|
||||
@@ -453,11 +453,11 @@ returns
|
||||
UserInfo.current_user_id = session_user.id
|
||||
|
||||
# get ticket# based on email headers
|
||||
if mail[ 'x-zammad-ticket-id'.to_sym ]
|
||||
ticket = Ticket.find_by(id: mail[ 'x-zammad-ticket-id'.to_sym ])
|
||||
if mail['x-zammad-ticket-id'.to_sym]
|
||||
ticket = Ticket.find_by(id: mail['x-zammad-ticket-id'.to_sym])
|
||||
end
|
||||
if mail[ 'x-zammad-ticket-number'.to_sym ]
|
||||
ticket = Ticket.find_by(number: mail[ 'x-zammad-ticket-number'.to_sym ])
|
||||
if mail['x-zammad-ticket-number'.to_sym]
|
||||
ticket = Ticket.find_by(number: mail['x-zammad-ticket-number'.to_sym])
|
||||
end
|
||||
|
||||
# set ticket state to open if not new
|
||||
@@ -476,8 +476,8 @@ returns
|
||||
end
|
||||
|
||||
# set ticket to open again
|
||||
if !mail[ 'x-zammad-ticket-followup-state'.to_sym ]
|
||||
if state_type.name != 'new' && !mail[ 'x-zammad-out-of-office'.to_sym ]
|
||||
if !mail['x-zammad-ticket-followup-state'.to_sym] && !mail['x-zammad-ticket-followup-state_id'.to_sym]
|
||||
if state_type.name != 'new' && !mail['x-zammad-out-of-office'.to_sym]
|
||||
ticket.state = Ticket::State.find_by(name: 'open')
|
||||
ticket.save!
|
||||
end
|
||||
@@ -601,12 +601,12 @@ returns
|
||||
header = "x-zammad-#{header_name}-#{suffix}-#{key_short}"
|
||||
end
|
||||
if mail[ header.to_sym ]
|
||||
Rails.logger.info "header #{header} found #{mail[ header.to_sym ]}"
|
||||
Rails.logger.info "header #{header} found #{mail[header.to_sym]}"
|
||||
item_object.class.reflect_on_all_associations.map { |assoc|
|
||||
|
||||
next if assoc.name.to_s != key_short
|
||||
|
||||
Rails.logger.info "ASSOC found #{assoc.class_name} lookup #{mail[ header.to_sym ]}"
|
||||
Rails.logger.info "ASSOC found #{assoc.class_name} lookup #{mail[header.to_sym]}"
|
||||
item = assoc.class_name.constantize
|
||||
|
||||
if item.respond_to?(:name)
|
||||
@@ -627,9 +627,9 @@ returns
|
||||
if suffix
|
||||
header = "x-zammad-#{header_name}-#{suffix}-#{key}"
|
||||
end
|
||||
if mail[ header.to_sym ]
|
||||
Rails.logger.info "header #{header} found #{mail[ header.to_sym ]}"
|
||||
item_object[key] = mail[ header.to_sym ]
|
||||
if mail[header.to_sym]
|
||||
Rails.logger.info "header #{header} found #{mail[header.to_sym]}"
|
||||
item_object[key] = mail[header.to_sym]
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
# process all database filter
|
||||
module Channel::Filter::Database
|
||||
|
||||
def self.run( _channel, mail )
|
||||
def self.run(_channel, mail)
|
||||
|
||||
# process postmaster filter
|
||||
filters = PostmasterFilter.where( active: true, channel: 'email' ).order(:name, :created_at)
|
||||
filters = PostmasterFilter.where(active: true, channel: 'email').order(:name, :created_at)
|
||||
filters.each { |filter|
|
||||
Rails.logger.info " process filter #{filter.name} ..."
|
||||
all_matches_ok = true
|
||||
|
||||
@@ -14,7 +14,7 @@ module Channel::Filter::FollowUpCheck
|
||||
return true
|
||||
end
|
||||
|
||||
setting = Setting.get('postmaster_follow_up_search_in')
|
||||
setting = Setting.get('postmaster_follow_up_search_in') || []
|
||||
|
||||
# get ticket# from body
|
||||
if setting.include?('body')
|
||||
@@ -39,7 +39,7 @@ module Channel::Filter::FollowUpCheck
|
||||
end
|
||||
|
||||
# get ticket# from references
|
||||
if setting.include?('references') || mail[ 'x-zammad-is-auto-response'.to_sym ] == true
|
||||
if setting.include?('references') || (mail[ 'x-zammad-is-auto-response'.to_sym ] == true || Setting.get('ticket_hook_position') == 'none')
|
||||
|
||||
# get all references 'References' + 'In-Reply-To'
|
||||
references = ''
|
||||
@@ -66,7 +66,7 @@ module Channel::Filter::FollowUpCheck
|
||||
end
|
||||
|
||||
# get ticket# from references current email has same subject as inital article
|
||||
if !mail[:subject].empty?
|
||||
if mail[:subject].present?
|
||||
|
||||
# get all references 'References' + 'In-Reply-To'
|
||||
references = ''
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
class Chat::Message < ApplicationModel
|
||||
include HtmlSanitized
|
||||
|
||||
sanitized_html :content
|
||||
end
|
||||
|
||||
46
app/models/concerns/html_sanitized.rb
Normal file
46
app/models/concerns/html_sanitized.rb
Normal file
@@ -0,0 +1,46 @@
|
||||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
module HtmlSanitized
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
included do
|
||||
before_create :sanitized_html_attributes
|
||||
before_update :sanitized_html_attributes
|
||||
end
|
||||
|
||||
def sanitized_html_attributes
|
||||
html_attributes = self.class.instance_variable_get(:@sanitized_html) || []
|
||||
return if html_attributes.empty?
|
||||
|
||||
html_attributes.each do |attribute|
|
||||
value = send(attribute)
|
||||
|
||||
next if value.blank?
|
||||
next if !sanitizeable?(attribute, value)
|
||||
|
||||
send("#{attribute}=".to_sym, HtmlSanitizer.strict(value))
|
||||
end
|
||||
end
|
||||
|
||||
def sanitizeable?(_attribute, _value)
|
||||
true
|
||||
end
|
||||
|
||||
# methods defined here are going to extend the class, not the instance of it
|
||||
class_methods do
|
||||
|
||||
=begin
|
||||
|
||||
serve methode to mark HTML attrbibutes that need to get sanitized
|
||||
|
||||
class Model < ApplicationModel
|
||||
include Sanitized
|
||||
sanitized_html :body
|
||||
end
|
||||
|
||||
=end
|
||||
|
||||
def sanitized_html(*attributes)
|
||||
@sanitized_html = attributes
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -663,6 +663,14 @@ to send no browser reload event, pass false
|
||||
raise 'At least one letters is needed'
|
||||
elsif name =~ /^(destroy|true|false|integer|select|drop|create|alter|index|table|varchar|blob|date|datetime|timestamp)$/
|
||||
raise "#{name} is a reserved word, please choose a different one"
|
||||
|
||||
# do not allow model method names as attributes
|
||||
else
|
||||
model = Kernel.const_get(object_lookup.name)
|
||||
record = model.new
|
||||
if record.respond_to?(name.to_sym) && !record.attributes.key?(name)
|
||||
raise "#{name} is a reserved word, please choose a different one"
|
||||
end
|
||||
end
|
||||
true
|
||||
end
|
||||
|
||||
@@ -46,13 +46,13 @@ class Observer::Ticket::Article::FillupFromEmail < ActiveRecord::Observer
|
||||
if !email_address
|
||||
raise "No email address found for group '#{ticket.group.name}'"
|
||||
end
|
||||
system_sender = "#{email_address.realname} <#{email_address.email}>"
|
||||
if record.created_by_id != 1 && Setting.get('ticket_define_email_from') == 'AgentNameSystemAddressName'
|
||||
seperator = Setting.get('ticket_define_email_from_seperator')
|
||||
sender = User.find(record.created_by_id)
|
||||
record.from = "#{sender.firstname} #{sender.lastname} #{seperator} #{system_sender}"
|
||||
seperator = Setting.get('ticket_define_email_from_seperator')
|
||||
sender = User.find(record.created_by_id)
|
||||
realname = "#{sender.firstname} #{sender.lastname} #{seperator} #{email_address.realname}"
|
||||
record.from = Channel::EmailBuild.recipient_line(realname, email_address.email)
|
||||
else
|
||||
record.from = system_sender
|
||||
record.from = Channel::EmailBuild.recipient_line(email_address.realname, email_address.email)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -30,6 +30,20 @@ class Observer::Ticket::ArticleChanges < ActiveRecord::Observer
|
||||
record.ticket.save
|
||||
end
|
||||
|
||||
def after_destroy(record)
|
||||
changed = false
|
||||
if article_count_update(record)
|
||||
changed = true
|
||||
end
|
||||
|
||||
# save ticket
|
||||
if !changed
|
||||
record.ticket.touch
|
||||
return
|
||||
end
|
||||
record.ticket.save
|
||||
end
|
||||
|
||||
# get article count
|
||||
def article_count_update(record)
|
||||
current_count = record.ticket.article_count
|
||||
|
||||
@@ -52,7 +52,7 @@ get signup roles
|
||||
|
||||
Role.signup_roles
|
||||
|
||||
returnes
|
||||
returns
|
||||
|
||||
[role1, role2, ...]
|
||||
|
||||
@@ -68,7 +68,7 @@ get signup role ids
|
||||
|
||||
Role.signup_role_ids
|
||||
|
||||
returnes
|
||||
returns
|
||||
|
||||
[role1, role2, ...]
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
# Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
|
||||
class Ticket::Article < ApplicationModel
|
||||
include HtmlSanitized
|
||||
|
||||
load 'ticket/article/assets.rb'
|
||||
include Ticket::Article::Assets
|
||||
load 'ticket/article/history_log.rb'
|
||||
@@ -16,6 +18,8 @@ class Ticket::Article < ApplicationModel
|
||||
before_create :check_subject, :check_message_id_md5
|
||||
before_update :check_subject, :check_message_id_md5
|
||||
|
||||
sanitized_html :body
|
||||
|
||||
notify_clients_support
|
||||
|
||||
activity_stream_support(
|
||||
@@ -164,6 +168,12 @@ get body as text with quote sign "> " at the beginning of each line
|
||||
body_as_text.word_wrap.message_quote
|
||||
end
|
||||
|
||||
def sanitizeable?(attribute, _value)
|
||||
return true if attribute != :body
|
||||
return false if content_type.blank?
|
||||
content_type =~ /html/i
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# strip not wanted chars
|
||||
|
||||
@@ -43,6 +43,14 @@ module Ticket::Number::Date
|
||||
# vehikel number. The modulus to 10 of this sum is substracted from
|
||||
# 10. See: http://www.pruefziffernberechnung.de/F/Fahrzeugnummer.shtml
|
||||
# (german)
|
||||
|
||||
# fix for https://github.com/zammad/zammad/issues/413 - can be removed later
|
||||
if config.class == FalseClass || config.class == TrueClass
|
||||
config = {
|
||||
checksum: config
|
||||
}
|
||||
end
|
||||
|
||||
if config[:checksum]
|
||||
chksum = 0
|
||||
mult = 1
|
||||
|
||||
@@ -16,32 +16,31 @@ returns
|
||||
=end
|
||||
|
||||
def self.all(data)
|
||||
current_user = data[:current_user]
|
||||
|
||||
# get customer overviews
|
||||
if data[:current_user].role?('Customer')
|
||||
role_id = Role.lookup(name: 'Customer').id
|
||||
overviews = if data[:current_user].organization_id && data[:current_user].organization.shared
|
||||
Overview.where(role_id: role_id, active: true).order(:prio)
|
||||
if current_user.permissions?('ticket.customer')
|
||||
overviews = if current_user.organization_id && current_user.organization.shared
|
||||
Overview.where(role_id: current_user.role_ids, active: true).order(:prio)
|
||||
else
|
||||
Overview.where(role_id: role_id, organization_shared: false, active: true).order(:prio)
|
||||
Overview.where(role_id: current_user.role_ids, organization_shared: false, active: true).order(:prio)
|
||||
end
|
||||
overviews_list = []
|
||||
overviews.each { |overview|
|
||||
user_ids = overview.user_ids
|
||||
next if !user_ids.empty? && !user_ids.include?(data[:current_user].id)
|
||||
next if !user_ids.empty? && !user_ids.include?(current_user.id)
|
||||
overviews_list.push overview
|
||||
}
|
||||
return overviews_list
|
||||
end
|
||||
|
||||
# get agent overviews
|
||||
return if !data[:current_user].role?('Agent')
|
||||
role_id = Role.lookup(name: 'Agent').id
|
||||
overviews = Overview.where(role_id: role_id, active: true).order(:prio)
|
||||
return [] if !current_user.permissions?('ticket.agent')
|
||||
overviews = Overview.where(role_id: current_user.role_ids, active: true).order(:prio)
|
||||
overviews_list = []
|
||||
overviews.each { |overview|
|
||||
user_ids = overview.user_ids
|
||||
next if !user_ids.empty? && !user_ids.include?(data[:current_user].id)
|
||||
next if !user_ids.empty? && !user_ids.include?(current_user.id)
|
||||
overviews_list.push overview
|
||||
}
|
||||
overviews_list
|
||||
@@ -86,17 +85,41 @@ returns
|
||||
overviews = Ticket::Overviews.all(
|
||||
current_user: user,
|
||||
)
|
||||
return [] if overviews.blank?
|
||||
|
||||
# get only tickets with permissions
|
||||
access_condition = Ticket.access_condition(user)
|
||||
|
||||
ticket_attributes = Ticket.new.attributes
|
||||
list = []
|
||||
overviews.each { |overview|
|
||||
query_condition, bind_condition, tables = Ticket.selector2sql(overview.condition, user)
|
||||
|
||||
order_by = "#{overview.order[:by]} #{overview.order[:direction]}"
|
||||
# validate direction
|
||||
raise "Invalid order direction '#{overview.order[:direction]}'" if overview.order[:direction] && overview.order[:direction] !~ /^(ASC|DESC)$/i
|
||||
|
||||
# check if order by exists
|
||||
order_by = overview.order[:by]
|
||||
if !ticket_attributes.key?(order_by)
|
||||
order_by = if ticket_attributes.key?("#{order_by}_id")
|
||||
"#{order_by}_id"
|
||||
else
|
||||
'created_at'
|
||||
end
|
||||
end
|
||||
order_by = "tickets.#{order_by} #{overview.order[:direction]}"
|
||||
|
||||
# check if group by exists
|
||||
if overview.group_by && !overview.group_by.empty?
|
||||
order_by = "#{overview.group_by}_id, #{order_by}"
|
||||
group_by = overview.group_by
|
||||
if !ticket_attributes.key?(group_by)
|
||||
group_by = if ticket_attributes.key?("#{group_by}_id")
|
||||
"#{group_by}_id"
|
||||
end
|
||||
end
|
||||
if group_by
|
||||
order_by = "tickets.#{group_by}, #{order_by}"
|
||||
end
|
||||
end
|
||||
|
||||
ticket_result = Ticket.select('id, updated_at')
|
||||
@@ -115,9 +138,10 @@ returns
|
||||
}
|
||||
tickets.push ticket_item
|
||||
}
|
||||
count = Ticket.where(access_condition).where(query_condition, *bind_condition).count()
|
||||
count = Ticket.where(access_condition).where(query_condition, *bind_condition).joins(tables).count()
|
||||
item = {
|
||||
overview: {
|
||||
name: overview.name,
|
||||
id: overview.id,
|
||||
view: overview.link,
|
||||
updated_at: overview.updated_at,
|
||||
|
||||
@@ -162,8 +162,9 @@ returns
|
||||
.order('tickets.created_at DESC')
|
||||
.limit(limit)
|
||||
else
|
||||
query_condition, bind_condition = selector2sql(condition)
|
||||
query_condition, bind_condition, tables = selector2sql(condition)
|
||||
tickets_all = Ticket.select('DISTINCT(tickets.id), tickets.created_at')
|
||||
.joins(tables)
|
||||
.where(access_condition)
|
||||
.where(query_condition, *bind_condition)
|
||||
.order('tickets.created_at DESC')
|
||||
|
||||
@@ -394,6 +394,32 @@ returns
|
||||
|
||||
=begin
|
||||
|
||||
returns all accessable permission ids of user
|
||||
|
||||
user = User.find(123)
|
||||
user.permissions_with_child_ids
|
||||
|
||||
returns
|
||||
|
||||
[permission1_id, permission2_id, permission3_id]
|
||||
|
||||
=end
|
||||
|
||||
def permissions_with_child_ids
|
||||
where = ''
|
||||
where_bind = [true]
|
||||
permissions.each { |permission_name, _value|
|
||||
where += ' OR ' if where != ''
|
||||
where += 'permissions.name = ? OR permissions.name LIKE ?'
|
||||
where_bind.push permission_name
|
||||
where_bind.push "#{permission_name}.%"
|
||||
}
|
||||
return [] if where == ''
|
||||
Object.const_get('Permission').where("permissions.active = ? AND (#{where})", *where_bind).pluck(:id)
|
||||
end
|
||||
|
||||
=begin
|
||||
|
||||
get all users with permission
|
||||
|
||||
users = User.with_permissions('admin.session')
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
Your #{product_name} password has been changed
|
||||
Your #{config.product_name} password has been changed
|
||||
|
||||
<p>Hi #{user.firstname},</p>
|
||||
<br>
|
||||
<p>The password for your #{product_name} account <b>#{user.login}</b> has been changed recently.</p>
|
||||
<p>The password for your #{config.product_name} account <b>#{user.login}</b> has been changed recently.</p>
|
||||
<br>
|
||||
<p>This activity is not known to you? If not, contact your system administrator.</p>
|
||||
<br>
|
||||
<p>Your #{product_name} Team</p>
|
||||
<p>Your #{config.product_name} Team</p>
|
||||
|
||||
48
config/initializers/html_sanitizer.rb
Normal file
48
config/initializers/html_sanitizer.rb
Normal file
@@ -0,0 +1,48 @@
|
||||
|
||||
# content of this tags will also be removed
|
||||
Rails.application.config.html_sanitizer_tags_remove_content = %w(
|
||||
style
|
||||
)
|
||||
|
||||
# only this tags are allowed
|
||||
Rails.application.config.html_sanitizer_tags_whitelist = %w(
|
||||
a abbr acronym address area article aside audio
|
||||
b bdi bdo big blockquote br
|
||||
canvas caption center cite code col colgroup command
|
||||
datalist dd del details dfn dir div dl dt em
|
||||
figcaption figure footer h1 h2 h3 h4 h5 h6 header hr
|
||||
i img ins kbd label legend li map mark menu meter nav
|
||||
ol output optgroup option p pre q
|
||||
s samp section small span strike strong sub summary sup
|
||||
text table tbody td tfoot th thead time tr tt u ul var video
|
||||
)
|
||||
|
||||
# attributes allowed for tags
|
||||
Rails.application.config.html_sanitizer_attributes_whitelist = {
|
||||
:all => %w(class dir lang style title translate data-signature data-signature-id),
|
||||
'a' => %w(href hreflang name rel),
|
||||
'abbr' => %w(title),
|
||||
'blockquote' => %w(cite),
|
||||
'col' => %w(span width),
|
||||
'colgroup' => %w(span width),
|
||||
'data' => %w(value),
|
||||
'del' => %w(cite datetime),
|
||||
'dfn' => %w(title),
|
||||
'img' => %w(align alt border height src srcset width),
|
||||
'ins' => %w(cite datetime),
|
||||
'li' => %w(value),
|
||||
'ol' => %w(reversed start type),
|
||||
'table' => %w(align bgcolor border cellpadding cellspacing frame rules sortable summary width),
|
||||
'td' => %w(abbr align axis colspan headers rowspan valign width),
|
||||
'th' => %w(abbr align axis colspan headers rowspan scope sorted valign width),
|
||||
'ul' => %w(type),
|
||||
'q' => %w(cite),
|
||||
'time' => %w(datetime pubdate),
|
||||
}
|
||||
|
||||
# only this css properties are allowed
|
||||
Rails.application.config.html_sanitizer_css_properties_whitelist = %w(
|
||||
width height
|
||||
max-width min-width
|
||||
max-height min-height
|
||||
)
|
||||
@@ -16,10 +16,10 @@ class CreateBase < ActiveRecord::Migration
|
||||
|
||||
create_table :users do |t|
|
||||
t.references :organization, null: true
|
||||
t.string :login, limit: 100, null: false
|
||||
t.string :login, limit: 255, null: false
|
||||
t.string :firstname, limit: 100, null: true, default: ''
|
||||
t.string :lastname, limit: 100, null: true, default: ''
|
||||
t.string :email, limit: 140, null: true, default: ''
|
||||
t.string :email, limit: 255, null: true, default: ''
|
||||
t.string :image, limit: 100, null: true
|
||||
t.string :image_source, limit: 200, null: true
|
||||
t.string :web, limit: 100, null: true, default: ''
|
||||
|
||||
10
db/migrate/20170119000001_login_email_length_650.rb
Normal file
10
db/migrate/20170119000001_login_email_length_650.rb
Normal file
@@ -0,0 +1,10 @@
|
||||
class LoginEmailLength650 < ActiveRecord::Migration
|
||||
def up
|
||||
|
||||
# return if it's a new setup
|
||||
return if !Setting.find_by(name: 'system_init_done')
|
||||
|
||||
change_column(:users, :login, :string, limit: 255)
|
||||
change_column(:users, :email, :string, limit: 255)
|
||||
end
|
||||
end
|
||||
92
lib/html_sanitizer.rb
Normal file
92
lib/html_sanitizer.rb
Normal file
@@ -0,0 +1,92 @@
|
||||
class HtmlSanitizer
|
||||
|
||||
def self.strict(string)
|
||||
|
||||
# config
|
||||
tags_remove_content = Rails.configuration.html_sanitizer_tags_remove_content
|
||||
tags_whitelist = Rails.configuration.html_sanitizer_tags_whitelist
|
||||
attributes_whitelist = Rails.configuration.html_sanitizer_attributes_whitelist
|
||||
css_properties_whitelist = Rails.configuration.html_sanitizer_css_properties_whitelist
|
||||
|
||||
scrubber = Loofah::Scrubber.new do |node|
|
||||
|
||||
# remove tags with subtree
|
||||
if tags_remove_content.include?(node.name)
|
||||
node.remove
|
||||
end
|
||||
|
||||
# replace tags, keep subtree
|
||||
if !tags_whitelist.include?(node.name)
|
||||
traversal(node, scrubber)
|
||||
end
|
||||
|
||||
# prepare src attribute
|
||||
if node['src']
|
||||
src = cleanup(node['src'])
|
||||
if src =~ /(javascript|livescript|vbscript):/i || src.start_with?('http', 'ftp', '//')
|
||||
traversal(node, scrubber)
|
||||
end
|
||||
end
|
||||
|
||||
# clean style / only use allowed style properties
|
||||
if node['style']
|
||||
pears = node['style'].downcase.gsub(/\t|\n|\r/, '').split(';')
|
||||
style = ''
|
||||
pears.each { |pear|
|
||||
prop = pear.split(':')
|
||||
next if !prop[0]
|
||||
key = prop[0].strip
|
||||
next if !css_properties_whitelist.include?(key)
|
||||
style += "#{pear};"
|
||||
}
|
||||
node['style'] = style
|
||||
if style == ''
|
||||
node.delete('style')
|
||||
end
|
||||
end
|
||||
|
||||
# scan for invalid link content
|
||||
%w(href style).each { |attribute_name|
|
||||
next if !node[attribute_name]
|
||||
href = cleanup(node[attribute_name])
|
||||
next if href !~ /(javascript|livescript|vbscript):/i
|
||||
node.delete(attribute_name)
|
||||
}
|
||||
|
||||
# remove attributes if not whitelisted
|
||||
node.each { |attribute, _value|
|
||||
attribute_name = attribute.downcase
|
||||
next if attributes_whitelist[:all].include?(attribute_name) || (attributes_whitelist[node.name] && attributes_whitelist[node.name].include?(attribute_name))
|
||||
node.delete(attribute)
|
||||
}
|
||||
|
||||
# prepare links
|
||||
if node['href']
|
||||
href = cleanup(node['href'])
|
||||
next if !href.start_with?('http', 'ftp', '//')
|
||||
node.set_attribute('rel', 'nofollow')
|
||||
node.set_attribute('target', '_blank')
|
||||
end
|
||||
end
|
||||
Loofah.fragment(string).scrub!(scrubber).to_s
|
||||
end
|
||||
|
||||
def self.traversal(node, scrubber)
|
||||
node.children.each { |child|
|
||||
if child.class == Nokogiri::XML::CDATA
|
||||
node.before Nokogiri::XML::Text.new(node.content, node.document)
|
||||
else
|
||||
node.before Loofah.fragment(child.to_s).scrub!(scrubber)
|
||||
end
|
||||
}
|
||||
node.remove
|
||||
end
|
||||
|
||||
def self.cleanup(string)
|
||||
string.downcase.gsub(/[[:space:]]|\t|\n|\r/, '').gsub(%r{/\*.*?\*/}, '').gsub(/<!--.*?-->/, '').gsub(/\[.+?\]/, '')
|
||||
end
|
||||
|
||||
private_class_method :traversal
|
||||
private_class_method :cleanup
|
||||
|
||||
end
|
||||
@@ -32,6 +32,7 @@ returns
|
||||
next if entry =~ %r{channel/}i
|
||||
next if entry =~ %r{observer/}i
|
||||
next if entry =~ %r{store/provider/}i
|
||||
next if entry =~ %r{models/concerns/}i
|
||||
entry.gsub!(dir, '')
|
||||
entry = entry.to_classname
|
||||
model_class = load_adapter(entry)
|
||||
|
||||
@@ -339,8 +339,6 @@ get count of tickets and tickets which match on selector
|
||||
end
|
||||
|
||||
def self.selector2query(selector, _current_user, aggs_interval, limit)
|
||||
filter_must = []
|
||||
filter_must_not = []
|
||||
query_must = []
|
||||
query_must_not = []
|
||||
if selector && !selector.empty?
|
||||
@@ -355,9 +353,9 @@ get count of tickets and tickets which match on selector
|
||||
t[:term][key_tmp] = data['value']
|
||||
end
|
||||
if data['operator'] == 'is'
|
||||
filter_must.push t
|
||||
query_must.push t
|
||||
elsif data['operator'] == 'is not'
|
||||
filter_must_not.push t
|
||||
query_must_not.push t
|
||||
elsif data['operator'] == 'contains'
|
||||
query_must.push t
|
||||
elsif data['operator'] == 'contains not'
|
||||
@@ -391,43 +389,18 @@ get count of tickets and tickets which match on selector
|
||||
from: aggs_interval[:from],
|
||||
to: aggs_interval[:to],
|
||||
}
|
||||
filter_must.push r
|
||||
query_must.push r
|
||||
end
|
||||
|
||||
if !query_must.empty? || !query_must_not.empty?
|
||||
if !data[:query][:filtered]
|
||||
data[:query][:filtered] = {}
|
||||
end
|
||||
if !data[:query][:filtered][:query]
|
||||
data[:query][:filtered][:query] = {}
|
||||
end
|
||||
if !data[:query][:filtered][:query][:bool]
|
||||
data[:query][:filtered][:query][:bool] = {}
|
||||
end
|
||||
if !data[:query][:bool]
|
||||
data[:query][:bool] = {}
|
||||
end
|
||||
|
||||
if !query_must.empty?
|
||||
data[:query][:filtered][:query][:bool][:must] = query_must
|
||||
data[:query][:bool][:must] = query_must
|
||||
end
|
||||
if !query_must_not.empty?
|
||||
data[:query][:filtered][:query][:bool][:must_not] = query_must_not
|
||||
end
|
||||
|
||||
if !filter_must.empty? || !filter_must.empty?
|
||||
if !data[:query][:filtered]
|
||||
data[:query][:filtered] = {}
|
||||
end
|
||||
if !data[:query][:filtered][:filter]
|
||||
data[:query][:filtered][:filter] = {}
|
||||
end
|
||||
if !data[:query][:filtered][:filter][:bool]
|
||||
data[:query][:filtered][:filter][:bool] = {}
|
||||
end
|
||||
end
|
||||
if !filter_must.empty?
|
||||
data[:query][:filtered][:filter][:bool][:must] = filter_must
|
||||
end
|
||||
if !filter_must_not.empty?
|
||||
data[:query][:filtered][:filter][:bool][:must_not] = filter_must_not
|
||||
data[:query][:bool][:must_not] = query_must_not
|
||||
end
|
||||
|
||||
# add sort
|
||||
|
||||
@@ -312,6 +312,27 @@ test('i18n', function() {
|
||||
var timestamp = App.i18n.translateTimestamp('2012-11-06T21:07:24Z', offset);
|
||||
equal(timestamp, '06.11.2012 21:07', 'de-de - timestamp translated correctly')
|
||||
|
||||
timestamp = App.i18n.translateTimestamp('', offset);
|
||||
equal(timestamp, '', 'de-de - timestamp translated correctly')
|
||||
|
||||
timestamp = App.i18n.translateTimestamp(null, offset);
|
||||
equal(timestamp, null, 'de-de - timestamp translated correctly')
|
||||
|
||||
timestamp = App.i18n.translateTimestamp(undefined, offset);
|
||||
equal(timestamp, undefined, 'de-de - timestamp translated correctly')
|
||||
|
||||
var date = App.i18n.translateDate('2012-11-06', 0)
|
||||
equal(date, '06.11.2012', 'de-de - date translated correctly')
|
||||
|
||||
date = App.i18n.translateDate('', 0)
|
||||
equal(date, '', 'de-de - date translated correctly')
|
||||
|
||||
date = App.i18n.translateDate(null, 0)
|
||||
equal(date, null, 'de-de - date translated correctly')
|
||||
|
||||
date = App.i18n.translateDate(undefined, 0)
|
||||
equal(date, undefined, 'de-de - date translated correctly')
|
||||
|
||||
// en
|
||||
App.i18n.set('en-us')
|
||||
translated = App.i18n.translateContent('yes')
|
||||
@@ -368,6 +389,27 @@ test('i18n', function() {
|
||||
timestamp = App.i18n.translateTimestamp('2012-11-06T21:07:24Z', offset)
|
||||
equal(timestamp, '11/06/2012 21:07', 'en - timestamp translated correctly')
|
||||
|
||||
timestamp = App.i18n.translateTimestamp('', offset);
|
||||
equal(timestamp, '', 'en - timestamp translated correctly')
|
||||
|
||||
timestamp = App.i18n.translateTimestamp(null, offset);
|
||||
equal(timestamp, null, 'en - timestamp translated correctly')
|
||||
|
||||
timestamp = App.i18n.translateTimestamp(undefined, offset);
|
||||
equal(timestamp, undefined, 'en - timestamp translated correctly')
|
||||
|
||||
date = App.i18n.translateDate('2012-11-06', 0)
|
||||
equal(date, '11/06/2012', 'en - date translated correctly')
|
||||
|
||||
date = App.i18n.translateDate('', 0)
|
||||
equal(date, '', 'en - date translated correctly')
|
||||
|
||||
date = App.i18n.translateDate(null, 0)
|
||||
equal(date, null, 'en - date translated correctly')
|
||||
|
||||
date = App.i18n.translateDate(undefined, 0)
|
||||
equal(date, undefined, 'en - date translated correctly')
|
||||
|
||||
// locale alias test
|
||||
// de
|
||||
App.i18n.set('de')
|
||||
|
||||
@@ -715,13 +715,14 @@ test("form postmaster filter", function() {
|
||||
},
|
||||
},
|
||||
set: {
|
||||
'x-zammad-ticket-customer': {
|
||||
value: 'customer'
|
||||
'x-zammad-ticket-customer_id': {
|
||||
value: 'customer',
|
||||
value_completion: ''
|
||||
},
|
||||
'x-zammad-ticket-group_id': {
|
||||
value: '1'
|
||||
},
|
||||
'x-zammad-ticket-owner': {
|
||||
'x-zammad-ticket-owner_id': {
|
||||
value: 'owner',
|
||||
value_completion: ''
|
||||
},
|
||||
@@ -757,13 +758,14 @@ test("form postmaster filter", function() {
|
||||
}
|
||||
},
|
||||
set: {
|
||||
'x-zammad-ticket-customer': {
|
||||
value: 'customer'
|
||||
'x-zammad-ticket-customer_id': {
|
||||
value: 'customer',
|
||||
value_completion: ''
|
||||
},
|
||||
'x-zammad-ticket-group_id': {
|
||||
value: '1'
|
||||
},
|
||||
'x-zammad-ticket-owner': {
|
||||
'x-zammad-ticket-owner_id': {
|
||||
value: 'owner',
|
||||
value_completion: ''
|
||||
},
|
||||
@@ -774,7 +776,7 @@ test("form postmaster filter", function() {
|
||||
};
|
||||
deepEqual(params, test_params, 'form param check')
|
||||
el.find('[name="set::x-zammad-ticket-priority_id::value"]').closest('.js-filterElement').find('.js-remove').click()
|
||||
el.find('[name="set::x-zammad-ticket-customer::value"]').closest('.js-filterElement').find('.js-remove').click()
|
||||
el.find('[name="set::x-zammad-ticket-customer_id::value"]').closest('.js-filterElement').find('.js-remove').click()
|
||||
App.Delay.set(function() {
|
||||
test("form param check after remove click", function() {
|
||||
params = App.ControllerForm.params(el)
|
||||
@@ -792,7 +794,7 @@ test("form postmaster filter", function() {
|
||||
}
|
||||
},
|
||||
set: {
|
||||
'x-zammad-ticket-owner': {
|
||||
'x-zammad-ticket-owner_id': {
|
||||
value: 'owner',
|
||||
value_completion: ''
|
||||
},
|
||||
|
||||
@@ -57,9 +57,72 @@ class AgentTicketActionLevel0Test < TestCase
|
||||
css: '.modal [name="email"]',
|
||||
value: "#{agent}@example.com",
|
||||
)
|
||||
exists_not(
|
||||
css: '.modal select[name="group_ids"]',
|
||||
exists(
|
||||
displayed: false,
|
||||
css: '.modal [name="group_ids"]',
|
||||
)
|
||||
exists(
|
||||
css: '.modal [name="group_ids"]:checked',
|
||||
)
|
||||
click(
|
||||
css: '.modal button.btn.btn--primary',
|
||||
fast: true,
|
||||
)
|
||||
watch_for(
|
||||
css: 'body div.modal',
|
||||
value: 'Sending',
|
||||
)
|
||||
watch_for_disappear(
|
||||
css: 'body div.modal',
|
||||
value: 'Sending',
|
||||
)
|
||||
|
||||
click(css: '#navigation a[href="#dashboard"]')
|
||||
click(css: '.active.content .tab[data-area="first-steps-widgets"]')
|
||||
watch_for(
|
||||
css: '.active.content',
|
||||
value: 'Configuration',
|
||||
)
|
||||
click(css: '.active.content .js-inviteAgent')
|
||||
modal_ready()
|
||||
set(
|
||||
css: '.modal [name="firstname"]',
|
||||
value: 'Bob2',
|
||||
)
|
||||
set(
|
||||
css: '.modal [name="lastname"]',
|
||||
value: 'Smith2',
|
||||
)
|
||||
set(
|
||||
css: '.modal [name="email"]',
|
||||
value: "#{agent}2@example.com",
|
||||
)
|
||||
|
||||
# disable agent role
|
||||
uncheck(
|
||||
css: '.modal [name="role_ids"][value=2]',
|
||||
)
|
||||
|
||||
exists(
|
||||
displayed: false,
|
||||
css: '.modal [name="group_ids"]',
|
||||
)
|
||||
exists_not(
|
||||
css: '.modal [name="group_ids"]:checked',
|
||||
)
|
||||
|
||||
# enable agent role
|
||||
check(
|
||||
css: '.modal [name="role_ids"][value=2]',
|
||||
)
|
||||
|
||||
exists(
|
||||
css: '.modal [name="group_ids"]',
|
||||
)
|
||||
exists(
|
||||
css: '.modal [name="group_ids"]:checked',
|
||||
)
|
||||
|
||||
click(
|
||||
css: '.modal button.btn.btn--primary',
|
||||
fast: true,
|
||||
|
||||
@@ -28,6 +28,13 @@ class CustomerTicketCreateTest < TestCase
|
||||
css: '.newTicket [data-name="body"]',
|
||||
value: 'some body 123äöü',
|
||||
)
|
||||
exists_not(
|
||||
css: '.newTicket input[name="customer_id"]',
|
||||
)
|
||||
exists_not(
|
||||
css: '.newTicket input[name="priority_id"]',
|
||||
)
|
||||
|
||||
click(css: '.newTicket button.js-submit')
|
||||
sleep 5
|
||||
|
||||
@@ -42,7 +49,7 @@ class CustomerTicketCreateTest < TestCase
|
||||
|
||||
# update ticket
|
||||
set(
|
||||
css: '.active [data-name="body"]',
|
||||
css: '.content.active [data-name="body"]',
|
||||
value: 'some body 1234 äöüß',
|
||||
no_click: true,
|
||||
)
|
||||
@@ -51,10 +58,10 @@ class CustomerTicketCreateTest < TestCase
|
||||
type: 'stayOnTab',
|
||||
)
|
||||
|
||||
click(css: '.active .js-submit')
|
||||
click(css: '.content.active .js-submit')
|
||||
|
||||
watch_for(
|
||||
css: '.active div.ticket-article',
|
||||
css: '.content.active div.ticket-article',
|
||||
value: 'some body 1234 äöüß',
|
||||
)
|
||||
end
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
require 'browser_test_helper'
|
||||
|
||||
class TranslationTest < TestCase
|
||||
|
||||
def test_preferences
|
||||
@browser = browser_instance
|
||||
login(
|
||||
@@ -250,4 +251,60 @@ class TranslationTest < TestCase
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
def test_admin_sync
|
||||
@browser = browser_instance
|
||||
login(
|
||||
username: 'master@example.com',
|
||||
password: 'test',
|
||||
url: browser_url,
|
||||
)
|
||||
tasks_close_all()
|
||||
|
||||
click(css: 'a[href="#current_user"]')
|
||||
click(css: 'a[href="#profile"]')
|
||||
click(css: 'a[href="#profile/language"]')
|
||||
select(
|
||||
css: '.language_item [name="locale"]',
|
||||
value: 'Deutsch',
|
||||
)
|
||||
click(css: '.content.active button[type="submit"]')
|
||||
watch_for(
|
||||
css: 'body',
|
||||
value: 'Sprache',
|
||||
)
|
||||
|
||||
click(css: 'a[href="#manage"]')
|
||||
click(css: 'a[href="#system/translation"]')
|
||||
|
||||
watch_for(
|
||||
css: '.content.active',
|
||||
value: 'Inline Übersetzung',
|
||||
)
|
||||
|
||||
click(css: '.content.active .js-syncChanges')
|
||||
watch_for(
|
||||
css: '.content.active .modal',
|
||||
value: 'Letzte Übersetzung laden',
|
||||
)
|
||||
watch_for_disappear(
|
||||
css: '.content.active .modal',
|
||||
timeout: 5 * 60,
|
||||
)
|
||||
|
||||
click(css: 'a[href="#current_user"]')
|
||||
click(css: 'a[href="#profile"]')
|
||||
click(css: 'a[href="#profile/language"]')
|
||||
select(
|
||||
css: '.language_item [name="locale"]',
|
||||
value: 'English (United States)',
|
||||
)
|
||||
click(css: '.content.active button[type="submit"]')
|
||||
watch_for(
|
||||
css: 'body',
|
||||
value: 'Language',
|
||||
)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -547,6 +547,12 @@ class TestCase < Test::Unit::TestCase
|
||||
css: '.some_class',
|
||||
)
|
||||
|
||||
exists(
|
||||
displayed: false, # true|false
|
||||
browser: browser1,
|
||||
css: '.some_class',
|
||||
)
|
||||
|
||||
=end
|
||||
|
||||
def exists(params)
|
||||
@@ -558,6 +564,16 @@ class TestCase < Test::Unit::TestCase
|
||||
screenshot(browser: instance, comment: 'exists_failed')
|
||||
raise "#{params[:css]} dosn't exist, but should"
|
||||
end
|
||||
|
||||
if params.key?(:displayed)
|
||||
if params[:displayed] == true && !instance.find_elements(css: params[:css])[0].displayed?
|
||||
raise "#{params[:css]} is not displayed, but should"
|
||||
end
|
||||
if params[:displayed] == false && instance.find_elements(css: params[:css])[0].displayed?
|
||||
raise "#{params[:css]} is displayed, but should not"
|
||||
end
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
require 'test_helper'
|
||||
|
||||
class SearchControllerTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
def base_data
|
||||
|
||||
# clear cache
|
||||
Cache.clear
|
||||
@@ -192,6 +192,7 @@ class SearchControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
test 'settings index with nobody' do
|
||||
base_data
|
||||
|
||||
params = {
|
||||
query: 'test 1234',
|
||||
@@ -222,6 +223,7 @@ class SearchControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
test 'settings index with admin' do
|
||||
base_data
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('search-admin@example.com', 'adminpw')
|
||||
|
||||
@@ -295,6 +297,7 @@ class SearchControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
test 'settings index with agent' do
|
||||
base_data
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('search-agent@example.com', 'agentpw')
|
||||
|
||||
@@ -368,6 +371,7 @@ class SearchControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
test 'settings index with customer 1' do
|
||||
base_data
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('search-customer1@example.com', 'customer1pw')
|
||||
|
||||
@@ -413,6 +417,7 @@ class SearchControllerTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
test 'settings index with customer 2' do
|
||||
base_data
|
||||
|
||||
credentials = ActionController::HttpAuthentication::Basic.encode_credentials('search-customer2@example.com', 'customer2pw')
|
||||
|
||||
|
||||
@@ -318,7 +318,7 @@ class TicketsControllerTest < ActionDispatch::IntegrationTest
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert_equal(ticket.id, result['ticket_id'])
|
||||
assert_equal('Tickets Agent via Zammad <zammad@localhost>', result['from'])
|
||||
assert_equal('"Tickets Agent via Zammad" <zammad@localhost>', result['from'])
|
||||
assert_equal('some subject', result['subject'])
|
||||
assert_equal('some body', result['body'])
|
||||
assert_equal('text/plain', result['content_type'])
|
||||
@@ -335,7 +335,7 @@ class TicketsControllerTest < ActionDispatch::IntegrationTest
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert_equal(ticket.id, result['ticket_id'])
|
||||
assert_equal('Tickets Agent via Zammad <zammad@localhost>', result['from'])
|
||||
assert_equal('"Tickets Agent via Zammad" <zammad@localhost>', result['from'])
|
||||
assert_equal('new subject', result['subject'])
|
||||
assert_equal('some body', result['body'])
|
||||
assert_equal('text/plain', result['content_type'])
|
||||
@@ -444,7 +444,7 @@ class TicketsControllerTest < ActionDispatch::IntegrationTest
|
||||
result = JSON.parse(@response.body)
|
||||
assert_equal(Hash, result.class)
|
||||
assert_equal(ticket.id, result['ticket_id'])
|
||||
assert_equal('Tickets Admin via Zammad <zammad@localhost>', result['from'])
|
||||
assert_equal('"Tickets Admin via Zammad" <zammad@localhost>', result['from'])
|
||||
assert_equal('some subject', result['subject'])
|
||||
assert_equal('some body', result['body'])
|
||||
assert_equal('text/plain', result['content_type'])
|
||||
|
||||
@@ -38,6 +38,9 @@ class ActiveSupport::TestCase
|
||||
|
||||
# remove background jobs
|
||||
Delayed::Job.destroy_all
|
||||
ActivityStream.destroy_all
|
||||
PostmasterFilter.destroy_all
|
||||
Ticket.destroy_all
|
||||
|
||||
# set current user
|
||||
UserInfo.current_user_id = nil
|
||||
|
||||
@@ -4,9 +4,8 @@ require 'test_helper'
|
||||
class ActivityStreamTest < ActiveSupport::TestCase
|
||||
admin_user = nil
|
||||
current_user = nil
|
||||
activity_record_delay = nil
|
||||
test 'aaa - setup' do
|
||||
role = Role.lookup(name: 'Admin')
|
||||
roles = Role.where(name: %w(Admin Agent))
|
||||
group = Group.lookup(name: 'Users')
|
||||
admin_user = User.create_or_update(
|
||||
login: 'admin',
|
||||
@@ -15,392 +14,200 @@ class ActivityStreamTest < ActiveSupport::TestCase
|
||||
email: 'bob@example.com',
|
||||
password: 'some_pass',
|
||||
active: true,
|
||||
role_ids: [role.id],
|
||||
roles: roles,
|
||||
group_ids: [group.id],
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1
|
||||
)
|
||||
current_user = User.lookup(email: 'nicole.braun@zammad.org')
|
||||
|
||||
activity_record_delay = if ENV['ZAMMAD_ACTIVITY_RECORD_DELAY']
|
||||
ENV['ZAMMAD_ACTIVITY_RECORD_DELAY'].to_i.seconds
|
||||
else
|
||||
90.seconds
|
||||
end
|
||||
end
|
||||
|
||||
test 'ticket+user' do
|
||||
tests = [
|
||||
ticket = Ticket.create(
|
||||
group_id: Group.lookup(name: 'Users').id,
|
||||
customer_id: current_user.id,
|
||||
owner_id: User.lookup(login: '-').id,
|
||||
title: 'Unit Test 1 (äöüß)!',
|
||||
state_id: Ticket::State.lookup(name: 'new').id,
|
||||
priority_id: Ticket::Priority.lookup(name: '2 normal').id,
|
||||
updated_by_id: current_user.id,
|
||||
created_by_id: current_user.id,
|
||||
)
|
||||
travel 2.seconds
|
||||
|
||||
# test 1
|
||||
{
|
||||
create: {
|
||||
ticket: {
|
||||
group_id: Group.lookup(name: 'Users').id,
|
||||
customer_id: current_user.id,
|
||||
owner_id: User.lookup(login: '-').id,
|
||||
title: 'Unit Test 1 (äöüß)!',
|
||||
state_id: Ticket::State.lookup(name: 'new').id,
|
||||
priority_id: Ticket::Priority.lookup(name: '2 normal').id,
|
||||
updated_by_id: current_user.id,
|
||||
created_by_id: current_user.id,
|
||||
},
|
||||
article: {
|
||||
updated_by_id: current_user.id,
|
||||
created_by_id: current_user.id,
|
||||
type_id: Ticket::Article::Type.lookup(name: 'phone').id,
|
||||
sender_id: Ticket::Article::Sender.lookup(name: 'Customer').id,
|
||||
from: 'Unit Test <unittest@example.com>',
|
||||
body: 'Unit Test 123',
|
||||
internal: false,
|
||||
},
|
||||
},
|
||||
update: {
|
||||
ticket: {
|
||||
title: 'Unit Test 1 (äöüß) - update!',
|
||||
state_id: Ticket::State.lookup(name: 'open').id,
|
||||
priority_id: Ticket::Priority.lookup(name: '1 low').id,
|
||||
},
|
||||
},
|
||||
update2: {
|
||||
ticket: {
|
||||
title: 'Unit Test 2 (äöüß) - update!',
|
||||
priority_id: Ticket::Priority.lookup(name: '2 normal').id,
|
||||
},
|
||||
},
|
||||
check: [
|
||||
{
|
||||
result: true,
|
||||
object: 'Ticket',
|
||||
type: 'update',
|
||||
},
|
||||
{
|
||||
result: true,
|
||||
object: 'Ticket::Article',
|
||||
type: 'create',
|
||||
},
|
||||
{
|
||||
result: true,
|
||||
object: 'Ticket',
|
||||
type: 'create',
|
||||
},
|
||||
{
|
||||
result: false,
|
||||
object: 'User',
|
||||
type: 'update',
|
||||
o_id: current_user.id,
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
tickets = []
|
||||
tests.each { |test|
|
||||
article = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
updated_by_id: current_user.id,
|
||||
created_by_id: current_user.id,
|
||||
type_id: Ticket::Article::Type.lookup(name: 'phone').id,
|
||||
sender_id: Ticket::Article::Sender.lookup(name: 'Customer').id,
|
||||
from: 'Unit Test <unittest@example.com>',
|
||||
body: 'Unit Test 123',
|
||||
internal: false,
|
||||
)
|
||||
|
||||
ticket = Ticket.create(test[:create][:ticket])
|
||||
test[:check][0][:o_id] = ticket.id
|
||||
test[:check][2][:o_id] = ticket.id
|
||||
test[:check][2][:created_at] = ticket.created_at
|
||||
test[:check][2][:created_by_id] = current_user.id
|
||||
sleep 2
|
||||
travel 100.seconds
|
||||
ticket.update_attributes(
|
||||
title: 'Unit Test 1 (äöüß) - update!',
|
||||
state_id: Ticket::State.lookup(name: 'open').id,
|
||||
priority_id: Ticket::Priority.lookup(name: '1 low').id,
|
||||
)
|
||||
updated_at = ticket.updated_at
|
||||
|
||||
test[:create][:article][:ticket_id] = ticket.id
|
||||
article = Ticket::Article.create(test[:create][:article])
|
||||
test[:check][1][:o_id] = article.id
|
||||
test[:check][1][:created_at] = article.created_at
|
||||
test[:check][1][:created_by_id] = current_user.id
|
||||
travel 1.second
|
||||
ticket.update_attributes(
|
||||
title: 'Unit Test 2 (äöüß) - update!',
|
||||
priority_id: Ticket::Priority.lookup(name: '2 normal').id,
|
||||
)
|
||||
|
||||
assert_equal(ticket.class.to_s, 'Ticket')
|
||||
assert_equal(article.class.to_s, 'Ticket::Article')
|
||||
# check activity_stream
|
||||
stream = admin_user.activity_stream(4)
|
||||
assert_equal(stream[0]['group_id'], ticket.group_id)
|
||||
assert_equal(stream[0]['o_id'], ticket.id)
|
||||
assert_equal(stream[0]['created_by_id'], current_user.id)
|
||||
assert_equal(stream[0]['created_at'].to_s, updated_at.to_s)
|
||||
assert_equal(stream[0]['object'], 'Ticket')
|
||||
assert_equal(stream[0]['type'], 'update')
|
||||
assert_equal(stream[1]['group_id'], ticket.group_id)
|
||||
assert_equal(stream[1]['o_id'], article.id)
|
||||
assert_equal(stream[1]['created_by_id'], current_user.id)
|
||||
assert_equal(stream[1]['created_at'].to_s, article.created_at.to_s)
|
||||
assert_equal(stream[1]['object'], 'Ticket::Article')
|
||||
assert_equal(stream[1]['type'], 'create')
|
||||
assert_equal(stream[2]['group_id'], ticket.group_id)
|
||||
assert_equal(stream[2]['o_id'], ticket.id)
|
||||
assert_equal(stream[2]['created_by_id'], current_user.id)
|
||||
assert_equal(stream[2]['created_at'].to_s, ticket.created_at.to_s)
|
||||
assert_equal(stream[2]['object'], 'Ticket')
|
||||
assert_equal(stream[2]['type'], 'create')
|
||||
assert_not(stream[3])
|
||||
|
||||
# update ticket
|
||||
if test[:update][:ticket]
|
||||
ticket.update_attributes(test[:update][:ticket])
|
||||
stream = current_user.activity_stream(4)
|
||||
assert(stream.empty?)
|
||||
|
||||
# check updated user
|
||||
test[:check][3][:o_id] = current_user.id
|
||||
test[:check][3][:created_at] = ticket.created_at
|
||||
test[:check][3][:created_by_id] = current_user.id
|
||||
end
|
||||
if test[:update2][:ticket]
|
||||
ticket = Ticket.find(ticket.id)
|
||||
ticket.update_attributes(test[:update2][:ticket])
|
||||
end
|
||||
if test[:update][:article]
|
||||
article.update_attributes(test[:update][:article])
|
||||
end
|
||||
|
||||
sleep activity_record_delay + 1
|
||||
if test[:update][:ticket]
|
||||
ticket.update_attributes(test[:update][:ticket])
|
||||
end
|
||||
if test[:update2][:ticket]
|
||||
ticket.update_attributes(test[:update2][:ticket])
|
||||
end
|
||||
|
||||
# remember ticket
|
||||
tickets.push ticket
|
||||
|
||||
# check activity_stream
|
||||
activity_stream_check(admin_user.activity_stream(3), test[:check])
|
||||
}
|
||||
|
||||
# delete tickets
|
||||
tickets.each { |ticket|
|
||||
ticket_id = ticket.id
|
||||
ticket.destroy
|
||||
found = Ticket.where(id: ticket_id).first
|
||||
assert_not(found, 'Ticket destroyed')
|
||||
}
|
||||
# cleanup
|
||||
ticket.destroy
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'organization' do
|
||||
tests = [
|
||||
|
||||
# test 1
|
||||
{
|
||||
create: {
|
||||
organization: {
|
||||
name: 'some name',
|
||||
updated_by_id: current_user.id,
|
||||
created_by_id: current_user.id,
|
||||
},
|
||||
},
|
||||
update1: {
|
||||
organization: {
|
||||
name: 'some name (äöüß)',
|
||||
},
|
||||
},
|
||||
update2: {
|
||||
organization: {
|
||||
name: 'some name 2 (äöüß)',
|
||||
},
|
||||
},
|
||||
check: [
|
||||
{
|
||||
result: true,
|
||||
object: 'Organization',
|
||||
type: 'update',
|
||||
},
|
||||
{
|
||||
result: true,
|
||||
object: 'Organization',
|
||||
type: 'create',
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
organizations = []
|
||||
tests.each { |test|
|
||||
organization = Organization.create(
|
||||
name: 'some name',
|
||||
updated_by_id: current_user.id,
|
||||
created_by_id: current_user.id,
|
||||
)
|
||||
travel 100.seconds
|
||||
assert_equal(organization.class, Organization)
|
||||
|
||||
organization = Organization.create(test[:create][:organization])
|
||||
test[:check][0][:o_id] = organization.id
|
||||
test[:check][0][:created_at] = organization.created_at
|
||||
test[:check][0][:created_by_id] = current_user.id
|
||||
sleep 2
|
||||
organization.update_attributes(name: 'some name (äöüß)')
|
||||
updated_at = organization.updated_at
|
||||
|
||||
assert_equal(organization.class.to_s, 'Organization')
|
||||
travel 10.seconds
|
||||
organization.update_attributes(name: 'some name 2 (äöüß)')
|
||||
|
||||
if test[:update1][:organization]
|
||||
organization.update_attributes(test[:update1][:organization])
|
||||
test[:check][1][:o_id] = organization.id
|
||||
test[:check][1][:updated_at] = organization.updated_at
|
||||
test[:check][1][:created_by_id] = current_user.id
|
||||
sleep activity_record_delay - 1
|
||||
end
|
||||
# check activity_stream
|
||||
stream = admin_user.activity_stream(3)
|
||||
assert_not(stream[0]['group_id'])
|
||||
assert_equal(stream[0]['o_id'], organization.id)
|
||||
assert_equal(stream[0]['created_by_id'], current_user.id)
|
||||
assert_equal(stream[0]['created_at'].to_s, updated_at.to_s)
|
||||
assert_equal(stream[0]['object'], 'Organization')
|
||||
assert_equal(stream[0]['type'], 'update')
|
||||
assert_not(stream[1]['group_id'])
|
||||
assert_equal(stream[1]['o_id'], organization.id)
|
||||
assert_equal(stream[1]['created_by_id'], current_user.id)
|
||||
assert_equal(stream[1]['created_at'].to_s, organization.created_at.to_s)
|
||||
assert_equal(stream[1]['object'], 'Organization')
|
||||
assert_equal(stream[1]['type'], 'create')
|
||||
assert_not(stream[2])
|
||||
|
||||
if test[:update2][:organization]
|
||||
organization.update_attributes(test[:update2][:organization])
|
||||
end
|
||||
stream = current_user.activity_stream(4)
|
||||
assert(stream.empty?)
|
||||
|
||||
# remember organization
|
||||
organizations.push organization
|
||||
|
||||
# check activity_stream
|
||||
activity_stream_check(admin_user.activity_stream(2), test[:check])
|
||||
}
|
||||
|
||||
# delete tickets
|
||||
organizations.each { |organization|
|
||||
organization_id = organization.id
|
||||
organization.destroy
|
||||
found = Organization.where(id: organization_id).first
|
||||
assert( !found, 'Organization destroyed')
|
||||
}
|
||||
# cleanup
|
||||
organization.destroy
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'user with update check false' do
|
||||
tests = [
|
||||
user = User.create(
|
||||
login: 'someemail@example.com',
|
||||
email: 'someemail@example.com',
|
||||
firstname: 'Bob Smith II',
|
||||
updated_by_id: current_user.id,
|
||||
created_by_id: current_user.id,
|
||||
)
|
||||
assert_equal(user.class, User)
|
||||
user.update_attributes(
|
||||
firstname: 'Bob U',
|
||||
lastname: 'Smith U',
|
||||
)
|
||||
|
||||
# test 1
|
||||
{
|
||||
create: {
|
||||
user: {
|
||||
login: 'someemail@example.com',
|
||||
email: 'someemail@example.com',
|
||||
firstname: 'Bob Smith II',
|
||||
updated_by_id: current_user.id,
|
||||
created_by_id: current_user.id,
|
||||
},
|
||||
},
|
||||
update1: {
|
||||
user: {
|
||||
firstname: 'Bob U',
|
||||
lastname: 'Smith U',
|
||||
},
|
||||
},
|
||||
check: [
|
||||
{
|
||||
result: true,
|
||||
object: 'User',
|
||||
type: 'create',
|
||||
},
|
||||
{
|
||||
result: false,
|
||||
object: 'User',
|
||||
type: 'update',
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
users = []
|
||||
tests.each { |test|
|
||||
# check activity_stream
|
||||
stream = admin_user.activity_stream(3)
|
||||
assert_not(stream[0]['group_id'])
|
||||
assert_equal(stream[0]['o_id'], user.id)
|
||||
assert_equal(stream[0]['created_by_id'], current_user.id)
|
||||
assert_equal(stream[0]['created_at'].to_s, user.created_at.to_s)
|
||||
assert_equal(stream[0]['object'], 'User')
|
||||
assert_equal(stream[0]['type'], 'create')
|
||||
assert_not(stream[1])
|
||||
|
||||
user = User.create(test[:create][:user])
|
||||
test[:check][0][:o_id] = user.id
|
||||
test[:check][0][:created_at] = user.created_at
|
||||
test[:check][0][:created_by_id] = current_user.id
|
||||
stream = current_user.activity_stream(4)
|
||||
assert(stream.empty?)
|
||||
|
||||
assert_equal(user.class.to_s, 'User')
|
||||
|
||||
if test[:update1][:user]
|
||||
user.update_attributes(test[:update1][:user])
|
||||
test[:check][1][:o_id] = user.id
|
||||
test[:check][1][:updated_at] = user.updated_at
|
||||
test[:check][1][:created_by_id] = current_user.id
|
||||
end
|
||||
|
||||
# remember organization
|
||||
users.push user
|
||||
|
||||
# check activity_stream
|
||||
activity_stream_check(admin_user.activity_stream(3), test[:check])
|
||||
}
|
||||
|
||||
# delete tickets
|
||||
users.each { |user|
|
||||
user_id = user.id
|
||||
user.destroy
|
||||
found = User.where( id: user_id ).first
|
||||
assert_not(found, 'User destroyed')
|
||||
}
|
||||
# cleanup
|
||||
user.destroy
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'user with update check true' do
|
||||
tests = [
|
||||
|
||||
# test 1
|
||||
{
|
||||
create: {
|
||||
user: {
|
||||
login: 'someemail@example.com',
|
||||
email: 'someemail@example.com',
|
||||
firstname: 'Bob Smith II',
|
||||
updated_by_id: current_user.id,
|
||||
created_by_id: current_user.id,
|
||||
},
|
||||
},
|
||||
update1: {
|
||||
user: {
|
||||
firstname: 'Bob U',
|
||||
lastname: 'Smith U',
|
||||
},
|
||||
},
|
||||
update2: {
|
||||
user: {
|
||||
firstname: 'Bob',
|
||||
lastname: 'Smith',
|
||||
},
|
||||
},
|
||||
check: [
|
||||
{
|
||||
result: true,
|
||||
object: 'User',
|
||||
type: 'update',
|
||||
},
|
||||
{
|
||||
result: true,
|
||||
object: 'User',
|
||||
type: 'create',
|
||||
},
|
||||
]
|
||||
},
|
||||
]
|
||||
users = []
|
||||
tests.each { |test|
|
||||
user = User.create(
|
||||
login: 'someemail@example.com',
|
||||
email: 'someemail@example.com',
|
||||
firstname: 'Bob Smith II',
|
||||
updated_by_id: current_user.id,
|
||||
created_by_id: current_user.id,
|
||||
)
|
||||
travel 100.seconds
|
||||
assert_equal(user.class, User)
|
||||
|
||||
user = User.create(test[:create][:user])
|
||||
test[:check][0][:o_id] = user.id
|
||||
test[:check][0][:created_at] = user.created_at
|
||||
test[:check][0][:created_by_id] = current_user.id
|
||||
user.update_attributes(
|
||||
firstname: 'Bob U',
|
||||
lastname: 'Smith U',
|
||||
)
|
||||
updated_at = user.updated_at
|
||||
|
||||
assert_equal(user.class.to_s, 'User')
|
||||
travel 10.seconds
|
||||
user.update_attributes(
|
||||
firstname: 'Bob',
|
||||
lastname: 'Smith',
|
||||
)
|
||||
|
||||
if test[:update1][:user]
|
||||
user.update_attributes(test[:update1][:user])
|
||||
test[:check][1][:o_id] = user.id
|
||||
test[:check][1][:updated_at] = user.updated_at
|
||||
test[:check][1][:created_by_id] = current_user.id
|
||||
end
|
||||
# check activity_stream
|
||||
stream = admin_user.activity_stream(3)
|
||||
assert_not(stream[0]['group_id'])
|
||||
assert_equal(stream[0]['o_id'], user.id)
|
||||
assert_equal(stream[0]['created_by_id'], current_user.id)
|
||||
assert_equal(stream[0]['created_at'].to_s, updated_at.to_s)
|
||||
assert_equal(stream[0]['object'], 'User')
|
||||
assert_equal(stream[0]['type'], 'update')
|
||||
assert_not(stream[1]['group_id'])
|
||||
assert_equal(stream[1]['o_id'], user.id)
|
||||
assert_equal(stream[1]['created_by_id'], current_user.id)
|
||||
assert_equal(stream[1]['created_at'].to_s, user.created_at.to_s)
|
||||
assert_equal(stream[1]['object'], 'User')
|
||||
assert_equal(stream[1]['type'], 'create')
|
||||
assert_not(stream[2])
|
||||
|
||||
# to verify update which need to be logged
|
||||
sleep activity_record_delay + 1
|
||||
stream = current_user.activity_stream(4)
|
||||
assert(stream.empty?)
|
||||
|
||||
if test[:update2][:user]
|
||||
user.update_attributes(test[:update2][:user])
|
||||
end
|
||||
|
||||
# remember organization
|
||||
users.push user
|
||||
|
||||
# check activity_stream
|
||||
activity_stream_check(admin_user.activity_stream(2), test[:check])
|
||||
}
|
||||
|
||||
# delete tickets
|
||||
users.each { |user|
|
||||
user_id = user.id
|
||||
user.destroy
|
||||
found = User.where(id: user_id).first
|
||||
assert(!found, 'User destroyed')
|
||||
}
|
||||
end
|
||||
|
||||
def activity_stream_check(activity_stream_list, checks)
|
||||
#activity_stream_list = activity_stream_list.reverse
|
||||
#puts 'AS ' + activity_stream_list.inspect
|
||||
check_count = 0
|
||||
checks.each { |check_item|
|
||||
check_count += 1
|
||||
|
||||
#puts '+++++++++++'
|
||||
#puts check_item.inspect
|
||||
check_list = 0
|
||||
activity_stream_list.each { |item|
|
||||
check_list += 1
|
||||
next if check_list != check_count
|
||||
#next if match
|
||||
#puts '--------'
|
||||
#puts item.inspect
|
||||
#puts check_item.inspect
|
||||
if check_item[:result]
|
||||
assert_equal(check_item[:object], item['object'])
|
||||
assert_equal(check_item[:type], item['type'])
|
||||
assert_equal(check_item[:o_id], item['o_id'])
|
||||
elsif check_item[:object] == item['object'] && check_item[:type] == item['type'] && check_item[:o_id] == item['o_id']
|
||||
assert(false, "entry should not exist #{item['object']}/#{item['type']}/#{item['o_id']}")
|
||||
end
|
||||
}
|
||||
}
|
||||
# cleanup
|
||||
user.destroy
|
||||
travel_back
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -6,7 +6,7 @@ class AssetsTest < ActiveSupport::TestCase
|
||||
|
||||
roles = Role.where(name: %w(Agent Admin))
|
||||
groups = Group.all
|
||||
org = Organization.create_or_update(
|
||||
org1 = Organization.create_or_update(
|
||||
name: 'some user org',
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
@@ -21,7 +21,7 @@ class AssetsTest < ActiveSupport::TestCase
|
||||
active: true,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
organization_id: org.id,
|
||||
organization_id: org1.id,
|
||||
roles: roles,
|
||||
groups: groups,
|
||||
)
|
||||
@@ -54,10 +54,10 @@ class AssetsTest < ActiveSupport::TestCase
|
||||
user3 = User.find(user3.id)
|
||||
assets = user3.assets({})
|
||||
|
||||
org = Organization.find(org.id)
|
||||
attributes = org.attributes_with_associations
|
||||
org1 = Organization.find(org1.id)
|
||||
attributes = org1.attributes_with_associations
|
||||
attributes.delete('user_ids')
|
||||
assert( diff(attributes, assets[:Organization][org.id]), 'check assets')
|
||||
assert( diff(attributes, assets[:Organization][org1.id]), 'check assets')
|
||||
|
||||
user1 = User.find(user1.id)
|
||||
attributes = user1.attributes_with_associations
|
||||
@@ -84,8 +84,8 @@ class AssetsTest < ActiveSupport::TestCase
|
||||
assert( diff(attributes, assets[:User][user3.id]), 'check assets' )
|
||||
|
||||
# touch org, check if user1 has changed
|
||||
sleep 2
|
||||
org2 = Organization.find(org.id)
|
||||
travel 2.seconds
|
||||
org2 = Organization.find(org1.id)
|
||||
org2.note = "some note...#{rand(9_999_999_999_999)}"
|
||||
org2.save
|
||||
|
||||
@@ -105,7 +105,7 @@ class AssetsTest < ActiveSupport::TestCase
|
||||
assets = user3.assets({})
|
||||
attributes = org2.attributes_with_associations
|
||||
attributes.delete('user_ids')
|
||||
assert( diff(attributes, assets[:Organization][org.id]), 'check assets')
|
||||
assert( diff(attributes, assets[:Organization][org1.id]), 'check assets')
|
||||
|
||||
user1 = User.find(user1.id)
|
||||
attributes = user1.attributes_with_associations
|
||||
@@ -130,6 +130,13 @@ class AssetsTest < ActiveSupport::TestCase
|
||||
attributes.delete('token_ids')
|
||||
attributes.delete('authorization_ids')
|
||||
assert( diff(attributes, assets[:User][user3.id]), 'check assets' )
|
||||
travel_back
|
||||
|
||||
user1.destroy
|
||||
user2.destroy
|
||||
user3.destroy
|
||||
org1.destroy
|
||||
org2.destroy
|
||||
|
||||
end
|
||||
|
||||
@@ -148,8 +155,8 @@ class AssetsTest < ActiveSupport::TestCase
|
||||
roles: roles,
|
||||
)
|
||||
|
||||
roles = Role.where( name: %w(Customer) )
|
||||
org = Organization.create_or_update(
|
||||
roles = Role.where( name: %w(Customer) )
|
||||
org = Organization.create_or_update(
|
||||
name: 'some customer org',
|
||||
updated_by_id: admin1.id,
|
||||
created_by_id: 1,
|
||||
@@ -232,7 +239,7 @@ class AssetsTest < ActiveSupport::TestCase
|
||||
assert_nil( assets[:User][user3.id], 'check assets' )
|
||||
|
||||
# touch user 2, check if org has changed
|
||||
sleep 2
|
||||
travel 2.seconds
|
||||
user_new_2 = User.find(user2.id)
|
||||
user_new_2.lastname = 'assets2'
|
||||
user_new_2.save
|
||||
@@ -261,6 +268,13 @@ class AssetsTest < ActiveSupport::TestCase
|
||||
attributes.delete('token_ids')
|
||||
attributes.delete('authorization_ids')
|
||||
assert( diff(attributes, assets[:User][user_new_2.id]), 'check assets' )
|
||||
travel_back
|
||||
|
||||
user1.destroy
|
||||
user2.destroy
|
||||
user3.destroy
|
||||
org.destroy
|
||||
org_new.destroy
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ class CalendarTest < ActiveSupport::TestCase
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
calendar2 = Calendar.create_or_update(
|
||||
name: 'US 2',
|
||||
timezone: 'America/Los_Angeles',
|
||||
@@ -88,6 +88,7 @@ class CalendarTest < ActiveSupport::TestCase
|
||||
|
||||
assert_equal(true, calendar2.default)
|
||||
assert_equal(false, calendar3.default)
|
||||
travel_back
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -208,19 +208,19 @@ class ChatTest < ActiveSupport::TestCase
|
||||
content: 'message 1',
|
||||
created_by_id: agent1.id,
|
||||
)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
Chat::Message.create(
|
||||
chat_session_id: chat_session6.id,
|
||||
content: 'message 2',
|
||||
created_by_id: agent1.id,
|
||||
)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
Chat::Message.create(
|
||||
chat_session_id: chat_session6.id,
|
||||
content: 'message 3',
|
||||
created_by_id: agent1.id,
|
||||
)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
Chat::Message.create(
|
||||
chat_session_id: chat_session6.id,
|
||||
content: 'message 4',
|
||||
@@ -351,7 +351,7 @@ class ChatTest < ActiveSupport::TestCase
|
||||
assert_equal(1, agent_state[:seads_available])
|
||||
assert_equal(4, agent_state[:seads_total])
|
||||
assert_equal(false, agent_state[:active])
|
||||
|
||||
travel_back
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -211,4 +211,20 @@ text
|
||||
assert_equal(html_should, html_with_fixes)
|
||||
end
|
||||
|
||||
test 'from checks' do
|
||||
|
||||
quoted_in_one_line = Channel::EmailBuild.recipient_line('Somebody @ "Company"', 'some.body@example.com')
|
||||
assert_equal('"Somebody @ \"Company\"" <some.body@example.com>', quoted_in_one_line)
|
||||
|
||||
quoted_in_one_line = Channel::EmailBuild.recipient_line('Somebody', 'some.body@example.com')
|
||||
assert_equal('Somebody <some.body@example.com>', quoted_in_one_line)
|
||||
|
||||
quoted_in_one_line = Channel::EmailBuild.recipient_line('Somebody | Some Org', 'some.body@example.com')
|
||||
assert_equal('"Somebody | Some Org" <some.body@example.com>', quoted_in_one_line)
|
||||
|
||||
quoted_in_one_line = Channel::EmailBuild.recipient_line('Test Master Agent via Support', 'some.body@example.com')
|
||||
assert_equal('"Test Master Agent via Support" <some.body@example.com>', quoted_in_one_line)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -27,11 +27,13 @@ class EmailProcessBounceTest < ActiveSupport::TestCase
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
email_raw_string = IO.binread('test/fixtures/mail33-undelivered-mail-returned-to-sender.box')
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('new', ticket_p.state.name)
|
||||
travel_back
|
||||
ticket.destroy
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -84,47 +84,92 @@ no reference "
|
||||
setting_orig = Setting.get('postmaster_follow_up_search_in')
|
||||
Setting.set('postmaster_follow_up_search_in', %w(body attachment references))
|
||||
|
||||
sleep 1
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_subject)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
|
||||
sleep 1
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_body)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
|
||||
sleep 1
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_attachment)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
|
||||
sleep 1
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references1)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
|
||||
sleep 1
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references2)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
|
||||
Setting.set('postmaster_follow_up_search_in', nil)
|
||||
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_subject)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_body)
|
||||
assert_not_equal(ticket.id, ticket_p.id)
|
||||
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_attachment)
|
||||
assert_not_equal(ticket.id, ticket_p.id)
|
||||
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references1)
|
||||
assert_not_equal(ticket.id, ticket_p.id)
|
||||
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references2)
|
||||
assert_not_equal(ticket.id, ticket_p.id)
|
||||
|
||||
Setting.set('postmaster_follow_up_search_in', 'references')
|
||||
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_subject)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_body)
|
||||
assert_not_equal(ticket.id, ticket_p.id)
|
||||
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_attachment)
|
||||
assert_not_equal(ticket.id, ticket_p.id)
|
||||
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references1)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references2)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
|
||||
Setting.set('postmaster_follow_up_search_in', setting_orig)
|
||||
|
||||
sleep 1
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_subject)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
|
||||
sleep 1
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_body)
|
||||
assert_not_equal(ticket.id, ticket_p.id)
|
||||
|
||||
sleep 1
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_attachment)
|
||||
assert_not_equal(ticket.id, ticket_p.id)
|
||||
|
||||
sleep 1
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references1)
|
||||
assert_not_equal(ticket.id, ticket_p.id)
|
||||
|
||||
sleep 1
|
||||
travel 1.second
|
||||
ticket_p, article_p, user_p = Channel::EmailParser.new.process({}, email_raw_string_references2)
|
||||
assert_not_equal(ticket.id, ticket_p.id)
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'process with follow up check with two external reference headers' do
|
||||
@@ -141,7 +186,7 @@ test 123
|
||||
"
|
||||
ticket_p1, article_p1, user_p1 = Channel::EmailParser.new.process({}, data1)
|
||||
|
||||
sleep 1
|
||||
travel 1.second
|
||||
|
||||
data1 = "From: me@example.com
|
||||
To: z@example.com
|
||||
@@ -166,7 +211,7 @@ test 123
|
||||
assert_equal(ticket_p2.id, ticket_p3.id)
|
||||
|
||||
Setting.set('postmaster_follow_up_search_in', setting_orig)
|
||||
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'process with follow up check - with auto responses and no T# in subject_build' do
|
||||
@@ -193,7 +238,7 @@ test 123
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
|
||||
# auto response without T# in subject, find follow up by references header
|
||||
email_raw_string = "From: bob@example.com
|
||||
@@ -211,6 +256,7 @@ Some Text"
|
||||
ticket = Ticket.find(ticket.id)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('open', ticket.state.name)
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'process with follow up check - email with more forgein T#\'s in subject' do
|
||||
@@ -237,7 +283,7 @@ Some Text"
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
|
||||
system_id = Setting.get('system_id')
|
||||
ticket_hook = Setting.get('ticket_hook')
|
||||
@@ -255,6 +301,7 @@ Some Text"
|
||||
ticket = Ticket.find(ticket.id)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('open', ticket.state.name)
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'process with follow up check - ticket initiated by customer without T# in subject and other people in Cc reply to all' do
|
||||
@@ -322,4 +369,41 @@ Some Text"
|
||||
Setting.set('postmaster_follow_up_search_in', setting_orig)
|
||||
end
|
||||
|
||||
test 'process with follow up check - with none ticket# in subject' do
|
||||
|
||||
setting_orig = Setting.get('postmaster_follow_up_search_in')
|
||||
Setting.set('postmaster_follow_up_search_in', [])
|
||||
ticket_hook_position_orig = Setting.get('ticket_hook_position')
|
||||
Setting.set('ticket_hook_position', 'none')
|
||||
|
||||
subject = 'some title'
|
||||
email_raw_string = "From: me@example.com
|
||||
To: bob@example.com
|
||||
Subject: #{subject}
|
||||
Message-ID: <123456789-follow-up-test-ticket_hook_position-none@linuxhotel.de>
|
||||
|
||||
Some Text"
|
||||
|
||||
ticket_p1, article_1, user_1, mail = Channel::EmailParser.new.process({}, email_raw_string)
|
||||
ticket1 = Ticket.find(ticket_p1.id)
|
||||
assert_equal(subject, ticket1.title)
|
||||
|
||||
# follow up possible because same subject
|
||||
subject = 'new subject lalala'
|
||||
email_raw_string = "From: bob@example.com
|
||||
To: me@example.com
|
||||
Subject: AW: #{subject}
|
||||
Message-ID: <123456789-follow-up-test-ticket_hook_position-none-2@linuxhotel.de>
|
||||
References: <123456789-follow-up-test-ticket_hook_position-none@linuxhotel.de>
|
||||
|
||||
Some Text"
|
||||
|
||||
ticket_p2, article_p2, user_p2, mail = Channel::EmailParser.new.process({}, email_raw_string)
|
||||
ticket2 = Ticket.find(ticket_p2.id)
|
||||
assert_equal(ticket1.id, ticket2.id)
|
||||
|
||||
Setting.set('ticket_hook_position', ticket_hook_position_orig)
|
||||
Setting.set('postmaster_follow_up_search_in', setting_orig)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -27,7 +27,7 @@ class EmailProcessOutOfOfficeTest < ActiveSupport::TestCase
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
|
||||
# exchange out of office example #1
|
||||
email_raw_string = "From: me@example.com
|
||||
@@ -86,7 +86,7 @@ Some Text"
|
||||
ticket = Ticket.find(ticket.id)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('closed', ticket.state.name)
|
||||
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'process with out of office check - zimbra' do
|
||||
@@ -113,7 +113,7 @@ Some Text"
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
|
||||
# exchange out of office example #1
|
||||
email_raw_string = "From: me@example.com
|
||||
@@ -164,7 +164,7 @@ Some Text"
|
||||
ticket = Ticket.find(ticket.id)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('closed', ticket.state.name)
|
||||
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'process with out of office check - cloud' do
|
||||
@@ -191,7 +191,7 @@ Some Text"
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
|
||||
# exchange out of office example #1
|
||||
email_raw_string = "From: me@example.com
|
||||
@@ -237,7 +237,7 @@ Some Text"
|
||||
ticket = Ticket.find(ticket.id)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('closed', ticket.state.name)
|
||||
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'process with out of office check - gmail' do
|
||||
@@ -264,7 +264,7 @@ Some Text"
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
|
||||
# gmail out of office example #1
|
||||
email_raw_string = "From: me@example.com
|
||||
@@ -294,6 +294,7 @@ Some Text 2"
|
||||
ticket = Ticket.find(ticket.id)
|
||||
assert_equal(ticket.id, ticket_p.id)
|
||||
assert_equal('open', ticket_p.state.name)
|
||||
travel_back
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
File diff suppressed because one or more lines are too long
74
test/unit/html_sanitizer_test.rb
Normal file
74
test/unit/html_sanitizer_test.rb
Normal file
@@ -0,0 +1,74 @@
|
||||
# encoding: utf-8
|
||||
require 'test_helper'
|
||||
|
||||
class HtmlSanitizerTest < ActiveSupport::TestCase
|
||||
|
||||
test 'xss' do
|
||||
assert_equal(HtmlSanitizer.strict('<b>123</b>'), '<b>123</b>')
|
||||
assert_equal(HtmlSanitizer.strict('<script><b>123</b></script>'), '<b>123</b>')
|
||||
assert_equal(HtmlSanitizer.strict('<script><style><b>123</b></style></script>'), '<style><b>123</b></style>')
|
||||
assert_equal(HtmlSanitizer.strict('<abc><i><b>123</b><bbb>123</bbb></i></abc>'), '<i><b>123</b>123</i>')
|
||||
assert_equal(HtmlSanitizer.strict('<abc><i><b>123</b><bbb>123<i><ccc>abc</ccc></i></bbb></i></abc>'), '<i><b>123</b>123<i>abc</i></i>')
|
||||
assert_equal(HtmlSanitizer.strict('<not_existing>123</not_existing>'), '123')
|
||||
assert_equal(HtmlSanitizer.strict('<script type="text/javascript">alert("XSS!");</script>'), 'alert("XSS!");')
|
||||
assert_equal(HtmlSanitizer.strict('<SCRIPT SRC=http://xss.rocks/xss.js></SCRIPT>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC="javascript:alert(\'XSS\');">'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC=javascript:alert(\'XSS\')>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC=JaVaScRiPt:alert(\'XSS\')>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC=`javascript:alert("RSnake says, \'XSS\'")`>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG """><SCRIPT>alert("XSS")</SCRIPT>">'), '<img>alert("XSS")">')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC=# onmouseover="alert(\'xxs\')">'), '<img src="#">')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC="jav ascript:alert(\'XSS\');">'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC="jav	ascript:alert(\'XSS\');">'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC="jav
ascript:alert(\'XSS\');">'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC="jav
ascript:alert(\'XSS\');">'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC="  javascript:alert(\'XSS\');">'), '<img src="">')
|
||||
assert_equal(HtmlSanitizer.strict('<SCRIPT/XSS SRC="http://xss.rocks/xss.js"></SCRIPT>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<SCRIPT/SRC="http://xss.rocks/xss.js"></SCRIPT>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<<SCRIPT>alert("XSS");//<</SCRIPT>'), '<alert("XSS");//<')
|
||||
assert_equal(HtmlSanitizer.strict('<SCRIPT SRC=http://xss.rocks/xss.js?< B >'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<SCRIPT SRC=//xss.rocks/.j>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC="javascript:alert(\'XSS\')"'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC="javascript:alert(\'XSS\')" abc<b>123</b>'), '123')
|
||||
assert_equal(HtmlSanitizer.strict('<iframe src=http://xss.rocks/scriptlet.html <'), '')
|
||||
assert_equal(HtmlSanitizer.strict('</script><script>alert(\'XSS\');</script>'), 'alert(\'XSS\');')
|
||||
assert_equal(HtmlSanitizer.strict('<STYLE>li {list-style-image: url("javascript:alert(\'XSS\')");}</STYLE><UL><LI>XSS</br>'), '<ul><li>XSS</li></ul>')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC=\'vbscript:msgbox("XSS")\'>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC="livescript:[code]">'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<svg/onload=alert(\'XSS\')>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<BODY ONLOAD=alert(\'XSS\')>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<LINK REL="stylesheet" HREF="javascript:alert(\'XSS\');">'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<STYLE>@import\'http://xss.rocks/xss.css\';</STYLE>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<META HTTP-EQUIV="Link" Content="<http://xss.rocks/xss.css>; REL=stylesheet">'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG STYLE="java/*XSS*/script:(alert(\'XSS\'), \'\')">'), '<img>')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG src="java/*XSS*/script:(alert(\'XSS\'), \'\')">'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<IFRAME SRC="javascript:alert(\'XSS\');"></IFRAME>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<TABLE><TD BACKGROUND="javascript:alert(\'XSS\')">'), '<table><td></td></table>')
|
||||
assert_equal(HtmlSanitizer.strict('<DIV STYLE="background-image: url(javascript:alert(\'XSS\'), \'\')">'), '<div></div>')
|
||||
assert_equal(HtmlSanitizer.strict('<a href="/some/path">test</a>'), '<a href="/some/path">test</a>')
|
||||
assert_equal(HtmlSanitizer.strict('<a href="https://some/path">test</a>'), '<a href="https://some/path" rel="nofollow" target="_blank">test</a>')
|
||||
assert_equal(HtmlSanitizer.strict('<XML ID="xss"><I><B><IMG SRC="javas<!-- -->cript:alert(\'XSS\')"></B></I></XML>'), '<i><b></b></i>')
|
||||
assert_equal(HtmlSanitizer.strict('<IMG SRC="javas<!-- -->cript:alert(\'XSS\')">'), '')
|
||||
assert_equal(HtmlSanitizer.strict(' <HEAD><META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=UTF-7"> </HEAD>+ADw-SCRIPT+AD4-alert(\'XSS\');+ADw-/SCRIPT+AD4-'), ' +ADw-SCRIPT+AD4-alert(\'XSS\');+ADw-/SCRIPT+AD4-')
|
||||
assert_equal(HtmlSanitizer.strict('<SCRIPT a=">" SRC="httx://xss.rocks/xss.js"></SCRIPT>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<A HREF="h
|
||||
tt p://6 6.000146.0x7.147/">XSS</A>'), '<a href="h%0Att%20%20p://6%206.000146.0x7.147/" rel="nofollow" target="_blank">XSS</a>')
|
||||
assert_equal(HtmlSanitizer.strict('<A HREF="//www.google.com/">XSS</A>'), '<a href="//www.google.com/" rel="nofollow" target="_blank">XSS</a>')
|
||||
assert_equal(HtmlSanitizer.strict('<form id="test"></form><button form="test" formaction="javascript:alert(1)">X</button>'), 'X')
|
||||
assert_equal(HtmlSanitizer.strict('<maction actiontype="statusline#http://google.com" xlink:href="javascript:alert(2)">CLICKME</maction>'), 'CLICKME')
|
||||
assert_equal(HtmlSanitizer.strict('<a xlink:href="javascript:alert(2)">CLICKME</a>'), '<a>CLICKME</a>')
|
||||
assert_equal(HtmlSanitizer.strict('<!--<img src="--><img src=x onerror=alert(1)//">'), '<img src="x">')
|
||||
assert_equal(HtmlSanitizer.strict('<![><img src="]><img src=x onerror=alert(1)//">'), '<img src="%5D><img%20src=x%20onerror=alert(1)//">')
|
||||
assert_equal(HtmlSanitizer.strict('<svg><![CDATA[><image xlink:href="]]><img src=xx:x onerror=alert(2)//"></svg>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<abc><img src="</abc><img src=x onerror=alert(1)//">'), '<img src="</abc><img%20src=x%20onerror=alert(1)//">')
|
||||
assert_equal(HtmlSanitizer.strict('<object data="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></object>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<embed src="data:text/html;base64,PHNjcmlwdD5hbGVydCgxKTwvc2NyaXB0Pg=="></embed>'), '')
|
||||
assert_equal(HtmlSanitizer.strict('<img[a][b]src=x[d]onerror[c]=[e]"alert(1)">'), '<img>')
|
||||
assert_equal(HtmlSanitizer.strict('<a href="[a]java[b]script[c]:alert(1)">XXX</a>'), '<a>XXX</a>')
|
||||
assert_equal(HtmlSanitizer.strict('<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>'), 'alert(1)')
|
||||
assert_equal(HtmlSanitizer.strict('<a style="position:fixed;top:0;left:0;width: 260px;height:100vh;background-color:red;display: block;" href="http://example.com"></a>'), '<a style="width: 260px;height:100vh;" href="http://example.com" rel="nofollow" target="_blank"></a>')
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -407,6 +407,26 @@ class ObjectManagerTest < ActiveSupport::TestCase
|
||||
}
|
||||
assert_equal(false, ObjectManager::Attribute.pending_migration?)
|
||||
|
||||
assert_raises(RuntimeError) {
|
||||
attribute18 = ObjectManager::Attribute.add(
|
||||
object: 'Ticket',
|
||||
name: 'delete',
|
||||
display: 'Test 18',
|
||||
data_type: 'input',
|
||||
data_option: {
|
||||
maxlength: 200,
|
||||
type: 'text',
|
||||
null: false,
|
||||
},
|
||||
active: true,
|
||||
screens: {},
|
||||
position: 20,
|
||||
created_by_id: 1,
|
||||
updated_by_id: 1,
|
||||
)
|
||||
}
|
||||
assert_equal(false, ObjectManager::Attribute.pending_migration?)
|
||||
|
||||
end
|
||||
|
||||
test 'b object manager attribute' do
|
||||
|
||||
@@ -81,7 +81,7 @@ class OrganizationRefObjectTouchTest < ActiveSupport::TestCase
|
||||
assert_equal(ticket.customer.id, customer1.id)
|
||||
assert_equal(ticket.organization.id, organization1.id)
|
||||
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
|
||||
organization1.name = 'Ref Object Update Org 1/1'
|
||||
organization1.save
|
||||
@@ -101,7 +101,7 @@ class OrganizationRefObjectTouchTest < ActiveSupport::TestCase
|
||||
assert(false, 'customer1.updated_at has not been updated')
|
||||
end
|
||||
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
|
||||
customer2.organization_id = organization1.id
|
||||
customer2.save
|
||||
@@ -123,5 +123,6 @@ class OrganizationRefObjectTouchTest < ActiveSupport::TestCase
|
||||
|
||||
delete = ticket.destroy
|
||||
assert(delete, 'ticket destroy')
|
||||
travel_back
|
||||
end
|
||||
end
|
||||
|
||||
@@ -123,4 +123,48 @@ class PermissionTest < ActiveSupport::TestCase
|
||||
|
||||
end
|
||||
|
||||
test 'user permission with childs' do
|
||||
|
||||
permission1 = Permission.create_or_update(
|
||||
name: 'admin.permission_child1',
|
||||
note: 'Admin Interface',
|
||||
preferences: {},
|
||||
active: true,
|
||||
)
|
||||
permission2 = Permission.create_or_update(
|
||||
name: 'admin.permission_child2',
|
||||
note: 'Admin Interface',
|
||||
preferences: {},
|
||||
active: false,
|
||||
)
|
||||
role_permission1 = Role.create_or_update(
|
||||
name: 'AdminPermissionChild1',
|
||||
note: 'To configure your permission child1.',
|
||||
preferences: {
|
||||
not: ['Customer'],
|
||||
},
|
||||
default_at_signup: false,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
role_permission1.permission_grand('admin')
|
||||
user_with_permission1 = User.create_or_update(
|
||||
login: 'setting-permission-child1',
|
||||
firstname: 'Setting',
|
||||
lastname: 'Admin Permission Child1',
|
||||
email: 'setting-admin-permission-child1@example.com',
|
||||
password: 'some_pw',
|
||||
active: true,
|
||||
roles: [role_permission1],
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert(user_with_permission1.permissions_with_child_ids.include?(permission1.id))
|
||||
assert_not(user_with_permission1.permissions_with_child_ids.include?(permission2.id))
|
||||
assert(user_with_permission1.permissions_with_child_ids.include?(Permission.find_by(name: 'admin').id))
|
||||
|
||||
# cleanup
|
||||
user_with_permission1.destroy
|
||||
role_permission1.destroy
|
||||
end
|
||||
end
|
||||
|
||||
@@ -29,11 +29,11 @@ class RecentViewTest < ActiveSupport::TestCase
|
||||
RecentView.user_log_destroy(user1)
|
||||
|
||||
RecentView.log(ticket1.class.to_s, ticket1.id, user1)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
RecentView.log(ticket2.class.to_s, ticket2.id, user1)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
RecentView.log(ticket1.class.to_s, ticket1.id, user1)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
RecentView.log(ticket1.class.to_s, ticket1.id, user1)
|
||||
|
||||
list = RecentView.list(user1)
|
||||
@@ -54,6 +54,7 @@ class RecentViewTest < ActiveSupport::TestCase
|
||||
|
||||
list = RecentView.list(user1)
|
||||
assert(!list[0], 'check if recent view list is empty')
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'existing tests' do
|
||||
|
||||
@@ -19,7 +19,7 @@ class SessionBasicTest < ActiveSupport::TestCase
|
||||
assert_equal(false, result, 'check 1 - expired')
|
||||
|
||||
# should be expired
|
||||
sleep 2
|
||||
travel 2.seconds
|
||||
result = Sessions::CacheIn.expired('last_run_test')
|
||||
assert_equal(true, result, 'check 1 - expired')
|
||||
|
||||
@@ -32,7 +32,7 @@ class SessionBasicTest < ActiveSupport::TestCase
|
||||
assert_equal(false, result, 'check 1 - expired')
|
||||
|
||||
# ignore expired
|
||||
sleep 2
|
||||
travel 2.seconds
|
||||
result = Sessions::CacheIn.get('last_run_test', ignore_expire: true)
|
||||
assert_equal(true, result, 'check 1 - ignore_expire')
|
||||
|
||||
@@ -50,6 +50,7 @@ class SessionBasicTest < ActiveSupport::TestCase
|
||||
Sessions::CacheIn.delete('last_run_delete')
|
||||
result = Sessions::CacheIn.get('last_run_delete')
|
||||
assert_equal(nil, nil, 'check delete')
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'c session create / update' do
|
||||
@@ -124,14 +125,14 @@ class SessionBasicTest < ActiveSupport::TestCase
|
||||
# next check should be empty
|
||||
result1 = collection_client1.push
|
||||
assert(!result1, 'check collections - recall')
|
||||
sleep 1
|
||||
travel 1.second
|
||||
result2 = collection_client2.push
|
||||
assert(!result2, 'check collections - recall')
|
||||
|
||||
# change collection
|
||||
group = Group.first
|
||||
group.touch
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
|
||||
# get whole collections
|
||||
result1 = collection_client1.push
|
||||
@@ -149,7 +150,7 @@ class SessionBasicTest < ActiveSupport::TestCase
|
||||
|
||||
# change collection
|
||||
group = Group.create(name: "SomeGroup::#{rand(999_999)}", active: true)
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
|
||||
# get whole collections
|
||||
result1 = collection_client1.push
|
||||
@@ -159,7 +160,7 @@ class SessionBasicTest < ActiveSupport::TestCase
|
||||
assert_equal(result1, result2, 'check collections')
|
||||
|
||||
# check again after create
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
result1 = collection_client1.push
|
||||
assert(!result1, 'check collections - after create - recall')
|
||||
result2 = collection_client2.push
|
||||
@@ -168,7 +169,7 @@ class SessionBasicTest < ActiveSupport::TestCase
|
||||
|
||||
# change collection
|
||||
group.destroy
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
|
||||
# get whole collections
|
||||
result1 = collection_client1.push
|
||||
@@ -178,12 +179,13 @@ class SessionBasicTest < ActiveSupport::TestCase
|
||||
assert_equal(result1, result2, 'check collections')
|
||||
|
||||
# check again after destroy
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
result1 = collection_client1.push
|
||||
assert(!result1, 'check collections - after destroy - recall')
|
||||
result2 = collection_client2.push
|
||||
assert(!result2, 'check collections - after destroy - recall')
|
||||
assert_equal(result1, result2, 'check collections')
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'c activity stream' do
|
||||
@@ -206,30 +208,39 @@ class SessionBasicTest < ActiveSupport::TestCase
|
||||
agent1.roles = roles
|
||||
assert(agent1.save, 'create/update agent1')
|
||||
|
||||
# create min. on activity record
|
||||
random_name = "Random:#{rand(9_999_999_999)}"
|
||||
Group.create_or_update(
|
||||
name: random_name,
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
as_client1 = Sessions::Backend::ActivityStream.new(agent1, {}, false, '123-1', 3)
|
||||
|
||||
# get as stream
|
||||
result1 = as_client1.push
|
||||
assert(result1, 'check as agent1')
|
||||
sleep 1
|
||||
travel 1.second
|
||||
|
||||
# next check should be empty
|
||||
result1 = as_client1.push
|
||||
assert(!result1, 'check as agent1 - recall')
|
||||
|
||||
# next check should be empty
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
result1 = as_client1.push
|
||||
assert(!result1, 'check as agent1 - recall 2')
|
||||
|
||||
agent1.update_attribute(:email, 'activity-stream-agent11@example.com')
|
||||
ticket = Ticket.create(title: '12323', group_id: 1, priority_id: 1, state_id: 1, customer_id: 1)
|
||||
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
|
||||
# get as stream
|
||||
result1 = as_client1.push
|
||||
assert( result1, 'check as agent1 - recall 3')
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'c ticket_create' do
|
||||
@@ -254,11 +265,12 @@ class SessionBasicTest < ActiveSupport::TestCase
|
||||
|
||||
Group.create(name: "SomeTicketCreateGroup::#{rand(999_999)}", active: true)
|
||||
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
|
||||
# get as stream
|
||||
result1 = ticket_create_client1.push
|
||||
assert(result1, 'check ticket_create - recall 3')
|
||||
travel_back
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -38,17 +38,17 @@ class SessionBasicTicketTest < ActiveSupport::TestCase
|
||||
assert(!result1, 'check ticket_overview_index - recall')
|
||||
|
||||
# next check should be empty / no changes
|
||||
sleep 3
|
||||
travel 3.seconds
|
||||
result1 = client1.push
|
||||
assert(!result1, 'check ticket_overview_index - recall 2')
|
||||
|
||||
# create ticket
|
||||
ticket = Ticket.create(title: '12323', group_id: 1, priority_id: 1, state_id: 1, customer_id: 1)
|
||||
sleep 3
|
||||
travel 3.seconds
|
||||
|
||||
result1 = client1.push
|
||||
assert(result1, 'check ticket_overview_index - recall 3')
|
||||
sleep 3
|
||||
travel 3.seconds
|
||||
|
||||
# chnage overview
|
||||
overviews = Ticket::Overviews.all(
|
||||
@@ -70,6 +70,7 @@ class SessionBasicTicketTest < ActiveSupport::TestCase
|
||||
Sessions::Backend::TicketOverviewList.reset(user.id)
|
||||
result1 = client1.push
|
||||
assert(result1, 'check ticket_overview_index - recall 7')
|
||||
travel_back
|
||||
|
||||
end
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ class SessionCollectionsTest < ActiveSupport::TestCase
|
||||
assert(check_if_collection_exists(result1, :Role), 'check collections - after init')
|
||||
assert(check_if_collection_exists(result1, :Signature), 'check collections - after init')
|
||||
assert(check_if_collection_exists(result1, :EmailAddress), 'check collections - after init')
|
||||
sleep 1
|
||||
travel 1.second
|
||||
result2 = collection_client2.push
|
||||
assert(result2, 'check collections')
|
||||
assert(check_if_collection_exists(result2, :Group), 'check collections - after init')
|
||||
@@ -108,7 +108,7 @@ class SessionCollectionsTest < ActiveSupport::TestCase
|
||||
# change collection
|
||||
group = Group.first
|
||||
group.touch
|
||||
sleep 3
|
||||
travel 3.seconds
|
||||
|
||||
# get whole collections
|
||||
result1 = collection_client1.push
|
||||
@@ -130,6 +130,7 @@ class SessionCollectionsTest < ActiveSupport::TestCase
|
||||
assert(result2.empty?, 'check collections - recall')
|
||||
result3 = collection_client3.push
|
||||
assert(result3.empty?, 'check collections - recall')
|
||||
travel_back
|
||||
end
|
||||
|
||||
def check_if_collection_exists(results, collection, attributes = nil)
|
||||
|
||||
@@ -242,17 +242,17 @@ class SessionEnhancedTest < ActiveSupport::TestCase
|
||||
'Group' => true,
|
||||
'User' => nil,
|
||||
}
|
||||
check_if_collection_reset_message_exists(client_id1_0, collections, 'init')
|
||||
check_if_collection_reset_message_exists(client_id1_1, collections, 'init')
|
||||
check_if_collection_reset_message_exists(client_id2, collections, 'init')
|
||||
assert_if_collection_reset_message_exists(client_id1_0, collections, 'init')
|
||||
assert_if_collection_reset_message_exists(client_id1_1, collections, 'init')
|
||||
assert_if_collection_reset_message_exists(client_id2, collections, 'init')
|
||||
|
||||
collections = {
|
||||
'Group' => nil,
|
||||
'User' => nil,
|
||||
}
|
||||
check_if_collection_reset_message_exists(client_id1_0, collections, 'init2')
|
||||
check_if_collection_reset_message_exists(client_id1_1, collections, 'init2')
|
||||
check_if_collection_reset_message_exists(client_id2, collections, 'init2')
|
||||
assert_if_collection_reset_message_exists(client_id1_0, collections, 'init2')
|
||||
assert_if_collection_reset_message_exists(client_id1_1, collections, 'init2')
|
||||
assert_if_collection_reset_message_exists(client_id2, collections, 'init2')
|
||||
|
||||
sleep 8
|
||||
|
||||
@@ -260,9 +260,9 @@ class SessionEnhancedTest < ActiveSupport::TestCase
|
||||
'Group' => nil,
|
||||
'User' => nil,
|
||||
}
|
||||
check_if_collection_reset_message_exists(client_id1_0, collections, 'init3')
|
||||
check_if_collection_reset_message_exists(client_id1_1, collections, 'init3')
|
||||
check_if_collection_reset_message_exists(client_id2, collections, 'init3')
|
||||
assert_if_collection_reset_message_exists(client_id1_0, collections, 'init3')
|
||||
assert_if_collection_reset_message_exists(client_id1_1, collections, 'init3')
|
||||
assert_if_collection_reset_message_exists(client_id2, collections, 'init3')
|
||||
|
||||
# change collection
|
||||
group = Group.first
|
||||
@@ -275,9 +275,9 @@ class SessionEnhancedTest < ActiveSupport::TestCase
|
||||
'Group' => true,
|
||||
'User' => nil,
|
||||
}
|
||||
check_if_collection_reset_message_exists(client_id1_0, collections, 'update')
|
||||
check_if_collection_reset_message_exists(client_id1_1, collections, 'update')
|
||||
check_if_collection_reset_message_exists(client_id2, collections, 'update')
|
||||
assert_if_collection_reset_message_exists(client_id1_0, collections, 'update')
|
||||
assert_if_collection_reset_message_exists(client_id1_1, collections, 'update')
|
||||
assert_if_collection_reset_message_exists(client_id2, collections, 'update')
|
||||
|
||||
# check if session still exists after idle cleanup
|
||||
sleep 4
|
||||
@@ -290,7 +290,7 @@ class SessionEnhancedTest < ActiveSupport::TestCase
|
||||
|
||||
end
|
||||
|
||||
def check_if_collection_reset_message_exists(client_id, collections_orig, type)
|
||||
def assert_if_collection_reset_message_exists(client_id, collections_orig, type)
|
||||
messages = Sessions.queue(client_id)
|
||||
#puts "cid: #{client_id}"
|
||||
#puts "m: #{messages.inspect}"
|
||||
@@ -309,7 +309,7 @@ class SessionEnhancedTest < ActiveSupport::TestCase
|
||||
}
|
||||
#puts "c: #{collections_result.inspect}"
|
||||
collections_orig.each { |key, _value|
|
||||
assert_equal( collections_orig[key], collections_result[key], "collection message for #{key} #{type}-check (client_id #{client_id})" )
|
||||
assert_equal(collections_orig[key], collections_result[key], "collection message for #{key} #{type}-check (client_id #{client_id})")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -184,7 +184,7 @@ class TagTest < ActiveSupport::TestCase
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
sleep 2
|
||||
travel 2.seconds
|
||||
Tag.tag_add(
|
||||
object: 'Ticket',
|
||||
o_id: ticket1.id,
|
||||
@@ -266,7 +266,7 @@ class TagTest < ActiveSupport::TestCase
|
||||
assert(tags_ticket2.include?('some tag4'))
|
||||
|
||||
# rename tag
|
||||
sleep 2
|
||||
travel 2.seconds
|
||||
tag_item3 = Tag::Item.find_by(name: 'some tag3')
|
||||
Tag::Item.rename(
|
||||
id: tag_item3.id,
|
||||
@@ -300,7 +300,7 @@ class TagTest < ActiveSupport::TestCase
|
||||
assert(tags_ticket2.include?('some tag4'))
|
||||
|
||||
# merge tags
|
||||
sleep 2
|
||||
travel 2.seconds
|
||||
Tag::Item.rename(
|
||||
id: tag_item3.id,
|
||||
name: 'some tag2',
|
||||
@@ -333,7 +333,7 @@ class TagTest < ActiveSupport::TestCase
|
||||
assert_not(Tag::Item.find_by(id: tag_item3.id))
|
||||
|
||||
# remove tag item
|
||||
sleep 2
|
||||
travel 2.seconds
|
||||
tag_item4 = Tag::Item.find_by(name: 'some TAG4')
|
||||
Tag::Item.remove(tag_item4.id)
|
||||
|
||||
@@ -359,6 +359,6 @@ class TagTest < ActiveSupport::TestCase
|
||||
assert_not_equal(ticket1_lookup4.updated_at.to_s, ticket1_lookup3.updated_at.to_s)
|
||||
ticket2_lookup4 = Ticket.lookup(id: ticket2.id)
|
||||
assert_not_equal(ticket2_lookup4.updated_at.to_s, ticket2_lookup3.updated_at.to_s)
|
||||
|
||||
travel_back
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,6 +8,14 @@ class TicketOverviewTest < ActiveSupport::TestCase
|
||||
customer1 = nil
|
||||
customer2 = nil
|
||||
customer3 = nil
|
||||
overview1 = nil
|
||||
overview2 = nil
|
||||
overview3 = nil
|
||||
overview4 = nil
|
||||
overview5 = nil
|
||||
overview6 = nil
|
||||
overview7 = nil
|
||||
overview8 = nil
|
||||
test 'aaa - setup' do
|
||||
|
||||
# create base
|
||||
@@ -93,7 +101,7 @@ class TicketOverviewTest < ActiveSupport::TestCase
|
||||
Overview.destroy_all
|
||||
UserInfo.current_user_id = 1
|
||||
overview_role = Role.find_by(name: 'Agent')
|
||||
Overview.create_or_update(
|
||||
overview1 = Overview.create_or_update(
|
||||
name: 'My assigned Tickets',
|
||||
link: 'my_assigned',
|
||||
prio: 1000,
|
||||
@@ -120,7 +128,7 @@ class TicketOverviewTest < ActiveSupport::TestCase
|
||||
},
|
||||
)
|
||||
|
||||
Overview.create_or_update(
|
||||
overview2 = Overview.create_or_update(
|
||||
name: 'Unassigned & Open',
|
||||
link: 'all_unassigned',
|
||||
prio: 1010,
|
||||
@@ -146,7 +154,7 @@ class TicketOverviewTest < ActiveSupport::TestCase
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
Overview.create_or_update(
|
||||
overview3 = Overview.create_or_update(
|
||||
name: 'My Tickets 2',
|
||||
link: 'my_tickets_2',
|
||||
prio: 1020,
|
||||
@@ -173,9 +181,36 @@ class TicketOverviewTest < ActiveSupport::TestCase
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
overview4 = Overview.create_or_update(
|
||||
name: 'My Tickets only with Note',
|
||||
link: 'my_tickets_onyl_with_note',
|
||||
prio: 1030,
|
||||
role_id: overview_role.id,
|
||||
user_ids: [agent1.id],
|
||||
condition: {
|
||||
'article.type_id' => {
|
||||
operator: 'is',
|
||||
value: Ticket::Article::Type.find_by(name: 'note').id,
|
||||
},
|
||||
'ticket.owner_id' => {
|
||||
operator: 'is',
|
||||
pre_condition: 'current_user.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',
|
||||
},
|
||||
)
|
||||
|
||||
overview_role = Role.find_by(name: 'Customer')
|
||||
Overview.create_or_update(
|
||||
overview5 = Overview.create_or_update(
|
||||
name: 'My Tickets',
|
||||
link: 'my_tickets',
|
||||
prio: 1100,
|
||||
@@ -201,7 +236,7 @@ class TicketOverviewTest < ActiveSupport::TestCase
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
Overview.create_or_update(
|
||||
overview6 = Overview.create_or_update(
|
||||
name: 'My Organization Tickets',
|
||||
link: 'my_organization_tickets',
|
||||
prio: 1200,
|
||||
@@ -228,7 +263,7 @@ class TicketOverviewTest < ActiveSupport::TestCase
|
||||
view_mode_default: 's',
|
||||
},
|
||||
)
|
||||
Overview.create_or_update(
|
||||
overview7 = Overview.create_or_update(
|
||||
name: 'My Organization Tickets (open)',
|
||||
link: 'my_organization_tickets_open',
|
||||
prio: 1200,
|
||||
@@ -258,7 +293,7 @@ class TicketOverviewTest < ActiveSupport::TestCase
|
||||
)
|
||||
|
||||
overview_role = Role.find_by(name: 'Admin')
|
||||
Overview.create_or_update(
|
||||
overview8 = Overview.create_or_update(
|
||||
name: 'Not Shown Admin',
|
||||
link: 'not_shown_admin',
|
||||
prio: 9900,
|
||||
@@ -282,14 +317,15 @@ class TicketOverviewTest < ActiveSupport::TestCase
|
||||
)
|
||||
end
|
||||
|
||||
test 'ticket create' do
|
||||
test 'bbb overiview index' do
|
||||
|
||||
result = Ticket::Overviews.all(
|
||||
current_user: agent1,
|
||||
)
|
||||
assert_equal(2, result.count)
|
||||
assert_equal(3, result.count)
|
||||
assert_equal('My assigned Tickets', result[0].name)
|
||||
assert_equal('Unassigned & Open', result[1].name)
|
||||
assert_equal('My Tickets only with Note', result[2].name)
|
||||
|
||||
result = Ticket::Overviews.all(
|
||||
current_user: agent2,
|
||||
@@ -322,4 +358,504 @@ class TicketOverviewTest < ActiveSupport::TestCase
|
||||
|
||||
end
|
||||
|
||||
test 'ccc overiview content' do
|
||||
|
||||
Ticket.destroy_all
|
||||
|
||||
result = Ticket::Overviews.index(agent1)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:count], 0)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets only with Note')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_onyl_with_note')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
assert_equal(result[2][:count], 0)
|
||||
|
||||
result = Ticket::Overviews.index(agent2)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:count], 0)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets 2')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_2')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
|
||||
ticket1 = Ticket.create(
|
||||
title: 'overview test 1',
|
||||
group: Group.lookup(name: 'OverviewTest'),
|
||||
customer_id: 2,
|
||||
state: Ticket::State.lookup(name: 'new'),
|
||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
article1 = Ticket::Article.create(
|
||||
ticket_id: ticket1.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'some subject',
|
||||
message_id: 'some@id',
|
||||
body: 'some message... 123',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
result = Ticket::Overviews.index(agent1)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert_not(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:tickets][0][:id], ticket1.id)
|
||||
assert_equal(result[1][:count], 1)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets only with Note')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_onyl_with_note')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
assert_equal(result[2][:count], 0)
|
||||
|
||||
result = Ticket::Overviews.index(agent2)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:count], 0)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets 2')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_2')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
|
||||
travel 1.second # because of mysql millitime issues
|
||||
ticket2 = Ticket.create(
|
||||
title: 'overview test 2',
|
||||
group: Group.lookup(name: 'OverviewTest'),
|
||||
customer_id: 2,
|
||||
state: Ticket::State.lookup(name: 'new'),
|
||||
priority: Ticket::Priority.lookup(name: '3 high'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
article2 = Ticket::Article.create(
|
||||
ticket_id: ticket2.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'some subject',
|
||||
message_id: 'some@id',
|
||||
body: 'some message... 123',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Agent'),
|
||||
type: Ticket::Article::Type.find_by(name: 'note'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
result = Ticket::Overviews.index(agent1)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert_not(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:tickets][0][:id], ticket1.id)
|
||||
assert_equal(result[1][:tickets][1][:id], ticket2.id)
|
||||
assert_equal(result[1][:count], 2)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets only with Note')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_onyl_with_note')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
assert_equal(result[2][:count], 0)
|
||||
|
||||
result = Ticket::Overviews.index(agent2)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:count], 0)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets 2')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_2')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
|
||||
ticket2.owner_id = agent1.id
|
||||
ticket2.save!
|
||||
|
||||
result = Ticket::Overviews.index(agent1)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[0][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[0][:count], 1)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert_not(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:tickets][0][:id], ticket1.id)
|
||||
assert_equal(result[1][:count], 1)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets only with Note')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_onyl_with_note')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert_equal(result[2][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[2][:count], 1)
|
||||
|
||||
result = Ticket::Overviews.index(agent2)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:count], 0)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets 2')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_2')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
|
||||
travel 1.second # because of mysql millitime issues
|
||||
ticket3 = Ticket.create(
|
||||
title: 'overview test 3',
|
||||
group: Group.lookup(name: 'OverviewTest'),
|
||||
customer_id: 2,
|
||||
state: Ticket::State.lookup(name: 'new'),
|
||||
priority: Ticket::Priority.lookup(name: '1 low'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
article3 = Ticket::Article.create(
|
||||
ticket_id: ticket3.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'some subject',
|
||||
message_id: 'some@id',
|
||||
body: 'some message... 123',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
travel_back
|
||||
|
||||
result = Ticket::Overviews.index(agent1)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[0][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[0][:count], 1)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert_not(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:tickets][0][:id], ticket1.id)
|
||||
assert_equal(result[1][:tickets][1][:id], ticket3.id)
|
||||
assert_equal(result[1][:count], 2)
|
||||
assert_equal(result[2][:overview][:id], overview4.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets only with Note')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_onyl_with_note')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert_equal(result[2][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[2][:count], 1)
|
||||
|
||||
result = Ticket::Overviews.index(agent2)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:count], 0)
|
||||
assert_equal(result[2][:overview][:id], overview3.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets 2')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_2')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
|
||||
overview2.order = {
|
||||
by: 'created_at',
|
||||
direction: 'DESC',
|
||||
}
|
||||
overview2.save!
|
||||
|
||||
result = Ticket::Overviews.index(agent1)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[0][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[0][:count], 1)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert_not(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:tickets][0][:id], ticket3.id)
|
||||
assert_equal(result[1][:tickets][1][:id], ticket1.id)
|
||||
assert_equal(result[1][:count], 2)
|
||||
assert_equal(result[2][:overview][:id], overview4.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets only with Note')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_onyl_with_note')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert_equal(result[2][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[2][:count], 1)
|
||||
|
||||
result = Ticket::Overviews.index(agent2)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:count], 0)
|
||||
assert_equal(result[2][:overview][:id], overview3.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets 2')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_2')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
|
||||
overview2.order = {
|
||||
by: 'priority_id',
|
||||
direction: 'DESC',
|
||||
}
|
||||
overview2.save!
|
||||
|
||||
result = Ticket::Overviews.index(agent1)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[0][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[0][:count], 1)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert_not(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:tickets][0][:id], ticket1.id)
|
||||
assert_equal(result[1][:tickets][1][:id], ticket3.id)
|
||||
assert_equal(result[1][:count], 2)
|
||||
assert_equal(result[2][:overview][:id], overview4.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets only with Note')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_onyl_with_note')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert_equal(result[2][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[2][:count], 1)
|
||||
|
||||
result = Ticket::Overviews.index(agent2)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:count], 0)
|
||||
assert_equal(result[2][:overview][:id], overview3.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets 2')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_2')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
|
||||
overview2.order = {
|
||||
by: 'priority_id',
|
||||
direction: 'ASC',
|
||||
}
|
||||
overview2.save!
|
||||
|
||||
result = Ticket::Overviews.index(agent1)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[0][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[0][:count], 1)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert_not(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:tickets][0][:id], ticket3.id)
|
||||
assert_equal(result[1][:tickets][1][:id], ticket1.id)
|
||||
assert_equal(result[1][:count], 2)
|
||||
assert_equal(result[2][:overview][:id], overview4.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets only with Note')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_onyl_with_note')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert_equal(result[2][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[2][:count], 1)
|
||||
|
||||
result = Ticket::Overviews.index(agent2)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:count], 0)
|
||||
assert_equal(result[2][:overview][:id], overview3.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets 2')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_2')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
|
||||
overview2.order = {
|
||||
by: 'priority',
|
||||
direction: 'DESC',
|
||||
}
|
||||
overview2.save!
|
||||
|
||||
result = Ticket::Overviews.index(agent1)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[0][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[0][:count], 1)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert_not(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:tickets][0][:id], ticket1.id)
|
||||
assert_equal(result[1][:tickets][1][:id], ticket3.id)
|
||||
assert_equal(result[1][:count], 2)
|
||||
assert_equal(result[2][:overview][:id], overview4.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets only with Note')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_onyl_with_note')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert_equal(result[2][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[2][:count], 1)
|
||||
|
||||
result = Ticket::Overviews.index(agent2)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:count], 0)
|
||||
assert_equal(result[2][:overview][:id], overview3.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets 2')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_2')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
|
||||
overview2.order = {
|
||||
by: 'priority',
|
||||
direction: 'ASC',
|
||||
}
|
||||
overview2.save!
|
||||
|
||||
result = Ticket::Overviews.index(agent1)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[0][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[0][:count], 1)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert_not(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:tickets][0][:id], ticket3.id)
|
||||
assert_equal(result[1][:tickets][1][:id], ticket1.id)
|
||||
assert_equal(result[1][:count], 2)
|
||||
assert_equal(result[2][:overview][:id], overview4.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets only with Note')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_onyl_with_note')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert_equal(result[2][:tickets][0][:id], ticket2.id)
|
||||
assert_equal(result[2][:count], 1)
|
||||
|
||||
result = Ticket::Overviews.index(agent2)
|
||||
assert_equal(result[0][:overview][:id], overview1.id)
|
||||
assert_equal(result[0][:overview][:name], 'My assigned Tickets')
|
||||
assert_equal(result[0][:overview][:view], 'my_assigned')
|
||||
assert_equal(result[0][:count], 0)
|
||||
assert_equal(result[0][:tickets].class, Array)
|
||||
assert(result[0][:tickets].empty?)
|
||||
assert_equal(result[1][:overview][:id], overview2.id)
|
||||
assert_equal(result[1][:overview][:name], 'Unassigned & Open')
|
||||
assert_equal(result[1][:overview][:view], 'all_unassigned')
|
||||
assert_equal(result[1][:tickets].class, Array)
|
||||
assert(result[1][:tickets].empty?)
|
||||
assert_equal(result[1][:count], 0)
|
||||
assert_equal(result[2][:overview][:id], overview3.id)
|
||||
assert_equal(result[2][:overview][:name], 'My Tickets 2')
|
||||
assert_equal(result[2][:overview][:view], 'my_tickets_2')
|
||||
assert_equal(result[2][:tickets].class, Array)
|
||||
assert(result[2][:tickets].empty?)
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -90,7 +90,7 @@ class TicketRefObjectTouchTest < ActiveSupport::TestCase
|
||||
assert(false, 'organization1.updated_at has not been updated')
|
||||
end
|
||||
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
|
||||
delete = ticket.destroy
|
||||
assert(delete, 'ticket destroy')
|
||||
@@ -109,11 +109,12 @@ class TicketRefObjectTouchTest < ActiveSupport::TestCase
|
||||
else
|
||||
assert(false, 'organization1.updated_at has not been updated')
|
||||
end
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'c - check if customer (not organization) has been updated' do
|
||||
|
||||
sleep 6
|
||||
travel 8.seconds
|
||||
ticket = Ticket.create(
|
||||
title: "some title2\n äöüß",
|
||||
group: Group.lookup(name: 'Users'),
|
||||
@@ -143,7 +144,7 @@ class TicketRefObjectTouchTest < ActiveSupport::TestCase
|
||||
assert(true, 'organization1.updated_at has not been updated')
|
||||
end
|
||||
|
||||
sleep 4
|
||||
travel 4.seconds
|
||||
|
||||
delete = ticket.destroy
|
||||
assert(delete, 'ticket destroy')
|
||||
@@ -162,6 +163,6 @@ class TicketRefObjectTouchTest < ActiveSupport::TestCase
|
||||
else
|
||||
assert(true, 'organization1.updated_at has not been updated')
|
||||
end
|
||||
|
||||
travel_back
|
||||
end
|
||||
end
|
||||
|
||||
@@ -100,7 +100,7 @@ class TicketSelectorTest < ActiveSupport::TestCase
|
||||
assert(ticket1, 'ticket created')
|
||||
assert_equal(ticket1.customer.id, customer1.id)
|
||||
assert_equal(ticket1.organization.id, organization1.id)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
|
||||
ticket2 = Ticket.create!(
|
||||
title: 'some title2',
|
||||
@@ -116,7 +116,7 @@ class TicketSelectorTest < ActiveSupport::TestCase
|
||||
assert(ticket2, 'ticket created')
|
||||
assert_equal(ticket2.customer.id, customer2.id)
|
||||
assert_equal(ticket2.organization_id, nil)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
|
||||
ticket3 = Ticket.create!(
|
||||
title: 'some title3',
|
||||
@@ -133,7 +133,7 @@ class TicketSelectorTest < ActiveSupport::TestCase
|
||||
assert(ticket3, 'ticket created')
|
||||
assert_equal(ticket3.customer.id, customer2.id)
|
||||
assert_equal(ticket3.organization_id, nil)
|
||||
sleep 1
|
||||
travel 1.second
|
||||
|
||||
# search not matching
|
||||
condition = {
|
||||
@@ -995,7 +995,7 @@ class TicketSelectorTest < ActiveSupport::TestCase
|
||||
|
||||
ticket_count, tickets = Ticket.selectors(condition, 10)
|
||||
assert_equal(ticket_count, 0)
|
||||
|
||||
travel_back
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -43,7 +43,7 @@ class TicketTest < ActiveSupport::TestCase
|
||||
assert_equal(ticket.close_at, nil, 'ticket.close_at verify - inbound')
|
||||
|
||||
# create inbound article #2
|
||||
sleep 2
|
||||
travel 2.seconds
|
||||
article_inbound2 = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
@@ -91,7 +91,7 @@ class TicketTest < ActiveSupport::TestCase
|
||||
assert_equal(ticket.close_at, nil, 'ticket.close_at verify - note')
|
||||
|
||||
# create outbound article
|
||||
sleep 2
|
||||
travel 2.seconds
|
||||
article_outbound = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_recipient@example.com',
|
||||
@@ -139,7 +139,7 @@ class TicketTest < ActiveSupport::TestCase
|
||||
assert_equal(ticket.close_at, nil, 'ticket.close_at verify - outbound')
|
||||
|
||||
# create inbound article #4
|
||||
sleep 2
|
||||
travel 2.seconds
|
||||
article_inbound4 = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
@@ -189,10 +189,32 @@ class TicketTest < ActiveSupport::TestCase
|
||||
|
||||
ticket = Ticket.find(ticket.id)
|
||||
assert_equal(ticket.state.name, 'closed', 'state verify')
|
||||
assert_equal(ticket.pending_time, nil )
|
||||
assert_equal(ticket.pending_time, nil)
|
||||
|
||||
# delete article
|
||||
article_note = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some person',
|
||||
subject: 'some note',
|
||||
body: 'some message',
|
||||
internal: true,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Agent'),
|
||||
type: Ticket::Article::Type.find_by(name: 'note'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
|
||||
ticket = Ticket.find(ticket.id)
|
||||
assert_equal(ticket.article_count, 7, 'ticket.article_count verify - note')
|
||||
|
||||
article_note.destroy
|
||||
|
||||
ticket = Ticket.find(ticket.id)
|
||||
assert_equal(ticket.article_count, 6, 'ticket.article_count verify - note')
|
||||
|
||||
delete = ticket.destroy
|
||||
assert(delete, 'ticket destroy')
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'ticket latest change' do
|
||||
@@ -207,7 +229,7 @@ class TicketTest < ActiveSupport::TestCase
|
||||
)
|
||||
assert_equal(Ticket.latest_change.to_s, ticket1.updated_at.to_s)
|
||||
|
||||
sleep 1
|
||||
travel 1.minute
|
||||
|
||||
ticket2 = Ticket.create(
|
||||
title: 'latest change 2',
|
||||
@@ -220,20 +242,21 @@ class TicketTest < ActiveSupport::TestCase
|
||||
)
|
||||
assert_equal(Ticket.latest_change.to_s, ticket2.updated_at.to_s)
|
||||
|
||||
sleep 1
|
||||
travel 1.minute
|
||||
|
||||
ticket1.title = 'latest change 1 - 1'
|
||||
ticket1.save
|
||||
assert_equal(Ticket.latest_change.to_s, ticket1.updated_at.to_s)
|
||||
|
||||
sleep 1
|
||||
travel 1.minute
|
||||
|
||||
ticket1.touch
|
||||
assert_equal(Ticket.latest_change.to_s, ticket1.updated_at.to_s)
|
||||
|
||||
ticket1.destroy
|
||||
assert_equal(Ticket.latest_change.to_s, ticket2.updated_at.to_s)
|
||||
|
||||
ticket2.destroy
|
||||
travel_back
|
||||
end
|
||||
|
||||
test 'ticket process_pending' do
|
||||
|
||||
185
test/unit/ticket_xss_test.rb
Normal file
185
test/unit/ticket_xss_test.rb
Normal file
@@ -0,0 +1,185 @@
|
||||
# encoding: utf-8
|
||||
require 'test_helper'
|
||||
|
||||
class TicketXssTest < ActiveSupport::TestCase
|
||||
test 'xss via model' do
|
||||
ticket = Ticket.create(
|
||||
title: 'test 123 <script type="text/javascript">alert("XSS!");</script>',
|
||||
group: Group.lookup(name: 'Users'),
|
||||
customer_id: 2,
|
||||
state: Ticket::State.lookup(name: 'new'),
|
||||
priority: Ticket::Priority.lookup(name: '2 normal'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert(ticket, 'ticket created')
|
||||
|
||||
assert_equal('test 123 <script type="text/javascript">alert("XSS!");</script>', ticket.title, 'ticket.title verify')
|
||||
assert_equal('Users', ticket.group.name, 'ticket.group verify')
|
||||
assert_equal('new', ticket.state.name, 'ticket.state verify')
|
||||
|
||||
article1 = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'some subject <script type="text/javascript">alert("XSS!");</script>',
|
||||
message_id: 'some@id',
|
||||
content_type: 'text/html',
|
||||
body: '<script type="text/javascript">alert("XSS!");</script>',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal('alert("XSS!");', article1.body, 'article1.body verify - inbound')
|
||||
|
||||
article2 = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'some subject <script type="text/javascript">alert("XSS!");</script>',
|
||||
message_id: 'some@id',
|
||||
content_type: 'text/html',
|
||||
body: 'please tell me this doesn\'t work: <script type="text/javascript">alert("XSS!");</script>',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal('please tell me this doesn\'t work: alert("XSS!");', article2.body, 'article2.body verify - inbound')
|
||||
|
||||
article3 = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'some subject <script type="text/javascript">alert("XSS!");</script>',
|
||||
message_id: 'some@id',
|
||||
content_type: 'text/html',
|
||||
body: 'please tell me this doesn\'t work: <table>ada<tr></tr></table><div class="adasd" id="123" data-abc="123"></div><div><a href="javascript:someFunction()">LINK</a><a href="http://lalal.de">aa</a><some_not_existing>ABC</some_not_existing>',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal("please tell me this doesn't work: <table>ada<tr></tr>
|
||||
</table><div class=\"adasd\"></div><div>
|
||||
<a>LINK</a><a href=\"http://lalal.de\" rel=\"nofollow\" target=\"_blank\">aa</a>ABC</div>", article3.body, 'article3.body verify - inbound')
|
||||
|
||||
article4 = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'some subject <script type="text/javascript">alert("XSS!");</script>',
|
||||
message_id: 'some@id',
|
||||
content_type: 'text/html',
|
||||
body: 'please tell me this doesn\'t work: <video>some video</video><foo>alal</foo>',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal("please tell me this doesn't work: <video>some video</video>alal", article4.body, 'article4.body verify - inbound')
|
||||
|
||||
article5 = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'some subject <script type="text/javascript">alert("XSS!");</script>',
|
||||
message_id: 'some@id',
|
||||
content_type: 'text/plain',
|
||||
body: 'please tell me this doesn\'t work: <table>ada<tr></tr></table><div class="adasd" id="123" data-signature-id="123"></div><div><a href="javascript:someFunction()">LINK</a><a href="http://lalal.de">aa</a><some_not_existing>ABC</some_not_existing>',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal('please tell me this doesn\'t work: <table>ada<tr></tr></table><div class="adasd" id="123" data-signature-id="123"></div><div><a href="javascript:someFunction()">LINK</a><a href="http://lalal.de">aa</a><some_not_existing>ABC</some_not_existing>', article5.body, 'article5.body verify - inbound')
|
||||
|
||||
article6 = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'some subject <script type="text/javascript">alert("XSS!");</script>',
|
||||
message_id: 'some@id',
|
||||
content_type: 'text/html',
|
||||
body: 'some message article helper test1 <div><img style="width: 85.5px; height: 49.5px" src="cid:15.274327094.140938@zammad.example.com">asdasd<img src="cid:15.274327094.140939@zammad.example.com"><br>',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal('some message article helper test1 <div>
|
||||
<img style="width: 85.5px; height: 49.5px;" src="cid:15.274327094.140938@zammad.example.com">asdasd<img src="cid:15.274327094.140939@zammad.example.com"><br>
|
||||
</div>', article6.body, 'article6.body verify - inbound')
|
||||
|
||||
article7 = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'some subject <script type="text/javascript">alert("XSS!");</script>',
|
||||
message_id: 'some@id',
|
||||
content_type: 'text/html',
|
||||
body: 'some message article helper test1 <div><img style="width: 85.5px; height: 49.5px" src="api/v1/ticket_attachment/123/123/123">asdasd<img src="api/v1/ticket_attachment/123/123/123"><br>',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal('some message article helper test1 <div>
|
||||
<img style="width: 85.5px; height: 49.5px;" src="api/v1/ticket_attachment/123/123/123">asdasd<img src="api/v1/ticket_attachment/123/123/123"><br>
|
||||
</div>', article7.body, 'article7.body verify - inbound')
|
||||
|
||||
article8 = Ticket::Article.create(
|
||||
ticket_id: ticket.id,
|
||||
from: 'some_sender@example.com',
|
||||
to: 'some_recipient@example.com',
|
||||
subject: 'some subject <script type="text/javascript">alert("XSS!");</script>',
|
||||
message_id: 'some@id',
|
||||
content_type: 'text/html',
|
||||
body: 'some message article helper test1 <a href="#" onclick="some_function();">abc</a> <a href="https://example.com" oNclIck="some_function();">123</a><body>123</body>',
|
||||
internal: false,
|
||||
sender: Ticket::Article::Sender.find_by(name: 'Customer'),
|
||||
type: Ticket::Article::Type.find_by(name: 'email'),
|
||||
updated_by_id: 1,
|
||||
created_by_id: 1,
|
||||
)
|
||||
assert_equal('some message article helper test1 <a href="#">abc</a> <a href="https://example.com" rel="nofollow" target="_blank">123</a>123', article8.body, 'article8.body verify - inbound')
|
||||
|
||||
end
|
||||
|
||||
test 'xss via mail' do
|
||||
data = 'From: ME Bob <me@example.com>
|
||||
To: customer@example.com
|
||||
Subject: some subject
|
||||
Content-Type: text/html
|
||||
MIME-Version: 1.0
|
||||
|
||||
no HTML <script type="text/javascript">alert(\'XSS\')</script>'
|
||||
|
||||
parser = Channel::EmailParser.new
|
||||
ticket, article, user = parser.process({}, data)
|
||||
assert_equal('text/html', ticket.articles.first.content_type)
|
||||
assert_equal('no HTML alert(\'XSS\')', ticket.articles.first.body)
|
||||
|
||||
data = 'From: ME Bob <me@example.com>
|
||||
To: customer@example.com
|
||||
Subject: some subject
|
||||
Content-Type: text/plain
|
||||
MIME-Version: 1.0
|
||||
|
||||
no HTML <script type="text/javascript">alert(\'XSS\')</script>'
|
||||
|
||||
parser = Channel::EmailParser.new
|
||||
ticket, article, user = parser.process({}, data)
|
||||
assert_equal('text/plain', ticket.articles.first.content_type)
|
||||
assert_equal('no HTML <script type="text/javascript">alert(\'XSS\')</script>', ticket.articles.first.body)
|
||||
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user