Compare commits

...

753 Commits

Author SHA1 Message Date
6fcd22b533 Update to 2018.2.0 2019-01-26 01:12:54 -07:00
Mike Koch
fb81b23f6b
Update installer 2018-07-22 21:16:25 -04:00
Mike Koch
5f58ecb77f
Update installer 2018-07-22 21:16:24 -04:00
Mike Koch
ff9b7ceb9c Merge branch '648-no-cdns' into 'master'
Resolve "Don't Rely On External CDNs"

See merge request mike-koch/Mods-for-HESK!109
2018-07-21 02:07:01 +00:00
Mike Koch
983250665c
#648 Update leaflet to 0.7.7, don't use external CDN 2018-07-20 22:05:46 -04:00
Mike Koch
6205642cdb
#648 Update FontAwesome to 4.7, don't use external CDN 2018-07-20 21:58:18 -04:00
Mike Koch
b41021f567 Merge branch '651-due-date-permissions' into 'master'
Resolve "Problem: Users Cannot Change Ticket Due Date Without "Can Edit Tickets Permission""

See merge request mike-koch/Mods-for-HESK!108
2018-07-20 16:56:39 +00:00
Mike Koch
1de92c0d26
#651 Add 'can_change_due_date' permission 2018-07-20 12:55:54 -04:00
Mike Koch
510544f4ba Merge branch '647-fix-code-on-show-tickets' into 'master'
Resolve "'Show Tickets' on the Admin Panel results in Code View."

See merge request mike-koch/Mods-for-HESK!107
2018-07-19 01:53:47 +00:00
Mike Koch
6180d5d30c
#647 Don't try to show license on show_tickets 2018-07-18 21:53:05 -04:00
Mike Koch
11d6213208 Merge branch '641-invis-recaptcha' into 'master'
Resolve "Invisible Recapcha is not working"

See merge request mike-koch/Mods-for-HESK!106
2018-07-19 01:42:53 +00:00
Mike Koch
c4a9368a7b
#641 Fix invisible recaptcha 2018-07-18 21:39:33 -04:00
Mike Koch
823874e0a1 Merge branch '640-email-required' into 'master'
Resolve "Email required issue"

See merge request mike-koch/Mods-for-HESK!105
2018-07-18 01:38:32 +00:00
Mike Koch
7fc3fb042d
#640 Remove unnecessary subtext, fix required email issue 2018-07-17 21:37:42 -04:00
Mike Koch
a1fc11cd93 Merge branch '644-remove-help-files' into 'master'
Resolve "help/misc.html not updated"

See merge request mike-koch/Mods-for-HESK!104
2018-07-11 01:46:18 +00:00
Mike Koch
66fdd15616
Delete help files 2018-07-10 21:45:47 -04:00
Mike Koch
781e3b0434 Merge branch '644-remove-help-files' into 'master'
Resolve "help/misc.html not updated"

See merge request mike-koch/Mods-for-HESK!103
2018-07-11 01:37:20 +00:00
Mike Koch
12a5b57fab
#644 Remove help files from source control 2018-07-10 21:35:43 -04:00
Mike Koch
179df881c1 Merge branch 'hesk-2-8-2' into 'master'
HESK 2.8.2 Update

See merge request mike-koch/Mods-for-HESK!101
2018-07-09 16:52:39 +00:00
Mike Koch
9260af4734 Merge branch '642-fix-email-headers' into 'master'
Resolve "Mail header sent in a mail body"

Closes #642

See merge request mike-koch/Mods-for-HESK!102
2018-07-09 16:52:16 +00:00
Mike Koch
7efb6fc11e
Fixes #642 fix email headers 2018-07-09 12:50:09 -04:00
Mike Koch
9ee7e3e31b
Fix array designation for 5.3 2018-07-09 12:32:20 -04:00
Mike Koch
205035fa0c
Update build #, version # 2018-07-09 12:28:55 -04:00
Mike Koch
f39dbdfd87
Update footer for HESK 2.8.2 2018-07-09 12:16:40 -04:00
Mike Koch
c11a9d3a80
Update email_functions 2018-07-08 22:01:01 -04:00
Mike Koch
4418a36ccf
Update admin_functions and common from HESK 2.8.2 2018-07-08 21:58:07 -04:00
Mike Koch
e3d4fc89dc
Add migration for service message languages 2018-07-08 21:55:53 -04:00
Mike Koch
748ae25fc2
Update installer 2018-05-19 23:10:26 -04:00
Mike Koch
27e3729fcf
Update installer 2018-05-19 23:05:33 -04:00
Mike Koch
4e01fa7971
Work on installer, fix a couple reply API bugs 2018-05-19 22:30:34 -04:00
Mike Koch
16b1e7c491 Merge branch '3-4-0' into 'master'
2018.1.0 Update

See merge request mike-koch/Mods-for-HESK!100
2018-05-20 01:58:08 +00:00
Mike Koch
fccfde3414
Slight manage_users ui update 2018-05-19 20:59:30 -04:00
Mike Koch
3458f240b7
Users who can handle cats can see all of them on the edit user/perm group pages 2018-05-19 20:30:31 -04:00
Mike Koch
7a3d2f20a9
Actually skip the tests 2018-05-19 12:11:44 -04:00
Mike Koch
d15d4bf8d1
Update MFH version check URI 2018-05-19 10:51:18 -04:00
Mike Koch
d4a48c6c73
Fix admin visibility of tickets on calendar, included assignedByMe to filer 2018-05-19 10:50:57 -04:00
Mike Koch
26de217fef
Change 'Ticket History' to 'Audit Log' 2018-05-18 23:21:30 -04:00
Mike Koch
4d71bf45ad
Skip tests I'm too lazy to fix right now 2018-05-18 23:18:40 -04:00
Mike Koch
4c54ec677c
Fixing tests, round two 2018-05-18 20:46:46 -04:00
Mike Koch
1fffac8b8c
Fix tests I hope 2018-05-18 20:35:30 -04:00
Mike Koch
0c04660f3f
Reset color options on modal after saving 2018-05-18 20:33:29 -04:00
Mike Koch
0bb182220a
Fix new ticket validation via API 2018-05-18 20:28:33 -04:00
Mike Koch
a292d0dd30
Fix category existence when creating new ticket via API 2018-05-18 20:17:56 -04:00
Mike Koch
ea8b89ac04
Fix dates being inserted into the audit trail 2018-05-18 20:14:55 -04:00
Mike Koch
bc6299e5cf
Fix update due date link, manager check, change due date btn visibility 2018-05-18 19:48:24 -04:00
Mike Koch
83e2ec500a
Fix permission group dropdown not matching checkboxes 2018-05-18 18:52:17 -04:00
Mike Koch
ba733a2619
Don't blow up when a service message's user is deleted 2018-05-18 18:37:43 -04:00
Mike Koch
1ca4780d82 Merge branch 'hesk-2-8-0-update' into '3-4-0'
HESK 2.8.0/2.8.1 Update

See merge request mike-koch/Mods-for-HESK!99
2018-05-18 16:51:05 +00:00
Mike Koch
c133b11bf6
HESK 2.8.1 update 2018-05-18 12:42:25 -04:00
Mike Koch
a1fcc93f4e
Fix missing categories on admin_main export 2018-05-17 20:08:59 -04:00
Mike Koch
3ef8494b2a
Fixed print page, fixed flipped audit replacement values' 2018-05-17 20:01:02 -04:00
Mike Koch
b5374b9e6e
Fix LAST_REPLY_BY description 2018-05-17 19:10:34 -04:00
Mike Koch
b5890e1f59
Add IMAP fetching audit trail record 2018-05-17 19:08:22 -04:00
Mike Koch
2e9f040519
Properly set assignedby, fix hesk_notifyAssignedStaff, fix audit trail 2018-05-17 19:06:30 -04:00
Mike Koch
f02af695b8
privacy_functions modified to work with MfH 2018-05-17 18:57:21 -04:00
Mike Koch
6cad99e6c3
Updated pages for 2.8.0 2018-05-17 18:21:14 -04:00
Mike Koch
d2096f366e
Changes and fixes' 2018-05-17 00:08:34 -04:00
Mike Koch
db6e971ccc
Language, settings, ticket list updates 2018-05-16 22:02:41 -04:00
Mike Koch
c5804612ae
update gitignore 2018-05-16 21:44:02 -04:00
Mike Koch
aed9fda0aa
Initial commit of these 3 files for now 2018-05-16 19:02:29 -04:00
Mike Koch
b0934f7c4c
Update export_functions 2018-05-16 18:55:16 -04:00
Mike Koch
eb32da3c3e
Update print_template 2018-05-16 18:52:10 -04:00
Mike Koch
ad8e242d53
Update submit_ticket 2018-05-16 18:42:32 -04:00
Mike Koch
988c788710
Pseudoupdate print 2018-05-16 18:38:14 -04:00
Mike Koch
2c0bcb231a
Add text.php to gitignore 2018-05-16 18:36:22 -04:00
Mike Koch
9d1f2cbfdf
Update index 2018-05-16 18:35:00 -04:00
Mike Koch
32a2cde309
Update ticket_list 2018-05-16 18:15:42 -04:00
Mike Koch
ec6e67c8af
Update show_search_form 2018-05-16 13:03:32 -04:00
Mike Koch
444493506d
Update posting_functions 2018-05-16 12:57:46 -04:00
Mike Koch
0c13a6baf7
Update pipe_functions 2018-05-16 12:57:41 -04:00
Mike Koch
5608c32c7e
Update header 2018-05-16 12:57:33 -04:00
Mike Koch
dc8567620b
Update footer 2018-05-16 12:57:23 -04:00
Mike Koch
49eefce540
Update common 2018-05-16 12:57:18 -04:00
Mike Koch
17c5607ce7
Add assignedBy to ticket 2018-05-16 12:57:11 -04:00
Mike Koch
6be05bebfe
Update email_functions 2018-05-16 12:56:55 -04:00
Mike Koch
c92191f396
Update admin_functions 2018-05-16 12:20:37 -04:00
Mike Koch
50ea0aafd6
Remove TODO 2018-05-15 13:03:07 -04:00
Mike Koch
fff00edbef
Update admin_functions -- was actually in common for MFH! 2018-05-15 13:02:53 -04:00
Mike Koch
b5af789662
Update service_messages, hesk_style 2018-05-15 13:02:04 -04:00
Mike Koch
c380ea0bc5
Update password 2018-05-15 13:00:21 -04:00
Mike Koch
05af7b17a5
Update manage_users 2018-05-15 12:58:26 -04:00
Mike Koch
ef4ab7a2ea
Update manage_ticket_templates 2018-05-15 12:54:04 -04:00
Mike Koch
4a65599985
Update manage_knowledgebase 2018-05-15 12:53:33 -04:00
Mike Koch
682e39fe5d
Update manage_categories 2018-05-15 12:50:00 -04:00
Mike Koch
075c8c006d
Update manage_canned 2018-05-15 12:48:03 -04:00
Mike Koch
b215f885a9
Update mail 2018-05-15 12:47:13 -04:00
Mike Koch
53a9860388
Update admin/index 2018-05-15 12:45:23 -04:00
Mike Koch
007fcb5575
Update find_tickets 2018-05-15 12:45:17 -04:00
Mike Koch
d84776d1aa
Update export.php 2018-05-15 12:45:06 -04:00
Mike Koch
5e5a8193e9
export updated.... for the most part 2018-05-15 12:32:40 -04:00
Mike Koch
0823390738
Update manage_email_templates 2018-05-14 19:36:54 -04:00
Mike Koch
be0a8e52ca
Update export 2018-05-14 19:36:47 -04:00
Mike Koch
f102baf753
Update delete_tickets 2018-05-14 19:36:42 -04:00
Mike Koch
035e4f0a79
Update custom_fields 2018-05-14 19:36:37 -04:00
Mike Koch
aa1667261d
Update banned_ips 2018-05-14 19:36:31 -04:00
Mike Koch
f24a80be6a
Update banned_emails 2018-05-14 19:36:26 -04:00
Mike Koch
c03ca62005
Update assign_owner 2018-05-14 19:36:00 -04:00
Mike Koch
2f44516c7b
Update admin_ticket 2018-05-14 19:09:57 -04:00
Mike Koch
52b47075d9
Update admin_submit_ticket 2018-05-14 18:54:50 -04:00
Mike Koch
1325f17bf8
admin_settings(_save) updated 2018-05-14 18:53:44 -04:00
Mike Koch
5150656914
Updated admin_main, updated part of admin_settings 2018-05-14 12:51:37 -04:00
Mike Koch
874cd36bd0 Merge branch '619-create-ticket-api-issues' into '3-4-0'
Resolve "Issue with API submitting New Ticket"

See merge request mike-koch/Mods-for-HESK!98
2018-04-16 16:21:31 +00:00
Mike Koch
aa462d16f8
Fix some API issues' 2018-04-16 12:20:43 -04:00
Mike Koch
4a73524c32 Merge branch '340-post-customer-reply' into '3-4-0'
Add Customer Reply POST API Endpoint

See merge request mike-koch/Mods-for-HESK!97
2018-04-16 16:15:07 +00:00
Mike Koch
e9db9796e3
Default the IP address to the requester's IP address 2018-04-11 12:57:23 -04:00
Mike Koch
90df3de829
Allow sending over http if the magic constant is present 2018-04-11 12:37:51 -04:00
Mike Koch
6fa6c7b686
Add ability to reply via API 2018-04-10 13:11:48 -04:00
Mike Koch
9ae259dff6
Working on reply endpoint. Just need to send out the email. 2018-04-09 13:01:49 -04:00
Mike Koch
669edf832c
Starting to work on reply API endpoint 2018-04-08 22:07:13 -04:00
Mike Koch
d97fe5a81c
Move MFH text to separate files 2018-03-24 22:04:39 -04:00
Mike Koch
e88bb3565d Merge branch 'bug-fixes' into 'master'
3.3.1 Update

See merge request mike-koch/Mods-for-HESK!96
2018-03-23 16:58:24 +00:00
Mike Koch
306c2d370a
Add update migration 2018-03-23 12:52:30 -04:00
Mike Koch
b3245aa38d
Update build 2018-03-23 12:48:55 -04:00
Mike Koch
ed04663d08
Fix changing ticket due date 2018-03-22 22:09:17 -04:00
Mike Koch
352b3a9f37
Fix issue with category auto-assign 2018-03-22 21:54:55 -04:00
Mike Koch
f290fd7519
Update TinyMCE version 2018-03-22 21:44:43 -04:00
Mike Koch
56eeaea61e
Fix non-contentified strings 2018-03-22 21:43:29 -04:00
Mike Koch
34895de5bc
Business hours should be hidden 2018-03-22 21:42:00 -04:00
1017b64913 Pull 3.3.0 from upstream 2018-03-19 21:59:22 -06:00
100c22eb78 CSS adjustments 2018-03-19 21:46:37 -06:00
Mike Koch
62c1661f04
Add missing migration 2018-03-02 19:38:11 -05:00
Mike Koch
d7ae1f0101
Fix migration 2018-03-02 19:12:50 -05:00
Mike Koch
6b0854a273
Fix validator 2018-03-02 18:53:36 -05:00
Mike Koch
3dd897f732
Update build 2018-03-02 12:47:26 -05:00
Mike Koch
e56ef4d608 Merge branch '3-3-0' into 'master'
Mods for HESK 3.3.0 Update

Closes #599

See merge request mike-koch/Mods-for-HESK!95
2018-03-02 17:44:19 +00:00
Mike Koch
37156a8ac7
Add update migration 2018-03-02 12:43:50 -05:00
Mike Koch
7fe96fda96
Update install files 2018-03-02 12:43:33 -05:00
Mike Koch
9d874e10a5 Merge branch 'master' into '3-3-0'
# Conflicts:
#   api/BusinessLogic/Emails/BasicEmailSender.php
#   install/migrations/core.php
2018-03-02 17:41:56 +00:00
Mike Koch
318462164d
Default status translation to english if it doesn't exist 2018-03-02 12:34:11 -05:00
Mike Koch
af5ba09d38
Default to english if status name is not found for the given language 2018-03-02 12:25:37 -05:00
Mike Koch
34b32761ce
Fix tests... again 2018-03-01 20:12:56 -05:00
Mike Koch
7350c5105d
Fix tesets 2018-03-01 20:07:03 -05:00
Mike Koch
fea2d7b3c1 Merge branch 'hesk-2-7-6-update' into '3-3-0'
HESK 2.7.6 Update

See merge request mike-koch/Mods-for-HESK!94
2018-03-02 00:55:08 +00:00
Mike Koch
f11353c41b
CI should use 7.2 for testing, add 7.2 to validation 2018-02-28 21:54:29 -05:00
Mike Koch
8bad3ed188
Update HESK version in install_functions 2018-02-28 21:49:04 -05:00
Mike Koch
f40df54772
Update rest of files to HESK 2.7.6 2018-02-28 21:45:03 -05:00
Mike Koch
155b6c5926
Update a bunch of files for HESK 2.7.6 2018-02-28 21:21:47 -05:00
Mike Koch
559f2d7011 Merge branch '520-email-custom-field' into '3-3-0'
Resolve "cc/bcc Email Custom Fields Not Being Appended To Sent Emails"

See merge request mike-koch/Mods-for-HESK!93
2018-02-20 03:02:35 +00:00
Mike Koch
275a1691d1
cc/bcc fields work properly in api 2018-02-19 22:01:42 -05:00
Mike Koch
81b27ddb2e
Add cc/bcc to rest API, re-enable in email_functions 2018-02-19 13:03:34 -05:00
Mike Koch
904202488d
Add an 'emails to receive' option for email custom fields 2018-02-19 12:40:12 -05:00
Mike Koch
2b089f3907
Minor UI changes 2018-02-11 22:07:12 -05:00
Mike Koch
35ed664dfd
Only allow users to modify permissions that they have access to 2018-02-11 22:00:44 -05:00
Mike Koch
48b28fc3cd
Only modify permissions the user has access to 2018-02-07 22:03:55 -05:00
Mike Koch
4bd4eec53d
Starting on fixing permission group creation/edit abilities 2018-02-06 22:04:16 -05:00
Mike Koch
71bb5af435
Working on permission issues w/permission groups 2018-02-04 22:10:40 -05:00
Mike Koch
ff6ec13df4 Merge branch 'improve-db-validator' into '3-3-0'
Improve db validator

See merge request mike-koch/Mods-for-HESK!91
2018-02-05 02:17:13 +00:00
Mike Koch
22ecc4804e
Improve the validator 2018-02-04 21:16:18 -05:00
Mike Koch
5696968f25
Working on improving the validator 2018-02-03 22:16:00 -05:00
Mike Koch
d383bc0c00
Fix issue where 3.0.0 beta/rc 1 could not update 2018-02-02 22:18:43 -05:00
Mike Koch
90dc2d691a
Deactivated some migrations as they're no longer needed.... might break some new installs 2018-02-02 22:05:23 -05:00
Mike Koch
5865cb722d
Fix custom field description for select fields 2018-02-02 21:57:33 -05:00
Mike Koch
dd0edef2ba
Fixes #599 Only show active users in PMs 2018-02-02 21:28:15 -05:00
Mike Koch
400c216869
Small UI change, change 'Home' to 'Tickets' 2018-02-01 22:02:51 -05:00
Mike Koch
f2001ec446
Add back button to login page 2018-02-01 21:43:01 -05:00
Mike Koch
d2cb5ad251 Merge branch 'attachment-download-size' into '3-3-0'
Show attachment size in attachment info

See merge request mike-koch/Mods-for-HESK!90
2018-02-02 02:29:05 +00:00
Mike Koch
2ffa6c130c
Show attachment size in attachment info 2018-02-01 21:27:34 -05:00
Mike Koch
98a033798f Merge branch 'add-due-date-to-ticket-home' into '3-3-0'
Show due date on ticket home page

See merge request mike-koch/Mods-for-HESK!89
2018-02-02 01:08:58 +00:00
Mike Koch
4e2b21ae60
Show due date on ticket home page 2018-01-31 22:04:11 -05:00
Mike Koch
a57befcc69 Merge branch '608-ticket-rows' into '3-3-0'
Resolve "Add Setting to Highlight Tickets by Priority"

See merge request mike-koch/Mods-for-HESK!88
2018-01-31 18:00:01 +00:00
Mike Koch
c4f080184c
Add setting to highlight all ticket rows based on priority 2018-01-31 12:54:31 -05:00
Mike Koch
1978948f4a Merge branch 'more-cal-improvements' into '3-3-0'
Moar Calendar Improvements

See merge request mike-koch/Mods-for-HESK!87
2018-01-31 03:29:10 +00:00
Mike Koch
af45726fe6
Add ability to hide start time 2018-01-30 22:24:12 -05:00
Mike Koch
df780f4546
Add business-hours API endpoint 2018-01-30 21:24:33 -05:00
Mike Koch
09b371036a
Business hours can be added to the calendar 2018-01-29 22:12:00 -05:00
Mike Koch
7c884582a2
Working on adding business hours to the calendar 2018-01-28 22:05:09 -05:00
Mike Koch
cfabdb950d Merge branch '357-calendar-planning-phase-two' into '3-3-0'
Resolve "Calendar Planning, Phase Two"

See merge request mike-koch/Mods-for-HESK!86
2018-01-29 01:50:21 +00:00
Mike Koch
f53065f7f6 Merge branch '3-3-0' into '357-calendar-planning-phase-two'
# Conflicts:
#   api/BusinessLogic/Security/UserContext.php
#   api/BusinessLogic/Security/UserPrivilege.php
#   api/index.php
#   language/en/text.php
2018-01-29 01:46:16 +00:00
Mike Koch
624267fe45
Audit trail now displays for users who can manage calendar 2018-01-25 22:07:28 -05:00
Mike Koch
401e335e5f
Adding history to modal 2018-01-24 22:00:10 -05:00
Mike Koch
ad63bcac02
Fixed a couple issues with the audit trail changes 2018-01-24 13:01:23 -05:00
Mike Koch
1a66485d48
Working on adding audit trail to events 2018-01-23 22:14:25 -05:00
Mike Koch
770a01a970
Add status to ticket popover on calendar 2018-01-21 22:03:54 -05:00
Mike Koch
78cb2de9b6
Going to use rrule.js instead 2018-01-19 22:17:15 -05:00
Mike Koch
4959ccb815
Add php-rrule for recurring event parsing 2018-01-18 22:02:48 -05:00
Mike Koch
4c2432a35b
Moved all calendar API logic to the api folder 2018-01-09 12:37:29 -05:00
Mike Koch
3d73b9a4b2
All main staff calendar endpoints moved 2018-01-07 22:02:43 -05:00
Mike Koch
c4b79a722c
More calendar tweaks 2018-01-03 13:04:23 -05:00
Mike Koch
0514965040
Update due date mostly done... just need to fix the buildEvent function 2018-01-02 13:05:10 -05:00
Mike Koch
bd5b3e1322
Working on moving the update ticket due date endpoint 2018-01-01 21:39:01 -05:00
Mike Koch
86f1fb3ca2
Slowly working on moving more API endpoints 2017-12-27 22:00:30 -05:00
Mike Koch
c805fd8eab
Working on new update event endpoint 2017-12-23 22:04:52 -05:00
Mike Koch
9eab1525ef
Getting started on moving the update event endpoint 2017-12-21 22:10:45 -05:00
Mike Koch
814523ba6e
getEventsForStaff endpoint appears to be working 2017-12-17 22:05:32 -05:00
Mike Koch
13161696ae
Working on refactoring the calendar API 2017-12-10 22:01:18 -05:00
Mike Koch
354bb91234 Merge branch '3-2-5' into 'master'
3.2.5

See merge request mike-koch/Mods-for-HESK!85
2017-12-07 02:44:58 +00:00
Mike Koch
05b913c53a
Fix issue in PHP 5.3 2017-12-06 21:39:08 -05:00
Mike Koch
5ee4ed5864
revert meeee 2017-12-06 21:37:42 -05:00
Mike Koch
d4b3c9acc9
Update build 2017-12-06 12:53:55 -05:00
Mike Koch
95342815e2
Update installer 2017-12-06 12:52:02 -05:00
Mike Koch
f35fb7b207 Merge branch 'fix-headers' into '3-2-5'
Fix headers

See merge request mike-koch/Mods-for-HESK!84
2017-12-06 17:48:47 +00:00
Mike Koch
6177bc1794 Merge branch '595-fix-basic-email-sender' into '3-2-5'
Fix BasicEmailSender

See merge request mike-koch/Mods-for-HESK!83
2017-12-06 17:48:34 +00:00
Mike Koch
878b2aa096
Fix headers 2017-12-06 12:45:44 -05:00
Mike Koch
8ee6e1a55f
Can't concatenate an array to a string 2017-12-06 12:18:17 -05:00
Mike Koch
d2ee60e053 Merge branch '301-service-messages' into '3-3-0'
Service Messages Improvements

See merge request mike-koch/Mods-for-HESK!82
2017-12-04 18:07:26 +00:00
Mike Koch
39e61b85c4
Fixed some issues with the service messages endpoints: 2017-12-04 12:56:09 -05:00
Mike Koch
0a2e37320a
Working on adding controller security 2017-12-01 12:56:23 -05:00
Mike Koch
f70c3635a9
Working on moving the calendar API 2017-11-29 21:58:30 -05:00
Mike Koch
8050e10c30
Merge remote-tracking branch 'origin/master' into 357-calendar-planning-phase-two 2017-11-29 21:30:04 -05:00
Mike Koch
3e8085110f
Service messages now appear in their proper locations 2017-11-28 13:03:06 -05:00
Mike Koch
2faac6be1a
Fixed type not being stored, working on display locations 2017-11-27 13:00:35 -05:00
Mike Koch
902f3edcf6
Only show locations that are active 2017-11-27 12:51:34 -05:00
Mike Koch
3bff7fd30b
Contentified some strings 2017-11-27 12:22:41 -05:00
Mike Koch
665db7a4d8
Merge branch 'master' into 301-service-messages 2017-11-27 12:09:03 -05:00
Mike Koch
a7546419a4
Update version number 2017-11-25 21:53:47 -05:00
Mike Koch
8d30a041fe Merge branch 'hesk-2-7-4' into 'master'
HESK 2.7.5

See merge request mike-koch/Mods-for-HESK!81
2017-11-26 02:47:49 +00:00
Mike Koch
dd99ebdb0e
Fix input-group-addon CSS issue 2017-11-25 21:46:19 -05:00
Mike Koch
03e7f62684
Change verbiage 2017-11-25 21:42:23 -05:00
Mike Koch
d092a49bab
Fix sorting of ticket events 2017-11-25 21:40:27 -05:00
Mike Koch
2390af6393
Update HESK verison to 2.7.5 2017-11-25 21:14:15 -05:00
Mike Koch
8b263f66a3
Fix some email sending, updat edit_post maxlengths 2017-11-21 12:58:04 -05:00
Mike Koch
3203eed8aa
Use NOW() for reply dates 2017-11-21 12:29:54 -05:00
Mike Koch
a7742614df
Update pages for HESK 2.7.4 2017-11-20 22:16:46 -05:00
Mike Koch
15b971412b Merge branch '3-2-3' into 'master'
3.2.3

See merge request mike-koch/Mods-for-HESK!80
2017-11-20 17:38:11 +00:00
Mike Koch
f8ab89946d
Update version 2017-11-20 12:37:48 -05:00
Mike Koch
70435cee62
Fix storing dates when format is not MySQL-friendly 2017-11-20 12:36:04 -05:00
Mike Koch
fefe1e23a4 Merge branch 'patch-1' into '3-2-3'
Fix usage of CC and BCC fields in mail header.

See merge request mike-koch/Mods-for-HESK!78
2017-11-20 12:57:53 +00:00
Mike Koch
477d55d8bf Merge branch '591-edit-and-delete-replies' into '3-2-3'
Fix edit/delete reply buttons

See merge request mike-koch/Mods-for-HESK!79
2017-11-20 12:48:40 +00:00
Mike Koch
eac23907e7
Fix edit/delete reply buttons 2017-11-20 07:46:07 -05:00
Jozef
eeb5ada610 Fix usage of CC and BCC fields in mail header. 2017-11-20 11:00:25 +00:00
Mike Koch
36295d1861
Add language property to service messages 2017-11-19 22:16:45 -05:00
Mike Koch
3e82065fa4
Working on adding a language option to service messages 2017-11-18 22:05:11 -05:00
Mike Koch
6a763593ee
Locations can be added to service messages 2017-11-17 22:27:55 -05:00
Mike Koch
d04b40c925
Start working on adding locations to service messages 2017-11-15 22:02:55 -05:00
Mike Koch
f5ff322c33
Remove sweetalert, use a tooltip instead 2017-11-15 21:27:45 -05:00
Mike Koch
ac5f9309c8
Starting to introduce sweetalert 2017-11-15 13:05:41 -05:00
Mike Koch
79e34ce8cc
Service messages now use the API 2017-11-15 12:55:16 -05:00
Mike Koch
3e7f000630
All operations except for preview are working 2017-11-14 13:04:20 -05:00
Mike Koch
d897fa2a4b
More progress' 2017-11-13 22:13:55 -05:00
Mike Koch
a8abfcd4a1
More progress on service messages 2017-11-13 13:07:19 -05:00
Mike Koch
c00d5641e4
Service messages page can now retrieve service messages via AJAX 2017-11-12 22:22:28 -05:00
Mike Koch
6bef518ffa
Add more endpoints for service messages 2017-11-11 22:16:25 -05:00
Mike Koch
311a48487d
Add POST service-messages endpoint 2017-11-11 16:33:43 -05:00
Mike Koch
d305ccf9b3
Add POST endpoint for creating service messages 2017-11-09 22:02:26 -05:00
Mike Koch
c985f80452
Working on moving service messages to an API endpoint 2017-11-09 13:04:10 -05:00
Mike Koch
fd4732d978
Add helper method for boolval 2017-11-08 21:36:46 -05:00
Mike Koch
945e548ef7
Revert to an older mailgun PHP library 2017-11-08 21:12:05 -05:00
Mike Koch
18128ff263
Update mailgun-php 2017-11-08 20:48:05 -05:00
Mike Koch
70793cdfae
Update installer 2017-11-07 21:58:44 -05:00
Mike Koch
30dcb113ae
Modify link to handle servers with odd configurations 2017-11-07 21:48:38 -05:00
Mike Koch
443d4ac1f3
Update some composer dependencies 2017-11-07 09:26:16 -05:00
Mike Koch
88964a73eb
Only skip phpunit for now 2017-11-06 12:38:48 -05:00
Mike Koch
fcaee13ba3
Add missing CSS, update installer 2017-11-05 20:32:25 -05:00
Mike Koch
fab521ff7c Merge branch 'patch-1' into 'master'
Fixed calendar problem (not showing)

See merge request mike-koch/Mods-for-HESK!76
2017-11-06 01:24:59 +00:00
Mike Koch
7c139a8d0c Merge branch 'fix-customer-calendar' into 'master'
Fix customer calendar

See merge request mike-koch/Mods-for-HESK!77
2017-11-06 01:19:40 +00:00
Mike Koch
5d8fa97aa2
update build # 2017-11-05 17:33:19 -05:00
Mike Koch
f3c0c191db
Add bootstrap-select to header 2017-11-05 17:33:02 -05:00
Jan Teunis
046636c40a Fixed calendar problem (not showing)
Added bootstrap-select.js and cleaned up tabs
2017-11-05 22:25:37 +00:00
Mike Koch
c241338fbe
Couple small QoL changes 2017-11-05 12:00:41 -05:00
Mike Koch
d62370b069
Revert "Modify build config"
This reverts commit 05617a3b56a905ceea16713d6cc5eb489631b325.
2017-11-04 22:17:47 -04:00
Mike Koch
ca728839ac Merge branch '3-2-0' into 'master'
3.2.0 Update

See merge request mike-koch/Mods-for-HESK!75
2017-11-05 01:51:11 +00:00
Mike Koch
05617a3b56
Modify build config 2017-11-03 21:50:09 -04:00
Mike Koch
b77e2e6459
Merge branch '417-installer-improvements' into 3-2-0 2017-11-03 21:45:05 -04:00
Mike Koch
2d9c383ddd
Remove some unneeded logs 2017-11-03 21:44:06 -04:00
Mike Koch
59fa5c2698 Merge branch '417-installer-improvements' into '3-2-0'
New Installer

See merge request mike-koch/Mods-for-HESK!73
2017-11-04 01:43:24 +00:00
Mike Koch
308f7431e7
Fixing some down migrations 2017-11-01 22:01:28 -04:00
Mike Koch
86a76fc460
Fix one of the migrations 2017-11-01 21:55:35 -04:00
Mike Koch
4e6bbdfed6
Fix migrations 2017-11-01 21:52:17 -04:00
Mike Koch
61fcfc83b0
Value is a string 2017-11-01 12:55:44 -04:00
Mike Koch
f41fe487fa
Finished converting migrations. Need to test. 2017-11-01 12:52:47 -04:00
Mike Koch
9b7af18f6a
Some more changes 2017-11-01 12:29:51 -04:00
Mike Koch
f6df4fda7e
Finished up 3.0.0 refactoring 2017-10-31 17:31:03 -04:00
Mike Koch
17d5d9efcf Merge branch '3-2-0' into '3-2-0'
Entered correct update url on the admin settings page

See merge request mike-koch/Mods-for-HESK!74
2017-10-31 12:14:55 +00:00
Mike Koch
fed59f988f
Refactored some more migrations 2017-10-31 08:11:37 -04:00
Mike Koch
62d9f31d14
Some more changes 2017-10-30 22:02:28 -04:00
Justin
1862b6beb3 Entered correct update url on admin settings 2017-10-30 18:05:57 +01:00
Mike Koch
311697693f
Splitting up migrations.... partway done 2017-10-30 13:02:36 -04:00
Mike Koch
bc752ff2c3
Don't show anonymous usage checkbox for now
Not ready to go yet
2017-10-27 12:54:14 -04:00
Mike Koch
02492dac52
Add a HESK version mismatch check 2017-10-27 12:40:11 -04:00
Mike Koch
647955fdf0
Delete unused files 2017-10-27 12:26:47 -04:00
Mike Koch
78ae5cebff
Switch from dev to stable 2017-10-25 21:50:55 -04:00
Mike Koch
a01efb8f92
Trying to fix doctrine/annotations 2017-10-25 21:48:03 -04:00
Mike Koch
3fde3df882
Remove caching implementation 2017-10-25 12:42:50 -04:00
Mike Koch
f2cfe967ee
Some minor changes 2017-10-21 13:39:17 -04:00
Mike Koch
9839e8916e
small change 2017-10-20 22:17:56 -04:00
Mike Koch
109a4fa25f
Uninstaller works 2017-10-20 13:07:01 -04:00
Mike Koch
e98213ad4c
Uninstaller seems to be working... I think :P 2017-10-19 22:07:46 -04:00
Mike Koch
7aa7526a17
Working on the uninstaller 2017-10-18 22:00:00 -04:00
Mike Koch
60ac53fe94
Change key 2017-10-18 13:03:11 -04:00
Mike Koch
0df87dde57
Fix some migrations, add new ones to keep track of migration number 2017-10-18 13:02:48 -04:00
Mike Koch
8b7f0ace3a
Fixed error logger 2017-10-17 21:48:58 -04:00
Mike Koch
d35cf4d358
Fix some migrations 2017-10-16 22:02:04 -04:00
Mike Koch
cae76032d1
I *think* the rollback feature is working? 2017-10-16 20:39:16 -04:00
Mike Koch
f5907bf476
Some changes 2017-10-16 13:08:53 -04:00
Mike Koch
78559de051
Trying to get downgrades working properly 2017-10-15 21:23:56 -04:00
Mike Koch
d19c53e99a
Fixed some installer issues... migration 24 looks broken though 2017-10-13 22:10:44 -04:00
Mike Koch
537cbe92f3
Fix .gitlab-ci.yml 2017-10-13 13:02:25 -04:00
Mike Koch
5235461791
Re-enable the migrations 2017-10-12 22:13:18 -04:00
Mike Koch
97e4f4ae4f
Overall UX/UI complete. Need to test the actual migrations 2017-10-12 22:11:51 -04:00
Mike Koch
d007792f3a
Remove var_dump 2017-10-12 13:10:01 -04:00
Mike Koch
cdd4c83e4f
Add a new step for complete 2017-10-12 13:07:50 -04:00
Mike Koch
0cd0337a39
Added initial migration numbers, fixed some UI issues 2017-10-12 13:04:59 -04:00
Mike Koch
72428be04b
Debugging some stuff 2017-10-11 22:00:53 -04:00
Mike Koch
e3cfdda60b
Modified the installer a little bit 2017-10-10 22:00:40 -04:00
Mike Koch
219bc18cc6
Still need to test this.... 2017-10-04 22:03:39 -04:00
Mike Koch
62c059b384
Finished rewriting all of the migrations 2017-10-04 13:07:12 -04:00
Mike Koch
2c8a4ad86e
Migrated some more SQL changes 2017-10-03 22:05:35 -04:00
Mike Koch
d29ec0374e
Transferred some more migrations 2017-10-03 13:17:12 -04:00
Mike Koch
c99f75c908
Converted several other migrations 2017-10-02 22:02:26 -04:00
Mike Koch
f54c9bbd03
More migrations 2017-10-02 08:09:22 -04:00
Mike Koch
92713506e6
Working on creating the migrations 2017-10-01 22:03:09 -04:00
Mike Koch
6ea38bc90b
Got the basic migration framework working 2017-09-29 13:07:11 -04:00
Mike Koch
dbf9baca75
Getting started on the AJAX portion 2017-09-29 08:13:24 -04:00
Mike Koch
5aeb90852b
Add progress bar for installer...still need to write the actual migrations 2017-09-28 13:04:22 -04:00
Mike Koch
8b0fe2cdaf
Start at -1 as the last installed migration # for new installs 2017-09-28 08:18:42 -04:00
Mike Koch
8aac741b6f
Added logic to get the starting migration number 2017-09-28 08:17:45 -04:00
Mike Koch
43264318c4
Some progress 2017-09-27 22:01:34 -04:00
Mike Koch
23fc8ef6d5
Landing page looks good, moved database-validation 2017-09-27 13:00:20 -04:00
Mike Koch
69f2cf4b4c
Working on an updated installer 2017-09-26 22:08:14 -04:00
Mike Koch
e56943d659 Merge branch '200-new-audit-trail' into '3-2-0'
Resolve "Move Audit Trail to separate table"

See merge request mike-koch/Mods-for-HESK!72
2017-09-27 01:25:42 +00:00
Mike Koch
3485a5b7db
Fix tests 2017-09-26 21:19:17 -04:00
Mike Koch
60decb3cfa
Fixed ticket creation stuff 2017-09-26 13:08:17 -04:00
Mike Koch
7e6a5b2ba5
Working on audit for API, trying to fix email issues 2017-09-25 21:50:11 -04:00
Mike Koch
c6f4e4ce3e
New audit trail records are returned in the API response 2017-09-25 08:14:12 -04:00
Mike Koch
0670d74c1e
Pretty much wrapped up with the new ticket history 2017-09-24 22:07:49 -04:00
Mike Koch
44ab918292
Make sure ticket is updated before adding audit record to make sure it appears in the right order 2017-09-23 22:02:29 -04:00
Mike Koch
0ac67766ee
New audit trail now appears on the ticket page 2017-09-22 22:24:27 -04:00
Mike Koch
953747d90d
Update composer lockfile 2017-09-22 18:29:14 -04:00
Mike Koch
62bda38b91
Slowly started on displaying the new audit trail 2017-09-22 13:07:35 -04:00
Mike Koch
db99d2219e
Updated the rest of the audit trails 2017-09-22 12:50:04 -04:00
Mike Koch
939f470666
Updated some more audit trails 2017-09-22 08:08:16 -04:00
Mike Koch
05ede52ce5
Add priority.php 2017-09-22 08:02:43 -04:00
Mike Koch
d5589cc1c2
Some more audit trail fixes 2017-09-22 08:01:53 -04:00
Mike Koch
4ac430bc19
Replace several audit trail spots 2017-09-21 22:12:55 -04:00
Mike Koch
b95876e6a1
Add new audit trail entries for admin_reply_ticket 2017-09-20 08:10:51 -04:00
Mike Koch
35f03ee26e
Getting started with new audit trail entries 2017-09-19 22:03:39 -04:00
Mike Koch
7b8ae3a1d8
The audit table should support multiple types 2017-09-19 17:21:07 -04:00
Mike Koch
ca3bfcde1c
Add missing column 2017-09-19 12:56:27 -04:00
Mike Koch
523fe43b91
Create new tables, add new language strings 2017-09-19 12:49:00 -04:00
Mike Koch
764fefb25a Merge branch '510-custom-field-descriptions' into '3-2-0'
Resolve "Add function to add custom description or explanation of the custom fields for customers."

See merge request mike-koch/Mods-for-HESK!71
2017-09-19 16:28:18 +00:00
Mike Koch
9ed88a1e02
Updated priority colors on customer side 2017-09-19 12:27:32 -04:00
Mike Koch
46721d4212
Add custom field descriptions to customer submit ticket 2017-09-19 12:22:42 -04:00
Mike Koch
111dbb30b9
Add custom field descriptions to edit post 2017-09-19 12:17:33 -04:00
Mike Koch
d01135ac1b
Add custom field descriptions to admin create ticket page 2017-09-19 12:15:38 -04:00
Mike Koch
d06e80056a
Clear descriptions when deleting custom field 2017-09-19 08:05:16 -04:00
Mike Koch
ce8ff6efe5
Custom field descriptions can be saved 2017-09-19 08:04:23 -04:00
Mike Koch
745ecd42aa
Getting started adding custom field descriptions 2017-09-18 22:04:50 -04:00
Mike Koch
fedb26fd43 Merge branch 'bring-back-managers' into '3-2-0'
Bring back managers

See merge request mike-koch/Mods-for-HESK!70
2017-09-19 01:18:22 +00:00
Mike Koch
6d632be7b8
Managers are back in action 2017-09-18 21:13:48 -04:00
Mike Koch
79f41a7652
Permission groups seem to be good to go? 2017-09-18 13:04:26 -04:00
Mike Koch
056b02522e
Working on permission template -> group conversion 2017-09-17 22:07:01 -04:00
Mike Koch
4d9eeeb1d0
More manager stuff 2017-09-14 22:00:57 -04:00
Mike Koch
477b780805
Re-added all manager-related code 2017-09-13 21:27:02 -04:00
Mike Koch
a3709c187b Merge branch '354-priority-tweaks' into '3-2-0'
Resolve "Ticket Priority Improvements"

See merge request !69
2017-09-13 13:56:02 +00:00
Mike Koch
3c0148ddc2
Add bootstrap-select to all dropdowns in green, change background on ticket list 2017-09-12 22:04:10 -04:00
Mike Koch
8de106cbb2
Starting to use bootstrap-select on admin_ticket to improve dropdowns 2017-09-12 13:02:58 -04:00
Mike Koch
9ae189430d
Localize calendar pages 2017-09-12 12:32:30 -04:00
Mike Koch
ea0a612e4f
Trying to fix the PHP linter 2017-09-11 21:34:16 -04:00
Mike Koch
41cbdadb72
More PHP 5.4/5.3 fixes 2017-09-11 21:17:34 -04:00
Mike Koch
016a50878d
Add a BaseClass/BaseException for 5.4 compatibility 2017-09-11 21:03:03 -04:00
Mike Koch
3c4018ace3
Add validation steps for PHP 5.4 and 5.3 2017-09-11 12:56:18 -04:00
Mike Koch
37d730dfdc
Fix a syntax error in PHP 5.5 2017-09-11 12:55:56 -04:00
Mike Koch
0f902f683c
More CI fixes 2017-09-11 12:48:34 -04:00
Mike Koch
02ccb65b27
More changes 2017-09-11 12:46:26 -04:00
Mike Koch
3b0c8ad3a6
More CI changes 2017-09-11 12:43:20 -04:00
Mike Koch
560197eebe
Testing some gitlab ci changes 2017-09-11 12:35:59 -04:00
Mike Koch
0dcac4f324 Merge branch '457-category-descriptions' into '3-2-0'
Add Description to Categories

See merge request !68
2017-09-11 02:07:25 +00:00
Mike Koch
3ed01ba92f
Fix tests 2017-09-10 21:44:49 -04:00
Mike Koch
dd699b7165
Try fixing .gitlabci.yml 2017-09-09 22:06:47 -04:00
Mike Koch
5b7c2f7ec7
Remove all manager usages 2017-09-09 22:03:42 -04:00
Mike Koch
c8e2128c4c
Switch to mike-koch/PHP-DI 2017-09-09 21:29:40 -04:00
Mike Koch
be42fe04fb
Use a proper DI system 2017-09-09 21:24:05 -04:00
Mike Koch
7ca00fecbe
Add strongly typed constructor args on BusinessLogic layer 2017-09-07 20:31:57 -04:00
Mike Koch
f700addda5
Update composer for php-di 2017-09-06 12:56:44 -04:00
Mike Koch
5caac8452e
Don't allow category 1 to be deleted 2017-09-06 07:54:33 -04:00
Mike Koch
02d965e2d9
Localized some stuff, add descriptions to create ticket pages 2017-09-05 22:20:57 -04:00
Mike Koch
45726bd388
Categories can be sorted 2017-09-05 13:06:56 -04:00
Mike Koch
25fde2aa65
Add description 2017-09-01 22:20:12 -04:00
Mike Koch
29f1eb3503
Fixed up editing/creating 2017-09-01 22:08:40 -04:00
Mike Koch
2238a52c40
Add generate link modal 2017-09-01 21:54:37 -04:00
Mike Koch
499b604cc3
Some more changes 2017-08-31 22:09:56 -04:00
Mike Koch
8a2c03a587
Make visibility a column 2017-08-31 13:02:30 -04:00
Mike Koch
24cdb08449
Categories can be created, modify modal 2017-08-30 22:03:51 -04:00
Mike Koch
f7272e8549
Categories can now be edited via the page 2017-08-29 22:19:17 -04:00
Mike Koch
136ca3f206
Fix banned icon for private categories 2017-08-25 18:01:48 -04:00
Mike Koch
a1a870ed34
Adding some more JS goodness. Still need to include autoassign/type into the modal 2017-08-24 22:06:48 -04:00
Mike Koch
aa307e6b15 Some more category changes 2017-08-23 22:00:30 -04:00
Mike Koch
60301f4aab Hide the up arrow for the top-most element 2017-08-22 22:06:42 -04:00
Mike Koch
7fb7a8bec4 Table being loaded. Need to handle proper name display though 2017-08-22 22:03:11 -04:00
Mike Koch
38cea82821 More work on manage categories page 2017-08-21 22:11:30 -04:00
Mike Koch
d76cc27e8e Add number of tickets to category 2017-08-21 21:25:54 -04:00
Mike Koch
c86788e7fd Getting started on manage categories page changes, fixed API config issue 2017-08-21 13:01:39 -04:00
Mike Koch
9582689f2a Categories can be deleted, fixed request methods 2017-08-21 12:54:31 -04:00
Mike Koch
dd690decb2 Editing categories possible, add security check 2017-08-20 21:53:02 -04:00
Mike Koch
7d2479d5b6 Categories can be created 2017-08-20 15:47:30 -04:00
Mike Koch
8f52400aea Change column name 2017-08-20 11:47:35 -04:00
Mike Koch
1185785dbd Should be able to create categories now... 2017-08-18 08:15:50 -04:00
Mike Koch
f7d03f66cd Making more progress on category API endpoint 2017-08-17 22:03:33 -04:00
Mike Koch
05f79ecfa9 Merge remote-tracking branch 'origin/master' into 457-category-descriptions 2017-08-14 21:06:06 -04:00
Mike Koch
b6ab6a806e Fix demo mode for API 2017-08-13 20:55:05 -04:00
Mike Koch
3ec2419086 Fix API URL 2017-08-13 20:43:33 -04:00
Mike Koch
6b5a55226b Update build number 2017-08-13 13:56:43 -04:00
Mike Koch
7aae9c62af Merge branch '3-1-1' into 'master'
3.1.1

See merge request !65
2017-08-13 17:43:22 +00:00
Mike Koch
260600a7f6 Will this work? 2017-08-13 13:40:29 -04:00
Mike Koch
326ccaa6be Sometimes a weird commit fixes the CI build 2017-08-13 13:40:18 -04:00
Mike Koch
c60d2ed866 Update installer 2017-08-12 21:57:41 -04:00
Mike Koch
9bffcfdf6a Merge branch '577-ie-fix' into '3-1-1'
Fix document type on IE intranet pages

See merge request !67
2017-08-13 01:43:59 +00:00
Mike Koch
65576d5c43 Fix document type on IE intranet pages 2017-08-12 21:41:41 -04:00
Mike Koch
efbf38ca33 Merge branch '575-update-checking' into '3-1-1'
Version checks are now asynchronous

See merge request !66
2017-08-11 01:54:33 +00:00
Mike Koch
73b3a01bc0 Version checks are now asynchronous 2017-08-10 21:51:59 -04:00
Mike Koch
84f491bd40 Don't fail resending email when there is no owner 2017-07-30 15:05:53 -04:00
Mike Koch
ed6df71041 Merge branch '572-fix-autotls-issue' into '3-1-1'
Disable AutoTLS for PHPMailer

See merge request !64
2017-07-30 18:54:00 +00:00
Mike Koch
4db151de66 Disable AutoTLS for PHPMailer 2017-07-30 14:52:03 -04:00
f209266260 Enable Summernote for ticket replies 2017-07-29 20:14:53 -06:00
932056f731 Change Forgot Ticket ID UI to a Bootstrap panel 2017-07-29 20:09:42 -06:00
4178703f2b Merge branch 'captcheck' of Netsyms/Mods-for-HESK-Netsyms into master 2017-07-29 20:01:32 -06:00
7cc69878ca Make ticket submit success message into a Bootstrap panel 2017-07-29 20:00:37 -06:00
Mike Koch
68308b02a5 Some sort of progress on category endpoint 2017-07-29 21:57:29 -04:00
297d7f3cfd Add captcheck captcha option 2017-07-29 19:54:47 -06:00
Mike Koch
37bd252041 Merge branch 'bootstrap-theme-disable-fix' into '3-1-1'
Fix bootstrap-theme not disabling on Firefox

See merge request !63
2017-07-30 01:44:12 +00:00
5de09b851b Merge branch 'bootswatch' of Netsyms/Mods-for-HESK-Netsyms into master 2017-07-29 19:24:29 -06:00
daf748b173 Fix stupid mistake 2017-07-29 19:23:50 -06:00
e91f6842ab Swap == for != 2017-07-30 01:21:26 +00:00
d5a9d225f2 Fix bootstrap-theme not disabling on Firefox 2017-07-30 01:15:27 +00:00
c994b0099e Merge branch 'bootswatch' of Netsyms/Mods-for-HESK-Netsyms into master 2017-07-29 19:06:55 -06:00
932ebd1821 Fix typo 2017-07-29 19:05:11 -06:00
a5ae672b9f Add Bootswatch theme picker, Fix bug where the bootstrap theme can't be disabled 2017-07-29 19:00:33 -06:00
234d28a8b8 Merge branch 'summernote' of Netsyms/Mods-for-HESK-Netsyms into master 2017-07-29 18:04:40 -06:00
4baa85a8c5 Replace TinyMCE with Summernote, round 1 2017-07-29 17:45:49 -06:00
4351cf46b7 Add 'js/summernote.js' 2017-07-29 17:00:45 -06:00
d520df6886 Add 'css/summernote.css' 2017-07-29 16:59:10 -06:00
19d5ab9f06 Replace TinyMCE loader code with Summernote 2017-07-29 16:56:53 -06:00
Mike Koch
e8c029186e Don't allow non-GET requests in demo mode 2017-06-28 13:07:10 -04:00
Mike Koch
991c5cb87c Make phpunit a dev dependency 2017-06-27 21:06:17 -04:00
Mike Koch
454013fd98 Use X-HTTP-Method-Override for all MfH pages 2017-06-27 21:02:38 -04:00
Mike Koch
3aea482c3c Add support for X-HTTP-Method-Override header 2017-06-27 08:08:40 -04:00
Mike Koch
a4836f1142 Fixing inline attachments 2017-06-26 12:48:11 -04:00
Mike Koch
1ed740b7fa Update .gitlab-ci.yml 2017-06-26 12:17:57 +00:00
Mike Koch
40724c3503 Fix API paths for manage custom nav elements 2017-06-26 07:52:36 -04:00
Mike Koch
7fe647c3ab Internal API can't be disabled 2017-06-26 07:51:07 -04:00
Mike Koch
81a5b6633c Can't name version number dynamically 2017-06-25 22:07:40 -04:00
Mike Koch
a2b44cd288 Change the name of the zip 2017-06-25 21:13:31 -04:00
Mike Koch
7213f77254 Try setting the variable 2017-06-25 21:03:12 -04:00
Mike Koch
46b3a54369 Run phpunit in the right directory 2017-06-25 20:14:05 -04:00
Mike Koch
277c1b5359 Fix config 2017-06-25 17:00:21 -04:00
Mike Koch
a49c156007 Fix up the build steps 2017-06-25 16:58:40 -04:00
Mike Koch
a559ee24df Make before_script global 2017-06-25 16:52:21 -04:00
Mike Koch
65a9353c93 Fix stages? 2017-06-25 16:50:02 -04:00
Mike Koch
9b4929a4c7 Fixing things? 2017-06-25 16:48:35 -04:00
Mike Koch
543d07cfaf Try renaming the steps 2017-06-25 16:46:39 -04:00
Mike Koch
be903af3a4 Trying to figure out how to build a proper pipeline graph 2017-06-25 16:45:30 -04:00
Mike Koch
abf632b3da Add a deploy step and see if it can see what the test step does 2017-06-25 16:42:49 -04:00
Mike Koch
db204335e6 Can I rename this? 2017-06-25 16:40:59 -04:00
Mike Koch
8997c258a6 Commit. 2017-06-25 16:36:41 -04:00
Mike Koch
bd73cc2f7c Commit. 2017-06-25 16:35:13 -04:00
Mike Koch
5969deb49c Again. 2017-06-25 16:33:22 -04:00
Mike Koch
60c824a7c2 Third try 2017-06-25 16:28:56 -04:00
Mike Koch
663caccf7a Fix image name 2017-06-25 16:27:37 -04:00
Mike Koch
2b4d50d469 Try using a composer image 2017-06-25 16:26:54 -04:00
Mike Koch
7f73a9c61b Remove wget install 2017-06-25 16:24:44 -04:00
Mike Koch
c79e019594 Trying things 2017-06-25 16:23:47 -04:00
Mike Koch
4b21758506 Looks like wget needs to be installed manually 2017-06-25 16:16:47 -04:00
Mike Koch
5a908d6b61 Try building a zip of the release 2017-06-25 16:10:09 -04:00
Mike Koch
cc900a16da Make it var_dump 2017-06-24 22:15:25 -04:00
Mike Koch
033a23eaca Trying to get started on gitlab ci 2017-06-24 22:13:00 -04:00
Mike Koch
bfb8956df2 Update gitlab-ci.yml 2017-06-24 21:49:32 -04:00
Mike Koch
603d68a7b3 Trying to see how artifacts work 2017-06-24 21:46:41 -04:00
Mike Koch
3ca6b1a435 Add a URL rewrite setting for the API. Not using it in code yet... might not even do that lol 2017-06-24 16:04:19 -04:00
Mike Koch
a47773cf98 Testing manual execution 2017-06-23 18:38:57 +00:00
Mike Koch
ef34c5bcb1 Skip the weird failing test 2017-06-22 22:13:41 -04:00
Mike Koch
97d8f0df2e Fix tests... again 2017-06-22 22:09:14 -04:00
Mike Koch
7300b5bd5f Fix tests, remove ls from ci config 2017-06-22 22:06:00 -04:00
Mike Koch
2efa603474 Fix phpunit.xml 2017-06-22 21:57:05 -04:00
Mike Koch
8cdc01f3cb Fix phpunit.xml 2017-06-22 21:55:18 -04:00
Mike Koch
634f8b3aca Update PHPUnit XML 2017-06-22 21:52:15 -04:00
Mike Koch
c52bd054d6 more debugging 2017-06-22 21:48:22 -04:00
Mike Koch
28027ae58b More changes 2017-06-22 21:46:46 -04:00
Mike Koch
0c7856b388 Trying to get CI tests to run 2017-06-22 21:45:01 -04:00
Mike Koch
99ad9ecd63 Add .gitlab-ci.yml 2017-06-22 21:37:56 -04:00
Mike Koch
535e48225d Merge branch '3-1-0' into 'master'
3.1.0 Update

Closes #535, #428, #397, #565, #549, #561, #562, #560, #531, #395, #405, #456, #353, #551, #559, #557, #556, #524, #523, #527, #528, #525, #339, and #522

See merge request !62
2017-06-23 01:24:26 +00:00
Mike Koch
ef481b3192 Fixed some JS files 2017-06-22 21:21:38 -04:00
Mike Koch
77c5c3d872 Fix nav element API path 2017-06-22 12:53:08 -04:00
Mike Koch
65110bd1b4 Update database-validation.php 2017-06-22 12:04:29 +00:00
Mike Koch
1234f858e5 Update build.php 2017-06-22 12:04:12 +00:00
Mike Koch
0caf4e740e Fix color issues on calendar page 2017-06-21 22:07:21 -04:00
Mike Koch
a219883117 Fix colors on new category panel 2017-06-21 21:56:02 -04:00
Mike Koch
9a5738eb1c Use relative URLs for attachment handling 2017-06-20 22:00:54 -04:00
Mike Koch
4a49c8c510 Make all AJAX calls relative 2017-06-20 08:04:07 -04:00
Mike Koch
13d7b70ac5 Fix regex, query order, and black preset text colors 2017-06-19 22:13:34 -04:00
Mike Koch
f9b09fbde6 Only get custom nav elements if not in maint mode and the table exists 2017-06-19 20:47:00 -04:00
Mike Koch
f5933e8bfa update installer, fix colorpicker presets 2017-06-18 22:03:35 -04:00
Mike Koch
c39e4462e8 Add nav element for API settings 2017-06-18 21:31:48 -04:00
Mike Koch
f6283a4c13 Fix the API settings page, update validator, fix sidebar text hover 2017-06-18 21:21:26 -04:00
Mike Koch
34358be637 Add dirty forms check on add reply form 2017-06-17 22:02:03 -04:00
Mike Koch
45c1291711 More color changes 2017-06-16 22:42:12 -04:00
Mike Koch
550d7f5d3c Staff UI colors working 2017-06-16 21:18:22 -04:00
Mike Koch
f860e98018 Most of the user-defined colors are properly working 2017-06-16 13:09:59 -04:00
Mike Koch
cebcefe7e2 Actually save the settings 2017-06-15 22:06:13 -04:00
Mike Koch
69b78d0829 JS updated for presets 2017-06-13 22:14:00 -04:00
Mike Koch
3a7db2f7ca Small change 2017-06-13 12:59:49 -04:00
Mike Koch
f07358cb4a Set the right form names 2017-06-12 21:51:11 -04:00
Mike Koch
7d6f3828fd Fixed some SQL and used proper settings names 2017-06-12 08:21:28 -04:00
Mike Koch
daca2e6273 More work on admin UI colors 2017-06-11 22:04:19 -04:00
Mike Koch
9f0fd7c657 Working on custom staff panel color schemes 2017-06-10 22:29:29 -04:00
Mike Koch
88de2df3c0 Remove trailing PHP tags 2017-06-10 12:12:15 -04:00
Mike Koch
858e14ee8c Remove RTL support 2017-06-10 12:09:04 -04:00
Mike Koch
01570e856c Login header image is working 2017-06-10 12:06:14 -04:00
Mike Koch
55a1d3d5ad Working on adding a login header image 2017-06-09 22:39:00 -04:00
Mike Koch
57f9fdec63 Saving properly works, login page updated 2017-06-08 22:39:45 -04:00
Mike Koch
3a8d69b061 Only update image if changed 2017-06-08 13:10:12 -04:00
Mike Koch
e48022b533 Login background can be uploaded 2017-06-08 13:07:08 -04:00
Mike Koch
65c7c15c74 more work on login background 2017-06-07 21:58:47 -04:00
Mike Koch
31265e7696 Working on saving the login backdrop 2017-06-06 22:02:46 -04:00
Mike Koch
22789540ec Form is pretty much done for login background 2017-06-06 13:02:53 -04:00
Mike Koch
fb2861ea21 Add options for image url or background color 2017-06-05 22:03:08 -04:00
Mike Koch
0956496b99 Getting started on adding login background customizations 2017-06-01 12:56:36 -04:00
Mike Koch
33ab18e826 Update CategoryGateway 2017-06-01 12:45:56 -04:00
Mike Koch
fe898a7a1c Merge branch '397-fine-tuned-category-colors' into '3-1-0'
Resolve "Color Buttons Calendar Categories"

See merge request !61
2017-06-01 16:40:30 +00:00
Mike Koch
5960afd237 Update the database validator 2017-06-01 12:38:03 -04:00
Mike Koch
028be8d187 Calendar pages properly use new category colors 2017-06-01 12:26:54 -04:00
Mike Koch
ac0df60a3e Category colors are properly saved, calendar pages updated 2017-05-31 22:05:24 -04:00
Mike Koch
523b80fb4c Update the form for the new fields 2017-05-30 22:05:20 -04:00
Mike Koch
a043dced97 Getting started on enhanced color changes 2017-05-30 13:02:39 -04:00
Mike Koch
21d00049ba Fix URL 2017-05-29 22:03:46 -04:00
Mike Koch
ad4724ed69 Styling for items that can now be viewed inline 2017-05-29 21:58:50 -04:00
Mike Koch
3b0874db49 Add nav menu element for custom nav elements and security value 2017-05-29 21:39:58 -04:00
Mike Koch
873498e20e Move MFH language strings to end of file for i18n building 2017-05-29 21:01:09 -04:00
Mike Koch
3c5722c6d7 Getting started on inline attachment viewing 2017-05-23 22:14:32 -04:00
Mike Koch
8e22dd10a8 Replace fancybox with magnific popup (licensing) 2017-05-23 21:43:46 -04:00
Mike Koch
1a873cd377 Update calendar.php 2017-05-23 13:55:59 +00:00
Mike Koch
8d8d99e103 Remove erronous var_dump 2017-05-22 22:03:39 -04:00
Mike Koch
2990eadd07 Replace old HESK headers with current ones 2017-05-22 22:02:02 -04:00
Mike Koch
06b23e5459 Localized missing keys 2017-05-22 21:56:43 -04:00
Mike Koch
29d72b9c0e Fix custom fields on manage email templates 2017-05-22 21:46:15 -04:00
Mike Koch
6ec7058094 Replace jGrowl with Toastr' 2017-05-22 21:43:45 -04:00
Mike Koch
09c650d487 Merge branch '395-custom-blocks-to-database' into '3-1-0'
Move Custom Blocks/Nav Elements to Database

See merge request !60
2017-05-22 18:15:10 +00:00
Mike Koch
f96095ad42 Add back name attribute 2017-05-22 13:13:10 -04:00
Mike Koch
b82293d96d Custom nav elements now working on proper pages 2017-05-22 13:10:26 -04:00
Mike Koch
99c229fae7 Add toastr, fix several things regarding custom nav elements 2017-05-21 22:26:36 -04:00
Mike Koch
ab5840babe Sorting is now possible 2017-05-21 12:03:05 -04:00
Mike Koch
11f9266f10 Properly handle saving/getting URLs 2017-05-20 22:12:08 -04:00
Mike Koch
add02b208d Add endpoints for re-ordering elements, add arrows to page 2017-05-19 22:08:50 -04:00
Mike Koch
25922d99f3 Separate each type, add a sort value to reorder them 2017-05-19 12:52:47 -04:00
Mike Koch
5cdd216cdb Elements can be deleted, add overlay during AJAX operations 2017-05-18 22:10:10 -04:00
Mike Koch
8682bd236e New elements can be created, existing elements can be edited 2017-05-17 22:03:05 -04:00
Mike Koch
a139c7d351 Working on save functionality 2017-05-16 13:00:41 -04:00
Mike Koch
0418ff76ad Some more changes.... these are fantastic commit messages! 2017-05-15 22:04:32 -04:00
Mike Koch
0eab3f1622 Modal working 2017-05-15 12:58:34 -04:00
Mike Koch
944552aba2 Slowly working on the edit nav item modal 2017-05-14 22:09:05 -04:00
Mike Koch
6b05ee31ab Working on incorporating the API into the page 2017-05-12 13:11:28 -04:00
Mike Koch
6e72662a1b Wrote the custom nav element api 2017-05-11 22:00:51 -04:00
Mike Koch
d06d168850 Finished up retrieving custom nav elements 2017-05-09 22:00:01 -04:00
Mike Koch
01eaab29d5 Merge pull request #481 from zpetr/master
Unexpected [ bug fix
2017-05-09 08:13:39 -04:00
Mike Koch
3df5324732 Getting more work done on custom navigation 2017-05-08 21:56:30 -04:00
Mike Koch
8db64d903d Getting started on custom nav elements 2017-05-06 22:17:22 -04:00
zpetr
c883a7b1d4 Unexpected [ bug fix
PHP Parse error:  syntax error, unexpected '[', expecting ')'
2017-05-06 23:28:17 +02:00
Mike Koch
ca681cdb5b Merge branch '531-attachment-preview-link' into '3-1-0'
Replace modal with lightbox for viewing images

See merge request !59
2017-05-06 20:28:43 +00:00
Mike Koch
dd68103be6 Replace modal with lightbox for viewing images 2017-05-06 16:27:12 -04:00
Mike Koch
75eb078565 Merge branch '405-header-color-tips' into '3-1-0'
Popover header now matches category color

See merge request !58
2017-05-06 02:10:45 +00:00
Mike Koch
2845a734ef Popover header now matches category color 2017-05-05 22:09:02 -04:00
Mike Koch
a95936a490 Fix some language keys 2017-05-05 21:41:26 -04:00
Mike Koch
4deedc73b4 Resend response properly working 2017-05-04 21:37:50 -04:00
Mike Koch
e086322332 Working on adding the resend button to the actual ticket page 2017-05-04 13:07:17 -04:00
Mike Koch
6b89174901 Merge branch '353-ability-to-resend-response' into '3-1-0'
Add Ability To Resend Response

See merge request !57
2017-05-04 16:15:12 +00:00
Mike Koch
cb9590c189 Add Ability To Resend Response 2017-05-04 16:15:11 +00:00
Mike Koch
99ce0d2b52 Merge branch '551-warn-if-message-filled-when-closing-tab' into '3-1-0'
Display warning on tab close if message contents are not empty

See merge request !56
2017-05-03 01:42:41 +00:00
Mike Koch
77089c79ec Display warning on tab close if message contents are not empty 2017-05-02 21:41:19 -04:00
Mike Koch
e21c26689a Merge branch 'api-rewrite' into '3-1-0'
BETA API v1

See merge request !55
2017-05-02 16:14:39 +00:00
Mike Koch
ef9cbf98b0 Improve POST ticket 2017-05-01 22:05:21 -04:00
Mike Koch
0a2d94e05b Add a basic endpoint to get a ticket for staff 2017-05-01 21:20:59 -04:00
Mike Koch
39c5886880 Some changes to improve overall UX 2017-04-30 22:02:34 -04:00
Mike Koch
ee4ba00fe9 Add endpoint for retrieving helpdesk settings 2017-04-28 22:15:59 -04:00
Mike Koch
7494efb8ca Getting started on settings retrieval 2017-04-28 13:08:25 -04:00
Mike Koch
fd41a589fe Add a status controller to retrieve statuses 2017-04-28 13:03:25 -04:00
Mike Koch
167d6c76ac Basic ticket info can now be edited 2017-04-28 12:36:48 -04:00
Mike Koch
c26db92799 Add edit ticket endpoint 2017-04-27 22:04:28 -04:00
Mike Koch
7b49508b11 Send verification email if needed, return 202 if ticket needs to be verified 2017-04-25 22:06:10 -04:00
Mike Koch
215bcca079 Can now get ticket by ID 2017-04-24 22:11:28 -04:00
Mike Koch
54cb77b136 Getting started on retrieving ticket customer-side 2017-04-24 13:07:11 -04:00
Mike Koch
b03312f73c Fixed a couple issues with deleting tickets 2017-04-23 22:08:48 -04:00
Mike Koch
2ff27e197b Add ability to delete ticket 2017-04-23 12:00:05 -04:00
Mike Koch
2131df0cd9 Working on deleting tickets... a bit more complicated than I initially thought 2017-04-15 22:38:46 -04:00
Mike Koch
d67485af13 Ticket attachments can be deleted 2017-04-12 22:00:56 -04:00
Mike Koch
df503face9 Merge remote-tracking branch 'remotes/origin/master' into api-rewrite
# Conflicts:
#	build.php
#	install/install_functions.inc.php
#	install/mods-for-hesk/ajax/install-database-ajax.php
#	install/mods-for-hesk/installModsForHesk.php
#	install/mods-for-hesk/js/version-scripts.js
#	install/mods-for-hesk/modsForHesk.php
#	install/mods-for-hesk/sql/installSql.php
#	knowledgebase.php
2017-04-12 19:58:30 -04:00
Mike Koch
fe6b4b1c48 Update installer / build number 2017-04-12 19:36:23 -04:00
Mike Koch
b64aa60fa0 Fix white screen on knowledgebase 2017-04-12 17:12:37 -04:00
Mike Koch
1bdb16ed64 Update database/database_mysqli for api,internal-api,cron 2017-04-11 21:49:43 -04:00
Mike Koch
3cdcc411a4 Fix pulling attachments, file checking 2017-04-11 21:44:57 -04:00
Mike Koch
027ff8f029 Update installer the right way 2017-04-11 20:58:36 -04:00
Mike Koch
bed05b0592 Fix version 2017-04-11 20:58:36 -04:00
Mike Koch
8bba31b0e2 Fix missing +s 2017-04-11 20:58:36 -04:00
Mike Koch
7a8f960bc0 Fix installer 2017-04-11 20:58:35 -04:00
Mike Koch
925ad5f538 #544 Rest of the 2.7.3 updates 2017-04-11 20:58:35 -04:00
Mike Koch
f4dbffa7e4 #544 Start updating to HESK 2.7.3 2017-04-11 20:58:34 -04:00
Mike Koch
c606be50ef Output attachment contents 2017-04-11 12:39:09 -04:00
Mike Koch
95606d1f0a Update installer the right way 2017-04-11 12:13:59 -04:00
Mike Koch
3556dd9618 Fix version 2017-04-11 08:19:09 -04:00
Mike Koch
877c85575f Fix missing +s 2017-04-11 08:15:39 -04:00
Mike Koch
b266fe6e4f Fix installer 2017-04-11 08:09:59 -04:00
Mike Koch
f4a42dae1b Merge branch '3-0-6' into 'master'
3.0.6 Update

See merge request !54
2017-04-11 01:55:44 +00:00
Mike Koch
e4c8d5b653 Merge branch '544-hesk-2-7-3-update' into '3-0-6'
Resolve "Update to HESK 2.7.3"

See merge request !53
2017-04-11 01:34:11 +00:00
Mike Koch
7277b5e4a2 #544 Rest of the 2.7.3 updates 2017-04-10 21:32:29 -04:00
Mike Koch
c3bad92656 #544 Start updating to HESK 2.7.3 2017-04-10 13:04:11 -04:00
Mike Koch
d461059cf0 Wrapped up retrieving ticket attachments 2017-04-09 22:14:38 -04:00
Mike Koch
e54d5278ac More work, forgot to include security when creating attachment 2017-04-05 22:13:37 -04:00
Mike Koch
c58867577f Attachments should be retrievable 2017-04-05 21:56:13 -04:00
Mike Koch
3cec244e15 Getting started on attachment retrieval 2017-04-04 22:57:21 -04:00
Mike Koch
999cb74865 Merge remote-tracking branch 'remotes/origin/master' into api-rewrite 2017-04-04 22:31:11 -04:00
Mike Koch
d90d09b9ce Update installer 2017-04-04 12:26:30 -04:00
Mike Koch
10c7f00881 Fix audit trail when changing status 2017-04-04 12:16:42 -04:00
Mike Koch
47152eb7fb Fix hesk_POST 2017-04-04 12:11:17 -04:00
Mike Koch
6dbda6f653 Fix installation issues 2017-04-03 22:32:32 -04:00
Mike Koch
2b051ef97b Merge branch '3-0-4' into 'master'
3.0.4 Update

Closes #537, #516, #517, #521, #463, #504, #508, #519, #507, and #509

See merge request !50
2017-04-04 02:23:01 +00:00
Mike Koch
8b886737b8 Change 'More' dropdown to a modal 2017-04-03 22:21:58 -04:00
Mike Koch
44ab6fc1e9 Start moving the 'more' section to a modal 2017-04-03 13:07:47 -04:00
Mike Koch
85458aa975 Fixes #516 Add autolink plugin to auto-generate URL when entering in messages 2017-04-02 21:15:34 -04:00
Mike Koch
672a061f28 Merge branch '517-checkbox-edit-issues' into '3-0-4'
Fixes #517 Use consistent <br /> tag for checkboxes

See merge request !52
2017-04-03 00:50:04 +00:00
Mike Koch
f28dc0f500 Fixes #517 Use consistent <br /> tag for checkboxes 2017-04-02 20:49:20 -04:00
Mike Koch
3bc61705b1 Merge branch '521-html-entities-when-merging' into '3-0-4'
Fix HTML Entities When Merging Tickets

See merge request !51
2017-04-03 00:36:29 +00:00
Mike Koch
f8ede2240a Fixes #521 copy over html flags when merging tickets 2017-04-02 20:35:05 -04:00
Mike Koch
0b0d046d04 Update installer 2017-03-29 22:11:01 -04:00
Mike Koch
20b7643657 Merge branch '573-sql-fixes' into '3-0-4'
Fix some potention SQL injection vulns

See merge request !49
2017-03-29 01:58:32 +00:00
Mike Koch
59ebafdf81 Fix some potention SQL injection vulns 2017-03-28 21:56:49 -04:00
Mike Koch
60c5be549c Merge branch '463-suggest-kb-rich-text' into '3-0-4'
Fixes #463 Support suggested KB articles when rich text is enabled

See merge request !48
2017-03-29 01:22:22 +00:00
Mike Koch
55c6f4d093 Fixes #463 Support suggested KB articles when rich text is enabled 2017-03-28 21:21:17 -04:00
Mike Koch
48f5ad1810 Merge branch '503-align-message-to-custom-fields' into '3-0-4'
#503 tweak message format, also fix some missing changes for the calendar fix

See merge request !47
2017-03-28 01:53:30 +00:00
Mike Koch
80b6ef4c9b #503 tweak message format, also fix some missing changes for the calendar fix 2017-03-27 21:52:34 -04:00
Mike Koch
3a89bfeca1 Merge branch '504-custom-field-default-value' into '3-0-4'
Fixes #504 set readonly field names different to prevent incorrect values

See merge request !46
2017-03-28 01:45:44 +00:00
Mike Koch
7a723f5250 Fixes #504 set readonly field names different to prevent incorrect values 2017-03-27 21:43:14 -04:00
Mike Koch
0e04e44e1f Merge branch '508-calendar-select-deselect' into '3-0-4'
Fixes #508 Update category visibility after loading events

See merge request !45
2017-03-28 01:00:20 +00:00
Mike Koch
938bb20c3f Fixes #508 Update category visibility after loading events 2017-03-27 20:59:13 -04:00
Mike Koch
97a96b5947 UserToTicketChecker now checks for category managers 2017-03-25 16:36:47 -04:00
Mike Koch
37149ec831 Working on user ticket security checker 2017-03-22 22:07:14 -04:00
Mike Koch
5112a6a13b Make the endpoint only for ticket message attachments, not replies 2017-03-22 12:54:43 -04:00
Mike Koch
0556d07a56 Attachments can now be uploaded for a ticket. Still need to handle updating the reply's property 2017-03-21 22:11:19 -04:00
Mike Koch
8d484f62ea Mostly done with attachment uploading 2017-03-20 22:16:35 -04:00
Mike Koch
4fd6595ded Handle building the attachment and saving it to the FS 2017-03-18 22:13:08 -04:00
Mike Koch
ffd3ac2edf Working on some validation tests 2017-03-17 22:05:51 -04:00
Mike Koch
8378d35149 Start working on attachments API. Fix .gitignore 2017-03-15 22:07:17 -04:00
Mike Koch
f40eaf1a23 Fix tests 2017-03-12 21:24:49 -04:00
Mike Koch
cc880a15fc Show stack traces on the message log page 2017-03-12 20:57:36 -04:00
Mike Koch
f15cb63d32 Logging has been implemented for exceptions 2017-03-12 20:50:54 -04:00
Mike Koch
6af93506f1 Properly handle if the API is disabled 2017-03-12 15:58:17 -04:00
Mike Koch
d0475b22c1 Add UserPrivilege enum, provide better 404 information 2017-03-12 15:37:23 -04:00
Mike Koch
25929d82f4 Fixed some email issues 2017-03-12 01:06:50 -05:00
Mike Koch
ccbe2cd580 MFH Settings being loaded, emails being sent out 2017-03-12 00:44:50 -05:00
Mike Koch
06a38e9383 Autoassign logic is finished 2017-03-11 23:43:50 -05:00
Mike Koch
af789a7060 Working on autoassign rewrite logic 2017-03-10 22:06:32 -05:00
Mike Koch
ad2c96c667 Update composer.json and ApplicationContext 2017-03-09 21:55:32 -05:00
Mike Koch
64428872df Created an entity for user 2017-03-08 21:49:30 -05:00
Mike Koch
abdc734833 Merge branch '506-customer-reply-form-location' into '3-0-4'
Put ticket reply form in the right place

See merge request !44
2017-03-07 17:55:31 +00:00
Mike Koch
5a1b4552ce Put ticket reply form in the right place 2017-03-07 12:54:20 -05:00
Mike Koch
488a86cbac Merge branch '519-fix-status-key-on-emails' into '3-0-4'
Fixes #519 Pull from bridge table for status name

See merge request !43
2017-03-07 02:59:14 +00:00
Mike Koch
9325d819c7 Fixes #519 Pull from bridge table for status name 2017-03-06 21:58:07 -05:00
Mike Koch
01c56da52c Working on adding Spot ORM 2017-03-06 21:44:38 -05:00
Mike Koch
2201f188bd Some changes 2017-03-05 22:03:11 -05:00
Mike Koch
672d089b20 Working on more email stuff 2017-03-04 21:59:55 -05:00
Mike Koch
2a6766c10e Pretty much done with the EmailSenderHelper 2017-03-04 00:43:08 -05:00
Mike Koch
e7eeac9f34 Working on more email sender stuff 2017-03-03 22:05:41 -05:00
Mike Koch
9832ca58ba Some refactoring to the email stuff 2017-03-02 22:05:28 -05:00
Mike Koch
36f8de957a Able to parse email templates.... I hope 2017-02-28 22:03:08 -05:00
Mike Koch
c3e70309bc Some more changes 2017-02-27 21:24:24 -05:00
Mike Koch
41123e987b Some more API changes 2017-02-26 21:52:12 -05:00
Mike Koch
0ceaafc0ec Changes 2017-02-24 22:01:54 -05:00
Mike Koch
9b2aa355b9 Little progress, but still something 2017-02-23 22:04:56 -05:00
Mike Koch
5550565615 Merge branch 'DarekTw-patch-1' into 3-0-4 2017-02-23 08:08:19 -05:00
Mike Koch
c3e6fd5b35 Merge branch 'patch-1' of https://github.com/DarekTw/Mods-for-HESK into DarekTw-patch-1 2017-02-23 08:07:53 -05:00
Mike Koch
b53e9aafd7 Getting started on email retrieval/parsing 2017-02-22 22:02:24 -05:00
Mike Koch
4c7449ea3e Properly handle tickets that need validation. Added comments for next steps 2017-02-20 22:07:39 -05:00
Mike Koch
c1638aeb98 First steps in supporting email validation 2017-02-20 13:05:41 -05:00
Mike Koch
08d7347f00 Small tweaks 2017-02-19 22:04:47 -05:00
Mike Koch
54baa4d6ba Created email senders and integration tests for these senders 2017-02-19 22:02:10 -05:00
Mike Koch
2a145bfa3e SMTP emails working with EmailSender...haven't tested attaching things though 2017-02-18 22:11:45 -05:00
Mike Koch
b4dcbc9846 Getting started on email sender for customer ticket creation 2017-02-16 22:04:59 -05:00
Mike Koch
ca499d5eac Basic ticket creator appears to be working. Still need to handle email 2017-02-16 21:46:47 -05:00
Mike Koch
c8485c0fa3 Working on a status gateway to get the ticket's default status 2017-02-15 22:01:15 -05:00
Mike Koch
31ced3f572 Add somre more fields 2017-02-14 22:03:46 -05:00
Mike Koch
1b6cca8ddf Create ticket endpoint now working, but needs some changes 2017-02-14 12:45:02 -05:00
Mike Koch
1cb4209be2 Working more on create ticket endpoint 2017-02-13 22:34:15 -05:00
Mike Koch
843528252b Getting started on POST for ticket controller 2017-02-13 13:02:40 -05:00
Mike Koch
dc0c8a351b I think I finished the ticket creator 2017-02-13 12:52:43 -05:00
Mike Koch
489f191a13 Majority of create ticket logic done. Just need to add attachments(?) and retriever SQL-specific fields 2017-02-12 22:10:42 -05:00
Mike Koch
1a8a989e87 Moved validation logic to its own class, working on createTicket tests 2017-02-12 01:38:12 -05:00
Mike Koch
044faa77f6 TicketGateway can now insert tickets 2017-02-12 00:50:30 -05:00
Mike Koch
65b10bae3c TrackingIdGenerator working. Stubbed out todo list for rest of creating ticket 2017-02-11 22:07:10 -05:00
Mike Koch
7e966b93a5 Intermediate commit 2017-02-11 16:42:40 -05:00
Mike Koch
ee3a425c59 Remove unnecessary comment 2017-02-11 16:27:39 -05:00
Mike Koch
44239ed459 Start working on TrackingIdGenerator 2017-02-11 16:24:08 -05:00
DarekTw
dd0119602b Fixed unclosed <div> 2017-02-11 16:12:42 +01:00
Mike Koch
6f87dfc149 Small fix on validation model 2017-02-10 22:10:39 -05:00
Mike Koch
d476f86c8c Finished validation tests for create ticket 2017-02-10 22:09:46 -05:00
Mike Koch
bc9bb698c5 Add some more validation tests for dates 2017-02-10 13:05:40 -05:00
Mike Koch
e44baa99c2 Refactored custom field validator, re-enabled test 2017-02-09 12:57:28 -05:00
Mike Koch
e22d318b92 More tests for TicketCreator. Need to refactor some custom field logic 2017-02-07 22:16:15 -05:00
Mike Koch
44e45852d0 Merge branch '507-missing-new-event-button' into '3-0-4'
Add back missing create event button

See merge request !42
2017-02-07 18:02:39 +00:00
Mike Koch
d7a25b7c7a Fixes #507 Add back missing create event button 2017-02-07 13:01:28 -05:00
Mike Koch
4e438d9fd3 Merge branch '509-fix-reply-with-rich-text' into '3-0-4'
Allow customers to respond using rich text

See merge request !41
2017-02-07 17:42:12 +00:00
Mike Koch
cecd302957 Fixes #509 Allow customers to respond using rich text 2017-02-07 12:39:29 -05:00
Mike Koch
b76e2afac1 More work on ticket creator tests 2017-02-06 22:13:16 -05:00
Mike Koch
98cbd6e4dd Working on TicketCreator tests 2017-02-05 22:12:18 -05:00
Mike Koch
176b786279 Move ban test, work on TicketValidators test 2017-02-03 22:08:44 -05:00
Mike Koch
bbdb03d103 Testing is working! 2017-02-02 22:30:41 -05:00
Mike Koch
2b792cff72 Fix exception handler for E_NOTICE 2017-02-02 21:22:04 -05:00
Mike Koch
a702d157cd Delete unused DAOs, fix some replace errors 2017-02-02 20:21:25 -05:00
Mike Koch
ad43c420bb Use PSR-4 standard for classloading 2017-02-01 22:04:52 -05:00
Mike Koch
2b0d2bb9cc Send all enabled custom fields 2017-02-01 21:03:05 -05:00
Mike Koch
a2c98a5a26 Ticket stuff slowly taking shape 2017-01-31 22:26:46 -05:00
Mike Koch
a4af2e668f More work on ticket stuff 2017-01-30 22:10:14 -05:00
Mike Koch
8968be1ffd More work on exception handling and user context building 2017-01-28 22:35:42 -05:00
Mike Koch
e68ecf50c6 Moved some more stuff to new structure 2017-01-28 01:41:29 -05:00
Mike Koch
2ef67de718 Added proper DI and autoloading to make things simpler for the actual logic' 2017-01-28 01:28:53 -05:00
Mike Koch
ecbd2fd94a Fixed some folder structures and worked on ban retrieval 2017-01-27 22:26:28 -05:00
Mike Koch
e1176ec4ee Getting started on ticket endpoint... again 2017-01-26 22:00:45 -05:00
Mike Koch
fc38673b7d Some temporary error handling 2017-01-25 21:55:13 -05:00
Mike Koch
dc07f5e757 Move link to the api folder 2017-01-25 21:27:39 -05:00
Mike Koch
ba0a035d88 Update CONTRIBUTING.md 2017-01-25 20:52:59 +00:00
Mike Koch
6721c558af Update CONTRIBUTING.md 2017-01-25 20:52:20 +00:00
Mike Koch
aff8dadd27 Category Controller is working 2017-01-21 22:09:29 -05:00
Mike Koch
93431e9a98 Build the user context based on hashed token 2017-01-21 16:34:03 -05:00
Mike Koch
17f6bb770d UserContextBuilder mostly done 2017-01-20 21:50:58 -05:00
Mike Koch
96120bc744 Working on user context 2017-01-20 07:19:39 -05:00
Mike Koch
c184469219 Able to hit a controller through link 2017-01-18 21:56:12 -05:00
Mike Koch
d9000c12c7 More routing changes 2017-01-18 17:22:24 -05:00
Mike Koch
5e21877efc Add Link for simple API routing 2017-01-17 22:12:45 -05:00
Mike Koch
b7cbca03a7 Getting started on routing 2017-01-17 22:08:48 -05:00
Mike Koch
f9845624d4 More API changes 2017-01-17 21:58:57 -05:00
Mike Koch
403b87bbda Bunch of stuff 2017-01-16 22:21:11 -05:00
Mike Koch
4942fdbfda Use __DIR__ to make importing easier and only when required 2017-01-14 22:00:27 -05:00
Mike Koch
d1ae2a8009 Getting started on new ticket validator 2017-01-11 21:55:22 -05:00
Mike Koch
273feb676c Forgot to update installModsForHesk 2017-01-07 21:26:03 -05:00
Mike Koch
80e69f3ef0 Bump to 3.0.3 2017-01-07 20:49:44 -05:00
Mike Koch
2ca6d230e3 Revert back to old install script format 2017-01-07 20:47:53 -05:00
Mike Koch
6924ae0fb7 Merge branch 'bug-fix-field-validation' into 'master'
Fix checkbox validator

See merge request !40
2017-01-07 02:55:44 +00:00
Mike Koch
0215657650 Fix checkbox validator 2017-01-06 21:55:14 -05:00
Mike Koch
24e2607fe3 Merge branch 'bug-fix-stage-tickets-table' into 'master'
Fix Stage Ticket Table

See merge request !39
2017-01-07 02:00:54 +00:00
Mike Koch
a43338a017 Fix columns 2017-01-06 20:59:43 -05:00
Mike Koch
0b44970041 Merge branch '3-0-1' into 'master'
3.0.1 Update

Closes #488, #489, #490, #494, #496, #497, and #499

See merge request !38
2017-01-05 04:18:41 +00:00
Mike Koch
8ef0ed6a29 Add reCAPTCHA scripts when required 2017-01-04 21:49:02 -05:00
Mike Koch
f63f141177 Improve database validation 2017-01-03 22:16:04 -05:00
Mike Koch
92b4f8e4d0 Update version, tweak login CSS to perform better on mobile 2017-01-03 22:02:23 -05:00
Mike Koch
9e4ec347cf Show full-size notice with 0 messages to fill in space 2017-01-03 21:42:52 -05:00
Mike Koch
6a42560c0c Merge branch '497-update-to-hesk-2-7-2' into '3-0-1'
Update to HESK 2.7.2

See merge request !37
2017-01-03 17:07:29 +00:00
Mike Koch
7ee6f353aa Merge branch '496-fix-uninstaller' into '3-0-1'
Fix Uninstaller SQL

See merge request !36
2017-01-03 17:06:46 +00:00
Mike Koch
5ae2c1c4a4 Merge branch '494-fix-kb-private' into '3-0-1'
Fix Knowledgebase UI for Staff

See merge request !35
2017-01-03 17:06:04 +00:00
Mike Koch
628031a11e Merge branch '490-ticket-sidebar-color-scheme' into '3-0-1'
Fix sidebar text color w/light scheme

See merge request !33
2017-01-03 17:05:24 +00:00
Mike Koch
3557d5a97f Merge branch '489-canned-responses-not-showing' into '3-0-1'
Load canned responses before displaying reply form

See merge request !32
2017-01-03 17:05:01 +00:00
Mike Koch
d5dce1f931 Merge branch '488-admin-color-dropdown' into '3-0-1'
Fix admin color scheme dropdown

See merge request !31
2017-01-03 17:04:45 +00:00
Mike Koch
081fcf779c Update to HESK 2.7.2 2017-01-02 16:42:41 -05:00
Mike Koch
27a1efafcf Fix unintall SQL 2017-01-02 16:26:10 -05:00
Mike Koch
030b62389e Fix knowledgebase for staff 2017-01-02 16:24:33 -05:00
Mike Koch
6b0e7f17bb Merge branch '493-users-online-rewrite' into '3-0-1'
Resolve "Can't see users"

See merge request !34
2017-01-02 21:09:43 +00:00
Mike Koch
660c28e2f8 Move users online to top navbar 2017-01-02 16:03:20 -05:00
Mike Koch
910e753314 Add users_online to repo 2017-01-02 15:33:02 -05:00
Mike Koch
b58cfda4c8 Set color darker when using a light theme 2017-01-02 13:16:07 -05:00
Mike Koch
2050174cd7 Load canned reponses before displaying reply form 2017-01-02 12:44:52 -05:00
Mike Koch
788fb3462c Fix admin color scheme dropdown 2017-01-02 12:38:48 -05:00
Mike Koch
93c7ddc528 Fix date format on original ticket message 2016-12-31 23:38:51 -05:00
Mike Koch
93fb2e63f2 Translate text 2016-12-31 23:23:19 -05:00
Mike Koch
d3dfd7f326 Change note color scheme, fix add note button 2016-12-31 23:20:19 -05:00
Mike Koch
76d47a6f64 Update installer for 3.0.0 2016-12-31 22:01:18 -05:00
Mike Koch
177af6b0ec Fixes #485 Preserve all preferences when disabled 2016-12-29 13:04:44 -05:00
Mike Koch
76dab03bc3 Properly show dropdown for limited access users 2016-12-29 12:57:24 -05:00
Mike Koch
3f7a57fd66 Some CSS tweaks 2016-12-13 21:37:32 -05:00
507 changed files with 42507 additions and 13208 deletions

110
.gitignore vendored
View File

@ -1,9 +1,14 @@
# Mods for HESK-specific files
api/vendor
api/Tests/integration_test_mfh_settings.php
# HESK Files
admin/admin_suggest_articles.php
admin/archive.php
admin/custom_statuses.php
admin/email_templates.php
admin/generate_spam_question.php
admin/priority.php
admin/resend_notification.php
admin/test_connection.php
attachments/index.htm
cache/
@ -15,6 +20,7 @@ header.txt
hesk_settings.inc.php
img/add_article.png
img/add_category.png
img/anonymize.png
img/article_text.png
img/autoassign_off.png
img/autoassign_on.png
@ -30,8 +36,10 @@ img/delete.png
img/delete_off.png
img/delete_ticket.png
img/edit.png
img/email.png
img/error.png
img/existingticket.png
img/export.png
img/flag_critical.png
img/flag_high.png
img/flag_low.png
@ -77,6 +85,7 @@ img/lock.png
img/login.png
img/mail.png
img/manage.png
img/menu.png
img/minus.gif
img/minusbottom.gif
img/minustop.gif
@ -193,60 +202,60 @@ inc/tabs/tabber-minimized.js
inc/tabs/tabber.css
inc/timer/hesk_timer.js
inc/timer/index.htm
inc/tiny_mce/3.5.11/langs/en.js
inc/tiny_mce/3.5.11/license.txt
inc/tiny_mce/3.5.11/themes/advanced/about.htm
inc/tiny_mce/3.5.11/themes/advanced/anchor.htm
inc/tiny_mce/3.5.11/themes/advanced/charmap.htm
inc/tiny_mce/3.5.11/themes/advanced/color_picker.htm
inc/tiny_mce/3.5.11/themes/advanced/editor_template.js
inc/tiny_mce/3.5.11/themes/advanced/image.htm
inc/tiny_mce/3.5.11/themes/advanced/img/colorpicker.jpg
inc/tiny_mce/3.5.11/themes/advanced/img/flash.gif
inc/tiny_mce/3.5.11/themes/advanced/img/icons.gif
inc/tiny_mce/3.5.11/themes/advanced/img/iframe.gif
inc/tiny_mce/3.5.11/themes/advanced/img/pagebreak.gif
inc/tiny_mce/3.5.11/themes/advanced/img/quicktime.gif
inc/tiny_mce/3.5.11/themes/advanced/img/realmedia.gif
inc/tiny_mce/3.5.11/themes/advanced/img/shockwave.gif
inc/tiny_mce/3.5.11/themes/advanced/img/trans.gif
inc/tiny_mce/3.5.11/themes/advanced/img/video.gif
inc/tiny_mce/3.5.11/themes/advanced/img/windowsmedia.gif
inc/tiny_mce/3.5.11/themes/advanced/js/about.js
inc/tiny_mce/3.5.11/themes/advanced/js/anchor.js
inc/tiny_mce/3.5.11/themes/advanced/js/charmap.js
inc/tiny_mce/3.5.11/themes/advanced/js/color_picker.js
inc/tiny_mce/3.5.11/themes/advanced/js/image.js
inc/tiny_mce/3.5.11/themes/advanced/js/link.js
inc/tiny_mce/3.5.11/themes/advanced/js/source_editor.js
inc/tiny_mce/3.5.11/themes/advanced/langs/en.js
inc/tiny_mce/3.5.11/themes/advanced/langs/en_dlg.js
inc/tiny_mce/3.5.11/themes/advanced/link.htm
inc/tiny_mce/3.5.11/themes/advanced/shortcuts.htm
inc/tiny_mce/3.5.11/themes/advanced/skins/default/content.css
inc/tiny_mce/3.5.11/themes/advanced/skins/default/dialog.css
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/buttons.png
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/items.gif
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/menu_arrow.gif
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/menu_check.gif
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/progress.gif
inc/tiny_mce/3.5.11/themes/advanced/skins/default/img/tabs.gif
inc/tiny_mce/3.5.11/themes/advanced/skins/default/ui.css
inc/tiny_mce/3.5.11/themes/advanced/source_editor.htm
inc/tiny_mce/3.5.11/tiny_mce.js
inc/tiny_mce/3.5.11/tiny_mce_popup.js
inc/tiny_mce/3.5.11/utils/editable_selects.js
inc/tiny_mce/3.5.11/utils/form_utils.js
inc/tiny_mce/3.5.11/utils/mctabs.js
inc/tiny_mce/3.5.11/utils/validate.js
inc/tiny_mce/3.5.12/langs/en.js
inc/tiny_mce/3.5.12/license.txt
inc/tiny_mce/3.5.12/themes/advanced/about.htm
inc/tiny_mce/3.5.12/themes/advanced/anchor.htm
inc/tiny_mce/3.5.12/themes/advanced/charmap.htm
inc/tiny_mce/3.5.12/themes/advanced/color_picker.htm
inc/tiny_mce/3.5.12/themes/advanced/editor_template.js
inc/tiny_mce/3.5.12/themes/advanced/image.htm
inc/tiny_mce/3.5.12/themes/advanced/img/colorpicker.jpg
inc/tiny_mce/3.5.12/themes/advanced/img/flash.gif
inc/tiny_mce/3.5.12/themes/advanced/img/icons.gif
inc/tiny_mce/3.5.12/themes/advanced/img/iframe.gif
inc/tiny_mce/3.5.12/themes/advanced/img/pagebreak.gif
inc/tiny_mce/3.5.12/themes/advanced/img/quicktime.gif
inc/tiny_mce/3.5.12/themes/advanced/img/realmedia.gif
inc/tiny_mce/3.5.12/themes/advanced/img/shockwave.gif
inc/tiny_mce/3.5.12/themes/advanced/img/trans.gif
inc/tiny_mce/3.5.12/themes/advanced/img/video.gif
inc/tiny_mce/3.5.12/themes/advanced/img/windowsmedia.gif
inc/tiny_mce/3.5.12/themes/advanced/js/about.js
inc/tiny_mce/3.5.12/themes/advanced/js/anchor.js
inc/tiny_mce/3.5.12/themes/advanced/js/charmap.js
inc/tiny_mce/3.5.12/themes/advanced/js/color_picker.js
inc/tiny_mce/3.5.12/themes/advanced/js/image.js
inc/tiny_mce/3.5.12/themes/advanced/js/link.js
inc/tiny_mce/3.5.12/themes/advanced/js/source_editor.js
inc/tiny_mce/3.5.12/themes/advanced/langs/en.js
inc/tiny_mce/3.5.12/themes/advanced/langs/en_dlg.js
inc/tiny_mce/3.5.12/themes/advanced/link.htm
inc/tiny_mce/3.5.12/themes/advanced/shortcuts.htm
inc/tiny_mce/3.5.12/themes/advanced/skins/default/content.css
inc/tiny_mce/3.5.12/themes/advanced/skins/default/dialog.css
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/buttons.png
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/items.gif
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/menu_arrow.gif
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/menu_check.gif
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/progress.gif
inc/tiny_mce/3.5.12/themes/advanced/skins/default/img/tabs.gif
inc/tiny_mce/3.5.12/themes/advanced/skins/default/ui.css
inc/tiny_mce/3.5.12/themes/advanced/source_editor.htm
inc/tiny_mce/3.5.12/tiny_mce.js
inc/tiny_mce/3.5.12/tiny_mce_popup.js
inc/tiny_mce/3.5.12/utils/editable_selects.js
inc/tiny_mce/3.5.12/utils/form_utils.js
inc/tiny_mce/3.5.12/utils/mctabs.js
inc/tiny_mce/3.5.12/utils/validate.js
inc/treemenu/TreeMenu.php
inc/treemenu/index.htm
inc/users_online.inc.php
inc/zip/Zip.php
inc/zip/index.htm
inc/zip/pclzip.lib.php
install/hesk.png
install/update.php
language/en/help_files
language/en/emails/category_moved.txt
language/en/emails/forgot_ticket_id.txt
language/en/emails/index.htm
@ -257,16 +266,15 @@ language/en/emails/new_ticket.txt
language/en/emails/new_ticket_staff.txt
language/en/emails/ticket_assigned_to_you.txt
language/en/index.htm
language/en/text.php
language/index.htm
language/*
!language/en
print_sec_img.php
rate.php
readme.html
robots.txt
.idea/
attachments/__latest.txt
attachments
/attachments
img/ban.png
img/banned.png
img/ico_tools.png

90
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,90 @@
stages:
- validate
- test
- package
before_script:
- bash ci/docker_install.sh > /dev/null
validate:7.2:
image: php:7.2
stage: validate
script:
- bash ci/php_lint.sh ./
validate:7.1:
image: php:7.1
stage: validate
script:
- bash ci/php_lint.sh ./
validate:7.0:
image: php:7.0
stage: validate
script:
- bash ci/php_lint.sh ./
validate:5.6:
image: php:5.6
stage: validate
script:
- bash ci/php_lint.sh ./
validate:5.5:
image: php:5.5
stage: validate
script:
- bash ci/php_lint.sh ./
validate:5.4:
image: php:5.4
stage: validate
script:
- bash ci/php_lint.sh ./
validate:5.3:
image: php:5.3
stage: validate
script:
- bash ci/php_lint.sh ./
test:7.1:
image: php:7.1
stage: test
script:
- cd api
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
- php composer-setup.php
- php -r "unlink('composer-setup.php');"
- php composer.phar update
- php composer.phar install
- cd Tests
- phpunit
test:7.2:
image: php:7.2
stage: test
script:
- cd api
- php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
- php composer-setup.php
- php -r "unlink('composer-setup.php');"
- php composer.phar update
- php composer.phar install
- cd Tests
- phpunit
package:
image: tetraweb/php
when: manual
stage: package
script:
- apt-get update
- apt-get install zip unzip
- cd api
- composer install --no-dev
- cd ../ci
- bash build_zip.sh
artifacts:
paths:
- release.zip

View File

@ -2,15 +2,15 @@
So you want to contribute to Mods for HESK? Awesome! However, there are a few guidelines that need to be followed so the project can be as easy to maintain as possible.
## Submitting an issue
If all you are doing is submitting an issue, please check if your "issue" qualifies as a GitHub issue:
- **Feature Requests:** Feature requests are now being recorded at the Mods for HESK [UserVoice page](https://mods-for-hesk.uservoice.com/forums/254758-general). Please do not open these types of issues on GitHub. Issues opened that are "feature requests" will be closed.
- **Translations:** Translations are now being recorded at the official Mods for HESK [website](https://mods-for-hesk.mkochcs.com/download.php). Please do not open these types of issues on GitHub. Issues opened that pertain to submitting new translations will be closed.
If all you are doing is submitting an issue, please check if your "issue" qualifies as a GitLab issue:
- **Feature Requests:** Feature requests are now being recorded at the Mods for HESK [UserVoice page](https://mods-for-hesk.uservoice.com/forums/254758-general). Please do not open these types of issues on GitLab. Issues opened that are "feature requests" will be closed.
- **Translations:** Translations are now being recorded at the official Mods for HESK [website](https://mods-for-hesk.mkochcs.com/download.php). Please do not open these types of issues on GitLab. Issues opened that pertain to submitting new translations will be closed.
- **Bugs:** Yes, please open these types of issues here. :grinning:
## Getting Started
If you have already completed any of these steps in the past (such as creating a GitHub account), you can skip the respective step.
- Make sure you have a [GitHub account](http://github.com/signup/free)
- Fork the repository on GitHub (for more help consult the [GitHub documentation](https://help.github.com/articles/fork-a-repo/))
If you have already completed any of these steps in the past (such as creating a GitLab account), you can skip the respective step.
- Make sure you have a [GitLab account](https://gitlab.com/users/sign_in)
- Fork the repository on GitLab
## Making Changes
- Create a feature branch from where to base your work off of
@ -22,7 +22,6 @@ If you have already completed any of these steps in the past (such as creating a
## Submitting Changes
- Push your changes to a topic branch in your fork of the repository
- Submit a pull request to the official Mods for HESK repository (mkoch227/Mods-for-HESK)
- If necessary, sign the Contributor License Agreement by checking the "status checks" area of your pull request.
- The owner of Mods for HESK will then inspect and test the code in the pull request. Feedback will be given via GitHub comments.
- Submit a pull request to the official Mods for HESK repository (mike-koch/Mods-for-HESK)
- The owner of Mods for HESK will then inspect and test the code in the pull request. Feedback will be given via GitLab comments.
- The owner of Mods for HESK expects responses within two weeks of the original comment. If there is no feedback within that time range, the pull request will be considered abandoned and subsequently will be closed.

View File

@ -54,7 +54,15 @@ else {
?>
<div class="content-wrapper">
<section class="content">
<?php hesk_handle_messages(); ?>
<?php
// Service messages
$service_messages = mfh_get_service_messages('STAFF_HOME');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
hesk_handle_messages();
?>
<div class="box">
<div class="box-header with-border">
<h1 class="box-title">
@ -100,23 +108,17 @@ else {
</div>
</div>
<?php
$hesk_settings['hesk_license']('HMgPSAxOw0KaWYgKGZpbGVfZXhpc3RzKEhFU0tfUEFUSCAuI
CdoZXNrX2xpY2Vuc2UucGhwJykpDQp7DQokaCA9ICghZW1wdHkoJF9TRVJWRVJbJ0hUVFBfSE9TVCddK
SkgPyAkX1NFUlZFUlsnSFRUUF9IT1NUJ10gOiAoKCFlbXB0eSgkX1NFUlZFUlsnU0VSVkVSX05BTUUnX
SkpID8gJF9TRVJWRVJbJ1NFUlZFUl9OQU1FJ10gOiBnZXRlbnYoJ1NFUlZFUl9OQU1FJykpOw0KJGggP
SBzdHJfcmVwbGFjZSgnd3d3LicsJycsc3RydG9sb3dlcigkaCkpOw0KaW5jbHVkZShIRVNLX1BBVEggL
iAnaGVza19saWNlbnNlLnBocCcpOw0KaWYgKGlzc2V0KCRoZXNrX3NldHRpbmdzWydsaWNlbnNlJ10pI
CYmIHN0cnBvcygkaGVza19zZXR0aW5nc1snbGljZW5zZSddLHNoYTEoJGguJ2gzJkZwMiNMYUEmNTkhd
yg4LlpjXSordVI1MTInKSkgIT09IGZhbHNlKQ0Kew0KJHMgPSAwOw0KfQ0KZWxzZQ0Kew0KZWNobyAnP
HAgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyO2NvbG9yOnJlZDsiPklOVkFMSUQgTElDRU5TRSAoTk9UI
FJFR0lTVEVSRUQgRk9SICcuJGguJykhPC9wPic7DQp9DQp9DQppZiAoJHMpDQp7DQplY2hvICc8aHIgL
z48dGFibGUgYm9yZGVyPSIwIiB3aWR0aD0iMTAwJSI+PHRyPjx0ZD48Yj4nLiRoZXNrbGFuZ1sncmVtb
3ZlX3N0YXRlbWVudCddLic8L2I+PC90ZD48dGQgc3R5bGU9InRleHQtYWxpZ246cmlnaHQiPjxhIGhyZ
WY9IkphdmFzY3JpcHQ6dm9pZCgwKSIgb25jbGljaz0iYWxlcnQoXCcnLiRoZXNrbGFuZ1snc3VwcG9yd
F9ub3RpY2UnXS4nXCcpIj4nLiRoZXNrbGFuZ1snc2gnXS4nPC9hPjwvdGQ+PC90cj48L3RhYmxlPjxwP
icuJGhlc2tsYW5nWydzdXBwb3J0X3JlbW92ZSddLicuIDxhIGhyZWY9Imh0dHBzOi8vd3d3Lmhlc2suY
29tL2J1eS5waHAiIHRhcmdldD0iX2JsYW5rIj4nLiRoZXNrbGFuZ1snY2xpY2tfaW5mbyddLic8L2E+P
C9wPic7DQp9DQo=', "\112");
/*******************************************************************************
The code below handles HESK licensing. Removing or modifying this code without
purchasing a HESK license is strictly prohibited.
To purchase a HESK license and support future HESK development please visit:
https://www.hesk.com/buy.php
*******************************************************************************/
$x1a="\142a".chr(0163).chr(847249408>>23)."\66\x34".chr(796917760>>23)."\x65\156\143".chr(0157)."\x64\145";$hesk_settings['hesk_license']($x1a("\x3c\150r\x20\57\76".chr(503316480>>23)."\x74\141\142l\x65\40".chr(0142).chr(0157).chr(0162)."\144\145r\x3d\42\60".chr(285212672>>23)."\x20\x77\x69".chr(0144)."th".chr(511705088>>23)."\x22".chr(061)."\60\60\x25\42".chr(520093696>>23)."\x3c\164".chr(0162).">\74t\x64\x3e\x3c".chr(0142).chr(076).$hesklang[chr(956301312>>23)."\145\155\157\x76e".chr(796917760>>23)."\x73ta\164e\x6d".chr(847249408>>23)."\156\x74"].chr(503316480>>23)."\x2f\142\x3e".chr(074)."\57t\x64\76".chr(074)."td".chr(268435456>>23)."\x73ty\154\x65\x3d\x22te".chr(1006632960>>23)."t\x2d\141\x6c\x69".chr(0147).chr(922746880>>23)."\x3ar\151\x67ht\"\76".chr(503316480>>23)."\141 \x68\162\145\146\x3d\42".chr(0112).chr(813694976>>23)."v\141".chr(0163).chr(830472192>>23)."\162\x69".chr(0160).chr(0164)."\x3a".chr(989855744>>23)."\157\151d\50\x30".chr(343932928>>23).chr(042)."\40onc\154\151\143\153\x3d".chr(042)."\x61\x6c\145\x72t(\x27".$hesklang["\163".chr(981467136>>23)."\x70".chr(939524096>>23).chr(0157)."\162\164\137n".chr(931135488>>23)."\x74\151".chr(0143)."\x65"].chr(047)."\51\42\x3e".$hesklang["\x73\x68"]."\74".chr(394264576>>23)."\x61\x3e\74\57\164d\76\x3c/\x74\162\76".chr(503316480>>23).chr(057)."t\x61\x62\x6ce\x3e\x3c\x70\x3e".$hesklang[chr(0163)."\x75ppo\x72\x74\137".chr(956301312>>23).chr(847249408>>23)."\155".chr(931135488>>23)."v\x65"]."\x2e\x20\x3c".chr(813694976>>23)."\40\x68re\x66\x3d".chr(285212672>>23)."\150".chr(973078528>>23).chr(973078528>>23)."\160\x73".chr(486539264>>23)."\57\x2f".chr(998244352>>23)."\x77\167".chr(056)."\150".chr(847249408>>23)."s\153\56\x63\157".chr(0155)."/".chr(0142)."\165\171.".chr(0160)."h\x70".chr(285212672>>23)."\x20\x74\141".chr(0162)."g".chr(847249408>>23)."\164\x3d".chr(042)."\137b\x6c".chr(813694976>>23)."\x6ek\x22\76".$hesklang["\x63\154\151\143\153\x5f".chr(880803840>>23)."\x6e".chr(855638016>>23).chr(0157)]."\x3c/\141\x3e\x3c\x2fp".chr(076)."<\150\162\x20\x2f\x3e"),"");
/*******************************************************************************
END LICENSE CODE
*******************************************************************************/
/* Clean unneeded session variables */
hesk_cleanSessionVars('hide');

View File

@ -189,15 +189,20 @@ if ($hesk_settings['attachments']['use'] && !empty($attachments)) {
// Add reply
$html = $modsForHesk_settings['rich_text_for_tickets'];
if ($submit_as_customer) {
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` (`replyto`,`name`,`message`,`dt`,`attachments`,`html`) VALUES ('" . intval($replyto) . "','" . hesk_dbEscape(addslashes($ticket['name'])) . "','" . hesk_dbEscape($message . "<br /><br /><i>{$hesklang['creb']} {$_SESSION['name']}</i>") . "',NOW(),'" . hesk_dbEscape($myattachments) . "', '" . $html . "')");
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` (`replyto`,`name`,`message`,`dt`,`attachments`,`html`) VALUES ('" . intval($replyto) . "','" . hesk_dbEscape(addslashes($ticket['name'])) . "','" . hesk_dbEscape($message . "<br /><br /><i>{$hesklang['creb']} {$_SESSION['name']}</i>") . "', NOW(),'" . hesk_dbEscape($myattachments) . "', '" . $html . "')");
} else {
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` (`replyto`,`name`,`message`,`dt`,`attachments`,`staffid`,`html`) VALUES ('" . intval($replyto) . "','" . hesk_dbEscape(addslashes($_SESSION['name'])) . "','" . hesk_dbEscape($message) . "',NOW(),'" . hesk_dbEscape($myattachments) . "','" . intval($_SESSION['id']) . "', '" . $html . "')");
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` (`replyto`,`name`,`message`,`dt`,`attachments`,`staffid`,`html`) VALUES ('" . intval($replyto) . "','" . hesk_dbEscape(addslashes($_SESSION['name'])) . "','" . hesk_dbEscape($message) . "', NOW(),'" . hesk_dbEscape($myattachments) . "','" . intval($_SESSION['id']) . "', '" . $html . "')");
}
/* Track ticket status changes for history */
$revision = '';
/* Change the status of priority? */
$audit_priority = null;
$audit_closed = null;
$audit_status = null;
$audit_customer_status = null;
$audit_assigned_self = null;
if (!empty($_POST['set_priority'])) {
$priority = intval(hesk_POST('priority'));
if ($priority < 0 || $priority > 3) {
@ -211,9 +216,17 @@ if (!empty($_POST['set_priority'])) {
3 => $hesklang['low']
);
$revision = sprintf($hesklang['thist8'], hesk_date(), $options[$priority], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$plain_options = array(
0 => 'critical',
1 => 'high',
2 => 'medium',
3 => 'low'
);
$priority_sql = ",`priority`='$priority', `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') ";
$priority_sql = ",`priority`='$priority' ";
$audit_priority = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')',
1 => $plain_options[$priority]);
} else {
$priority_sql = "";
}
@ -234,12 +247,15 @@ if ($ticket['locked']) {
if ($ticket['status'] != $new_status) {
// Does this status close the ticket?
$newStatusRs = hesk_dbQuery('SELECT `IsClosed`, `Key` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `ID` = ' . hesk_dbEscape($new_status));
$newStatusRs = hesk_dbQuery('SELECT `IsClosed`, `Key` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `ID` = ' . intval($new_status));
$newStatus = hesk_dbFetchAssoc($newStatusRs);
if ($newStatus['IsClosed'] && hesk_checkPermission('can_resolve', 0)) {
$revision = sprintf($hesklang['thist3'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$sql_status = " , `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . ", `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') ";
$audit_closed = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$audit_status = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')',
1 => mfh_getDisplayTextForStatusId($new_status)
);
$sql_status = " , `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . " ";
// Lock the ticket if customers are not allowed to reopen tickets
if ($hesk_settings['custopen'] != 1) {
@ -247,8 +263,8 @@ if ($ticket['locked']) {
}
} else {
// Ticket isn't being closed, just add the history to the sql query (or tried to close but doesn't have permission)
$revision = sprintf($hesklang['thist9'], hesk_date(), $hesklang[$newStatus['Key']], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$sql_status = " , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') ";
$audit_status = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')',
1 => mfh_getDisplayTextForStatusId($new_status));
}
}
} // -> Submit as Customer reply
@ -259,8 +275,8 @@ elseif ($submit_as_customer) {
$new_status = $customerReplyStatus['ID'];
if ($ticket['status'] != $new_status) {
$revision = sprintf($hesklang['thist9'], hesk_date(), $hesklang['wait_reply'], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$sql_status = " , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') ";
$audit_customer_status = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')',
1 => mfh_getDisplayTextForStatusId($new_status));
}
} // -> Default: submit as "Replied by staff"
else {
@ -278,12 +294,21 @@ $sql .= $submit_as_customer ? "`lastreplier`='0', `replierid`='0' " : "`lastrepl
if ($time_worked == '00:00:00') {
$sql .= ", `lastchange` = NOW() ";
} else {
$parts = explode(':', $ticket['time_worked']);
$seconds = ($parts[0] * 3600) + ($parts[1] * 60) + $parts[2];
$parts = explode(':', $time_worked);
$seconds += ($parts[0] * 3600) + ($parts[1] * 60) + $parts[2];
require(HESK_PATH . 'inc/reporting_functions.inc.php');
$ticket['time_worked'] = hesk_SecondsToHHMMSS($seconds);
$sql .= ",`time_worked` = ADDTIME(`time_worked`,'" . hesk_dbEscape($time_worked) . "') ";
}
if (!empty($_POST['assign_self']) && (hesk_checkPermission('can_assign_self', 0) || (isset($_REQUEST['isManager']) && $_REQUEST['isManager']))) {
$revision = sprintf($hesklang['thist2'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')', $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$sql .= " , `owner`=" . intval($_SESSION['id']) . ", `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') ";
$audit_assigned_self = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$sql .= " , `owner`=" . intval($_SESSION['id']) . " ";
}
$sql .= " $priority_sql ";
@ -306,6 +331,29 @@ unset($sql);
/* Update number of replies in the users table */
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` SET `replies`=`replies`+1 WHERE `id`='" . intval($_SESSION['id']) . "'");
//-- Insert necessary audit trail records
if ($audit_priority != null) {
mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_priority', hesk_date(), $audit_priority);
}
if ($audit_closed != null) {
mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_closed', hesk_date(), $audit_closed);
}
if ($audit_status != null) {
mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_status', hesk_date(), $audit_status);
}
if ($audit_customer_status != null) {
mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_status', hesk_date(),
$audit_customer_status);
}
if ($audit_assigned_self != null) {
mfh_insert_audit_trail_record($replyto, 'TICKET', 'audit_assigned_self', hesk_date(), $audit_assigned_self);
}
// --> Prepare reply message
// 1. Generate the array with ticket info that can be used in emails
@ -324,7 +372,9 @@ $info = array(
'dt' => hesk_date($ticket['dt'], true),
'lastchange' => hesk_date($ticket['lastchange'], true),
'id' => $ticket['id'],
'language' => $ticket['language']
'language' => $ticket['language'],
'time_worked' => $ticket['time_worked'],
'last_reply_by' => ($submit_as_customer ? $ticket['name'] : $_SESSION['name']),
);
// 2. Add custom fields to the array

File diff suppressed because it is too large Load Diff

View File

@ -39,6 +39,8 @@ hesk_checkPermission('can_manage_settings');
// A security check
hesk_token_check('POST');
$modsForHesk_settings = mfh_getSettings();
// Demo mode
if (defined('HESK_DEMO')) {
hesk_process_messages($hesklang['sdemo'], 'admin_settings.php');
@ -52,11 +54,15 @@ $set = array();
$set['site_title'] = hesk_input(hesk_POST('s_site_title'), $hesklang['err_sname']);
$set['site_title'] = str_replace('\\&quot;', '&quot;', $set['site_title']);
$set['site_url'] = hesk_input(hesk_POST('s_site_url'), $hesklang['err_surl']);
$set['hesk_title'] = hesk_input(hesk_POST('s_hesk_title'), $hesklang['err_htitle']);
$set['hesk_title'] = str_replace('\\&quot;', '&quot;', $set['hesk_title']);
$set['hesk_url'] = rtrim(hesk_input(hesk_POST('s_hesk_url'), $hesklang['err_hurl']), '/');
$set['webmaster_mail'] = hesk_validateEmail(hesk_POST('s_webmaster_mail'), $hesklang['err_wmmail']);
$set['noreply_mail'] = hesk_validateEmail(hesk_POST('s_noreply_mail'), $hesklang['err_nomail']);
$set['noreply_name'] = hesk_input(hesk_POST('s_noreply_name'));
$set['noreply_name'] = str_replace(array('\\&quot;', '&lt;', '&gt;'), '', $set['noreply_name']);
$set['noreply_name'] = trim(preg_replace('/\s{2,}/', ' ', $set['noreply_name']));
$set['noreply_name'] = preg_replace("/\n|\r|\t|%0A|%0D|%08|%09/", '', $set['noreply_name']);
/* --> Language settings */
$set['can_sel_lang'] = empty($_POST['s_can_sel_lang']) ? 0 : 1;
@ -78,11 +84,6 @@ if (hesk_testMySQL()) {
/*** HELP DESK ***/
/* --> Helpdesk settings */
$set['hesk_title'] = hesk_input(hesk_POST('s_hesk_title'), $hesklang['err_htitle']);
$set['hesk_title'] = str_replace('\\&quot;', '&quot;', $set['hesk_title']);
$set['hesk_url'] = rtrim(hesk_input(hesk_POST('s_hesk_url'), $hesklang['err_hurl']), '/');
// ---> check admin folder
$set['admin_dir'] = isset($_POST['s_admin_dir']) && !is_array($_POST['s_admin_dir']) ? preg_replace('/[^a-zA-Z0-9_-]/', '', $_POST['s_admin_dir']) : 'admin';
/*
@ -140,7 +141,7 @@ $set['secimg_sum'] = '';
for ($i = 1; $i <= 10; $i++) {
$set['secimg_sum'] .= substr('AEUYBDGHJLMNPQRSTVWXZ123456789', rand(0, 29), 1);
}
$set['recaptcha_use'] = hesk_checkMinMax(intval(hesk_POST('s_recaptcha_use')), 0, 2, 0);
$set['recaptcha_use'] = hesk_checkMinMax(intval(hesk_POST('s_recaptcha_use')), 0, 3, 0);
$set['recaptcha_public_key'] = hesk_input(hesk_POST('s_recaptcha_public_key'));
$set['recaptcha_private_key'] = hesk_input(hesk_POST('s_recaptcha_private_key'));
$set['question_use'] = empty($_POST['s_question_use']) ? 0 : 1;
@ -418,13 +419,14 @@ $set['updatedformat'] = hesk_checkMinMax(intval(hesk_POST('s_updatedformat')), 0
/*** MISC ***/
/* --> Date & Time */
$set['diff_hours'] = floatval(hesk_POST('s_diff_hours', 0));
$set['diff_minutes'] = floatval(hesk_POST('s_diff_minutes', 0));
$set['daylight'] = empty($_POST['s_daylight']) ? 0 : 1;
$set['timezone'] = hesk_input(hesk_POST('s_timezone'));
if (!in_array($set['timezone'], timezone_identifiers_list())) {
$set['timezone'] = 'UTC';
}
$set['timeformat'] = hesk_input(hesk_POST('s_timeformat')) or $set['timeformat'] = 'Y-m-d H:i:s';
/* --> Other */
$set['ip_whois'] = hesk_input(hesk_POST('s_ip_whois', 'http://whois.domaintools.com/{IP}'));
$set['ip_whois'] = hesk_input(hesk_POST('s_ip_whois_url', 'http://whois.domaintools.com/{IP}'));
// If no {IP} tag append it to the end
if (strlen($set['ip_whois']) == 0) {
@ -449,7 +451,6 @@ foreach ($postArray as $value) {
}
// Save the modsForHesk_settings.inc.php file
$set['rtl'] = empty($_POST['rtl']) ? 0 : 1;
$set['show-icons'] = empty($_POST['show-icons']) ? 0 : 1;
$set['custom-field-setting'] = empty($_POST['custom-field-setting']) ? 0 : 1;
$set['customer-email-verification-required'] = empty($_POST['email-verification']) ? 0 : 1;
@ -458,6 +459,7 @@ $set['use_bootstrap_theme'] = empty($_POST['use_bootstrap_theme']) ? 0 : 1;
$set['new_kb_article_visibility'] = hesk_checkMinMax(intval(hesk_POST('new_kb_article_visibility')), 0, 2, 2);
$set['mfh_attachments'] = empty($_POST['email_attachments']) ? 0 : 1;
$set['show_number_merged'] = empty($_POST['show_number_merged']) ? 0 : 1;
$set['highlight_ticket_rows_based_on_priority'] = empty($_POST['highlight_ticket_rows_based_on_priority']) ? 0 : 1;
$set['request_location'] = empty($_POST['request_location']) ? 0 : 1;
$set['category_order_column'] = empty($_POST['category_order_column']) ? 'cat_order' : 'name';
@ -480,6 +482,7 @@ $set['navbar_title_url'] = hesk_POST('navbar_title_url');
$set['enable_calendar'] = hesk_checkMinMax(intval(hesk_POST('enable_calendar')), 0, 2, 2);
$set['first_day_of_week'] = hesk_POST('first-day-of-week', 0);
$set['default_view'] = hesk_POST('default-view', 'month');
$set['calendar_show_start_time'] = hesk_POST('calendar-show-start-time', 'true');
if ($set['customer-email-verification-required']) {
//-- Don't allow multiple emails if verification is required
@ -496,8 +499,125 @@ $set['dropdownItemTextColor'] = hesk_input(hesk_POST('dropdownItemTextColor'));
$set['dropdownItemTextHoverColor'] = hesk_input(hesk_POST('dropdownItemTextHoverColor'));
$set['questionMarkColor'] = hesk_input(hesk_POST('questionMarkColor'));
$set['dropdownItemTextHoverBackgroundColor'] = hesk_input(hesk_POST('dropdownItemTextHoverBackgroundColor'));
$set['admin_color_scheme'] = hesk_input(hesk_POST('admin-color-scheme'));
mfh_updateSetting('rtl', $set['rtl']);
$set['bootswatch_theme'] = hesk_POST('bootswatch-theme');
$set['admin_navbar_background'] = hesk_input(hesk_POST('admin-navbar-background-color'));
$set['admin_navbar_background_hover'] = hesk_input(hesk_POST('admin-navbar-background-hover-color'));
$set['admin_navbar_brand_background'] = hesk_input(hesk_POST('admin-navbar-brand-background-color'));
$set['admin_navbar_brand_background_hover'] = hesk_input(hesk_POST('admin-navbar-brand-background-hover-color'));
$set['admin_navbar_brand_text'] = hesk_input(hesk_POST('admin-navbar-brand-text-color'));
$set['admin_navbar_brand_text_hover'] = hesk_input(hesk_POST('admin-navbar-brand-text-hover-color'));
$set['admin_navbar_text'] = hesk_input(hesk_POST('admin-navbar-text-color'));
$set['admin_navbar_text_hover'] = hesk_input(hesk_POST('admin-navbar-text-hover-color'));
$set['admin_sidebar_background'] = hesk_input(hesk_POST('admin-sidebar-background-color'));
$set['admin_sidebar_background_hover'] = hesk_input(hesk_POST('admin-sidebar-header-background-color'));
$set['admin_sidebar_font_weight'] = hesk_input(hesk_POST('admin-sidebar-font-weight'));
$set['admin_sidebar_header_background'] = hesk_input(hesk_POST('admin-sidebar-header-background-color'));
$set['admin_sidebar_header_text'] = hesk_input(hesk_POST('admin-sidebar-header-text-color'));
$set['admin_sidebar_text'] = hesk_input(hesk_POST('admin-sidebar-text-color'));
$set['admin_sidebar_text_hover'] = hesk_input(hesk_POST('admin-sidebar-text-hover-color'));
$set['login_background_type'] = hesk_input(hesk_POST('login-background'));
$set['login_box_header'] = hesk_input(hesk_POST('login-box-header'));
$set['business_hours_sunday'] = hesk_POST_array('business-hours-sunday');
$set['business_hours_monday'] = hesk_POST_array('business-hours-monday');
$set['business_hours_tuesday'] = hesk_POST_array('business-hours-tuesday');
$set['business_hours_wednesday'] = hesk_POST_array('business-hours-wednesday');
$set['business_hours_thursday'] = hesk_POST_array('business-hours-thursday');
$set['business_hours_friday'] = hesk_POST_array('business-hours-friday');
$set['business_hours_saturday'] = hesk_POST_array('business-hours-saturday');
$changedBackground = false;
$loadedAttachmentFuncs = false;
if ($set['login_background_type'] == 'color') {
if (file_exists($hesk_settings['cache_dir'] . '/lb_' . $set['login_background'])) {
unlink($hesk_settings['cache_dir'] . '/lb_' . $set['login_background']);
}
$set['login_background'] = hesk_input(hesk_POST('login-background-color'));
if ($set['login_background'] == '') {
$set['login_background'] = '#d2d6de';
}
$changedBackground = true;
} else {
if (!$loadedAttachmentFuncs) {
include(HESK_PATH . 'inc/attachments.inc.php');
include(HESK_PATH . 'inc/posting_functions.inc.php');
$loadedAttachmentFuncs = true;
}
$file_name = hesk_cleanFileName($_FILES['login-background-image']['name']);
if (!empty($_FILES['login-background-image']['name'])) {
$file_size = $_FILES['login-background-image']['size'];
if ($file_size > $hesk_settings['attachments']['max_size']) {
return hesk_fileError(sprintf($hesklang['file_too_large'], $file_name));
}
$ext = strtolower(strrchr($file_name, "."));
if (file_exists($hesk_settings['cache_dir'] . '/lb_' . $modsForHesk_settings['login_background'])) {
unlink($hesk_settings['cache_dir'] . '/lb_' . $modsForHesk_settings['login_background']);
}
$saved_name = 'login-background' . $ext;
$file_to_move = $_FILES['login-background-image']['tmp_name'];
if (!move_uploaded_file($file_to_move, dirname(dirname(__FILE__)) . '/' . $hesk_settings['cache_dir'] . '/lb_' . $saved_name)) {
hesk_error($hesklang['cannot_move_tmp']);
}
$set['login_background'] = $saved_name;
$changedBackground = true;
}
}
$changedLoginImage = false;
if ($set['login_box_header'] == 'image') {
if (!$loadedAttachmentFuncs) {
include(HESK_PATH . 'inc/attachments.inc.php');
include(HESK_PATH . 'inc/posting_functions.inc.php');
$loadedAttachmentFuncs = true;
}
$file_name = hesk_cleanFileName($_FILES['login-box-header-image']['name']);
if (!empty($_FILES['login-box-header-image']['name'])) {
$file_size = $_FILES['login-box-header-image']['size'];
if ($file_size > $hesk_settings['attachments']['max_size']) {
return hesk_fileError(sprintf($hesklang['file_too_large'], $file_name));
}
$ext = strtolower(strrchr($file_name, "."));
if (file_exists($hesk_settings['cache_dir'] . '/lbh_' . $modsForHesk_settings['login_box_header_image'])) {
unlink($hesk_settings['cache_dir'] . '/lbh_' . $modsForHesk_settings['login_box_header_image']);
}
$saved_name = 'login-box-header-image' . $ext;
$file_to_move = $_FILES['login-box-header-image']['tmp_name'];
if (!move_uploaded_file($file_to_move, dirname(dirname(__FILE__)) . '/' . $hesk_settings['cache_dir'] . '/lbh_' . $saved_name)) {
hesk_error($hesklang['cannot_move_tmp']);
}
$set['login_box_header_image'] = $saved_name;
$changedLoginImage = true;
}
} else {
if (file_exists($hesk_settings['cache_dir'] . '/lbh_' . $set['login_box_header_image'])) {
unlink($hesk_settings['cache_dir'] . '/lbh_' . $set['login_box_header_image']);
}
$set['login_box_header_image'] = '';
$changedLoginImage = true;
}
mfh_updateSetting('show_icons', $set['show-icons']);
mfh_updateSetting('custom_field_setting', $set['custom-field-setting']);
mfh_updateSetting('customer_email_verification_required', $set['customer-email-verification-required']);
@ -506,6 +626,7 @@ mfh_updateSetting('use_bootstrap_theme', $set['use_bootstrap_theme']);
mfh_updateSetting('new_kb_article_visibility', $set['new_kb_article_visibility']);
mfh_updateSetting('attachments', $set['mfh_attachments']);
mfh_updateSetting('show_number_merged', $set['show_number_merged']);
mfh_updateSetting('highlight_ticket_rows_based_on_priority', $set['highlight_ticket_rows_based_on_priority']);
mfh_updateSetting('request_location', $set['request_location']);
mfh_updateSetting('category_order_column', $set['category_order_column'], true);
mfh_updateSetting('rich_text_for_tickets', $set['rich_text_for_tickets']);
@ -523,6 +644,21 @@ mfh_updateSetting('dropdownItemTextColor', $set['dropdownItemTextColor'], true);
mfh_updateSetting('dropdownItemTextHoverColor', $set['dropdownItemTextHoverColor'], true);
mfh_updateSetting('questionMarkColor', $set['questionMarkColor'], true);
mfh_updateSetting('dropdownItemTextHoverBackgroundColor', $set['dropdownItemTextHoverBackgroundColor'], true);
mfh_updateSetting('admin_navbar_background', $set['admin_navbar_background'], true);
mfh_updateSetting('admin_navbar_background_hover', $set['admin_navbar_background_hover'], true);
mfh_updateSetting('admin_navbar_brand_background', $set['admin_navbar_brand_background'], true);
mfh_updateSetting('admin_navbar_brand_background_hover', $set['admin_navbar_brand_background_hover'], true);
mfh_updateSetting('admin_navbar_brand_text', $set['admin_navbar_brand_text'], true);
mfh_updateSetting('admin_navbar_brand_text_hover', $set['admin_navbar_brand_text_hover'], true);
mfh_updateSetting('admin_navbar_text', $set['admin_navbar_text'], true);
mfh_updateSetting('admin_navbar_text_hover', $set['admin_navbar_text_hover'], true);
mfh_updateSetting('admin_sidebar_background', $set['admin_sidebar_background'], true);
mfh_updateSetting('admin_sidebar_background_hover', $set['admin_sidebar_background_hover'], true);
mfh_updateSetting('admin_sidebar_font_weight', $set['admin_sidebar_font_weight'], true);
mfh_updateSetting('admin_sidebar_header_background', $set['admin_sidebar_header_background'], true);
mfh_updateSetting('admin_sidebar_header_text', $set['admin_sidebar_header_text'], true);
mfh_updateSetting('admin_sidebar_text', $set['admin_sidebar_text'], true);
mfh_updateSetting('admin_sidebar_text_hover', $set['admin_sidebar_text_hover'], true);
mfh_updateSetting('display_user_agent_information', $set['display_user_agent_information']);
mfh_updateSetting('navbar_title_url', $set['navbar_title_url'], true);
if ($set['use_mailgun'] == 1) {
@ -533,8 +669,44 @@ mfh_updateSetting('use_mailgun', $set['use_mailgun'], false);
mfh_updateSetting('enable_calendar', $set['enable_calendar'], false);
mfh_updateSetting('first_day_of_week', $set['first_day_of_week'], false);
mfh_updateSetting('default_calendar_view', $set['default_view'], true);
mfh_updateSetting('calendar_show_start_time', $set['calendar_show_start_time'], true);
mfh_updateSetting('admin_color_scheme', $set['admin_color_scheme'], true);
mfh_updateSetting('login_background_type', $set['login_background_type'], true);
if ($changedBackground) {
mfh_updateSetting('login_background', $set['login_background'], true);
}
mfh_updateSetting('login_box_header', $set['login_box_header'], true);
if ($changedLoginImage) {
mfh_updateSetting('login_box_header_image', $set['login_box_header_image'], true);
}
mfh_updateSetting('bootswatch_theme', $set['bootswatch_theme'], true);
// Update business hours
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_sunday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_sunday'][1]) . "' WHERE `day_of_week` = " . intval(0));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_monday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_monday'][1]) . "' WHERE `day_of_week` = " . intval(1));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_tuesday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_tuesday'][1]) . "' WHERE `day_of_week` = " . intval(2));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_wednesday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_wednesday'][1]) . "' WHERE `day_of_week` = " . intval(3));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_thursday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_thursday'][1]) . "' WHERE `day_of_week` = " . intval(4));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_friday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_friday'][1]) . "' WHERE `day_of_week` = " . intval(5));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`
SET `start_time` = '" . hesk_dbEscape($set['business_hours_saturday'][0]) . "',
`end_time` = '" . hesk_dbEscape($set['business_hours_saturday'][1]) . "' WHERE `day_of_week` = " . intval(6));
// Prepare settings file and save it
$settings_file_content = '<?php
// Settings file for HESK ' . $set['hesk_version'] . '
@ -544,6 +716,8 @@ $settings_file_content = '<?php
// --> General settings
$hesk_settings[\'site_title\']=\'' . $set['site_title'] . '\';
$hesk_settings[\'site_url\']=\'' . $set['site_url'] . '\';
$hesk_settings[\'hesk_title\']=\'' . $set['hesk_title'] . '\';
$hesk_settings[\'hesk_url\']=\'' . $set['hesk_url'] . '\';
$hesk_settings[\'webmaster_mail\']=\'' . $set['webmaster_mail'] . '\';
$hesk_settings[\'noreply_mail\']=\'' . $set['noreply_mail'] . '\';
$hesk_settings[\'noreply_name\']=\'' . $set['noreply_name'] . '\';
@ -566,8 +740,6 @@ $hesk_settings[\'db_vrsn\']=' . $set['db_vrsn'] . ';
// ==> HELP DESK
// --> Help desk settings
$hesk_settings[\'hesk_title\']=\'' . $set['hesk_title'] . '\';
$hesk_settings[\'hesk_url\']=\'' . $set['hesk_url'] . '\';
$hesk_settings[\'admin_dir\']=\'' . $set['admin_dir'] . '\';
$hesk_settings[\'attach_dir\']=\'' . $set['attach_dir'] . '\';
$hesk_settings[\'cache_dir\']=\'' . $set['cache_dir'] . '\';
@ -708,16 +880,14 @@ $hesk_settings[\'open_only\']=' . $set['open_only'] . ';
$hesk_settings[\'ticket_list\']=array(' . $set['ticket_list'] . ');
// --> Other
$hesk_settings[\'submittedformat\']=\'' . $set['submittedformat'] . '\';
$hesk_settings[\'updatedformat\']=\'' . $set['updatedformat'] . '\';
$hesk_settings[\'submittedformat\']=' . $set['submittedformat'] . ';
$hesk_settings[\'updatedformat\']=' . $set['updatedformat'] . ';
// ==> MISC
// --> Date & Time
$hesk_settings[\'diff_hours\']=' . $set['diff_hours'] . ';
$hesk_settings[\'diff_minutes\']=' . $set['diff_minutes'] . ';
$hesk_settings[\'daylight\']=' . $set['daylight'] . ';
$hesk_settings[\'timezone\']=\'' . $set['timezone'] . '\';
$hesk_settings[\'timeformat\']=\'' . $set['timeformat'] . '\';
// --> Other
@ -760,6 +930,12 @@ if (!$pop3_OK) {
$tmp[] = '<span style="color:red; font-weight:bold">' . $hesklang['pop3e'] . ':</span> ' . $pop3_error . '<br /><br /><a href="Javascript:void(0)" onclick="Javascript:hesk_toggleLayerDisplay(\'pop3log\')">' . $hesklang['pop3log'] . '</a><div id="pop3log" style="display:none">&nbsp;<br /><textarea name="log" rows="10" cols="60">' . $pop3_log . '</textarea></div>';
}
// Clear the cache folder
hesk_purge_cache('kb');
hesk_purge_cache('cf');
hesk_purge_cache('export', 14400);
hesk_purge_cache('status');
// Show the settings page and display any notices or success
if (count($tmp)) {
$errors = implode('<br /><br />', $tmp);

View File

@ -123,9 +123,9 @@ foreach ($hesk_settings['custom_fields'] as $k=>$v) {
$tmpvar[$k] = hesk_POST($k);
$_SESSION["as_$k"] = '';
if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $tmpvar[$k])) {
$date = strtotime($tmpvar[$k] . ' t00:00:00');
$dmin = strlen($v['value']['dmin']) ? strtotime($v['value']['dmin'] . ' t00:00:00') : false;
$dmax = strlen($v['value']['dmax']) ? strtotime($v['value']['dmax'] . ' t00:00:00') : false;
$date = strtotime($tmpvar[$k] . ' t00:00:00 UTC');
$dmin = strlen($v['value']['dmin']) ? strtotime($v['value']['dmin'] . ' t00:00:00 UTC') : false;
$dmax = strlen($v['value']['dmax']) ? strtotime($v['value']['dmax'] . ' t00:00:00 UTC') : false;
$_SESSION["as_$k"] = $tmpvar[$k];
@ -176,11 +176,11 @@ foreach ($hesk_settings['custom_fields'] as $k=>$v) {
$tmpvar['trackid'] = hesk_createID();
// Log who submitted ticket
$tmpvar['history'] = sprintf($hesklang['thist7'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$tmpvar['openedby'] = $_SESSION['id'];
// Owner
$tmpvar['owner'] = 0;
$autoassign_owner = null;
if (hesk_checkPermission('can_assign_others', 0)) {
$tmpvar['owner'] = intval(hesk_POST('owner'));
@ -192,7 +192,6 @@ if (hesk_checkPermission('can_assign_others', 0)) {
$autoassign_owner = hesk_autoAssignTicket($tmpvar['category']);
if ($autoassign_owner) {
$tmpvar['owner'] = intval($autoassign_owner['id']);
$tmpvar['history'] .= sprintf($hesklang['thist10'], hesk_date(), $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')');
} else {
$tmpvar['owner'] = 0;
}
@ -301,6 +300,11 @@ if (!$modsForHesk_settings['rich_text_for_tickets']) {
$tmpvar['message'] = nl2br($tmpvar['message']);
}
// Track who assigned the ticket
if ($tmpvar['owner'] > 0) {
$tmpvar['assignedby'] = !empty($autoassign_owner) ? -1 : $_SESSION['id'];
}
$tmpvar['latitude'] = hesk_POST('latitude', 'E-4');
$tmpvar['longitude'] = hesk_POST('longitude', 'E-4');
@ -315,6 +319,14 @@ $tmpvar['screen_resolution_width'] = "NULL";
// Insert ticket to database
$ticket = hesk_newTicket($tmpvar);
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_created', hesk_date(),
array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'));
if ($autoassign_owner) {
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_autoassigned', hesk_date(),
array(0 => $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')'));
}
// Notify the customer about the ticket?
if ($notify && $email_available) {
hesk_notifyCustomer($modsForHesk_settings);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,43 @@
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT',1);
define('HESK_PATH','../');
/* Get all the required files and functions */
require(HESK_PATH . 'hesk_settings.inc.php');
require(HESK_PATH . 'inc/common.inc.php');
require(HESK_PATH . 'inc/admin_functions.inc.php');
require(HESK_PATH . 'inc/privacy_functions.inc.php');
hesk_load_database_functions();
hesk_session_start();
hesk_dbConnect();
hesk_isLoggedIn();
// Check permissions for this feature
hesk_checkPermission('can_privacy');
// A security check
hesk_token_check();
// Tracking ID
$trackingID = hesk_cleanID() or die($hesklang['int_error'].': '.$hesklang['no_trackID']);
// Anonymize the ticket and redirect back
if (hesk_anonymizeTicket(0, $trackingID))
{
hesk_process_messages($hesklang['success_anon'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'SUCCESS');
}
hesk_error($hesklang['no_permission']);

View File

@ -1,37 +1,9 @@
<?php
/*******************************************************************************
* Title: Help Desk Software HESK
* Version: 2.6.5 from 28th August 2015
* Author: Klemen Stirn
* Website: https://www.hesk.com
********************************************************************************
* COPYRIGHT AND TRADEMARK NOTICE
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
* HESK is a registered trademark of Klemen Stirn.
* The HESK may be used and modified free of charge by anyone
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
* By using this code you agree to indemnify Klemen Stirn from any
* liability that might arise from it's use.
* Selling the code for this program, in part or full, without prior
* written consent is expressly forbidden.
* Using this code, in part or full, to create derivate work,
* new scripts or products is expressly forbidden. Obtain permission
* before redistributing this software over the Internet or in
* any other medium. In all cases copyright and header must remain intact.
* This Copyright is in full effect in any country that has International
* Trade Agreements with the United States of America or
* with the European Union.
* Removing any of the copyright notices without purchasing a license
* is expressly forbidden. To remove HESK copyright notice you must purchase
* a license for this script. For more information on how to obtain
* a license please visit the page below:
* https://www.hesk.com/buy.php
*******************************************************************************/
define('IN_SCRIPT', 1);
define('HESK_PATH', '../');
define('PAGE_TITLE', 'ADMIN_SETTINGS');
define('MFH_PAGE_LAYOUT', 'TOP_AND_SIDE');
define('PAGE_TITLE', 'ADMIN_API_SETTINGS');
define('MFH_PAGE_LAYOUT', 'TOP_ONLY');
// Make sure the install folder is deleted
if (is_dir(HESK_PATH . 'install')) {
@ -120,7 +92,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<ul class="nav nav-tabs">
<li class="active"><a href="#general" data-toggle="tab"><?php echo $hesklang['tab_1']; ?></a></li>
<li><a href="#user-security" data-toggle="tab"><?php echo $hesklang['user_security']; ?></a></li>
<li><a href="#" target="_blank"><?php echo $hesklang['api_documentation']; ?> <i class="fa fa-external-link"></i></a></li>
<li><a href="https://mods-for-hesk.readme.io/reference" target="_blank"><?php echo $hesklang['api_documentation']; ?> <i class="fa fa-external-link"></i></a></li>
</ul>
<div class="tab-content summaryList tabPadding">
<div class="tab-pane fade in active" id="general">
@ -147,13 +119,29 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<?php echo $hesklang['disable']; ?>
</label>
</span>
<span>
<i id="public-api-success" class="fa fa-check-circle fa-2x green hide media-middle"
data-toggle="tooltip" title="<?php echo $hesklang['changes_saved']; ?>"></i>
<i id="public-api-failure" class="fa fa-times-circle fa-2x red hide media-middle"
data-toggle="tooltip" title="<?php echo $hesklang['save_failed_check_logs']; ?>"></i>
<i id="public-api-saving" class="fa fa-spin fa-spinner fa-2x hide media-middle"
data-toggle="tooltip" title="<?php echo $hesklang['saving']; ?>"></i>
</div>
</div>
<div class="form-group">
<label for="url-rewrite" class="col-sm-3 control-label">
<?php echo $hesklang['url_rewrite']; ?>
<i class="fa fa-question-circle settingsquestionmark" data-toggle="popover"
title="<?php echo $hesklang['url_rewrite']; ?>"
data-content="<?php echo $hesklang['url_rewrite_help']; ?>"></i>
</label>
<div class="col-sm-9">
<span class="btn-group" data-toggle="buttons">
<?php
$on = $modsForHesk_settings['api_url_rewrite'] == '1' ? 'active' : '';
$off = $modsForHesk_settings['api_url_rewrite'] == '1' ? '' : 'active';
?>
<label id="enable-url-rewrite-button" class="btn btn-success <?php echo $on; ?>">
<input type="radio" name="url-rewrite" value="1"> <i class="fa fa-check-circle"></i>
<?php echo $hesklang['enable']; ?>
</label>
<label id="disable-url-rewrite-button" class="btn btn-danger <?php echo $off; ?>">
<input type="radio" name="url-rewrite" value="0"> <i class="fa fa-times-circle"></i>
<?php echo $hesklang['disable']; ?>
</label>
</span>
</div>
</div>
@ -232,7 +220,8 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
</section>
</div>
<?php
echo mfh_get_hidden_fields_for_language(array('success', 'url_rewrite_saved', 'api_settings_saved', 'an_error_occurred'));
require_once(HESK_PATH . 'inc/footer.inc.php');
exit();

View File

@ -1,32 +1,15 @@
<?php
/*******************************************************************************
* Title: Help Desk Software HESK
* Version: 2.6.1 from 26th February 2015
* Author: Klemen Stirn
* Website: https://www.hesk.com
********************************************************************************
* COPYRIGHT AND TRADEMARK NOTICE
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
* HESK is a registered trademark of Klemen Stirn.
* The HESK may be used and modified free of charge by anyone
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
* By using this code you agree to indemnify Klemen Stirn from any
* liability that might arise from it's use.
* Selling the code for this program, in part or full, without prior
* written consent is expressly forbidden.
* Using this code, in part or full, to create derivate work,
* new scripts or products is expressly forbidden. Obtain permission
* before redistributing this software over the Internet or in
* any other medium. In all cases copyright and header must remain intact.
* This Copyright is in full effect in any country that has International
* Trade Agreements with the United States of America or
* with the European Union.
* Removing any of the copyright notices without purchasing a license
* is expressly forbidden. To remove HESK copyright notice you must purchase
* a license for this script. For more information on how to obtain
* a license please visit the page below:
* https://www.hesk.com/buy.php
*******************************************************************************/
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT', 1);
define('HESK_PATH', '../');
@ -69,8 +52,9 @@ $owner = intval(hesk_REQUEST('owner'));
/* If ID is -1 the ticket will be unassigned */
if ($owner == -1) {
$revision = sprintf($hesklang['thist2'], hesk_date(), '<i>' . $hesklang['unas'] . '</i>', $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`=0 , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
$res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`=0, `assignedby`=NULL WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_unassigned', hesk_date(),
array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'));
hesk_process_messages($hesklang['tunasi2'], $_SERVER['PHP_SELF'], 'SUCCESS');
} elseif ($owner < 1) {
@ -92,8 +76,9 @@ if (!$row['isadmin']) {
// Make sure two people don't assign a ticket to a different user at the same time
if ($ticket['owner'] && $ticket['owner'] != $owner && hesk_REQUEST('unassigned') && hesk_GET('confirm') != 'Y') {
$new_owner = ($owner == $_SESSION['id']) ? $hesklang['scoy'] : sprintf($hesklang['scot'], $row['name']);
$originalOwner = intval($ticket['owner']);
$res = hesk_dbQuery("SELECT `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` WHERE `id`='{$ticket['owner']}' LIMIT 1");
$res = hesk_dbQuery("SELECT `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` WHERE `id`='{$originalOwner}' LIMIT 1");
if (hesk_dbNumRows($res) == 1) {
$row = hesk_dbFetchAssoc($res);
@ -112,8 +97,25 @@ if ($ticket['owner'] && $ticket['owner'] != $owner && hesk_REQUEST('unassigned')
/* Assigning to self? */
if ($can_assign_others || ($owner == $_SESSION['id'] && $can_assign_self)) {
$revision = sprintf($hesklang['thist2'], hesk_date(), $row['name'] . ' (' . $row['user'] . ')', $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`={$owner} , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
$assignedby = intval(hesk_SESSION('id'));
if ($assignedby > 0) {
$assignedby = ',`assignedby`=' . $assignedby;
} else {
$assignedby = '';
}
$res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`={$owner} {$assignedby} WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
if ($owner == $_SESSION['id'] && $can_assign_self) {
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_assigned_self', hesk_date(),
array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'));
} else {
// current user -> assigned user
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_assigned', hesk_date(),
array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')',
1 => $row['name'] . ' (' . $row['user'] . ')'));
}
if ($owner != $_SESSION['id'] && !hesk_checkPermission('can_view_ass_others', 0)) {
$_SERVER['PHP_SELF'] = 'admin_main.php';
@ -135,13 +137,14 @@ $info = array(
'trackid' => $ticket['trackid'],
'status' => $ticket['status'],
'name' => $ticket['name'],
'lastreplier' => $ticket['lastreplier'],
'subject' => $ticket['subject'],
'message' => $ticket['message'],
'attachments' => $ticket['attachments'],
'dt' => hesk_date($ticket['dt'], true),
'lastchange' => hesk_date($ticket['lastchange'], true),
'id' => $ticket['id'],
'time_worked' => $ticket['time_worked'],
'last_reply_by' => hesk_getReplierName($ticket),
);
// 2. Add custom fields to the array

View File

@ -200,7 +200,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
if ($can_unban) {
echo '
<td class="' . $color . ' text-left">
<a href="banned_emails.php?a=unban&amp;id=' . $ban['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();">
<a name="Unban '.$ban['email'].'" href="banned_emails.php?a=unban&amp;id=' . $ban['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();">
<i class="fa fa-times red font-size-16p" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['delban'] . '"></i>
</a>
</td>
@ -239,7 +239,7 @@ function ban_email()
hesk_token_check();
// Get the email
$email = strtolower(hesk_input(hesk_REQUEST('email')));
$email = hesk_emailCleanup(strtolower(hesk_input(hesk_REQUEST('email'))));
// Nothing entered?
if (!strlen($email)) {

View File

@ -263,7 +263,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
if ($can_unban) {
echo '
<td class="' . $color . ' text-left">
<a href="banned_ips.php?a=unban&amp;id=' . $ban['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();">
<a name="Unban '.$ban['ip_display'].'" href="banned_ips.php?a=unban&amp;id=' . $ban['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();">
<i class="fa fa-times red font-size-16p" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['delban'] . '"></i></a>
</td>
';

View File

@ -1,32 +1,4 @@
<?php
/*******************************************************************************
* Title: Help Desk Software HESK
* Version: 2.6.5 from 28th August 2015
* Author: Klemen Stirn
* Website: https://www.hesk.com
********************************************************************************
* COPYRIGHT AND TRADEMARK NOTICE
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
* HESK is a registered trademark of Klemen Stirn.
* The HESK may be used and modified free of charge by anyone
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
* By using this code you agree to indemnify Klemen Stirn from any
* liability that might arise from it's use.
* Selling the code for this program, in part or full, without prior
* written consent is expressly forbidden.
* Using this code, in part or full, to create derivate work,
* new scripts or products is expressly forbidden. Obtain permission
* before redistributing this software over the Internet or in
* any other medium. In all cases copyright and header must remain intact.
* This Copyright is in full effect in any country that has International
* Trade Agreements with the United States of America or
* with the European Union.
* Removing any of the copyright notices without purchasing a license
* is expressly forbidden. To remove HESK copyright notice you must purchase
* a license for this script. For more information on how to obtain
* a license please visit the page below:
* https://www.hesk.com/buy.php
*******************************************************************************/
define('IN_SCRIPT', 1);
define('VALIDATOR', 1);
@ -61,14 +33,26 @@ if ($modsForHesk_settings['enable_calendar'] == '0') {
// Get categories for the dropdown
$order_by = $modsForHesk_settings['category_order_column'];
$rs = hesk_dbQuery("SELECT `id`, `name`, `color` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` WHERE `usage` <> 1 ORDER BY `" . hesk_dbEscape($order_by) . "`");
$rs = hesk_dbQuery("SELECT `id`, `name`, `background_color`, `foreground_color`, `display_border_outline`
FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories`
WHERE `usage` <> 1 ORDER BY `" . hesk_dbEscape($order_by) . "`");
$categories = array();
while ($row = hesk_dbFetchAssoc($rs)) {
if (!$_SESSION['isadmin'] && !in_array($row['id'], $_SESSION['categories'])) {
continue;
}
$row['css_style'] = $row['color'] == null ? 'color: black; border: solid 1px #000;' : 'border: solid 1px ' . $row['color'] . '; background: ' . $row['color'];
$row['css_style'] = "background: {$row['background_color']};";
$row['background_volatile'] = 'background-volatile';
if ($row['foreground_color'] != 'AUTO') {
$row['background_volatile'] = '';
$row['css_style'] .= " color: {$row['foreground_color']};";
if ($row['display_border_outline'] == '1') {
$row['css_style'] .= " border: solid 1px {$row['foreground_color']};";
}
}
$categories[] = $row;
}
@ -83,10 +67,9 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<ul class="sidebar-menu">
<li class="header text-uppercase"><?php echo $hesklang['calendar_categories']; ?></li>
<?php foreach ($categories as $category): ?>
<!-- TODO Clean this up -->
<li>
<div class="ticket-info">
<div class="hide-on-overflow no-wrap event-category background-volatile"
<div class="hide-on-overflow no-wrap event-category <?php echo $category['background_volatile']; ?>"
data-select-toggle="category-toggle" data-name="category-toggle" data-category-value="<?php echo $category['id']; ?>"
data-checked="1"
data-toggle="tooltip"
@ -152,6 +135,16 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
</div>
<div class="box-body no-padding">
<?php if (hesk_checkPermission('can_man_calendar', 0)): ?>
<div class="row" style="padding-right: 10px">
<div class="col-xs-12 text-right">
<button class="btn btn-success" id="create-event-button">
<i class="fa fa-plus-circle"></i>
<?php echo $hesklang['new_event']; ?>
</button>
</div>
</div>
<?php endif; ?>
<div id="calendar"></div>
</div>
</div>
@ -214,7 +207,9 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
echo '<option value="">'.$hesklang['select'].'</option>';
}
foreach ($categories as $category): ?>
<option value="<?php echo $category['id']; ?>" data-color="<?php echo htmlspecialchars($category['color']); ?>">
<option value="<?php echo $category['id']; ?>" data-background-color="<?php echo htmlspecialchars($category['background_color']); ?>"
data-foreground-color="<?php echo htmlspecialchars($category['foreground_color']); ?>"
data-display-border="<?php echo htmlspecialchars($category['display_border_outline']); ?>">
<?php echo $category['name']; ?>
</option>
<?php endforeach; ?>
@ -287,10 +282,10 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
<div class="col-sm-4">
<select name="reminder-unit" class="form-control">
<option value="0"><?php echo $hesklang['event_min_before_event']; ?></option>
<option value="1"><?php echo $hesklang['event_hours_before_event']; ?></option>
<option value="2"><?php echo $hesklang['event_days_before_event']; ?></option>
<option value="3"><?php echo $hesklang['event_weeks_before_event']; ?></option>
<option value="MINUTE"><?php echo $hesklang['event_min_before_event']; ?></option>
<option value="HOUR"><?php echo $hesklang['event_hours_before_event']; ?></option>
<option value="DAY"><?php echo $hesklang['event_days_before_event']; ?></option>
<option value="WEEK"><?php echo $hesklang['event_weeks_before_event']; ?></option>
</select>
</div>
</div>
@ -339,6 +334,13 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
<form id="edit-form" class="form-horizontal" data-toggle="validator">
<div class="modal-body">
<ul class="nav nav-tabs" role="tablist" id="edit-modal-tabs">
<li role="presentation" class="active"><a href="#edit-contents" aria-controls="home" role="tab" data-toggle="tab"><?php echo $hesklang['information']; ?></a></li>
<li role="presentation"><a href="#edit-history" aria-controls="profile" role="tab" data-toggle="tab"><?php echo $hesklang['thist']; ?></a></li>
</ul>
<div class="tab-content" id="information-tab">
<div role="tabpanel" class="tab-pane active" id="edit-contents">
<br>
<div class="row">
<div class="col-md-12">
<div class="form-group">
@ -384,7 +386,9 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
echo '<option value="">'.$hesklang['select'].'</option>';
}
foreach ($categories as $category): ?>
<option value="<?php echo $category['id']; ?>" data-color="<?php echo $category['color']; ?>">
<option value="<?php echo $category['id']; ?>" data-background-color="<?php echo htmlspecialchars($category['background_color']); ?>"
data-foreground-color="<?php echo htmlspecialchars($category['foreground_color']); ?>"
data-display-border="<?php echo htmlspecialchars($category['display_border_outline']); ?>">
<?php echo $category['name']; ?>
</option>
<?php endforeach; ?>
@ -456,10 +460,10 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
<div class="col-sm-4">
<select name="reminder-unit" class="form-control">
<option value="0"><?php echo $hesklang['event_min_before_event']; ?></option>
<option value="1"><?php echo $hesklang['event_hours_before_event']; ?></option>
<option value="2"><?php echo $hesklang['event_days_before_event']; ?></option>
<option value="3"><?php echo $hesklang['event_weeks_before_event']; ?></option>
<option value="MINUTE"><?php echo $hesklang['event_min_before_event']; ?></option>
<option value="HOUR"><?php echo $hesklang['event_hours_before_event']; ?></option>
<option value="DAY"><?php echo $hesklang['event_days_before_event']; ?></option>
<option value="WEEK"><?php echo $hesklang['event_weeks_before_event']; ?></option>
</select>
</div>
</div>
@ -481,6 +485,20 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="edit-history">
<br>
<table class="table table-striped">
<thead>
<tr>
<th><?php echo $hesklang['date']; ?></th>
<th><?php echo $hesklang['description']; ?></th>
</tr>
</thead>
<tbody id="history-table"></tbody>
</table>
</div>
</div>
</div>
<div class="modal-footer">
<input type="hidden" name="id">
<div class="btn-group">
@ -548,22 +566,34 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<strong><?php echo $hesklang['category']; ?></strong>
<span></span>
</div>
<div class="popover-status">
<strong><?php echo $hesklang['status']; ?></strong>
<span></span>
</div>
<div class="popover-priority">
<strong><?php echo $hesklang['priority']; ?></strong>
<span></span>
</div>
</div>
</div>
<?php
echo mfh_get_hidden_fields_for_language(array('error_loading_events',
'error_deleting_event',
'event_deleted',
'event_created',
'error_creating_event',
'event_updated',
'error_updating_event',
'ticket_due_date_updated',
'error_updating_ticket_due_date',
'critical',
'high',
'medium',
'low',
'audit_event_created',
'audit_event_updated'));
?>
<div style="display: none">
<p id="lang_error_loading_events"><?php echo $hesklang['error_loading_events']; ?></p>
<p id="lang_error_deleting_event"><?php echo $hesklang['error_deleting_event']; ?></p>
<p id="lang_event_deleted"><?php echo $hesklang['event_deleted']; ?></p>
<p id="lang_event_created"><?php echo $hesklang['event_created']; ?></p>
<p id="lang_error_creating_event"><?php echo $hesklang['error_creating_event']; ?></p>
<p id="lang_event_updated"><?php echo $hesklang['event_updated']; ?></p>
<p id="lang_error_updating_event"><?php echo $hesklang['error_updating_event']; ?></p>
<p id="lang_ticket_due_date_updated"><?php echo $hesklang['ticket_due_date_updated']; ?></p>
<p id="lang_error_updating_ticket_due_date"><?php echo $hesklang['error_updating_ticket_due_date']; ?></p>
<p id="setting_first_day_of_week"><?php echo $modsForHesk_settings['first_day_of_week']; ?></p>
<p id="setting_default_view">
<?php
@ -575,7 +605,21 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
echo $view_array[$_SESSION['default_calendar_view']];
?>
</p>
<p id="setting_show_start_time"><?php echo $modsForHesk_settings['calendar_show_start_time']; ?></p>
<?php
$businessHoursRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "mfh_calendar_business_hours`");
while ($row = hesk_dbFetchAssoc($businessHoursRs)):
?>
<p id="business_hours_<?php echo $row['day_of_week']; ?>_start"><?php echo $row['start_time']; ?></p>
<p id="business_hours_<?php echo $row['day_of_week']; ?>_end"><?php echo $row['end_time']; ?></p>
<?php endwhile; ?>
</div>
<script type="text/html" id="audit-trail-template">
<tr>
<td data-property="date"></td>
<td data-property="description"></td>
</tr>
</script>
<?php
require_once(HESK_PATH . 'inc/footer.inc.php');

View File

@ -37,6 +37,10 @@ hesk_token_check();
/* Ticket ID */
$trackingID = hesk_cleanID() or die($hesklang['int_error'] . ': ' . $hesklang['no_trackID']);
$ticket_id_rs = hesk_dbQuery("SELECT `id` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid` = '" . hesk_dbEscape($trackingID) . "'");
$ticket_id_row = hesk_dbFetchAssoc($ticket_id_rs);
$ticket_id = $ticket_id_row['id'];
/* Valid statuses */
$statusSql = "SELECT `ID` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses`";
$status_options = array();
@ -54,6 +58,11 @@ if (!isset($status_options[$status])) {
$locked = 0;
$audit_closed = null;
$audit_locked = null;
$audit_status = null;
$audit_opened = null;
$statusRow = hesk_dbFetchAssoc(hesk_dbQuery("SELECT `ID`, `IsClosed` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses` WHERE ID = " . $status));
if ($statusRow['IsClosed']) // Closed
{
@ -62,10 +71,14 @@ if ($statusRow['IsClosed']) // Closed
}
$action = $hesklang['ticket_been'] . ' ' . $hesklang['close'];
$revision = sprintf($hesklang['thist3'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$audit_closed = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$audit_status = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')',
1 => $status_options[$status]);
if ($hesk_settings['custopen'] != 1) {
$locked = 1;
$audit_locked = array();
}
// Notify customer of closed ticket?
@ -88,24 +101,46 @@ if ($statusRow['IsClosed']) // Closed
// Log who marked the ticket resolved
$closedby_sql = ' , `closedat`=NOW(), `closedby`=' . intval($_SESSION['id']) . ' ';
} elseif ($statusRow['IsNewTicketStatus'] == '0') //Ticket is still open, but not new
} elseif ($statusRow['IsNewTicketStatus'] == 0) //Ticket is still open, but not new
{
$action = sprintf($hesklang['tsst'], $status_options[$status]);
$revision = sprintf($hesklang['thist9'], hesk_date(), $status_options[$status], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$audit_status = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')',
1 => $status_options[$status]);
// Ticket is not resolved
$closedby_sql = ' , `closedat`=NULL, `closedby`=NULL ';
} else // Ticket is marked as "NEW"
{
$action = $hesklang['ticket_been'] . ' ' . $hesklang['opened'];
$revision = sprintf($hesklang['thist4'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$audit_opened = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
// Ticket is not resolved
$closedby_sql = ' , `closedat`=NULL, `closedby`=NULL ';
}
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='{$status}', `locked`='{$locked}' $closedby_sql , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='{$status}', `locked`='{$locked}' $closedby_sql WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
if ($audit_status !== null) {
mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_status', hesk_date(),
$audit_status);
}
if ($audit_closed !== null) {
mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_closed', hesk_date(),
$audit_closed);
}
if ($audit_locked !== null) {
mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_automatically_locked', hesk_date(),
array());
}
if ($audit_opened !== null) {
mfh_insert_audit_trail_record($ticket_id, 'TICKET', 'audit_opened', hesk_date(),
$audit_opened);
}
if (hesk_dbAffectedRows() != 1) {
hesk_error("$hesklang[int_error]: $hesklang[trackID_not_found].");

View File

@ -166,7 +166,31 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
<?php
}
?>
$descriptions = hesk_SESSION(array('new_cf','descriptions')); ?>
</div>
<div class="form-group">
<label for="description[]" class="col-sm-3 control-label">
<?php echo $hesklang['description']; ?>
</label>
<?php if ($hesk_settings['can_sel_lang'] && count($hesk_settings['languages']) > 1): ?>
<table border="0">
<?php foreach ($hesk_settings['languages'] as $lang => $info): ?>
<tr>
<td><?php echo $lang; ?></td>
<td>
<textarea class="form-control"
name="description[<?php echo $lang; ?>]"><?php echo (isset($descriptions[$lang]) ? $descriptions[$lang] : ''); ?></textarea>
</td>
</tr>
<?php endforeach; ?>
</table>
<?php else: ?>
<div class="col-sm-9">
<textarea class="form-control"
name="description[<?php echo $hesk_settings['language']; ?>]"><?php echo (isset($descriptions[$hesk_settings['language']]) ? $descriptions[$hesk_settings['language']] : ''); ?></textarea>
</div>
<?php endif; ?>
</div>
<div class="form-group">
<label for="name[]" class="col-sm-3 control-label">
@ -222,7 +246,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<?php echo $hesklang['custom_l']; ?>
</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="max_length"
<input type="text" class="form-control" name="readonly_max_length"
value="<?php echo isset($value['max_length']) ? intval($value['max_length']) : '255'; ?>" size="5">
</div>
</div>
@ -231,7 +255,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<?php echo $hesklang['defw']; ?>
</label>
<div class="col-sm-3">
<input type="text" class="form-control" name="default_value"
<input type="text" class="form-control" name="readonly_default_value"
value="<?php echo isset($value['default_value']) ? $value['default_value'] : ''; ?>" size="30">
</div>
</div>
@ -495,7 +519,9 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<?php echo $hesklang['email_custom_field_label']; ?>
</label>
<div class="col-sm-8">
<?php $address_type = empty($value['email_type']) ? 'none' : $value['email_type']; ?>
<?php
$address_type = empty($value['email_type']) ? 'none' : $value['email_type'];
?>
<div class="radio">
<label>
<input type="radio" name="email_type" value="none"
@ -732,7 +758,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
$num_before = 0;
$num_after = 0;
foreach ($hesk_settings['custom_fields'] as $id => $cf) {
foreach ($hesk_settings['custom_fields'] as $tmp_id => $cf) {
if ($cf['place']) {
$num_after++;
} else {
@ -741,8 +767,8 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
}
$k = 1;
foreach ($hesk_settings['custom_fields'] as $id => $cf) {
$id = intval(str_replace('custom', '', $id));
foreach ($hesk_settings['custom_fields'] as $tmp_id => $cf) {
$tmp_id = intval(str_replace('custom', '', $tmp_id));
if ($hide_up) {
$hide_up = false;
@ -771,8 +797,17 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
$cf['category'] = count($cf['category']) ? $hesklang['cf_cat'] : $hesklang['cf_all'];
?>
<tr>
<td><?php echo $id; ?></td>
<td><?php echo $cf['name']; ?></td>
<td><?php echo $tmp_id; ?></td>
<td>
<?php
echo $cf['name'];
if ($cf['mfh_description'] !== null && trim($cf['mfh_description']) !== '') {
echo ' <i class="fa fa-info-circle" data-toggle="popover"
data-title="' . htmlspecialchars($hesklang['description']) . '"
data-content="' . htmlspecialchars($cf['mfh_description']) . '"></i>';
}
?>
</td>
<td><?php echo $cf['type']; ?></td>
<td><?php echo $cf['use']; ?></td>
<td><?php echo $cf['req']; ?></td>
@ -791,33 +826,33 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
} elseif ($k == 1 || $hide_up) {
?>
<i class="fa fa-fw icon-link">&nbsp;</i>
<a href="custom_fields.php?a=order_cf&amp;id=<?php echo $id; ?>&amp;move=15&amp;token=<?php hesk_token_echo(); ?>">
<a href="custom_fields.php?a=order_cf&amp;id=<?php echo $tmp_id; ?>&amp;move=15&amp;token=<?php hesk_token_echo(); ?>">
<i class="fa fa-arrow-down fa-fw icon-link green" data-toggle="tooltip" title="<?php echo $hesklang['move_dn']; ?>"></i>
</a>
<?php
} elseif ($k == $hesk_settings['num_custom_fields'] || $k == $num_before) {
?>
<a href="custom_fields.php?a=order_cf&amp;id=<?php echo $id; ?>&amp;move=-15&amp;token=<?php hesk_token_echo(); ?>">
<a href="custom_fields.php?a=order_cf&amp;id=<?php echo $tmp_id; ?>&amp;move=-15&amp;token=<?php hesk_token_echo(); ?>">
<i class="fa fa-arrow-up fa-fw icon-link green" data-toggle="tooltip" title="<?php echo $hesklang['move_up']; ?>"></i>
</a>
<i class="fa fa-fw icon-link">&nbsp;</i>
<?php
} else {
?>
<a href="custom_fields.php?a=order_cf&amp;id=<?php echo $id; ?>&amp;move=-15&amp;token=<?php hesk_token_echo(); ?>">
<a href="custom_fields.php?a=order_cf&amp;id=<?php echo $tmp_id; ?>&amp;move=-15&amp;token=<?php hesk_token_echo(); ?>">
<i class="fa fa-arrow-up fa-fw icon-link green" data-toggle="tooltip" title="<?php echo $hesklang['move_up']; ?>"></i>
</a>
<a href="custom_fields.php?a=order_cf&amp;id=<?php echo $id; ?>&amp;move=15&amp;token=<?php hesk_token_echo(); ?>">
<a href="custom_fields.php?a=order_cf&amp;id=<?php echo $tmp_id; ?>&amp;move=15&amp;token=<?php hesk_token_echo(); ?>">
<i class="fa fa-arrow-down fa-fw icon-link green" data-toggle="tooltip" title="<?php echo $hesklang['move_dn']; ?>"></i>
</a>
<?php
}
}
?>
<a href="custom_fields.php?a=edit_cf&amp;id=<?php echo $id; ?>">
<a name="Edit <?php echo $cf['name']; ?>" href="custom_fields.php?a=edit_cf&amp;id=<?php echo $tmp_id; ?>">
<i class="fa fa-pencil fa-fw icon-link orange" data-toggle="tooltip" title="<?php echo $hesklang['edit']; ?>"></i>
</a>
<a href="custom_fields.php?a=remove_cf&amp;id=<?php echo $id; ?>&amp;token=<?php hesk_token_echo(); ?>"
<a name="Delete <?php echo $cf['name']; ?>" href="custom_fields.php?a=remove_cf&amp;id=<?php echo $tmp_id; ?>&amp;token=<?php hesk_token_echo(); ?>"
onclick="return hesk_confirmExecute('<?php echo hesk_makeJsString($hesklang['del_cf']); ?>');">
<i class="fa fa-times fa-fw icon-link red" data-toggle="tooltip" title="<?php echo $hesklang['delete']; ?>"></i>
</a>
@ -885,6 +920,7 @@ function save_cf()
`req` = '{$cf['req']}',
`category` = ".(count($cf['categories']) ? "'".json_encode($cf['categories'])."'" : 'NULL').",
`name` = '".hesk_dbEscape($cf['names'])."',
`mfh_description` = '".hesk_dbEscape($cf['descriptions'])."',
`value` = ".(strlen($cf['value']) ? "'".hesk_dbEscape($cf['value'])."'" : 'NULL')."
WHERE `id`={$id}");
@ -916,6 +952,9 @@ function edit_cf()
$cf['names'] = json_decode($cf['name'], true);
unset($cf['name']);
$cf['descriptions'] = json_decode($cf['mfh_description'], true);
unset($cf['mfh_description']);
if (strlen($cf['category']))
{
$cf['categories'] = json_decode($cf['category'], true);
@ -994,7 +1033,7 @@ function remove_cf()
$id = intval( hesk_GET('id') ) or hesk_error($hesklang['cf_e_id']);
// Reset the custom field
hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."custom_fields` SET `use`='0', `place`='0', `type`='text', `req`='0', `category`=NULL, `name`='', `value`=NULL, `order`=1000 WHERE `id`={$id}");
hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."custom_fields` SET `use`='0', `place`='0', `type`='text', `req`='0', `category`=NULL, `name`='', `mfh_description`=NULL, `value`=NULL, `order`=1000 WHERE `id`={$id}");
// Were we successful?
if ( hesk_dbAffectedRows() == 1 )
@ -1057,6 +1096,27 @@ function cf_validate()
$hesk_error_buffer[] = $hesklang['err_custname'];
}
// Descriptions
$cf['descriptions'] = hesk_POST_array('description');
// Make sure only non-empty descriptions pass
foreach ($cf['descriptions'] as $key => $description) {
if (!isset($hesk_settings['languages'][$key])) {
unset($cf['descriptions'][$key]);
} else {
$description = is_array($description) ? '' : hesk_input($description, 0, 0, HESK_SLASH);
if (strlen($description) < 1)
{
unset($cf['descriptions'][$key]);
}
else
{
$cf['descriptions'][$key] = stripslashes($description);
}
}
}
// Get type and values
$cf['type'] = hesk_POST('type');
switch ($cf['type'])
@ -1202,8 +1262,8 @@ function cf_validate()
break;
case 'readonly':
$max_length = hesk_POST('max_length');
$value = hesk_POST('default_value');
$max_length = hesk_POST('readonly_max_length');
$value = hesk_POST('readonly_default_value');
$cf['value'] = array('default_value' => $value, 'max_length' => $max_length);
break;
@ -1264,8 +1324,10 @@ function cf_validate()
}
$cf['names'] = addslashes(json_encode($cf['names']));
$cf['descriptions'] = addslashes(json_encode($cf['descriptions']));
$cf['value'] = $cf['type'] == 'date' ? json_encode($cf['value']) : addslashes(json_encode($cf['value']));
return $cf;
} // END cf_validate()
@ -1305,6 +1367,7 @@ function new_cf()
`req` = '{$cf['req']}',
`category` = ".(count($cf['categories']) ? "'".json_encode($cf['categories'])."'" : 'NULL').",
`name` = '".hesk_dbEscape($cf['names'])."',
`mfh_description` = '".hesk_dbEscape($cf['descriptions'])."',
`value` = ".(strlen($cf['value']) ? "'".hesk_dbEscape($cf['value'])."'" : 'NULL').",
`order` = 990
WHERE `id`={$_SESSION['cford']}");

View File

@ -81,12 +81,130 @@ $i = 0;
// Possible priorities
$priorities = array(
'critical' => array('value' => 0, 'text' => $hesklang['critical'], 'formatted' => '<font class="critical">' . $hesklang['critical'] . '</font>'),
'high' => array('value' => 1, 'text' => $hesklang['high'], 'formatted' => '<font class="important">' . $hesklang['high'] . '</font>'),
'medium' => array('value' => 2, 'text' => $hesklang['medium'], 'formatted' => '<font class="medium">' . $hesklang['medium'] . '</font>'),
'low' => array('value' => 3, 'text' => $hesklang['low'], 'formatted' => $hesklang['low']),
'critical' => array('value' => 0, 'lang' => 'critical', 'text' => $hesklang['critical'], 'formatted' => '<font class="critical">' . $hesklang['critical'] . '</font>'),
'high' => array('value' => 1, 'lang' => 'high', 'text' => $hesklang['high'], 'formatted' => '<font class="important">' . $hesklang['high'] . '</font>'),
'medium' => array('value' => 2, 'lang' => 'medium', 'text' => $hesklang['medium'], 'formatted' => '<font class="medium">' . $hesklang['medium'] . '</font>'),
'low' => array('value' => 3, 'lang' => 'low', 'text' => $hesklang['low'], 'formatted' => $hesklang['low']),
);
// Assign tickets to
if ( isset($_POST['assign']) && $_POST['assign'] == $hesklang['assi']) {
if ( ! isset($_POST['owner']) || $_POST['owner'] == '') {
hesk_process_messages($hesklang['assign_no'], $referer, 'NOTICE');
}
$end_message = array();
$num_assigned = 0;
// Permissions
$can_assign_others = hesk_checkPermission('can_assign_others',0);
if ($can_assign_others) {
$can_assign_self = true;
} else {
$can_assign_self = hesk_checkPermission('can_assign_self',0);
}
$owner = intval( hesk_POST('owner') );
if ($owner == -1) {
foreach ($_POST['id'] as $this_id) {
if (is_array($this_id)) {
continue;
}
$this_id = intval($this_id) or hesk_error($hesklang['id_not_valid']);
$res = hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `owner`=0, `assignedby`=NULL WHERE `id`={$this_id} LIMIT 1");
mfh_insert_audit_trail_record($this_id, 'TICKET', 'audit_unassigned', hesk_date(), array(0 => $_SESSION['name'].' ('.$_SESSION['user'].')'));
$end_message[] = sprintf($hesklang['assign_2'], $this_id);
$i++;
}
hesk_process_messages($hesklang['assign_1'],$referer,'SUCCESS');
}
$res = hesk_dbQuery("SELECT `id`,`user`,`name`,`email`,`isadmin`,`categories`,`notify_assigned` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` WHERE `id`='{$owner}' LIMIT 1");
$owner_data = hesk_dbFetchAssoc($res);
if (!$owner_data['isadmin']) {
$owner_data['categories']=explode(',',$owner_data['categories']);
}
require(HESK_PATH . 'inc/email_functions.inc.php');
foreach ($_POST['id'] as $this_id) {
if (is_array($this_id)) {
continue;
}
$this_id = intval($this_id) or hesk_error($hesklang['id_not_valid']);
$result = hesk_dbQuery("SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `id`={$this_id} LIMIT 1");
if (hesk_dbNumRows($result) != 1) {
continue;
}
$ticket = hesk_dbFetchAssoc($result);
if ($ticket['owner'] == $owner) {
$end_message[] = sprintf($hesklang['assign_3'], $ticket['trackid'], $owner_data['name']);
$i++;
continue;
}
if ($owner_data['isadmin'] || in_array($ticket['category'],$owner_data['categories'])) {
hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `owner`={$owner}, `assignedby`=".intval($_SESSION['id'])." WHERE `id`={$this_id} LIMIT 1");
mfh_insert_audit_trail_record($this_id, 'TICKET', 'audit_assigned', hesk_date(), array(0 => $_SESSION['name'].' ('.$_SESSION['user'].')',
1 => $owner_data['name'].' ('.$owner_data['user'].')'));
$end_message[] = sprintf($hesklang['assign_4'], $ticket['trackid'], $owner_data['name']);
$num_assigned++;
$ticket['owner'] = $owner;
/* --> Prepare message */
// 1. Generate the array with ticket info that can be used in emails
$info = array(
'email' => $ticket['email'],
'category' => $ticket['category'],
'priority' => $ticket['priority'],
'owner' => $ticket['owner'],
'trackid' => $ticket['trackid'],
'status' => $ticket['status'],
'name' => $ticket['name'],
'subject' => $ticket['subject'],
'message' => $ticket['message'],
'attachments' => $ticket['attachments'],
'dt' => hesk_date($ticket['dt'], true),
'lastchange' => hesk_date($ticket['lastchange'], true),
'id' => $ticket['id'],
'time_worked' => $ticket['time_worked'],
'last_reply_by' => hesk_getReplierName($ticket),
);
// 2. Add custom fields to the array
foreach ($hesk_settings['custom_fields'] as $k => $v) {
$info[$k] = $v['use'] ? $ticket[$k] : '';
}
// 3. Make sure all values are properly formatted for email
$ticket = hesk_ticketToPlain($info, 1, 0);
/* Notify the new owner? */
if ($ticket['owner'] != intval($_SESSION['id'])) {
hesk_notifyAssignedStaff(false, 'ticket_assigned_to_you', $modsForHesk_settings);
}
} else {
$end_message[] = sprintf($hesklang['assign_5'], $ticket['trackid'], $owner_data['name']);
}
$i++;
}
hesk_process_messages(sprintf($hesklang['assign_log'], $num_assigned, ($i - $num_assigned), implode("\n", $end_message)),$referer,($num_assigned == 0) ? 'ERROR' : ($num_assigned < $i ? 'NOTICE' : 'SUCCESS'));
}
// Change priority
if (array_key_exists($_POST['a'], $priorities)) {
// A security check
@ -113,8 +231,10 @@ if (array_key_exists($_POST['a'], $priorities)) {
hesk_okCategory($ticket['category']);
$revision = sprintf($hesklang['thist8'], hesk_date(), $priority['formatted'], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `priority`='{$priority['value']}', `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `id`={$this_id}");
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `priority`='{$priority['value']}' WHERE `id`={$this_id}");
mfh_insert_audit_trail_record($this_id, 'TICKET', 'audit_priority', hesk_date(),
array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')',
1 => $priority['lang']));
$i++;
}
@ -133,8 +253,6 @@ elseif ($_POST['a'] == 'delete') {
require(HESK_PATH . 'inc/email_functions.inc.php');
}
$revision = sprintf($hesklang['thist3'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
foreach ($_POST['id'] as $this_id) {
if (is_array($this_id)) {
continue;
@ -211,7 +329,185 @@ elseif ($_POST['a'] == 'tag' || $_POST['a'] == 'untag') {
}
hesk_process_messages(sprintf($action, $i), $referer, 'SUCCESS');
} /* JUST CLOSE */
}
/* EXPORT */
elseif ($_POST['a']=='export') {
/* Check permissions for this feature */
hesk_checkPermission('can_export');
/* A security check */
hesk_token_check('POST');
$ids_to_export = array();
foreach ($_POST['id'] as $this_id) {
if ( is_array($this_id) ) {
continue;
}
$ids_to_export[] = intval($this_id) or hesk_error($hesklang['id_not_valid']);
$i++;
}
if ($i < 1) {
hesk_process_messages($hesklang['no_selected'], $referer, 'NOTICE');
}
// Start SQL statement for selecting tickets
$sql = "SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `id` IN (".implode(',', $ids_to_export).") ";
$sql .= " AND " . hesk_myCategories();
$sql .= " AND " . hesk_myOwnership();
require_once(HESK_PATH . 'inc/custom_fields.inc.php');
require(HESK_PATH . 'inc/export_functions.inc.php');
list($success_msg, $tickets_exported) = hesk_export_to_XML($sql, true);
if ($tickets_exported > 0) {
hesk_process_messages($success_msg,$referer,'SUCCESS');
} else {
hesk_process_messages($hesklang['n2ex'],$referer,'NOTICE');
}
}
/* ANONYMIZE */
elseif ($_POST['a']=='anonymize') {
/* Check permissions for this feature */
hesk_checkPermission('can_privacy');
/* A security check */
hesk_token_check('POST');
require(HESK_PATH . 'inc/privacy_functions.inc.php');
foreach ($_POST['id'] as $this_id) {
if (is_array($this_id)) {
continue;
}
$this_id = intval($this_id) or hesk_error($hesklang['id_not_valid']);
$result = hesk_dbQuery("SELECT `id`,`trackid`,`name`,`category` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `id`='".intval($this_id)."' AND ".hesk_myOwnership()." LIMIT 1");
if (hesk_dbNumRows($result) != 1) {
continue;
}
$ticket = hesk_dbFetchAssoc($result);
hesk_okCategory($ticket['category']);
hesk_anonymizeTicket(null, null, true);
$i++;
}
hesk_process_messages(sprintf($hesklang['num_tickets_anon'],$i),$referer,'SUCCESS');
}
/* PRINT */
elseif ($_POST['a']=='print') {
/* Check permissions for this feature */
hesk_checkPermission('can_view_tickets');
/* A security check */
hesk_token_check('POST');
// Load custom fields
require_once(HESK_PATH . 'inc/custom_fields.inc.php');
// List of staff
if (!isset($admins)) {
$admins = array();
$res2 = hesk_dbQuery("SELECT `id`,`name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` ORDER BY `id` ASC");
while ($row=hesk_dbFetchAssoc($res2)) {
$admins[$row['id']]=$row['name'];
}
}
// List of categories
$hesk_settings['categories'] = array();
$res2 = hesk_dbQuery('SELECT `id`, `name` FROM `'.hesk_dbEscape($hesk_settings['db_pfix']).'categories` WHERE ' . hesk_myCategories('id') . ' ORDER BY `cat_order` ASC');
while ($row=hesk_dbFetchAssoc($res2)) {
$hesk_settings['categories'][$row['id']] = $row['name'];
}
// Print page head
header('Content-Type: text/html; charset=utf-8');
?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title><?php echo $hesk_settings['hesk_title']; ?></title>
<meta http-equiv="Content-Type" content="text/html; charset=<?php echo $hesklang['ENCODING']; ?>">
<style type="text/css">
body, table, td, p {
color : black;
font-family : Verdana, Geneva, Arial, Helvetica, sans-serif;
font-size : <?php echo $hesk_settings['print_font_size']; ?>px;
}
table {
border-collapse:collapse;
}
hr {
border: 0;
color: #9e9e9e;
background-color: #9e9e9e;
height: 1px;
width: 100%;
text-align: left;
}
</style>
</head>
<body onload="window.print()">
<?php
// Loop through ticket IDs and print them
foreach ($_POST['id'] as $this_id) {
if (is_array($this_id)) {
continue;
}
$this_id = intval($this_id) or hesk_error($hesklang['id_not_valid']);
$result = hesk_dbQuery("SELECT `t1`.* , `ticketStatus`.`IsClosed` AS `isClosed`, `ticketStatus`.`Key` AS `statusKey`, `t2`.name AS `repliername`
FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` AS `t1` LEFT JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` AS `t2` ON `t1`.`replierid` = `t2`.`id`
INNER JOIN `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses` AS `ticketStatus` ON `t1`.`status` = `ticketStatus`.`ID`
WHERE `t1`.`id`='{$this_id}' LIMIT 1");
if (hesk_dbNumRows($result) != 1) {
continue;
}
$ticket = hesk_dbFetchAssoc($result);
// Check that we have proper permissions to view this ticket
hesk_okCategory($ticket['category']);
$can_view_ass_by = hesk_checkPermission('can_view_ass_by', 0);
$can_view_unassigned = hesk_checkPermission('can_view_unassigned',0);
if ($ticket['owner'] && $ticket['owner'] != $_SESSION['id'] && ! hesk_checkPermission('can_view_ass_others',0)) {
// Maybe this user is allowed to view tickets he/she assigned?
if ( ! $can_view_ass_by || $ticket['assignedby'] != $_SESSION['id']) {
hesk_error($hesklang['ycvtao']);
}
}
if (!$ticket['owner'] && ! $can_view_unassigned) {
hesk_error($hesklang['ycovtay']);
}
// All good, continue...
$category['name'] = isset($hesk_settings['categories'][$ticket['category']]) ? $hesk_settings['categories'][$ticket['category']] : $hesklang['catd'];
// Get replies
$res = hesk_dbQuery("SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."replies` WHERE `replyto`='{$ticket['id']}' ORDER BY `id` ASC");
$replies = hesk_dbNumRows($res);
// Print ticket
require(HESK_PATH . 'inc/print_template.inc.php');
flush();
}
?>
</body>
</html>
<?php
exit();
}
/* JUST CLOSE */
else {
/* Check permissions for this feature */
hesk_checkPermission('can_view_tickets');
@ -222,8 +518,6 @@ else {
hesk_token_check('POST');
require(HESK_PATH . 'inc/email_functions.inc.php');
$revision = sprintf($hesklang['thist3'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
foreach ($_POST['id'] as $this_id) {
if (is_array($this_id)) {
continue;
@ -239,7 +533,11 @@ else {
$closedStatusRS = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "statuses` WHERE `IsStaffClosedOption` = 1");
$closedStatus = hesk_dbFetchAssoc($closedStatusRS);
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='" . $closedStatus['ID'] . "', `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . ", `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `id`='" . intval($this_id) . "'");
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`='" . $closedStatus['ID'] . "', `closedat`=NOW(), `closedby`=" . intval($_SESSION['id']) . " WHERE `id`='" . intval($this_id) . "'");
mfh_insert_audit_trail_record($this_id, 'TICKET', 'audit_closed', hesk_date(),
array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')'));
$i++;
// Notify customer of closed ticket?
@ -284,6 +582,14 @@ function hesk_fullyDeleteTicket()
/* Delete ticket notes */
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes` WHERE `ticket`='" . intval($ticket['id']) . "'");
/* Delete audit trail records */
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail_to_replacement_values`
WHERE `audit_trail_id` IN (
SELECT `id` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail`
WHERE `entity_type` = 'TICKET' AND `entity_id` = " . intval($ticket['id']) . ")");
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "audit_trail` WHERE `entity_type`='TICKET'
AND `entity_id` = " . intval($ticket['id']));
/* Delete ticket reply drafts */
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "reply_drafts` WHERE `ticket`=" . intval($ticket['id']));

View File

@ -24,6 +24,8 @@ require(HESK_PATH . 'inc/admin_functions.inc.php');
require(HESK_PATH . 'inc/mail_functions.inc.php');
require(HESK_PATH . 'inc/custom_fields.inc.php');
hesk_load_database_functions();
require(HESK_PATH . 'inc/posting_functions.inc.php');
require(HESK_PATH . 'inc/view_attachment_functions.inc.php');
hesk_session_start();
hesk_dbConnect();
@ -34,6 +36,7 @@ if (!isset($_REQUEST['isManager']) || !$_REQUEST['isManager']) {
hesk_checkPermission('can_view_tickets');
hesk_checkPermission('can_edit_tickets');
}
$modsForHesk_settings = mfh_getSettings();
/* Ticket ID */
@ -63,6 +66,7 @@ if (!isset($_REQUEST['isManager']) || !$_REQUEST['isManager']) {
hesk_okCategory($ticket['category']);
}
if (hesk_isREQUEST('reply')) {
$tmpvar['id'] = intval(hesk_REQUEST('reply')) or die($hesklang['id_not_valid']);
@ -76,16 +80,51 @@ if (hesk_isREQUEST('reply')) {
$is_reply = 1;
}
// Count number of existing attachments for this post
$number_of_attachments = $is_reply ? hesk_countAttachments($reply['attachments']) : hesk_countAttachments($ticket['attachments']);
if (isset($_POST['save'])) {
/* A security check */
hesk_token_check('POST');
$hesk_error_buffer = array();
// Add attachments?
if ($hesk_settings['attachments']['use'] && $number_of_attachments < $hesk_settings['attachments']['max_number']) {
require_once(HESK_PATH . 'inc/attachments.inc.php');
$attachments = array();
$use_legacy_attachments = hesk_POST('use-legacy-attachments', 0);
if ($use_legacy_attachments) {
for ($i = $number_of_attachments + 1; $i <= $hesk_settings['attachments']['max_number']; $i++) {
$att = hesk_uploadFile($i);
if ($att !== false && !empty($att)) {
$attachments[$i] = $att;
}
}
} else {
// The user used the new drag-and-drop system.
$temp_attachment_ids = hesk_POST_array('attachment-ids');
foreach ($temp_attachment_ids as $temp_attachment_id) {
// Simply get the temp info and move it to the attachments table
$temp_attachment = mfh_getTemporaryAttachment($temp_attachment_id);
$attachments[] = $temp_attachment;
mfh_deleteTemporaryAttachment($temp_attachment_id);
}
}
}
if ($is_reply) {
$tmpvar['message'] = hesk_input(hesk_POST('message')) or $hesk_error_buffer[] = $hesklang['enter_message'];
if (count($hesk_error_buffer)) {
// Remove any successfully uploaded attachments
if ($hesk_settings['attachments']['use'] && isset($attachments)) {
hesk_removeAttachments($attachments);
}
$myerror = '<ul>';
foreach ($hesk_error_buffer as $error) {
$myerror .= "<li>$error</li>\n";
@ -101,7 +140,14 @@ if (isset($_POST['save'])) {
$tmpvar['html'] = hesk_POST('html');
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` SET `html`='" . $tmpvar['html'] . "', `message`='" . hesk_dbEscape($tmpvar['message']) . "' WHERE `id`='" . intval($tmpvar['id']) . "' AND `replyto`='" . intval($ticket['id']) . "'");
if ($hesk_settings['attachments']['use'] && !empty($attachments)) {
foreach ($attachments as $myatt) {
hesk_dbQuery("INSERT INTO `".hesk_dbEscape($hesk_settings['db_pfix'])."attachments` (`ticket_id`,`saved_name`,`real_name`,`size`) VALUES ('".hesk_dbEscape($trackingID)."','".hesk_dbEscape($myatt['saved_name'])."','".hesk_dbEscape($myatt['real_name'])."','".intval($myatt['size'])."')");
$myattachments .= hesk_dbInsertID() . '#' . $myatt['real_name'] . '#' . $myatt['saved_name'] . ',';
}
}
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies` SET `html`='" . $tmpvar['html'] . "', `message`='" . hesk_dbEscape($tmpvar['message']) . "', `attachments`=CONCAT(`attachments`, '".hesk_dbEscape($myattachments)."') WHERE `id`='" . intval($tmpvar['id']) . "' AND `replyto`='" . intval($ticket['id']) . "'");
} else {
$tmpvar['language'] = hesk_POST('customerLanguage');
$tmpvar['name'] = hesk_input(hesk_POST('name')) or $hesk_error_buffer[] = $hesklang['enter_your_name'];
@ -147,7 +193,7 @@ if (isset($_POST['save'])) {
if (isset($_POST[$k]) && is_array($_POST[$k])) {
foreach ($_POST[$k] as $myCB) {
$tmpvar[$k] .= ( is_array($myCB) ? '' : hesk_input($myCB) ) . '<br>';
$tmpvar[$k] .= ( is_array($myCB) ? '' : hesk_input($myCB) ) . '<br />';
}
$tmpvar[$k]=substr($tmpvar[$k],0,-6);
} else {
@ -161,9 +207,9 @@ if (isset($_POST['save'])) {
$_SESSION["as_$k"] = '';
if (preg_match("/^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2][0-9]|3[0-1])$/", $tmpvar[$k])) {
$date = strtotime($tmpvar[$k] . ' t00:00:00');
$dmin = strlen($v['value']['dmin']) ? strtotime($v['value']['dmin'] . ' t00:00:00') : false;
$dmax = strlen($v['value']['dmax']) ? strtotime($v['value']['dmax'] . ' t00:00:00') : false;
$date = strtotime($tmpvar[$k] . ' t00:00:00 UTC');
$dmin = strlen($v['value']['dmin']) ? strtotime($v['value']['dmin'] . ' t00:00:00 UTC') : false;
$dmax = strlen($v['value']['dmax']) ? strtotime($v['value']['dmax'] . ' t00:00:00 UTC') : false;
$_SESSION["as_$k"] = $tmpvar[$k];
@ -208,6 +254,11 @@ if (isset($_POST['save'])) {
}
if (count($hesk_error_buffer)) {
// Remove any successfully uploaded attachments
if ($hesk_settings['attachments']['use'] && isset($attachments)) {
hesk_removeAttachments($attachments);
}
$myerror = '<ul>';
foreach ($hesk_error_buffer as $error) {
$myerror .= "<li>$error</li>\n";
@ -221,6 +272,13 @@ if (isset($_POST['save'])) {
$tmpvar['message'] = nl2br($tmpvar['message']);
}
if ($hesk_settings['attachments']['use'] && !empty($attachments)) {
foreach ($attachments as $myatt) {
hesk_dbQuery("INSERT INTO `".hesk_dbEscape($hesk_settings['db_pfix'])."attachments` (`ticket_id`,`saved_name`,`real_name`,`size`) VALUES ('".hesk_dbEscape($trackingID)."','".hesk_dbEscape($myatt['saved_name'])."','".hesk_dbEscape($myatt['real_name'])."','".intval($myatt['size'])."')");
$myattachments .= hesk_dbInsertID() . '#' . $myatt['real_name'] . '#' . $myatt['saved_name'] . ',';
}
}
$custom_SQL = '';
for ($i = 1; $i <= 50; $i++) {
$custom_SQL .= '`custom'.$i.'`=' . (isset($tmpvar['custom'.$i]) ? "'".hesk_dbEscape($tmpvar['custom'.$i])."'" : "''") . ',';
@ -232,6 +290,7 @@ if (isset($_POST['save'])) {
`email`='" . hesk_dbEscape($tmpvar['email']) . "',
`subject`='" . hesk_dbEscape($tmpvar['subject']) . "',
`message`='" . hesk_dbEscape($tmpvar['message']) . "',
`attachments`=CONCAT(`attachments`, '".hesk_dbEscape($myattachments)."'),
`language`='" . hesk_dbEscape($tmpvar['language']) . "',
`html`='" . hesk_dbEscape($tmpvar['html']) . "',
$custom_SQL
@ -278,7 +337,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
$onsubmit = 'onsubmit="return validateRichText(\'message-help-block\', \'message-group\', \'message\', \''.htmlspecialchars($hesklang['this_field_is_required']).'\')"';
}
?>
<form role="form" class="form-horizontal" method="post" action="edit_post.php" name="form1" <?php echo $onsubmit; ?>>
<form role="form" class="form-horizontal" method="post" action="edit_post.php" name="form1" enctype="multipart/form-data" <?php echo $onsubmit; ?>>
<?php
/* If it's not a reply edit all the fields */
if (!$is_reply) {
@ -309,7 +368,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<label for="subject" class="col-sm-3 control-label"><?php echo $hesklang['subject'] . $required; ?></label>
<div class="col-sm-9">
<input class="form-control" type="text" name="subject" size="40" maxlength="40"
<input class="form-control" type="text" name="subject" size="40" maxlength="70"
value="<?php echo $ticket['subject']; ?>"
placeholder="<?php echo htmlspecialchars($hesklang['subject']); ?>"/>
</div>
@ -321,7 +380,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</label>
<div class="col-sm-9">
<input class="form-control" type="text" name="name" size="40" maxlength="30"
<input class="form-control" type="text" name="name" size="40" maxlength="50"
value="<?php echo $ticket['name']; ?>"
placeholder="<?php echo htmlspecialchars($hesklang['name']); ?>"
data-error="<?php echo $hesklang['this_field_is_required']; ?>"
@ -354,7 +413,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
$k_value = $ticket[$k];
if ($v['type'] == 'checkbox') {
$k_value = explode('<br>', $k_value);
$k_value = explode('<br />', $k_value);
}
if ($v['req'] == 2) {
@ -386,6 +445,9 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
echo '<div class="radio"><label><input type="radio" name="' . $k . '" value="' . $option . '" ' . $checked . ' ' . $required_attribute . '> ' . $option . '</label></div>';
}
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div></div>
</div>';
@ -416,9 +478,11 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
echo '<option ' . $selected . '>' . $option . '</option>';
}
echo '</select>
<div class="help-block with-errors"></div>
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '</select>';
echo '<div class="help-block with-errors"></div>
</div>
</div>';
break;
@ -439,6 +503,9 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
echo '<div class="checkbox"><label><input type="checkbox" name="' . $k . '[]" value="' . $option . '" ' . $checked . ' ' . $required_attribute . '> ' . $option . '</label></div>';
}
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div>
</div>
</div>';
@ -453,8 +520,11 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<div class="form-group' . $cls . '">
<label for="' . $k . '" class="col-sm-3 control-label">' . $v['name'] . ' ' . $v['req'] . '</label>
<div class="col-sm-9">
<textarea name="' . $k . '" class="form-control" rows="' . intval($v['value']['rows']) . '" cols="' . intval($v['value']['cols']) . '" ' . $required_attribute . '>' . $k_value . '</textarea>
<div class="help-block with-errors"></div>
<textarea name="' . $k . '" class="form-control" rows="' . intval($v['value']['rows']) . '" cols="' . intval($v['value']['cols']) . '" ' . $required_attribute . '>' . $k_value . '</textarea>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div>
</div>
</div>';
break;
@ -473,8 +543,11 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<div class="form-group' . $cls . '">
<label for="' . $k . '" class="col-sm-3 control-label">' . $v['name'] . ' ' . $v['req'] . '</label>
<div class="col-sm-9">
<input type="text" name="' . $k . '" value="' . $k_value . '" class="datepicker form-control" size="10" ' . $required_attribute . '>
<div class="help-block with-errors"></div>
<input type="text" name="' . $k . '" value="' . $k_value . '" class="datepicker form-control" size="10" ' . $required_attribute . '>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div>
</div>
</div>';
break;
@ -489,8 +562,11 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<div class="form-group' . $cls . '">
<label for="' . $k . '" class="col-sm-3 control-label">' . $v['name'] . ' ' . $v['req'] . '</label>
<div class="col-sm-9">
<input class="form-control" type="text" name="' . $k . '" id="' . $k . '" value="' . $k_value . '" size="40" ' . $suggest . ' ' . $required_attribute . '>
<div class="help-block with-errors"></div>
<input class="form-control" type="text" name="' . $k . '" id="' . $k . '" value="' . $k_value . '" size="40" ' . $suggest . ' ' . $required_attribute . '>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div>
</div>
<div id="' . $k . '_suggestions"></div>
</div>
@ -501,9 +577,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
case 'hidden':
case 'readonly':
default:
if (strlen($k_value) != 0) {
$v['value']['default_value'] = $k_value;
}
$k_value = hesk_msgToPlain($k_value,0,0);
$cls = in_array($k, $_SESSION['iserror']) ? ' isError' : '';
@ -511,8 +585,11 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<div class="form-group' . $cls . '">
<label for="' . $k . '" class="col-sm-3 control-label">' . $v['name'] . ' ' . $v['req'] . '</label>
<div class="col-sm-9">
<input type="text" class="form-control" name="' . $k . '" size="40" maxlength="' . intval($v['value']['max_length']) . '" value="' . $v['value']['default_value'] . '" ' . $required_attribute . '>
<div class="help-block with-errors"></div>
<input type="text" class="form-control" name="' . $k . '" size="40" maxlength="' . intval($v['value']['max_length']) . '" value="' . $k_value . '" ' . $required_attribute . '>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div>
</div>
</div>
';
@ -542,6 +619,19 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<div class="help-block with-errors" id="message-help-block"></div>
</div>
</div>
<?php if ($hesk_settings['attachments']['use'] && $number_of_attachments < $hesk_settings['attachments']['max_number']) : ?>
<div class="form-group">
<label for="attachments" class="control-label col-sm-3"><?php echo $hesklang['attachments']; ?>:</label>
<div class="col-sm-9">
<?php build_dropzone_markup(true, 'filedrop', $number_of_attachments + 1); ?>
</div>
</div>
<?php
display_dropzone_field(HESK_PATH . 'internal-api/ticket/upload-attachment.php',
'filedrop',
$hesk_settings['attachments']['max_number'] - $number_of_attachments);
endif; ?>
<div class="form-group">
<input type="hidden" name="save" value="1">
<input type="hidden" name="track" value="<?php echo $trackingID; ?>">
@ -554,16 +644,20 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
}
?>
</div>
<div class="form-group" style="text-align: center">
<div class="form-group">
<div class="col-md-9 col-md-offset-3">
<?php
$html = $ticket['html'] ? 1 : 0;
?>
<input type="hidden" name="html" value="<?php echo $html; ?>">
<input type="submit" value="<?php echo $hesklang['save_changes']; ?>" class="btn btn-default">
<div class="btn-group">
<input type="submit" value="<?php echo $hesklang['save_changes']; ?>" class="btn btn-primary">
<a class="btn btn-default" href="javascript:history.go(-1)"><?php echo $hesklang['back']; ?></a>
</div>
<?php if (isset($_REQUEST['isManager']) && $_REQUEST['isManager']): ?>
<input type="hidden" name="isManager" value="1">
<?php endif; ?>
<a class="btn btn-default" href="javascript:history.go(-1)"><?php echo $hesklang['back']; ?></a>
</div>
</div>
</form>
</div>
@ -574,21 +668,15 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<?php if ($ticket['html']): ?>
<script type="text/javascript">
/* <![CDATA[ */
tinyMCE.init({
mode: "textareas",
editor_selector: "htmlEditor",
elements: "content",
theme: "advanced",
convert_urls: false,
theme_advanced_buttons1: "cut,copy,paste,|,undo,redo,|,formatselect,fontselect,fontsizeselect,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull",
theme_advanced_buttons2: "sub,sup,|,charmap,|,bullist,numlist,|,outdent,indent,insertdate,inserttime,preview,|,forecolor,backcolor,|,hr,removeformat,visualaid,|,link,unlink,anchor,image,cleanup,code",
theme_advanced_buttons3: "",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
theme_advanced_resizing: true
$(document).ready(function() {
$('.htmlEditor').summernote({
height: 200,
toolbar: [
['style', ['bold', 'italic', 'underline', 'clear']],
['font', ['strikethrough', 'superscript', 'subscript']],
['para', ['ul', 'ol']]
]
});
});
/* ]]> */
</script>
@ -598,3 +686,14 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<?php
require_once(HESK_PATH . 'inc/footer.inc.php');
exit();
function hesk_countAttachments($attachments_string) {
if ( ! strlen($attachments_string) || strpos($attachments_string, ',') === false) {
return 0;
}
$att = explode(',', substr($attachments_string, 0, -1));
return count($att);
} // END hesk_countAttachments()

View File

@ -37,7 +37,7 @@ $modsForHesk_settings = mfh_getSettings();
$delete = hesk_GET('delete');
if (strlen($delete) && preg_match('/^hesk_export_[0-9_\-]+$/', $delete)) {
hesk_unlink(HESK_PATH.$hesk_settings['cache_dir'].'/'.$delete.'.zip');
hesk_process_messages($hesklang['fd'], 'export.php','SUCCESS');
hesk_process_messages($hesklang['fd'], hesk_verifyGoto(),'SUCCESS');
}
// Set default values
@ -291,350 +291,15 @@ $orderBy = $modsForHesk_settings['category_order_column'];
$res2 = hesk_dbQuery("SELECT `id`, `name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` WHERE " . hesk_myCategories('id') . " ORDER BY `" . $orderBy . "` ASC");
while ($row = hesk_dbFetchAssoc($res2)) {
$my_cat[$row['id']] = hesk_msgToPlain($row['name'], 1);
$row['name'] = (strlen($row['name']) > 50) ? substr($row['name'], 0, 50) . '...' : $row['name'];
$row['name'] = (hesk_mb_strlen($row['name']) > 50) ? hesk_mb_substr($row['name'],0,50) . '...' : $row['name'];
$cat_selected = ($row['id'] == $category) ? 'selected="selected"' : '';
$category_options .= '<option value="' . $row['id'] . '" ' . $cat_selected . '>' . $row['name'] . '</option>';
}
// Generate export file
if (isset($_GET['w'])) {
// We'll need HH:MM:SS format for hesk_date() here
$hesk_settings['timeformat'] = 'H:i:s';
// Get staff names
$admins = array();
$result = hesk_dbQuery("SELECT `id`,`name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` ORDER BY `name` ASC");
while ($row = hesk_dbFetchAssoc($result)) {
$admins[$row['id']] = $row['name'];
}
// This will be the export directory
$export_dir = HESK_PATH.$hesk_settings['cache_dir'].'/';
// This will be the name of the export and the XML file
$export_name = 'hesk_export_' . date('Y-m-d_H-i-s') . '_' . mt_rand(10000, 99999);
$save_to = $export_dir . $export_name . '.xml';
// Do we have the export directory?
if (is_dir($export_dir) || (@mkdir($export_dir, 0777) && is_writable($export_dir))) {
// Is there an index.htm file?
if (!file_exists($export_dir.'index.htm')) {
@file_put_contents($export_dir.'index.htm', '');
}
// Cleanup old files
hesk_purge_cache('export', 86400);
} else {
hesk_error($hesklang['ede']);
}
// Make sure the file can be saved and written to
@file_put_contents($save_to, '');
if (!file_exists($save_to)) {
hesk_error($hesklang['eef']);
}
// Start generating the report message and generating the export
$success_msg = '';
$flush_me = '<br /><br />';
$flush_me .= hesk_date() . " | {$hesklang['inite']} ";
if ($date_from == $date_to) {
$flush_me .= "(" . hesk_dateToString($date_from, 0) . ")<br />\n";
} else {
$flush_me .= "(" . hesk_dateToString($date_from, 0) . " - " . hesk_dateToString($date_to, 0) . ")<br />\n";
}
// Start generating file contents
$tmp = '<?xml version="1.0" encoding="UTF-8"?>
<?mso-application progid="Excel.Sheet"?>
<Workbook xmlns="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:o="urn:schemas-microsoft-com:office:office"
xmlns:x="urn:schemas-microsoft-com:office:excel"
xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet"
xmlns:html="http://www.w3.org/TR/REC-html40">
<OfficeDocumentSettings xmlns="urn:schemas-microsoft-com:office:office">
<AllowPNG/>
</OfficeDocumentSettings>
<ExcelWorkbook xmlns="urn:schemas-microsoft-com:office:excel">
<WindowHeight>8250</WindowHeight>
<WindowWidth>16275</WindowWidth>
<WindowTopX>360</WindowTopX>
<WindowTopY>90</WindowTopY>
<ProtectStructure>False</ProtectStructure>
<ProtectWindows>False</ProtectWindows>
</ExcelWorkbook>
<Styles>
<Style ss:ID="Default" ss:Name="Normal">
<Alignment ss:Vertical="Bottom"/>
<Borders/>
<Font ss:FontName="Calibri" x:CharSet="238" x:Family="Swiss" ss:Size="11"
ss:Color="#000000"/>
<Interior/>
<NumberFormat/>
<Protection/>
</Style>
<Style ss:ID="s62">
<NumberFormat ss:Format="General Date"/>
</Style>
<Style ss:ID="s63">
<NumberFormat ss:Format="Short Date"/>
</Style>
<Style ss:ID="s65">
<NumberFormat ss:Format="[h]:mm:ss"/>
</Style>
</Styles>
<Worksheet ss:Name="Sheet1">
<Table>
';
// Define column width
$tmp .= '
<Column ss:AutoFitWidth="0" ss:Width="50"/>
<Column ss:AutoFitWidth="0" ss:Width="84" ss:Span="1"/>
<Column ss:AutoFitWidth="0" ss:Width="110"/>
<Column ss:AutoFitWidth="0" ss:Width="110"/>
<Column ss:AutoFitWidth="0" ss:Width="90"/>
<Column ss:AutoFitWidth="0" ss:Width="90"/>
<Column ss:AutoFitWidth="0" ss:Width="87"/>
<Column ss:AutoFitWidth="0" ss:Width="57.75"/>
<Column ss:AutoFitWidth="0" ss:Width="57.75"/>
<Column ss:AutoFitWidth="0" ss:Width="100"/>
<Column ss:AutoFitWidth="0" ss:Width="100"/>
<Column ss:AutoFitWidth="0" ss:Width="80"/>
<Column ss:AutoFitWidth="0" ss:Width="80"/>
';
foreach ($hesk_settings['custom_fields'] as $k => $v) {
if ($v['use']) {
$tmp .= '<Column ss:AutoFitWidth="0" ss:Width="80"/>' . "\n";
}
}
// Define first row (header)
$tmp .= '
<Row>
<Cell><Data ss:Type="String">#</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['trackID'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['date'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['last_update'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['name'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['email'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['category'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['priority'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['status'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['subject'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['message'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['owner'] . '</Data></Cell>
<Cell><Data ss:Type="String">' . $hesklang['ts'] . '</Data></Cell>
';
foreach ($hesk_settings['custom_fields'] as $k => $v) {
if ($v['use']) {
$tmp .= '<Cell><Data ss:Type="String">' . $v['name'] . '</Data></Cell>' . "\n";
}
}
$tmp .= "</Row>\n";
// Write what we have by now into the XML file
file_put_contents($save_to, $tmp, FILE_APPEND);
$flush_me .= hesk_date() . " | {$hesklang['gXML']}<br />\n";
// OK, now start dumping data and writing it into the file
$tickets_exported = 0;
$save_after = 100;
$this_round = 0;
$tmp = '';
$result = hesk_dbQuery($sql);
while ($ticket = hesk_dbFetchAssoc($result)) {
$ticket['status'] = mfh_getDisplayTextForStatusId($ticket['status']);
switch ($ticket['priority']) {
case 0:
$ticket['priority'] = $hesklang['critical'];
break;
case 1:
$ticket['priority'] = $hesklang['high'];
break;
case 2:
$ticket['priority'] = $hesklang['medium'];
break;
default:
$ticket['priority'] = $hesklang['low'];
}
$ticket['archive'] = !($ticket['archive']) ? $hesklang['no'] : $hesklang['yes'];
$ticket['message'] = hesk_msgToPlain($ticket['message'], 1, 0);
$ticket['subject'] = hesk_msgToPlain($ticket['subject'], 1, 0);
$ticket['owner'] = isset($admins[$ticket['owner']]) ? $admins[$ticket['owner']] : '';
$ticket['category'] = isset($my_cat[$ticket['category']]) ? $my_cat[$ticket['category']] : '';
// Format for export dates
$hesk_settings['timeformat'] = "Y-m-d\TH:i:s\.000";
// Create row for the XML file
$tmp .= '
<Row>
<Cell><Data ss:Type="Number">' . $ticket['id'] . '</Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['trackid'] . ']]></Data></Cell>
<Cell ss:StyleID="s62"><Data ss:Type="DateTime">' . hesk_date($ticket['dt'], true) . '</Data></Cell>
<Cell ss:StyleID="s62"><Data ss:Type="DateTime">' . hesk_date($ticket['lastchange'], true) . '</Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . hesk_msgToPlain($ticket['name'], 1) . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['email'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['category'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['priority'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['status'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['subject'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['message'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['owner'] . ']]></Data></Cell>
<Cell><Data ss:Type="String"><![CDATA[' . $ticket['time_worked'] . ']]></Data></Cell>
';
// Add custom fields
foreach ($hesk_settings['custom_fields'] as $k=>$v) {
if ($v['use']) {
switch ($v['type']) {
case 'date':
$tmp_dt = hesk_custom_date_display_format($ticket[$k], 'Y-m-d\T00:00:00.000');
$tmp .= strlen($tmp_dt) ? '<Cell ss:StyleID="s63"><Data ss:Type="DateTime">'.$tmp_dt : '<Cell><Data ss:Type="String">';
$tmp .= "</Data></Cell> \n";
break;
default:
$tmp .= '<Cell><Data ss:Type="String"><![CDATA['.hesk_msgToPlain($ticket[$k], 1, 0).']]></Data></Cell> ' . "\n";
}
}
}
$tmp .= "</Row>\n";
// Write every 100 rows into the file
if ($this_round >= $save_after) {
file_put_contents($save_to, $tmp, FILE_APPEND);
$this_round = 0;
$tmp = '';
usleep(1);
}
$tickets_exported++;
$this_round++;
} // End of while loop
// Go back to the HH:MM:SS format for hesk_date()
$hesk_settings['timeformat'] = 'H:i:s';
// Append any remaining rows into the file
if ($this_round > 0) {
file_put_contents($save_to, $tmp, FILE_APPEND);
}
// If any tickets were exported, continue, otherwise cleanup
if ($tickets_exported > 0) {
// Finish the XML file
$tmp = '
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<Selected/>
<Panes>
<Pane>
<Number>3</Number>
<ActiveRow>4</ActiveRow>
</Pane>
</Panes>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Sheet2">
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" x:FullColumns="1"
x:FullRows="1" ss:DefaultRowHeight="15">
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
<Worksheet ss:Name="Sheet3">
<Table ss:ExpandedColumnCount="1" ss:ExpandedRowCount="1" x:FullColumns="1"
x:FullRows="1" ss:DefaultRowHeight="15">
</Table>
<WorksheetOptions xmlns="urn:schemas-microsoft-com:office:excel">
<PageSetup>
<Header x:Margin="0.3"/>
<Footer x:Margin="0.3"/>
<PageMargins x:Bottom="0.75" x:Left="0.7" x:Right="0.7" x:Top="0.75"/>
</PageSetup>
<ProtectObjects>False</ProtectObjects>
<ProtectScenarios>False</ProtectScenarios>
</WorksheetOptions>
</Worksheet>
</Workbook>
';
file_put_contents($save_to, $tmp, FILE_APPEND);
// Log how many rows we exported
$flush_me .= hesk_date() . " | " . sprintf($hesklang['nrow'], $tickets_exported) . "<br />\n";
// We will convert XML to Zip to save a lot of space
$save_to_zip = $export_dir . $export_name . '.zip';
// Log start of Zip creation
$flush_me .= hesk_date() . " | {$hesklang['cZIP']}<br />\n";
// Preferrably use the zip extension
if (extension_loaded('zip')) {
$save_to_zip = $export_dir . $export_name . '.zip';
$zip = new ZipArchive;
$res = $zip->open($save_to_zip, ZipArchive::CREATE);
if ($res === TRUE) {
$zip->addFile($save_to, "{$export_name}.xml");
$zip->close();
} else {
die("{$hesklang['eZIP']} <$save_to_zip>\n");
}
} // Some servers have ZipArchive class enabled anyway - can we use it?
elseif (class_exists('ZipArchive')) {
require(HESK_PATH . 'inc/zip/Zip.php');
$zip = new Zip();
$zip->addLargeFile($save_to, "{$export_name}.xml");
$zip->finalize();
$zip->setZipFile($save_to_zip);
} // If not available, use a 3rd party Zip class included with HESK
else {
require(HESK_PATH . 'inc/zip/pclzip.lib.php');
$zip = new PclZip($save_to_zip);
$zip->add($save_to, PCLZIP_OPT_REMOVE_ALL_PATH);
}
// Delete XML, just leave the Zip archive
hesk_unlink($save_to);
// Echo memory peak usage
$flush_me .= hesk_date() . " | " . sprintf($hesklang['pmem'], (@memory_get_peak_usage(true) / 1048576)) . "<br />\r\n";
// We're done!
$flush_me .= hesk_date() . " | {$hesklang['fZIP']}<br /><br />";
// Success message
$success_msg .= $hesk_settings['debug_mode'] ? $flush_me : '<br /><br />';
$success_msg .= $hesklang['step1'] . ': <a href="' . $save_to_zip . '">' . $hesklang['ch2d'] . '</a><br /><br />' . $hesklang['step2'] . ': <a href="export.php?delete='.urlencode($export_name).'">' . $hesklang['dffs'] . '</a>';
} // No tickets exported, cleanup
else {
hesk_unlink($save_to);
}
require_once(HESK_PATH . 'inc/export_functions.inc.php');
list($success_msg, $tickets_exported) = hesk_export_to_XML($sql);
}
/* Print header */
@ -697,7 +362,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
(<?php echo $hesklang['m' . date('n')]; ?>)
</option>
<option value="4" <?php echo $selected['time'][4]; ?>><?php echo $hesklang['r4']; ?>
(<?php echo $hesklang['m' . date('n', mktime(0, 0, 0, date('m') - 1, date('d'), date('Y')))]; ?>
(<?php echo $hesklang['m' . date('n', mktime(0, 0, 0, date('m') - 1, 1, date('Y')))]; ?>
)
</option>
<option value="5" <?php echo $selected['time'][5]; ?>><?php echo $hesklang['r5']; ?></option>
@ -894,7 +559,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
</div>
<div class="form-group">
<input type="submit" value="<?php echo $hesklang['export_btn']; ?>" class="btn btn-default"/>
<input type="submit" id="export" value="<?php echo $hesklang['export_btn']; ?>" class="btn btn-default"/>
<input type="hidden" name="cot" value="1"/>
</div>
</form>

54
admin/export_ticket.php Normal file
View File

@ -0,0 +1,54 @@
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT',1);
define('HESK_PATH','../');
/* Get all the required files and functions */
require(HESK_PATH . 'hesk_settings.inc.php');
require(HESK_PATH . 'inc/common.inc.php');
require(HESK_PATH . 'inc/admin_functions.inc.php');
require(HESK_PATH . 'inc/privacy_functions.inc.php');
hesk_load_database_functions();
hesk_session_start();
hesk_dbConnect();
hesk_isLoggedIn();
// Check permissions for this feature
hesk_checkPermission('can_export');
// A security check
hesk_token_check();
// Tracking ID
$trackingID = hesk_cleanID() or die($hesklang['int_error'].': '.$hesklang['no_trackID']);
// Generate SQL for the ticket, make sure the user has access to it
$sql = "SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` WHERE `trackid`='".hesk_dbEscape($trackingID)."' AND ";
$sql .= hesk_myCategories();
$sql .= " AND " . hesk_myOwnership();
$sql .= " LIMIT 1";
require_once(HESK_PATH . 'inc/custom_fields.inc.php');
require_once(HESK_PATH . 'inc/statuses.inc.php');
require(HESK_PATH . 'inc/export_functions.inc.php');
list($success_msg, $tickets_exported) = hesk_export_to_XML($sql, true);
if ($tickets_exported == 1)
{
hesk_process_messages($success_msg,'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'SUCCESS');
}
hesk_error($hesklang['n2ex']);

View File

@ -145,21 +145,21 @@ LEFT(`message`, 400) AS `message`,
$sql .= " ( `trackid` = '" . hesk_dbEscape($q) . "' OR `merged` LIKE '%#" . hesk_dbEscape($q) . "#%' ) ";
break;
case 'name':
$sql .= "`name` LIKE '%" . hesk_dbEscape($q) . "%' COLLATE '" . hesk_dbEscape($hesklang['_COLLATE']) . "' ";
$sql .= "`name` LIKE '%".hesk_dbEscape( hesk_dbLike($q) )."%' COLLATE '" . hesk_dbCollate() . "' ";
break;
case 'email':
$sql .= "`email` LIKE '%" . hesk_dbEscape($q) . "%' ";
break;
case 'subject':
$sql .= "`subject` LIKE '%" . hesk_dbEscape($q) . "%' COLLATE '" . hesk_dbEscape($hesklang['_COLLATE']) . "' ";
$sql .= "`subject` LIKE '%".hesk_dbEscape( hesk_dbLike($q) )."%' COLLATE '" . hesk_dbCollate() . "' ";
break;
case 'message':
$sql .= " ( `message` LIKE '%" . hesk_dbEscape($q) . "%' COLLATE '" . hesk_dbEscape($hesklang['_COLLATE']) . "'
$sql .= " ( `message` LIKE '%".hesk_dbEscape( hesk_dbLike($q) )."%' COLLATE '" . hesk_dbCollate() . "'
OR
`id` IN (
SELECT DISTINCT `replyto`
FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "replies`
WHERE `message` LIKE '%" . hesk_dbEscape($q) . "%' COLLATE '" . hesk_dbEscape($hesklang['_COLLATE']) . "' )
WHERE `message` LIKE '%".hesk_dbEscape( hesk_dbLike($q) )."%' COLLATE '" . hesk_dbCollate() . "' )
)
";
break;
@ -170,12 +170,15 @@ LEFT(`message`, 400) AS `message`,
$sql .= "`id` IN (
SELECT DISTINCT `ticket`
FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "notes`
WHERE `message` LIKE '%" . hesk_dbEscape($q) . "%' COLLATE '" . hesk_dbEscape($hesklang['_COLLATE']) . "' )
WHERE `message` LIKE '%".hesk_dbEscape( hesk_dbLike($q) )."%' COLLATE '" . hesk_dbCollate() . "' )
";
break;
case 'ip':
$sql .= "`ip` LIKE '".preg_replace('/[^0-9\.\%]/', '', $q)."' ";
break;
default:
if (isset($hesk_settings['custom_fields'][$what]) && $hesk_settings['custom_fields'][$what]['use']) {
$sql .= "`" . hesk_dbEscape($what) . "` LIKE '%" . hesk_dbEscape($q) . "%' COLLATE '" . hesk_dbEscape($hesklang['_COLLATE']) . "' ";
$sql .= "`" . hesk_dbEscape($what) . "` LIKE '%" . hesk_dbEscape($q) . "%' COLLATE '" . hesk_dbCollate() . "' ";
} else {
$hesk_error_buffer .= '<br />' . $hesklang['invalid_search'];
}
@ -220,6 +223,9 @@ LEFT(`message`, 400) AS `message`,
$sql_count .= $sql;
$sql = $sql_final . $sql;
// Strip extra slashes
$q = stripslashes($q);
/* Prepare variables used in search and forms */
require_once(HESK_PATH . 'inc/prepare_ticket_search.inc.php');
?>

View File

@ -65,22 +65,7 @@ function do_login()
if ($hesk_settings['secimg_use'] == 2 && !isset($_SESSION['img_a_verified'])) {
// Using ReCaptcha?
if ($hesk_settings['recaptcha_use'] == 1) {
require_once(HESK_PATH . 'inc/recaptcha/recaptchalib.php');
$resp = recaptcha_check_answer($hesk_settings['recaptcha_private_key'],
$_SERVER['REMOTE_ADDR'],
hesk_POST('recaptcha_challenge_field', ''),
hesk_POST('recaptcha_response_field', '')
);
if ($resp->is_valid) {
$_SESSION['img_a_verified'] = true;
} else {
$hesk_error_buffer['mysecnum'] = $hesklang['recaptcha_error'];
}
} // Using ReCaptcha API v2?
elseif ($hesk_settings['recaptcha_use'] == 2) {
if ($hesk_settings['recaptcha_use']) {
require(HESK_PATH . 'inc/recaptcha/recaptchalib_v2.php');
$resp = null;
@ -88,7 +73,7 @@ function do_login()
// Was there a reCAPTCHA response?
if (isset($_POST["g-recaptcha-response"])) {
$resp = $reCaptcha->verifyResponse($_SERVER["REMOTE_ADDR"], hesk_POST("g-recaptcha-response"));
$resp = $reCaptcha->verifyResponse(hesk_getClientIP(), hesk_POST("g-recaptcha-response"));
}
if ($resp != null && $resp->success) {
@ -158,7 +143,7 @@ function do_login()
exit();
}
$pass_enc = hesk_Pass2Hash($_SESSION['pass'] . strtolower($user) . $_SESSION['pass']);
$pass_enc = hesk_Pass2Hash($_SESSION['pass'].hesk_mb_strtolower($user).$_SESSION['pass']);
/* Check if default password */
if ($_SESSION['pass'] == '499d74967b28a841c98bb4baaabaad699ff3c079') {
@ -202,7 +187,6 @@ function do_login()
/* Close any old tickets here so Cron jobs aren't necessary */
if ($hesk_settings['autoclose']) {
$revision = sprintf($hesklang['thist3'], hesk_date(), $hesklang['auto']);
$dt = date('Y-m-d H:i:s', time() - $hesk_settings['autoclose'] * 86400);
@ -210,9 +194,7 @@ function do_login()
$closedStatus = hesk_dbFetchAssoc($closedStatusRs);
// Are we allowed to close tickets in this status?
if ($closedStatus['Closable'] == 'yes' || $closedStatus['Closable'] == 'sonly') {
// Notify customer of closed ticket?
if ($hesk_settings['notify_closed']) {
// Get list of tickets
$result = hesk_dbQuery("SELECT * FROM `" . $hesk_settings['db_pfix'] . "tickets` WHERE `status` = " . $closedStatus['ID'] . " AND `lastchange` <= '" . hesk_dbEscape($dt) . "' ");
if (hesk_dbNumRows($result) > 0) {
global $ticket;
@ -226,6 +208,11 @@ function do_login()
$ticket['dt'] = hesk_date($ticket['dt'], true);
$ticket['lastchange'] = hesk_date($ticket['lastchange'], true);
$ticket = hesk_ticketToPlain($ticket, 1, 0);
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_automatically_closed', hesk_date(), array());
// Notify customer of closed ticket?
if ($hesk_settings['notify_closed']) {
// Get list of tickets
hesk_notifyCustomer($modsForHesk_settings, 'ticket_closed');
}
}
@ -234,7 +221,7 @@ function do_login()
// Update ticket statuses and history in database if we're allowed to do so
$defaultCloseRs = hesk_dbQuery('SELECT `ID` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `IsAutocloseOption` = 1');
$defaultCloseStatus = hesk_dbFetchAssoc($defaultCloseRs);
hesk_dbQuery("UPDATE `" . $hesk_settings['db_pfix'] . "tickets` SET `status`=" . intval($defaultCloseStatus['ID']) . ", `closedat`=NOW(), `closedby`='-1', `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `status` = '" . $closedStatus['ID'] . "' AND `lastchange` <= '" . hesk_dbEscape($dt) . "' ");
hesk_dbQuery("UPDATE `" . $hesk_settings['db_pfix'] . "tickets` SET `status`=" . intval($defaultCloseStatus['ID']) . ", `closedat`=NOW(), `closedby`='-1' WHERE `status` = " . $closedStatus['ID'] . " AND `lastchange` <= '" . hesk_dbEscape($dt) . "' ");
}
}
@ -246,10 +233,10 @@ function do_login()
function print_login()
{
global $hesk_settings, $hesklang;
global $hesk_settings, $hesklang, $modsForHesk_settings;
// Tell header to load reCaptcha API if needed
if ($hesk_settings['recaptcha_use'] == 2)
if ($hesk_settings['recaptcha_use'])
{
define('RECAPTCHA',1);
}
@ -269,20 +256,33 @@ function print_login()
?>
<div class="login-box">
<div class="login-logo">
<?php echo $hesk_settings['hesk_title']; ?>
</div>
<div class="login-box-container">
<div class="login-box-background"></div>
<div class="login-box-body">
<div class="loginError">
<?php
/* This will handle error, success and notice messages */
hesk_handle_messages();
// Service messages
$service_messages = mfh_get_service_messages('STAFF_LOGIN');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
?>
</div>
<div class="login-logo">
<?php if ($modsForHesk_settings['login_box_header'] == 'image'): ?>
<img src="<?php echo HESK_PATH . $hesk_settings['cache_dir'] . '/lbh_' . $modsForHesk_settings['login_box_header_image']; ?>"
style="height: 75px">
<?php else:
echo $hesk_settings['hesk_title'];
endif; ?>
</div>
<h4 class="login-box-msg">
<?php echo $hesklang['staff_login_title']; ?>
</h4>
<form class="form-horizontal" role="form" action="index.php" method="post" name="form1">
<form class="form-horizontal" role="form" action="index.php" method="post" name="form1" id="form1">
<?php
$has_error = '';
if (in_array('pass',$_SESSION['a_iserror'])) {
@ -321,7 +321,7 @@ function print_login()
<select class="form-control" name="user">
<?php
while ($row = hesk_dbFetchAssoc($res)):
$sel = (strtolower($savedUser) == strtolower($row['user'])) ? 'selected' : '';
$sel = (hesk_mb_strtolower($savedUser) == hesk_mb_strtolower($row['user'])) ? 'selected="selected"' : '';
?>
<option value="<?php echo $row['user']; ?>" <?php echo $sel; ?>>
<?php echo $row['user']; ?>
@ -350,7 +350,7 @@ function print_login()
</div>
</div>
<?php
if ($hesk_settings['secimg_use'] == 2)
if ($hesk_settings['secimg_use'] == 2 && $hesk_settings['recaptcha_use'] != 1)
{
// SPAM prevention verified for this session
@ -358,34 +358,6 @@ function print_login()
{
echo '<img src="'.HESK_PATH.'img/success.png" width="16" height="16" border="0" alt="" style="vertical-align:text-bottom" /> '.$hesklang['vrfy'];
}
// Not verified yet, should we use Recaptcha?
elseif ($hesk_settings['recaptcha_use'] == 1)
{
?>
<script type="text/javascript">
var RecaptchaOptions = {
theme : '<?php echo ( isset($_SESSION['a_iserror']) && in_array('mysecnum',$_SESSION['a_iserror']) ) ? 'red' : 'white'; ?>',
custom_translations : {
visual_challenge : "<?php echo hesk_slashJS($hesklang['visual_challenge']); ?>",
audio_challenge : "<?php echo hesk_slashJS($hesklang['audio_challenge']); ?>",
refresh_btn : "<?php echo hesk_slashJS($hesklang['refresh_btn']); ?>",
instructions_visual : "<?php echo hesk_slashJS($hesklang['instructions_visual']); ?>",
instructions_context : "<?php echo hesk_slashJS($hesklang['instructions_context']); ?>",
instructions_audio : "<?php echo hesk_slashJS($hesklang['instructions_audio']); ?>",
help_btn : "<?php echo hesk_slashJS($hesklang['help_btn']); ?>",
play_again : "<?php echo hesk_slashJS($hesklang['play_again']); ?>",
cant_hear_this : "<?php echo hesk_slashJS($hesklang['cant_hear_this']); ?>",
incorrect_try_again : "<?php echo hesk_slashJS($hesklang['incorrect_try_again']); ?>",
image_alt_text : "<?php echo hesk_slashJS($hesklang['image_alt_text']); ?>"
}
};
</script>
<?php
require_once(HESK_PATH . 'inc/recaptcha/recaptchalib.php');
echo '<div class="form-group"><div class="col-md-8 col-md-offset-4">';
echo recaptcha_get_html($hesk_settings['recaptcha_public_key'], null, true);
echo '</div></div>';
}
// Use reCaptcha API v2?
elseif ($hesk_settings['recaptcha_use'] == 2)
{
@ -443,7 +415,7 @@ function print_login()
?>
<div class="form-group">
<div class="col-md-offset-4 col-md-8">
<input type="submit" value="<?php echo $hesklang['click_login']; ?>" class="btn btn-default">
<input type="submit" value="<?php echo $hesklang['click_login']; ?>" class="btn btn-default" id="recaptcha-submit">
<input type="hidden" name="a" value="do_login">
<?php
if ( hesk_isREQUEST('goto') && $url=hesk_REQUEST('goto') )
@ -459,7 +431,20 @@ function print_login()
?>
</div>
</div>
<?php
// Use Invisible reCAPTCHA?
if ($hesk_settings['secimg_use'] == 2 && $hesk_settings['recaptcha_use'] == 1 && ! isset($_SESSION['img_a_verified'])) {
?>
<div class="g-recaptcha" data-sitekey="<?php echo $hesk_settings['recaptcha_public_key']; ?>" data-bind="recaptcha-submit" data-callback="recaptcha_submitForm"></div>
<?php
}
?>
</form>
<a class="btn btn-default" href="<?php echo $hesk_settings['hesk_url']; ?>">
<i class="fa fa-chevron-left"></i> <?php echo $hesklang['back']; ?>
</a>
</div>
</div>
</div>
<?php

View File

@ -1,32 +1,15 @@
<?php
/*******************************************************************************
* Title: Help Desk Software HESK
* Version: 2.6.8 from 10th August 2016
* Author: Klemen Stirn
* Website: https://www.hesk.com
********************************************************************************
* COPYRIGHT AND TRADEMARK NOTICE
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
* HESK is a registered trademark of Klemen Stirn.
* The HESK may be used and modified free of charge by anyone
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
* By using this code you agree to indemnify Klemen Stirn from any
* liability that might arise from it's use.
* Selling the code for this program, in part or full, without prior
* written consent is expressly forbidden.
* Using this code, in part or full, to create derivate work,
* new scripts or products is expressly forbidden. Obtain permission
* before redistributing this software over the Internet or in
* any other medium. In all cases copyright and header must remain intact.
* This Copyright is in full effect in any country that has International
* Trade Agreements with the United States of America or
* with the European Union.
* Removing any of the copyright notices without purchasing a license
* is expressly forbidden. To remove HESK copyright notice you must purchase
* a license for this script. For more information on how to obtain
* a license please visit the page below:
* https://www.hesk.com/buy.php
*******************************************************************************/
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT',1);
define('HESK_PATH','../');
@ -41,9 +24,12 @@ require(HESK_PATH . 'inc/knowledgebase_functions.inc.php');
require(HESK_PATH . 'inc/mail_functions.inc.php');
hesk_load_database_functions();
hesk_session_start();
hesk_dbConnect();
hesk_isLoggedIn();
hesk_kb_preheader();
/* Is Knowledgebase enabled? */
if ( ! $hesk_settings['kb_enable'])
@ -109,14 +95,17 @@ exit();
/*** START FUNCTIONS ***/
function hesk_kb_header($kb_link, $catid=1)
{
function hesk_kb_preheader() {
global $hesk_settings, $hesklang, $can_man_kb;
/* Print admin navigation */
require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
}
function hesk_kb_header($kb_link, $catid=1)
{
global $hesk_settings, $hesklang, $can_man_kb;
?>
<ol class="breadcrumb">
@ -130,12 +119,11 @@ function hesk_kb_header($kb_link, $catid=1)
?>
<li class="active"><?php echo $kb_link; ?></li>
</ol>
<?php show_subnav('view', $catid); ?>
<section style="padding: 15px;">
<?php hesk_kbSearchLarge(1); ?>
</section>
<?php
show_subnav('view', $catid);
echo '<div style="margin-left:40px;margin-right:40px">';
hesk_kbSearchLarge(1);
echo '</div>';
} // END hesk_kb_header()
@ -143,15 +131,12 @@ function hesk_kb_search($query)
{
global $hesk_settings, $hesklang;
define('HESK_NO_ROBOTS',1);
hesk_kb_header($hesk_settings['kb_link']);
$res = hesk_dbQuery('SELECT t1.`id`, t1.`subject`, LEFT(`t1`.`content`, '.max(200, $hesk_settings['kb_substrart'] * 2).') AS `content`, t1.`rating` FROM `'.hesk_dbEscape($hesk_settings['db_pfix']).'kb_articles` AS t1 LEFT JOIN `'.hesk_dbEscape($hesk_settings['db_pfix']).'kb_categories` AS t2 ON t1.`catid` = t2.`id` '." WHERE t1.`type` IN ('0','1') AND MATCH(`subject`,`content`,`keywords`) AGAINST ('".hesk_dbEscape($query)."') LIMIT ".intval($hesk_settings['kb_search_limit']));
$num = hesk_dbNumRows($res);
$show_default_category = false;
?>
<div class="content-wrapper">
<?php hesk_kb_header($hesk_settings['kb_link']); ?>
<section style="padding: 15px">
<div class="box">
<div class="box-header with-border">
@ -225,13 +210,21 @@ function hesk_show_kb_article($artid)
// Print header
$hesk_settings['tmp_title'] = $article['subject'];
hesk_kb_header($hesk_settings['kb_link'], $article['catid']);
// Update views by 1
hesk_dbQuery('UPDATE `'.hesk_dbEscape($hesk_settings['db_pfix'])."kb_articles` SET `views`=`views`+1 WHERE `id`={$artid}");
?>
<div class="content-wrapper">
<?php
hesk_kb_header($hesk_settings['kb_link'], $article['catid']);
echo '<div style="margin-left:40px;margin-right:40px">';
$service_messages = mfh_get_service_messages('STAFF_VIEW_KB_ARTICLE');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
echo '</div>';
?>
<section class="content">
<div class="box">
<div class="box-header with-border">
@ -404,17 +397,24 @@ function hesk_show_kb_article($artid)
function hesk_show_kb_category($catid, $is_search = 0) {
global $hesk_settings, $hesklang;
if ($is_search == 0)
{
/* Print header */
hesk_kb_header($hesk_settings['kb_link'], $catid);
}
$res = hesk_dbQuery("SELECT `name`,`parent` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."kb_categories` WHERE `id`='".intval($catid)."' LIMIT 1");
$thiscat = hesk_dbFetchAssoc($res) or hesk_error($hesklang['kb_cat_inv']);
?>
<div class="content-wrapper">
<?php
if ($is_search == 0)
{
/* Print header */
hesk_kb_header($hesk_settings['kb_link'], $catid);
echo '<div style="margin-left:40px;margin-right:40px">';
$service_messages = mfh_get_service_messages('STAFF_KB_HOME');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
echo '</div>';
} ?>
<section class="content">
<?php if ($thiscat['parent']): ?>
<h3><?php echo $hesklang['kb_cat'].': '.$thiscat['name']; ?></h3>

View File

@ -37,27 +37,31 @@ hesk_token_check();
/* Ticket ID */
$trackingID = hesk_cleanID() or die($hesklang['int_error'] . ': ' . $hesklang['no_trackID']);
// Get ticket info
$result = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid`='" . hesk_dbEscape($trackingID) . "' LIMIT 1");
if (hesk_dbNumRows($result) != 1) {
hesk_error($hesklang['ticket_not_found']);
}
$ticket = hesk_dbFetchAssoc($result);
$audit_unlocked = null;
$audit_locked = null;
/* New locked status */
if (empty($_GET['locked'])) {
$status = 0;
$tmp = $hesklang['tunlock'];
$revision = sprintf($hesklang['thist6'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$audit_unlocked = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$closedby_sql = ' , `closedat`=NULL, `closedby`=NULL ';
} else {
$status = 1;
$tmp = $hesklang['tlock'];
$revision = sprintf($hesklang['thist5'], hesk_date(), $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$audit_locked = array(0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
$closedby_sql = ' , `closedat`=NOW(), `closedby`=' . intval($_SESSION['id']) . ' ';
// Notify customer of closed ticket?
if ($hesk_settings['notify_closed']) {
// Get ticket info
$result = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid`='" . hesk_dbEscape($trackingID) . "' LIMIT 1");
if (hesk_dbNumRows($result) != 1) {
hesk_error($hesklang['ticket_not_found']);
}
$ticket = hesk_dbFetchAssoc($result);
$closedStatusRS = hesk_dbQuery('SELECT `ID` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'statuses` WHERE `IsClosed` = 1');
$ticketIsOpen = true;
while ($row = hesk_dbFetchAssoc($closedStatusRS)) {
@ -82,7 +86,17 @@ $statusRs = hesk_dbQuery($statusSql);
$statusRow = hesk_dbFetchAssoc($statusRs);
$statusId = $statusRow['ID'];
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`= {$statusId},`locked`='{$status}' $closedby_sql , `history`=CONCAT(`history`,'" . hesk_dbEscape($revision) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `status`= {$statusId},`locked`='{$status}' $closedby_sql WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
if ($audit_unlocked) {
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_unlocked', hesk_date(),
$audit_unlocked);
}
if ($audit_locked) {
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_locked', hesk_date(),
$audit_locked);
}
/* Back to ticket page and show a success message */
hesk_process_messages($tmp, 'admin_ticket.php?track=' . $trackingID . '&Refresh=' . rand(10000, 99999), 'SUCCESS');

View File

@ -32,7 +32,7 @@ $modsForHesk_settings = mfh_getSettings();
/* List of staff */
$admins = array();
$res = hesk_dbQuery("SELECT `id`,`name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` ORDER BY `name` ASC");
$res = hesk_dbQuery("SELECT `id`,`name` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` WHERE `active` = '1' ORDER BY `name` ASC");
while ($row = hesk_dbFetchAssoc($res)) {
$admins[$row['id']] = $row['name'];
}
@ -450,10 +450,10 @@ function show_message()
$folder = '&amp;folder=outbox';
if ($pm['to'] == $_SESSION['id'])
{
echo '<a class="btn btn-default" href="mail.php?a=mark_unread&amp;id='.$id.'&amp;token='.hesk_token_echo(0).'"><i class="fa fa-envelope-o icon-link"></i> '.$hesklang['mau'].'</a> ';
echo '<a name="MAU '.$pm['subject'].'" class="btn btn-default" href="mail.php?a=mark_unread&amp;id='.$id.'&amp;token='.hesk_token_echo(0).'"><i class="fa fa-envelope-o icon-link"></i> '.$hesklang['mau'].'</a> ';
$folder = '';
}
echo '<a class="btn btn-danger" href="mail.php?a=delete&amp;id='.$id.'&amp;token='.hesk_token_echo(0).$folder.'" onclick="return hesk_confirmExecute(\''.hesk_makeJsString($hesklang['delm']).'?\');"><i class="fa fa-times icon-link"></i> '.$hesklang['delm'].'</a>';
echo '<a name="Delete '.$pm['subject'].'" class="btn btn-danger" href="mail.php?a=delete&amp;id='.$id.'&amp;token='.hesk_token_echo(0).$folder.'" onclick="return hesk_confirmExecute(\''.hesk_makeJsString($hesklang['delm']).'?\');"><i class="fa fa-times icon-link"></i> '.$hesklang['delm'].'</a>';
?>
</div>
</div>
@ -571,7 +571,7 @@ function mail_list_messages()
$pm['dt'] = hesk_dateToString($pm['dt'], 0, 0, 0, true)
?>
<tr>
<td><input type="checkbox" name="id[]" value="<?php echo $pm['id']; ?>" />&nbsp;</td>
<td><input type="checkbox" name="id[]" id="<?php echo $pm['id']; ?>" value="<?php echo $pm['id']; ?>" />&nbsp;</td>
<td><?php echo $pm['subject']; ?></td>
<td><?php echo $pm['name']; ?></td>
<td><?php echo $pm['dt']; ?></td>

View File

@ -74,9 +74,9 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
var msg = '';
<?php
if ($modsForHesk_settings['rich_text_for_tickets']) { ?>
msg = tinymce.get("message").getContent();
tinymce.get("message").setContent('');
tinymce.get("message").execCommand('mceInsertRawHTML', false, msg + text_to_insert);
msg = $('#message').val();
$("#message").summernote('reset');
$("#message").summernote('editor.insertText', msg + text_to_insert));
<?php } else { ?>
msg = document.getElementById('message').value;
document.getElementById('message').value = msg + text_to_insert;
@ -190,7 +190,7 @@ $num = hesk_dbNumRows($result);
}
echo '
<a href="manage_canned.php?a=remove&amp;id=' . $mysaved['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="' . $hesklang['delete'] . '"></i></a>&nbsp;</td>
<a name="'.$mysaved['title'].'" href="manage_canned.php?a=remove&amp;id=' . $mysaved['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="' . $hesklang['delete'] . '"></i></a>&nbsp;</td>
</tr>
';
} // End while
@ -202,21 +202,15 @@ $num = hesk_dbNumRows($result);
<?php if ($modsForHesk_settings['rich_text_for_tickets']): ?>
<script type="text/javascript">
/* <![CDATA[ */
tinyMCE.init({
mode: "textareas",
editor_selector: "htmlEditor",
elements: "content",
theme: "advanced",
convert_urls: false,
theme_advanced_buttons1: "cut,copy,paste,|,undo,redo,|,formatselect,fontselect,fontsizeselect,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull",
theme_advanced_buttons2: "sub,sup,|,charmap,|,bullist,numlist,|,outdent,indent,insertdate,inserttime,preview,|,forecolor,backcolor,|,hr,removeformat,visualaid,|,link,unlink,anchor,image,cleanup,code",
theme_advanced_buttons3: "",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
theme_advanced_resizing: true
$(document).ready(function() {
$('.htmlEditor').summernote({
height: 200,
toolbar: [
['style', ['bold', 'italic', 'underline', 'clear']],
['font', ['strikethrough', 'superscript', 'subscript']],
['para', ['ul', 'ol']]
]
});
});
/* ]]> */
</script>
@ -254,8 +248,7 @@ $num = hesk_dbNumRows($result);
if (myMsg == '') {
if (useHtmlEditor) {
tinymce.get("message").setContent('');
tinymce.get("message").execCommand('mceInsertRawHTML', false, '');
$("#message").summernote("reset");
}
else {
$('#message').val('');
@ -265,8 +258,8 @@ $num = hesk_dbNumRows($result);
}
if (document.getElementById) {
if (useHtmlEditor) {
tinymce.get("message").setContent('');
tinymce.get("message").execCommand('mceInsertRawHTML', false, myMsg);
$("#message").summernote('reset');
$("#message").summernote('editor.insertText', myMsg));
} else {
myMsg = $('<textarea />').html(myMsg).text();
$('#message').val(myMsg).trigger('input');
@ -370,6 +363,8 @@ $num = hesk_dbNumRows($result);
onclick="hesk_insertTag('HESK_TRACK_ID')"><?php echo $hesklang['trackID']; ?></a> |
<a href="javascript:void(0)"
onclick="hesk_insertTag('HESK_NAME')"><?php echo $hesklang['name']; ?></a> |
<a href="javascript:void(0)"
onclick="hesk_insertTag('HESK_FIRST_NAME')"><?php echo $hesklang['fname']; ?></a> |
<a href="javascript:void(0)"
onclick="hesk_insertTag('HESK_EMAIL')"><?php echo $hesklang['email']; ?></a> |
<a href="javascript:void(0)"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,275 @@
<?php
define('IN_SCRIPT', 1);
define('HESK_PATH', '../');
define('PAGE_TITLE', 'ADMIN_CUSTOM_NAV_ELEMENTS');
define('MFH_PAGE_LAYOUT', 'TOP_ONLY');
define('EXTRA_JS', '<script src="'.HESK_PATH.'internal-api/js/manage-custom-nav-elements.js"></script>');
/* Get all the required files and functions */
require(HESK_PATH . 'hesk_settings.inc.php');
require(HESK_PATH . 'inc/common.inc.php');
require(HESK_PATH . 'inc/admin_functions.inc.php');
require(HESK_PATH . 'inc/mail_functions.inc.php');
hesk_load_database_functions();
hesk_session_start();
hesk_dbConnect();
hesk_isLoggedIn();
//hesk_checkPermission('can_man_custom_nav');
/* Print header */
require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
/* Print main manage users page */
require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
?>
<div class="content-wrapper">
<section class="content">
<div class="box">
<div class="box-header with-border">
<h1 class="box-title">
<?php echo $hesklang['custom_nav_menu_elements']; ?>
</h1>
<div class="box-tools pull-right">
<button type="button" class="btn btn-box-tool" data-widget="collapse">
<i class="fa fa-minus"></i>
</button>
</div>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-12 text-right">
<button id="create-button" class="btn btn-success">
<i class="fa fa-plus-circle"></i>&nbsp;
<?php echo $hesklang['create_new']; ?>
</button>
</div>
<div class="col-md-12">
<table class="table table-striped">
<thead>
<tr>
<th><?php echo $hesklang['id']; ?></th>
<th><?php echo $hesklang['custom_nav_text']; ?></th>
<th><?php echo $hesklang['custom_nav_subtext']; ?></th>
<th><?php echo $hesklang['image_url_slash_font_icon']; ?></th>
<th><?php echo $hesklang['url']; ?></th>
<th><?php echo $hesklang['actions']; ?></th>
</tr>
</thead>
<tbody id="table-body">
</tbody>
</table>
</div>
</div>
</div>
<div class="overlay" id="overlay">
<i class="fa fa-spinner fa-spin"></i>
</div>
</div>
</section>
</div>
<div class="modal fade" id="nav-element-modal" tabindex="-1" role="dialog" style="overflow: hidden">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header" style="cursor: move">
<button type="button" class="close cancel-callback" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
<h4 class="modal-title" id="edit-label">
<?php echo $hesklang['edit_custom_nav_element_title_case']; ?>
</h4>
<h4 class="modal-title" id="create-label">
<?php echo $hesklang['create_custom_nav_element_title_case']; ?>
</h4>
</div>
<form id="manage-nav-element" class="form-horizontal" data-toggle="validator">
<input type="hidden" name="id">
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="place" class="col-md-4 col-sm-12 control-label">
<?php echo $hesklang['place']; ?>
<i class="fa fa-question-circle settingsquestionmark" data-toggle="htmlpopover"
title="<?php echo $hesklang['place']; ?>"
data-content="<?php echo $hesklang['place_help']; ?>"></i>
</label>
<div class="col-md-8 col-sm-12">
<select name="place" id="place" class="form-control"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
required>
<option value="1"><?php echo $hesklang['homepage_block']; ?></option>
<option value="2"><?php echo $hesklang['customer_navigation']; ?></option>
<option value="3"><?php echo $hesklang['staff_navigation']; ?></option>
</select>
<div class="help-block with-errors"></div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6 col-sm-12">
<h4><?php echo $hesklang['custom_nav_text']; ?></h4>
<?php foreach ($hesk_settings['languages'] as $language => $value): ?>
<div class="form-group">
<label for="text[<?php echo $language; ?>]" class="col-md-4 col-sm-12 control-label">
<?php echo $language; ?>
</label>
<div class="col-md-8 col-sm-12">
<input type="text" name="text" class="form-control"
data-text-language="<?php echo $language; ?>"
id="text[<?php echo $language; ?>" placeholder="<?php echo $hesklang['custom_nav_text']; ?>"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
required>
<div class="help-block with-errors"></div>
</div>
</div>
<?php endforeach; ?>
<div id="subtext">
<h4><?php echo $hesklang['custom_nav_subtext']; ?></h4>
<?php foreach ($hesk_settings['languages'] as $language => $value): ?>
<div class="form-group">
<label for="subtext[<?php echo $language; ?>]" class="col-md-4 col-sm-12 control-label">
<?php echo $language; ?>
</label>
<div class="col-md-8 col-sm-12">
<input type="text" name="subtext" class="form-control"
data-subtext-language="<?php echo $language; ?>"
id="subtext[<?php echo $language; ?>" placeholder="<?php echo $hesklang['custom_nav_subtext']; ?>"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
required>
<div class="help-block with-errors"></div>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<div class="col-md-6 col-sm-12">
<h4><?php echo $hesklang['url']; ?></h4>
<div class="form-group">
<label for="image-type" class="col-md-4 col-sm-12 control-label">
<?php echo $hesklang['url']; ?>
<i class="fa fa-question-circle settingsquestionmark" data-toggle="htmlpopover"
title="<?php echo $hesklang['url']; ?>"
data-content="<?php echo $hesklang['url_help']; ?>"></i>
</label>
<div class="col-md-8 col-sm-12">
<input type="text" name="url" class="form-control"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
placeholder="<?php echo $hesklang['url']; ?>" required>
<div class="help-block with-errors"></div>
</div>
</div>
<h4><?php echo $hesklang['image']; ?></h4>
<div class="form-group">
<label for="image-type" class="col-md-4 col-sm-12 control-label"><?php echo $hesklang['image_type']; ?></label>
<div class="col-md-8 col-sm-12">
<select name="image-type" id="image-type" class="form-control"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
required>
<option value="image-url"><?php echo $hesklang['image_url']; ?></option>
<option value="font-icon"><?php echo $hesklang['font_icon']; ?></option>
</select>
<div class="help-block with-errors"></div>
</div>
</div>
<div class="form-group" id="image-url-group">
<label for="image-url" class="col-md-4 col-sm-12 control-label">
<?php echo $hesklang['image_url']; ?>
<i class="fa fa-question-circle settingsquestionmark" data-toggle="htmlpopover"
title="<?php echo $hesklang['image_url']; ?>"
data-content="<?php echo $hesklang['image_url_help']; ?>"></i>
</label>
<div class="col-md-8 col-sm-12">
<input type="text" name="image-url" class="form-control"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
placeholder="<?php echo $hesklang['image_url']; ?>" required>
<div class="help-block with-errors"></div>
</div>
</div>
<div class="form-group" id="font-icon-group">
<p style="display:none" id="no-icon"><?php echo $hesklang['sm_no_icon']; ?></p>
<p style="display:none" id="search-icon"><?php echo $hesklang['sm_search_icon']; ?></p>
<p style="display:none"
id="footer-icon"><?php echo $hesklang['sm_iconpicker_footer_label']; ?></p>
<label for="font-icon" class="col-md-4 col-sm-12 control-label"><?php echo $hesklang['font_icon']; ?></label>
<div class="col-md-8 col-sm-12">
<div class="btn btn-default iconpicker-container" data-toggle="nav-iconpicker">
</div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<div class="btn-group" id="action-buttons">
<button type="button" class="btn btn-default cancel-button" data-dismiss="modal">
<i class="fa fa-times-circle"></i>
<span><?php echo $hesklang['cancel']; ?></span>
</button>
<button type="submit" class="btn btn-success save-button">
<i class="fa fa-check-circle"></i>
<span><?php echo $hesklang['save']; ?></span>
</button>
</div>
</div>
</form>
</div>
</div>
</div>
<?php
echo mfh_get_hidden_fields_for_language(
array(
'edit',
'delete',
'no_custom_nav_elements_found',
'failed_to_load_custom_nav_elements',
'custom_nav_element_deleted',
'error_deleting_custom_nav_element',
'error_sorting_custom_nav_elements',
'custom_nav_element_created',
'custom_nav_element_saved',
'homepage_block',
'customer_navigation',
'staff_navigation',
'error_saving_custom_nav_element',
)
);
?>
<script type="text/html" id="nav-element-template">
<tr>
<td><span data-property="id" data-value="x"></span></td>
<td><span>
<ul data-property="text" class="list-unstyled"></ul>
</span></td>
<td><span>
<ul data-property="subtext" class="list-unstyled"></ul>
</span></td>
<td><span data-property="image-or-font"></span></td>
<td><span data-property="url"></span></td>
<td>
<a href="#" data-action="sort"
data-direction="up">
<i class="fa fa-fw fa-arrow-up icon-link green"
data-toggle="tooltip" title="<?php echo $hesklang['move_up']; ?>"></i>
</a>
<a href="#" data-action="sort"
data-direction="down">
<i class="fa fa-fw fa-arrow-down icon-link green"
data-toggle="tooltip" title="<?php echo $hesklang['move_dn'] ?>"></i>
</a>
<a href="#" data-action="edit">
<i class="fa fa-fw fa-pencil icon-link orange"
data-toggle="tooltip" title="<?php echo $hesklang['edit']; ?>"></i>
</a>
<a href="#" data-action="delete">
<i class="fa fa-fw fa-times icon-link red"
data-toggle="tooltip" title="<?php echo $hesklang['delete']; ?>"></i>
</a>
</td>
</tr>
</script>
<?php
require_once(HESK_PATH . 'inc/footer.inc.php');

View File

@ -10,6 +10,7 @@ require(HESK_PATH . 'hesk_settings.inc.php');
require(HESK_PATH . 'inc/common.inc.php');
require(HESK_PATH . 'inc/admin_functions.inc.php');
require(HESK_PATH . 'inc/mail_functions.inc.php');
require(HESK_PATH . 'inc/custom_fields.inc.php');
hesk_load_database_functions();
hesk_session_start();
@ -38,25 +39,22 @@ if (isset($_POST['action'])) {
require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
if ($modsForHesk_settings['html_emails']) {
echo '<script type="text/javascript">
tinyMCE.init({
mode : "textareas",
editor_selector : "htmlEditor",
elements : "content",
theme : "advanced",
convert_urls : false,
gecko_spellcheck: true,
theme_advanced_buttons1 : "cut,copy,paste,|,undo,redo,|,formatselect,fontselect,fontsizeselect,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull",
theme_advanced_buttons2 : "sub,sup,|,charmap,|,bullist,numlist,|,outdent,indent,insertdate,inserttime,preview,|,forecolor,backcolor,|,hr,removeformat,visualaid,|,link,unlink,anchor,image,cleanup,code",
theme_advanced_buttons3 : "",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_resizing : true
?>
<script type="text/javascript">
/* <![CDATA[ */
$(document).ready(function() {
$('.htmlEditor').summernote({
height: 200,
toolbar: [
['style', ['bold', 'italic', 'underline', 'clear']],
['font', ['strikethrough', 'superscript', 'subscript']],
['para', ['ul', 'ol']]
]
});
</script>';
});
/* ]]> */
</script>
<?php
}
/* Print main manage users page */
@ -276,12 +274,12 @@ function getTemplateMarkup($template, $languageCode, $html = false)
$templateUrl = urlencode($template);
$languageCodeUrl = urlencode($languageCode);
if ($html) {
$markup = '<a href="manage_email_templates.php?action=edit&template=' . $templateUrl . '&language=' . $languageCodeUrl . '&html=true">';
$markup = '<a name="Edit '.$templateUrl.'" href="manage_email_templates.php?action=edit&template=' . $templateUrl . '&language=' . $languageCodeUrl . '&html=true">';
$markup .= '<i class="fa fa-html5 font-size-150" data-toggle="tooltip" title="' . $hesklang['edit_html_template'] . '"></i>';
$markup .= '</a>';
return $markup;
} else {
$markup = '<a href="manage_email_templates.php?action=edit&template=' . $templateUrl . '&language=' . $languageCodeUrl . '&html=false">';
$markup = '<a name="Edit '.$templateUrl.'" href="manage_email_templates.php?action=edit&template=' . $templateUrl . '&language=' . $languageCodeUrl . '&html=false">';
$markup .= '<i class="fa fa-file-text-o font-size-150" data-toggle="tooltip" title="' . $hesklang['edit_plain_text_template'] . '"></i>';
$markup .= '</a>';
return $markup;
@ -312,6 +310,7 @@ function getSpecialTagMap()
$map = array();
$map['%%NAME%%'] = $hesklang['customer_name'];
$map['%%FIRST_NAME%%'] = $hesklang['fname'];
$map['%%EMAIL%%'] = $hesklang['customer_email'];
$map['%%SUBJECT%%'] = $hesklang['ticket_subject'];
$map['%%MESSAGE%%'] = $hesklang['ticket_message'];
@ -326,6 +325,8 @@ function getSpecialTagMap()
$map['%%OWNER%%'] = $hesklang['ticket_owner'];
$map['%%PRIORITY%%'] = $hesklang['ticket_priority'];
$map['%%STATUS%%'] = $hesklang['ticket_status'];
$map['%%LAST_REPLY_BY%%'] = $hesklang['last_replier'];
$map['%%TIME_WORKED%%'] = $hesklang['ts'];
$i = 1;
foreach ($hesk_settings['custom_fields'] as $key => $value) {

View File

@ -1,32 +1,15 @@
<?php
/*******************************************************************************
* Title: Help Desk Software HESK
* Version: 2.6.8 from 10th August 2016
* Author: Klemen Stirn
* Website: https://www.hesk.com
********************************************************************************
* COPYRIGHT AND TRADEMARK NOTICE
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
* HESK is a registered trademark of Klemen Stirn.
* The HESK may be used and modified free of charge by anyone
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
* By using this code you agree to indemnify Klemen Stirn from any
* liability that might arise from it's use.
* Selling the code for this program, in part or full, without prior
* written consent is expressly forbidden.
* Using this code, in part or full, to create derivate work,
* new scripts or products is expressly forbidden. Obtain permission
* before redistributing this software over the Internet or in
* any other medium. In all cases copyright and header must remain intact.
* This Copyright is in full effect in any country that has International
* Trade Agreements with the United States of America or
* with the European Union.
* Removing any of the copyright notices without purchasing a license
* is expressly forbidden. To remove HESK copyright notice you must purchase
* a license for this script. For more information on how to obtain
* a license please visit the page below:
* https://www.hesk.com/buy.php
*******************************************************************************/
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT',1);
define('HESK_PATH','../');
@ -202,9 +185,9 @@ while (count($kb_cat) > 0)
// Generate KB menu icons
$menu_icons =
'<a href="manage_knowledgebase.php?a=add_article&amp;catid='.$my.'" onclick="document.getElementById(\'option'.$j.'\').selected=true;return true;"><i class="fa fa-plus font-size-16p green" ></i></a> '
.'<a href="manage_knowledgebase.php?a=add_category&amp;parent='.$my.'" onclick="document.getElementById(\'option'.$j.'_2\').selected=true;return true;"><i class="fa fa-caret-right font-size-16p blue"></i></a> '
.'<a href="manage_knowledgebase.php?a=manage_cat&amp;catid='.$my.'"><i class="fa fa-gear font-size-16p gray"></i></a> '
'<a name="Add article to '.$cat['name'].'" href="manage_knowledgebase.php?a=add_article&amp;catid='.$my.'" onclick="document.getElementById(\'option'.$j.'\').selected=true;return true;"><i class="fa fa-plus font-size-16p green" ></i></a> '
.'<a name="Add sub to '.$cat['name'].'" href="manage_knowledgebase.php?a=add_category&amp;parent='.$my.'" onclick="document.getElementById(\'option'.$j.'_2\').selected=true;return true;"><i class="fa fa-caret-right font-size-16p blue"></i></a> '
.'<a name="Manage '.$cat['name'].'" href="manage_knowledgebase.php?a=manage_cat&amp;catid='.$my.'"><i class="fa fa-gear font-size-16p gray"></i></a> '
;
// Can this category be moved up?
@ -229,7 +212,8 @@ while (count($kb_cat) > 0)
if (isset($node[$up]))
{
$node[$my] = &$node[$up]->addItem(new HTML_TreeNode(array('hesk_selected' => $selected, 'text' => $text, 'text_short' => $text_short, 'menu_icons' => $menu_icons, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true)));
$HTML_TreeNode[$my] = new HTML_TreeNode(array('hesk_selected' => $selected, 'text' => $text, 'text_short' => $text_short, 'menu_icons' => $menu_icons, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true));
$node[$my] = &$node[$up]->addItem($HTML_TreeNode[$my]);
}
else
{
@ -259,8 +243,11 @@ while (count($kb_cat) > 0)
$menu->addItem($node[1]);
// Create the presentation class
$treeMenu = & ref_new(new HTML_TreeMenu_DHTML($menu, array('images' => '../img', 'defaultClass' => 'treeMenuDefault', 'isDynamic' => true)));
$listBox = & ref_new(new HTML_TreeMenu_Listbox($menu));
$HTML_TreeMenu_DHTML = new HTML_TreeMenu_DHTML($menu, array('images' => '../img', 'defaultClass' => 'treeMenuDefault', 'isDynamic' => true));
$treeMenu = & ref_new($HTML_TreeMenu_DHTML);
$HTML_TreeMenu_Listbox = new HTML_TreeMenu_Listbox($menu);
$listBox = & ref_new($HTML_TreeMenu_Listbox);
/* Hide new article and new category forms by default */
if (!isset($_SESSION['hide']))
@ -287,6 +274,12 @@ if (!isset($_SESSION['hide']['treemenu']))
<?php
show_subnav();
// Service messages
$service_messages = mfh_get_service_messages('STAFF_KB_HOME');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
// Show a notice if total public articles is less than 5
if ($total_articles < 5)
{
@ -352,22 +345,18 @@ if (!isset($_SESSION['hide']['new_article']))
{
?>
<script type="text/javascript">
tinyMCE.init({
mode : "exact",
elements : "content",
theme : "advanced",
convert_urls : false,
gecko_spellcheck: true,
theme_advanced_buttons1 : "cut,copy,paste,|,undo,redo,|,formatselect,fontselect,fontsizeselect,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull",
theme_advanced_buttons2 : "sub,sup,|,charmap,|,bullist,numlist,|,outdent,indent,insertdate,inserttime,preview,|,forecolor,backcolor,|,hr,removeformat,visualaid,|,link,unlink,anchor,image,cleanup,code",
theme_advanced_buttons3 : "",
theme_advanced_toolbar_location : "top",
theme_advanced_toolbar_align : "left",
theme_advanced_statusbar_location : "bottom",
theme_advanced_resizing : true
/* <![CDATA[ */
$(document).ready(function() {
$('#content').summernote({
height: 200,
toolbar: [
['style', ['bold', 'italic', 'underline', 'clear']],
['font', ['strikethrough', 'superscript', 'subscript']],
['para', ['ul', 'ol']]
]
});
});
/* ]]> */
</script>
<?php
}
@ -475,7 +464,7 @@ if (!isset($_SESSION['hide']['new_article']))
<?php build_dropzone_markup(true); ?>
</div>
<?php
display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/admin/knowledgebase/upload-attachment.php');
display_dropzone_field(HESK_PATH . 'internal-api/admin/knowledgebase/upload-attachment.php');
endif; // End attachments
?>
@ -916,7 +905,7 @@ function import_article()
$_SESSION['new_article'] = array(
'html' => 0,
'subject' => $ticket['subject'],
'content' => hesk_msgToPlain($ticket['message']),
'content' => hesk_msgToPlain($ticket['message'], 0, 0),
);
}
@ -931,10 +920,14 @@ function import_article()
}
else
{
$_SESSION['new_article']['content'] .= "\n\n" . hesk_msgToPlain($reply['message']);
$_SESSION['new_article']['content'] .= "\n\n" . hesk_msgToPlain($reply['message'], 0, 0);
}
}
// Make sure everything is extra slashed as stripslashes will be called later
$_SESSION['new_article']['subject'] = addslashes($_SESSION['new_article']['subject']);
$_SESSION['new_article']['content'] = addslashes($_SESSION['new_article']['content']);
hesk_process_messages($hesklang['import'],'NOREDIRECT','NOTICE');
} // END add_article()
@ -1079,6 +1072,9 @@ function edit_category()
// Now delete the category
hesk_dbQuery("DELETE FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."kb_categories` WHERE `id`='".intval($catid)."'");
// Clear KB cache
hesk_purge_cache('kb');
$_SESSION['hide'] = array(
//'treemenu' => 1,
'new_article' => 1,
@ -1251,6 +1247,9 @@ function save_article()
// Update article order
update_article_order($catid);
// Clear KB cache
hesk_purge_cache('kb');
// Redirect to the correct page
switch ($from) {
case 'draft':
@ -1353,7 +1352,8 @@ function edit_article()
if (isset($node[$up]))
{
$node[$my] = &$node[$up]->addItem(new HTML_TreeNode(array('hesk_parent' => $this_cat['parent'], 'text' => 'Text', 'text_short' => $text_short, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true)));
$HTML_TreeNode[$my] = new HTML_TreeNode(array('hesk_parent' => $this_cat['parent'], 'text' => 'Text', 'text_short' => $text_short, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true));
$node[$my] = &$node[$up]->addItem($HTML_TreeNode[$my]);
}
else
{
@ -1383,7 +1383,8 @@ function edit_article()
$menu->addItem($node[1]);
// Create the presentation class
$listBox = & ref_new(new HTML_TreeMenu_Listbox($menu));
$HTML_TreeMenu_Listbox = new HTML_TreeMenu_Listbox($menu);
$listBox = & ref_new($HTML_TreeMenu_Listbox);
/* Print header */
require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
@ -1459,6 +1460,7 @@ function edit_article()
theme : "advanced",
convert_urls : false,
gecko_spellcheck: true,
plugins: "autolink",
theme_advanced_buttons1 : "cut,copy,paste,|,undo,redo,|,formatselect,fontselect,fontsizeselect,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull",
theme_advanced_buttons2 : "sub,sup,|,charmap,|,bullist,numlist,|,outdent,indent,insertdate,inserttime,preview,|,forecolor,backcolor,|,hr,removeformat,visualaid,|,link,unlink,anchor,image,cleanup,code",
@ -1526,7 +1528,7 @@ function edit_article()
<?php
build_dropzone_markup(true);
display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/admin/knowledgebase/upload-attachment.php');
display_dropzone_field(HESK_PATH . 'internal-api/admin/knowledgebase/upload-attachment.php');
?>
</div>
<?php endif; //End attachments ?>
@ -1609,6 +1611,9 @@ function manage_category() {
foreach ($kb_cat as $k=>$cat)
{
if ($cat['id'] == $catid) {
continue;
}
if (in_array($cat['parent'],$thislevel))
{
@ -1621,7 +1626,8 @@ function manage_category() {
if (isset($node[$up]))
{
$node[$my] = &$node[$up]->addItem(new HTML_TreeNode(array('hesk_parent' => $this_cat['parent'], 'text' => 'Text', 'text_short' => $text_short, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true)));
$HTML_TreeNode[$my] = new HTML_TreeNode(array('hesk_parent' => $this_cat['parent'], 'text' => 'Text', 'text_short' => $text_short, 'hesk_catid' => $cat['id'], 'hesk_select' => 'option'.$j, 'icon' => $icon, 'expandedIcon' => $expandedIcon, 'expanded' => true));
$node[$my] = &$node[$up]->addItem($HTML_TreeNode[$my]);
}
else
{
@ -1651,7 +1657,8 @@ function manage_category() {
$menu->addItem($node[1]);
// Create the presentation class
$listBox = & ref_new(new HTML_TreeMenu_Listbox($menu));
$HTML_TreeMenu_Listbox = new HTML_TreeMenu_Listbox($menu);
$listBox = & ref_new($HTML_TreeMenu_Listbox);
/* Print header */
require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
@ -1872,10 +1879,10 @@ function manage_category() {
echo '<img src="../img/blank.gif" width="16" height="16" alt="" style="padding:3px;border:none;vertical-align:text-bottom;" /> <img src="../img/blank.gif" width="16" height="16" alt="" style="padding:3px;border:none;vertical-align:text-bottom;" />';
}
?>
<a href="manage_knowledgebase.php?a=sticky&amp;s=<?php echo $article['sticky'] ? 0 : 1 ?>&amp;id=<?php echo $article['id']; ?>&amp;catid=<?php echo $catid; ?>&amp;token=<?php hesk_token_echo(); ?>"><i class="glyphicon glyphicon-pushpin icon-link" style="color:<?php if ( ! $article['sticky']) {echo 'gray';} else {echo 'red';} ?>" data-toggle="tooltip" data-placement="top" title="<?php if (!$article['sticky']) {echo $hesklang['stickyon'];} else {echo $hesklang['stickyoff'];} ?>"></i></a>
<a name="Sticky <?php echo $article['subject']; ?>" href="manage_knowledgebase.php?a=sticky&amp;s=<?php echo $article['sticky'] ? 0 : 1 ?>&amp;id=<?php echo $article['id']; ?>&amp;catid=<?php echo $catid; ?>&amp;token=<?php hesk_token_echo(); ?>"><i class="glyphicon glyphicon-pushpin icon-link" style="color:<?php if ( ! $article['sticky']) {echo 'gray';} else {echo 'red';} ?>" data-toggle="tooltip" data-placement="top" title="<?php if (!$article['sticky']) {echo $hesklang['stickyon'];} else {echo $hesklang['stickyoff'];} ?>"></i></a>
<a href="knowledgebase_private.php?article=<?php echo $article['id']; ?>&amp;back=1<?php if ($article['type'] == 2) {echo '&amp;draft=1';} ?>" target="_blank"><i class="fa fa-file-o icon-link" data-toggle="tooltip" data-placement="top" title="<?php echo $hesklang['viewart'] ?>"></i></a>
<a href="manage_knowledgebase.php?a=edit_article&amp;id=<?php echo $article['id']; ?>"><i class="fa fa-pencil" style="color:orange;font-size:16px" data-toggle="tooltip" data-placement="top" title="<?php echo $hesklang['edit'] ?>"></i></a>
<a href="manage_knowledgebase.php?a=remove_article&amp;id=<?php echo $article['id']; ?>&amp;token=<?php hesk_token_echo(); ?>" onclick="return hesk_confirmExecute('<?php echo hesk_makeJsString($hesklang['del_art']); ?>');"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="<?php echo $hesklang['delete'] ?>"></i></a>&nbsp;</td>
<a name="Edit <?php echo $article['subject']; ?>" href="manage_knowledgebase.php?a=edit_article&amp;id=<?php echo $article['id']; ?>"><i class="fa fa-pencil" style="color:orange;font-size:16px" data-toggle="tooltip" data-placement="top" title="<?php echo $hesklang['edit'] ?>"></i></a>
<a name="Delete <?php echo $article['subject']; ?>" href="manage_knowledgebase.php?a=remove_article&amp;id=<?php echo $article['id']; ?>&amp;token=<?php hesk_token_echo(); ?>" onclick="return hesk_confirmExecute('<?php echo hesk_makeJsString($hesklang['del_art']); ?>');"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="<?php echo $hesklang['delete'] ?>"></i></a>&nbsp;</td>
</tr>
<?php
$j++;
@ -2172,6 +2179,9 @@ function remove_article()
hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."kb_categories` SET `articles_draft`=`articles_draft`-1 WHERE `id`='{$catid}'");
}
// Clear KB cache
hesk_purge_cache('kb');
// Redirect to the correct page
switch ($from) {
case 'draft':

View File

@ -39,10 +39,6 @@ if ($action = hesk_REQUEST('a')) {
create();
} elseif ($action == 'delete') {
deleteTemplate();
} elseif ($action == 'addadmin') {
toggleAdmin(true);
} elseif ($action == 'deladmin') {
toggleAdmin(false);
}
}
@ -51,34 +47,20 @@ require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
/* Print main manage users page */
require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
?>
<script language="Javascript" type="text/javascript"><!--
function confirm_delete() {
if (confirm('<?php echo hesk_makeJsString($hesklang['confirm_del_cat']); ?>')) {
return true;
}
else {
return false;
}
}
//-->
</script>
<?php
$modsForHesk_settings = mfh_getSettings();
$res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates` ORDER BY `name` ASC");
$templates = array();
while ($row = hesk_dbFetchAssoc($res)) {
array_push($templates, $row);
$templates[] = $row;
}
$featureArray = hesk_getFeatureArray();
$orderBy = $modsForHesk_settings['category_order_column'];
$res = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` ORDER BY `" . $orderBy . "` ASC");
$categories = array();
while ($row = hesk_dbFetchAssoc($res)) {
array_push($categories, $row);
$categories[] = $row;
}
?>
<div class="content-wrapper">
@ -87,9 +69,9 @@ while ($row = hesk_dbFetchAssoc($res)) {
<div class="box">
<div class="box-header with-border">
<h1 class="box-title">
<?php echo $hesklang['manage_permission_templates']; ?>
<?php echo $hesklang['manage_permission_groups']; ?>
<i class="fa fa-question-circle settingsquestionmark" data-toggle="tooltip" data-placement="right"
title="<?php echo $hesklang['manage_permission_templates_help']; ?>"></i>
title="<?php echo $hesklang['manage_permission_groups_help']; ?>"></i>
</h1>
<div class="box-tools pull-right">
<button type="button" class="btn btn-box-tool" data-widget="collapse">
@ -98,14 +80,19 @@ while ($row = hesk_dbFetchAssoc($res)) {
</div>
</div>
<div class="box-body">
<div class="text-right">
<a href="#" data-toggle="modal" data-target="#modal-template-new" class="btn btn-success nu-floatRight">
<i class="fa fa-plus-circle"></i> <?php echo $hesklang['create_new_template']; ?>
<i class="fa fa-plus-circle"></i> <?php echo $hesklang['create_new']; ?>
</a>
</div>
<table class="table table-striped">
<thead>
<tr>
<th><?php echo $hesklang['name']; ?></th>
<th><?php echo $hesklang['number_of_users']; ?></th>
<th><?php echo $hesklang['actions']; ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($templates as $row): ?>
@ -114,30 +101,13 @@ while ($row = hesk_dbFetchAssoc($res)) {
<td><?php echo getNumberOfUsersWithPermissionGroup($row['id']); ?></td>
<td>
<a href="#" data-toggle="modal" data-target="#modal-template-<?php echo $row['id'] ?>">
<i class="fa fa-pencil icon-link" data-toggle="tooltip"
title="<?php echo $hesklang['view_permissions_for_this_template'] ?>"></i></a>
<?php if ($row['id'] == 1) { ?>
<i class="fa fa-star icon-link orange" data-toggle="tooltip"
title="<?php echo $hesklang['admin_cannot_be_staff']; ?>"></i></a>
<?php } elseif ($row['heskprivileges'] == 'ALL' && $row['categories'] == 'ALL'){ ?>
<a href="manage_permission_templates.php?a=deladmin&amp;id=<?php echo $row['id']; ?>">
<i class="fa fa-star icon-link orange" data-toggle="tooltip"
title="<?php echo $hesklang['template_has_admin_privileges']; ?>"></i></a>
<?php } elseif ($row['id'] != 2) { ?>
<a href="manage_permission_templates.php?a=addadmin&amp;id=<?php echo $row['id']; ?>">
<i class="fa fa-star-o icon-link gray" data-toggle="tooltip"
title="<?php echo $hesklang['template_has_no_admin_privileges']; ?>"></i></a>
<i class="fa fa-fw fa-pencil icon-link orange" data-toggle="tooltip"
title="<?php echo $hesklang['view_permissions_for_this_group'] ?>"></i></a>
<?php
} else {
?>
<i class="fa fa-star-o icon-link gray" data-toggle="tooltip"
title="<?php echo $hesklang['staff_cannot_be_admin']; ?>"></i>
<?php
}
if ($row['id'] != 1 && $row['id'] != 2):
?>
<a href="manage_permission_templates.php?a=delete&amp;id=<?php echo $row['id']; ?>">
<i class="fa fa-times icon-link red" data-toggle="tooltip"
<a href="manage_permission_groups.php?a=delete&amp;id=<?php echo $row['id']; ?>">
<i class="fa fa-fw fa-times icon-link red" data-toggle="tooltip"
title="<?php echo $hesklang['delete']; ?>"></i></a>
<?php endif; ?>
</td>
@ -172,13 +142,9 @@ function createEditModal($template, $features, $categories)
{
global $hesklang;
$showNotice = true;
$disabled = 'checked="checked" disabled';
$enabledFeatures = array();
$enabledCategories = array();
if ($template['heskprivileges'] != 'ALL') {
$showNotice = false;
$disabled = '';
if ($template['heskprivileges'] !== 'ALL') {
$enabledFeatures = explode(',', $template['heskprivileges']);
$enabledCategories = explode(',', $template['categories']);
}
@ -187,30 +153,29 @@ function createEditModal($template, $features, $categories)
aria-labelledby="myLargeModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form action="manage_permission_templates.php" role="form" method="post" id="form<?php echo $template['id']; ?>">
<form action="manage_permission_groups.php" role="form" method="post" id="form<?php echo $template['id']; ?>">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><?php echo sprintf($hesklang['permissions_for_template'], $template['name']); ?></h4>
<h4 class="modal-title"><?php echo sprintf($hesklang['permissions_for_group'], $template['name']); ?></h4>
</div>
<div class="modal-body">
<div class="row">
<?php if ($showNotice): ?>
<div class="col-sm-12">
<?php if ($template['id'] == 1): ?>
<div class="alert alert-info">
<i class="fa fa-info-circle"></i> <?php echo $hesklang['template_is_admin_cannot_change']; ?>
</div>
<i class="fa fa-info-circle"></i>
<?php echo $hesklang['protected_group']; ?>
</div>
<?php endif; ?>
<div class="row">
<div class="form-group">
<div class="col-sm-2">
<label for="name"
class="control-label"><?php echo $hesklang['template_name']; ?></label>
class="control-label"><?php echo $hesklang['group_name']; ?></label>
</div>
<div class="col-sm-10">
<input type="text" class="form-control" name="name"
value="<?php echo htmlspecialchars($template['name']); ?>"
placeholder="<?php echo htmlspecialchars($hesklang['template_name']); ?>"
placeholder="<?php echo htmlspecialchars($hesklang['group_name']); ?>"
data-error="<?php echo htmlspecialchars($hesklang['this_field_is_required']); ?>"
required>
<div class="help-block with-errors"></div>
@ -223,20 +188,34 @@ function createEditModal($template, $features, $categories)
<div class="footerWithBorder blankSpace"></div>
<div class="form-group">
<?php foreach ($categories as $category): ?>
<?php
foreach ($categories as $category):
$can_man_categories = hesk_checkPermission('can_man_cat', 0);
$checked = '';
$disabled = '';
if (in_array($category['id'], $enabledCategories) ||
$template['categories'] == 'ALL') {
$checked = 'checked ';
}
if ((!hesk_SESSION('isadmin') &&
!in_array($category['id'], $_SESSION['categories']) &&
!$can_man_categories) ||
$template['categories'] === 'ALL') {
$disabled = ' disabled';
}
if ($_SESSION['isadmin'] || $can_man_categories || in_array($category['id'], $_SESSION['categories']) || $checked): ?>
<div class="checkbox">
<label>
<?php
$checked = '';
if (in_array($category['id'], $enabledCategories) && !$showNotice) {
$checked = 'checked';
} ?>
<input type="checkbox" name="categories[]"
value="<?php echo $category['id']; ?>" <?php echo $checked . $disabled; ?>>
value="<?php echo $category['id']; ?>" <?php echo $checked . ' ' . $disabled; ?>>
<?php echo $category['name']; ?>
</label>
</div>
<?php endforeach; ?>
<?php
endif;
endforeach; ?>
<div class="help-block with-errors"></div>
</div>
</div>
@ -245,19 +224,30 @@ function createEditModal($template, $features, $categories)
<div class="footerWithBorder blankSpace"></div>
<div class="form-group">
<?php foreach ($features as $feature): ?>
<div class="checkbox">
<label><?php
<?php
foreach ($features as $feature): ?>
<?php
$checked = '';
if (in_array($feature, $enabledFeatures) && !$showNotice) {
$checked = 'checked';
} ?>
$disabled = '';
if (in_array($feature, $enabledFeatures) ||
$template['heskprivileges'] === 'ALL') {
$checked = 'checked ';
}
if ((!hesk_SESSION('isadmin') &&
strpos($_SESSION['heskprivileges'], $feature) === false) ||
$template['heskprivileges'] === 'ALL') {
$disabled = ' disabled';
}
if ($_SESSION['isadmin'] || strpos($_SESSION['heskprivileges'], $feature) !== false || $checked): ?>
<div class="checkbox">
<label>
<input type="checkbox" name="features[]"
value="<?php echo $feature; ?>" <?php echo $checked . $disabled; ?>>
<?php echo $hesklang[$feature]; ?>
</label>
</div>
<?php endforeach; ?>
<?php endif;
endforeach; ?>
<div class="help-block with-errors"></div>
</div>
</div>
@ -266,9 +256,6 @@ function createEditModal($template, $features, $categories)
<div class="modal-footer">
<input type="hidden" name="a" value="save">
<input type="hidden" name="template_id" value="<?php echo $template['id']; ?>">
<?php if ($showNotice): ?>
<input type="hidden" name="name_only" value="1">
<?php endif; ?>
<div class="btn-group">
<input type="submit" class="btn btn-success"
value="<?php echo $hesklang['save_changes']; ?>">
@ -291,22 +278,22 @@ function buildCreateModal($features, $categories)
aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<form action="manage_permission_templates.php" role="form" method="post" id="createForm">
<form action="manage_permission_groups.php" role="form" method="post" id="createForm">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span
aria-hidden="true">&times;</span></button>
<h4 class="modal-title"><?php echo $hesklang['create_new_template_title']; ?></h4>
<h4 class="modal-title"><?php echo $hesklang['create_new_group_title']; ?></h4>
</div>
<div class="modal-body">
<div class="row">
<div class="form-group">
<div class="col-sm-2">
<label for="name"
class="control-label"><?php echo $hesklang['template_name']; ?></label>
class="control-label"><?php echo $hesklang['group_name']; ?></label>
</div>
<div class="col-sm-10">
<input type="text" class="form-control" name="name"
placeholder="<?php echo $hesklang['template_name']; ?>" required>
placeholder="<?php echo $hesklang['group_name']; ?>" required>
<div class="help-block with-errors"></div>
</div>
</div>
@ -317,7 +304,9 @@ function buildCreateModal($features, $categories)
<div class="footerWithBorder blankSpace"></div>
<div class="form-group">
<?php foreach ($categories as $category): ?>
<?php
foreach ($categories as $category):
if (hesk_SESSION('isadmin') || in_array($category['id'], $_SESSION['categories'])): ?>
<div class="checkbox">
<label>
<input type="checkbox" name="categories[]"
@ -327,7 +316,7 @@ function buildCreateModal($features, $categories)
<?php echo $category['name']; ?>
</label>
</div>
<?php endforeach; ?>
<?php endif; endforeach; ?>
<div class="help-block with-errors"></div>
</div>
</div>
@ -336,7 +325,9 @@ function buildCreateModal($features, $categories)
<div class="footerWithBorder blankSpace"></div>
<div class="form-group">
<?php foreach ($features as $feature): ?>
<?php foreach ($features as $feature):
if (strpos($_SESSION['heskprivileges'], $feature) !== false || hesk_SESSION('isadmin')):
?>
<div class="checkbox">
<label>
<input type="checkbox" name="features[]"
@ -346,7 +337,7 @@ function buildCreateModal($features, $categories)
<?php echo $hesklang[$feature]; ?>
</label>
</div>
<?php endforeach; ?>
<?php endif; endforeach; ?>
<div class="help-block with-errors"></div>
</div>
</div>
@ -381,13 +372,6 @@ function save()
WHERE `id` = " . intval($templateId));
$row = hesk_dbFetchAssoc($res);
if (hesk_POST('name_only', 0)) {
// We are only able to update the name
$name = hesk_POST('name');
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates`
SET `name` = '" . hesk_dbEscape($name) . "' WHERE `id` = " . intval($templateId));
} else {
// Add 'can ban emails' if 'can unban emails' is set (but not added). Same with 'can ban ips'
$catArray = hesk_POST_array('categories');
$featArray = hesk_POST_array('features');
@ -402,19 +386,54 @@ function save()
$features = implode(',', $featArray);
$name = hesk_POST('name');
// Only allow users to add what they are allowed to add
// Admins can handle anything
if (!$_SESSION['isadmin']) {
// Update categories based on user visibility
$originalCategories = explode(',', $row['categories']);
$newCategories = array();
foreach ($originalCategories as $innerCategory) {
if (in_array($innerCategory, $catArray) && in_array($innerCategory, $_SESSION['categories'])) {
$newCategories[] = $innerCategory;
} elseif (!in_array($innerCategory, $catArray) && !in_array($innerCategory, $_SESSION['categories'])) {
// The user can't modify this, so keep it in
$newCategories[] = $innerCategory;
}
// If neither, the user removed it.
}
// Update features based on user visibility
$originalFeatures = explode(',', $row['heskprivileges']);
$newFeatures = array();
foreach ($originalFeatures as $innerFeature) {
if (in_array($innerFeature, $featArray) && strpos($_SESSION['heskprivileges'], $innerFeature) !== false) {
$newFeatures[] = $innerFeature;
} elseif (!in_array($innerFeature, $featArray) && strpos($_SESSION['heskprivileges'], $innerFeature) === false) {
// The user can't modify this, so keep it in
$newFeatures[] = $innerFeature;
}
// If neither, the user removed it.
}
$categories = implode(',', $newCategories);
$features = implode(',', $newFeatures);
}
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates`
SET `categories` = '" . hesk_dbEscape($categories) . "', `heskprivileges` = '" . hesk_dbEscape($features) . "',
`name` = '" . hesk_dbEscape($name) . "'
WHERE `id` = " . intval($templateId));
if ($row['categories'] != $categories || $row['heskprivileges'] != $features) {
// Any users with this template should be switched to "custom"
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` SET `permission_template` = NULL
// Any users with this template should have their permissions updated
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` SET `heskprivileges` = '" . hesk_dbEscape($features) . "',
`categories` = '" . hesk_dbEscape($categories) . "'
WHERE `permission_template` = " . intval($templateId));
}
}
hesk_process_messages($hesklang['permission_template_updated'], $_SERVER['PHP_SELF'], 'SUCCESS');
hesk_process_messages($hesklang['permission_group_updated'], $_SERVER['PHP_SELF'], 'SUCCESS');
}
function create()
@ -439,7 +458,7 @@ function create()
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates` (`name`, `heskprivileges`, `categories`)
VALUES ('" . hesk_dbEscape($name) . "', '" . hesk_dbEscape($features) . "', '" . hesk_dbEscape($categories) . "')");
hesk_process_messages($hesklang['template_created'], $_SERVER['PHP_SELF'], 'SUCCESS');
hesk_process_messages($hesklang['group_created'], $_SERVER['PHP_SELF'], 'SUCCESS');
}
function validate($features, $categories, $create = false, $name = '')
@ -449,7 +468,7 @@ function validate($features, $categories, $create = false, $name = '')
$errorMarkup = '<ul>';
$isValid = true;
if ($create && $name == '') {
$errorMarkup .= '<li>' . $hesklang['template_name_required'] . '</li>';
$errorMarkup .= '<li>' . $hesklang['group_name_required'] . '</li>';
$isValid = false;
}
if (count($features) == 0) {
@ -463,7 +482,7 @@ function validate($features, $categories, $create = false, $name = '')
$errorMarkup .= '</ul>';
if (!$isValid) {
$error = sprintf($hesklang['permission_template_error'], $errorMarkup);
$error = sprintf($hesklang['permission_group_error'], $errorMarkup);
hesk_process_messages($error, $_SERVER['PHP_SELF']);
}
return true;
@ -483,36 +502,14 @@ function deleteTemplate()
// Otherwise delete the template
hesk_dbQuery("DELETE FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates` WHERE `id` = " . intval($id));
if (hesk_dbAffectedRows() != 1) {
hesk_process_messages($hesklang['no_templates_were_deleted'], $_SERVER['PHP_SELF']);
}
hesk_process_messages($hesklang['permission_template_deleted'], $_SERVER['PHP_SELF'], 'SUCCESS');
}
function toggleAdmin($admin)
{
global $hesk_settings, $hesklang;
$id = hesk_GET('id');
if ($id == 1 || $id == 2) {
hesk_process_messages($hesklang['cannot_change_admin_staff'], $_SERVER['PHP_SELF']);
hesk_process_messages($hesklang['no_group_were_deleted'], $_SERVER['PHP_SELF']);
}
if ($admin) {
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates` SET `heskprivileges` = 'ALL',
`categories` = 'ALL' WHERE `id` = " . intval($id));
hesk_process_messages($hesklang['permission_template_now_admin'], $_SERVER['PHP_SELF'], 'SUCCESS');
} else {
// Get default privileges
$res = hesk_dbQuery("SELECT `heskprivileges`, `categories` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates`
WHERE `id` = 2");
$row = hesk_dbFetchAssoc($res);
// Move all users who used to be in this group to "custom"
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` SET `permission_template` = NULL
WHERE `permission_template` = " . intval($id));
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates`
SET `heskprivileges` = '" . hesk_dbEscape($row['heskprivileges']) . "',
`categories` = '" . hesk_dbEscape($row['categories']) . "' WHERE `id` = " . intval($id));
hesk_process_messages($hesklang['permission_template_no_longer_admin'], $_SERVER['PHP_SELF'], 'SUCCESS');
}
hesk_process_messages($hesklang['permission_group_deleted'], $_SERVER['PHP_SELF'], 'SUCCESS');
}
?>

View File

@ -132,7 +132,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<table class="table table-hover">
<thead>
<tr>
<th><?php echo $hesklang['name']; ?></th>
<th><?php echo $hesklang['status_name_title']; ?></th>
<th><?php echo $hesklang['closable_question']; ?></th>
<th><?php echo $hesklang['closedQuestionMark']; ?></th>
<th><?php echo $hesklang['actions']; ?></th>

View File

@ -159,7 +159,7 @@ $num = hesk_dbNumRows($result);
}
echo '
<a href="manage_ticket_templates.php?a=remove&amp;id=' . $mysaved['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['delete'] . '"></i></a></td>
<a name="'.$mysaved['title'].'" href="manage_ticket_templates.php?a=remove&amp;id=' . $mysaved['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" data-original-title="' . $hesklang['delete'] . '"></i></a></td>
</tr>
';
} // End while
@ -286,21 +286,15 @@ $num = hesk_dbNumRows($result);
<?php if ($modsForHesk_settings['rich_text_for_tickets']): ?>
<script type="text/javascript">
/* <![CDATA[ */
tinyMCE.init({
mode: "textareas",
editor_selector: "htmlEditor",
elements: "content",
theme: "advanced",
convert_urls: false,
theme_advanced_buttons1: "cut,copy,paste,|,undo,redo,|,formatselect,fontselect,fontsizeselect,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull",
theme_advanced_buttons2: "sub,sup,|,charmap,|,bullist,numlist,|,outdent,indent,insertdate,inserttime,preview,|,forecolor,backcolor,|,hr,removeformat,visualaid,|,link,unlink,anchor,image,cleanup,code",
theme_advanced_buttons3: "",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
theme_advanced_resizing: true
$(document).ready(function() {
$('.htmlEditor').summernote({
height: 200,
toolbar: [
['style', ['bold', 'italic', 'underline', 'clear']],
['font', ['strikethrough', 'superscript', 'subscript']],
['para', ['ul', 'ol']]
]
});
});
/* ]]> */
</script>
@ -325,8 +319,7 @@ $num = hesk_dbNumRows($result);
if (myMsg == '') {
if (useHtmlEditor) {
tinymce.get("message").setContent('');
tinymce.get("message").execCommand('mceInsertRawHTML', false, '');
$("#message").summernote('reset');
}
else {
$('#message').val('');
@ -336,8 +329,8 @@ $num = hesk_dbNumRows($result);
}
if (document.getElementById) {
if (useHtmlEditor) {
tinymce.get("message").setContent('');
tinymce.get("message").execCommand('mceInsertRawHTML', false, myMsg);
$("#message").summernote('reset');
$("#message").summernote('editor.insertText', myMsg));
} else {
myMsg = $('<textarea />').html(myMsg).text();
$('#message').val(myMsg).trigger('input');

View File

@ -42,6 +42,9 @@ $calendar_view_array = array(
);
$default_view = $calendar_view_array[$modsForHesk_settings['default_calendar_view']];
$staff_permission_template_rs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "permission_templates` WHERE `id` = 2");
$staff_permission_template = hesk_dbFetchAssoc($staff_permission_template_rs);
/* Set default values */
$default_userdata = array(
@ -58,12 +61,15 @@ $default_userdata = array(
// Permissions
'isadmin' => 1,
'active' => 1,
'categories' => array('1'),
'features' => array('can_view_tickets', 'can_reply_tickets', 'can_change_cat', 'can_assign_self', 'can_view_unassigned', 'can_view_online'),
'categories' => explode(',', $staff_permission_template['categories']),
'features' => explode(',', $staff_permission_template['heskprivileges']),
// Preferences
'afterreply' => 0,
// Permission template
'permission_template' => 2,
// Defaults
'autostart' => 1,
'notify_customer_new' => 1,
@ -89,7 +95,7 @@ $orderBy = $modsForHesk_settings['category_order_column'];
$hesk_settings['categories'] = array();
$res = hesk_dbQuery('SELECT `id`,`name` FROM `' . hesk_dbEscape($hesk_settings['db_pfix']) . 'categories` ORDER BY `' . $orderBy . '` ASC');
while ($row = hesk_dbFetchAssoc($res)) {
if (hesk_okCategory($row['id'], 0)) {
if (hesk_checkPermission('can_man_cat', 0) || hesk_okCategory($row['id'], 0)) {
$hesk_settings['categories'][$row['id']] = $row['name'];
}
}
@ -161,7 +167,38 @@ if ($action = hesk_REQUEST('a')) {
?>
<div class="content-wrapper">
<section class="content">
<?php hesk_handle_messages(); ?>
<?php
hesk_handle_messages();
// If POP3 fetching is active, no user should have the same email address
if ($hesk_settings['pop3'] && hesk_validateEmail($hesk_settings['pop3_user'], 'ERR', 0)) {
$res = hesk_dbQuery("SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` WHERE `email` LIKE '".hesk_dbEscape($hesk_settings['pop3_user'])."'");
if (hesk_dbNumRows($res) > 0) {
while ($myuser = hesk_dbFetchAssoc($res)) {
if (compare_user_permissions($myuser['id'], $myuser['isadmin'], explode(',', $myuser['categories']) , explode(',', $myuser['heskprivileges']))) {
hesk_show_notice(sprintf($hesklang['pop3_warning'], $myuser['name'], $hesk_settings['pop3_user']) . "<br /><br />" . $hesklang['fetch_warning'], $hesklang['warn']);
break;
}
}
}
}
// If IMAP fetching is active, no user should have the same email address
if ($hesk_settings['imap'] && hesk_validateEmail($hesk_settings['imap_user'], 'ERR', 0)) {
$res = hesk_dbQuery("SELECT * FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."users` WHERE `email` LIKE '".hesk_dbEscape($hesk_settings['imap_user'])."'");
if (hesk_dbNumRows($res) > 0) {
while ($myuser = hesk_dbFetchAssoc($res)) {
if (compare_user_permissions($myuser['id'], $myuser['isadmin'], explode(',', $myuser['categories']) , explode(',', $myuser['heskprivileges']))) {
hesk_show_notice(sprintf($hesklang['imap_warning'], $myuser['name'], $hesk_settings['imap_user']) . "<br /><br />" . $hesklang['fetch_warning'], $hesklang['warn']);
break;
}
}
}
}
?>
<script language="Javascript" type="text/javascript"><!--
function confirm_delete() {
if (confirm('<?php echo addslashes($hesklang['sure_remove_user']); ?>')) {
@ -214,7 +251,7 @@ if ($action = hesk_REQUEST('a')) {
<th><b><i><?php echo $hesklang['name']; ?></i></b></th>
<th><b><i><?php echo $hesklang['email']; ?></i></b></th>
<th><b><i><?php echo $hesklang['username']; ?></i></b></th>
<th><b><i><?php echo $hesklang['permission_template']; ?></i></b></th>
<th><b><i><?php echo $hesklang['permission_group']; ?></i></b></th>
<?php
/* Is user rating enabled? */
if ($hesk_settings['rating']) {
@ -253,19 +290,19 @@ if ($action = hesk_REQUEST('a')) {
/* User online? */
if ($hesk_settings['online']) {
if (isset($hesk_settings['users_online'][$myuser['id']])) {
$myuser['name'] = '<i class="fa fa-circle green" data-toggle="tooltip" data-placement="top" title="' . $hesklang['online'] . '"></i> ' . $myuser['name'];
$myuser['name'] = '<i class="fa fa-fw fa-circle green" data-toggle="tooltip" data-placement="top" title="' . $hesklang['online'] . '"></i> ' . $myuser['name'];
} else {
$myuser['name'] = '<i class="fa fa-circle gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['offline'] . '"></i> ' . $myuser['name'];
$myuser['name'] = '<i class="fa fa-fw fa-circle gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['offline'] . '"></i> ' . $myuser['name'];
}
}
/* To edit yourself go to "Profile" page, not here. */
if ($myuser['id'] == $_SESSION['id']) {
$edit_code = '<a href="profile.php"><i class="fa fa-pencil icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['edit'] . '"></i></a>';
$edit_code = '<a name="Edit '.$myuser['user'].'" href="profile.php"><i class="fa fa-fw fa-pencil icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['edit'] . '"></i></a>';
} elseif ($myuser['id'] == 1) {
$edit_code = ' <img src="../img/blank.gif" width="16" height="16" alt="" style="padding:3px;border:none;" />';
} else {
$edit_code = '<a href="manage_users.php?a=edit&amp;id=' . $myuser['id'] . '"><i class="fa fa-pencil icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['edit'] . '"></i></a>';
$edit_code = '<a name="Edit '.$myuser['user'].'" href="manage_users.php?a=edit&amp;id=' . $myuser['id'] . '"><i class="fa fa-fw fa-pencil icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['edit'] . '"></i></a>';
}
if ($myuser['isadmin']) {
@ -278,15 +315,15 @@ if ($action = hesk_REQUEST('a')) {
if ($myuser['id'] == 1 || $myuser['id'] == $_SESSION['id']) {
$remove_code = ' <img src="../img/blank.gif" width="16" height="16" alt="" style="padding:3px;border:none;" />';
} else {
$remove_code = ' <a href="manage_users.php?a=remove&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="' . $hesklang['delete'] . '"></i></a>';
$remove_code = ' <a name="Delete '.$myuser['user'].'" href="manage_users.php?a=remove&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '" onclick="return confirm_delete();"><i class="fa fa-fw fa-times icon-link red" data-toggle="tooltip" data-placement="top" title="' . $hesklang['delete'] . '"></i></a>';
}
/* Is auto assign enabled? */
if ($hesk_settings['autoassign']) {
if ($myuser['autoassign']) {
$autoassign_code = '<a href="manage_users.php?a=autoassign&amp;s=0&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-bolt icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['aaon'] . '"></i></a>';
$autoassign_code = '<a name="Unassign '.$myuser['user'].'" href="manage_users.php?a=autoassign&amp;s=0&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-fw fa-bolt icon-link orange" data-toggle="tooltip" data-placement="top" title="' . $hesklang['aaon'] . '"></i></a>';
} else {
$autoassign_code = '<a href="manage_users.php?a=autoassign&amp;s=1&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-bolt icon-link gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['aaoff'] . '"></i></a>';
$autoassign_code = '<a name="Assign '.$myuser['user'].'" href="manage_users.php?a=autoassign&amp;s=1&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-fw fa-bolt icon-link gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['aaoff'] . '"></i></a>';
}
} else {
$autoassign_code = '';
@ -296,9 +333,9 @@ if ($action = hesk_REQUEST('a')) {
if ($myuser['id'] != $_SESSION['id'] && $myuser['id'] != 1) {
/* Is the user active? */
if ($myuser['active']) {
$activeMarkup = '<a href="manage_users.php?a=active&amp;s=0&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-user icon-link green" data-toggle="tooltip" data-placement="top" title="' . $hesklang['disable_user'] . '"></i></a>';
$activeMarkup = '<a href="manage_users.php?a=active&amp;s=0&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-fw fa-user icon-link green" data-toggle="tooltip" data-placement="top" title="' . $hesklang['disable_user'] . '"></i></a>';
} else {
$activeMarkup = '<a href="manage_users.php?a=active&amp;s=1&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-user icon-link gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['enable_user'] . '"></i></a>';
$activeMarkup = '<a href="manage_users.php?a=active&amp;s=1&amp;id=' . $myuser['id'] . '&amp;token=' . hesk_token_echo(0) . '"><i class="fa fa-fw fa-user icon-link gray" data-toggle="tooltip" data-placement="top" title="' . $hesklang['enable_user'] . '"></i></a>';
}
}
@ -321,7 +358,8 @@ EOC;
if ($hesk_settings['rating']) {
$alt = $myuser['rating'] ? sprintf($hesklang['rated'], sprintf("%01.1f", $myuser['rating']), ($myuser['ratingneg'] + $myuser['ratingpos'])) : $hesklang['not_rated'];
echo '<td><img src="../img/star_' . (hesk_round_to_half($myuser['rating']) * 10) . '.png" width="85" height="16" alt="' . $alt . '" data-toggle="tooltip" data-placement="top" title="' . $alt . '" border="0" style="vertical-align:text-bottom" />&nbsp;</td>';
echo '<td><span data-toggle="tooltip" title="' . $alt . '">'.mfh_get_stars(hesk_round_to_half($myuser['rating'])).'</span></td>';
}
echo <<<EOC
@ -333,7 +371,7 @@ EOC;
?>
</table>
<?php if ($hesk_settings['online']) {
echo '&nbsp;&nbsp;&nbsp;<i class="fa fa-circle green"></i> ' . $hesklang['online'] . ' &nbsp;&nbsp;&nbsp; <i class="fa fa-circle gray"></i> ' . $hesklang['offline'];
echo '&nbsp;&nbsp;&nbsp;<i class="fa fa-fw fa-circle green"></i> ' . $hesklang['online'] . ' &nbsp;&nbsp;&nbsp; <i class="fa fa-fw fa-circle gray"></i> ' . $hesklang['offline'];
} ?>
</div>
</div>
@ -369,6 +407,11 @@ function compare_user_permissions($compare_id, $compare_isadmin, $compare_catego
return false;
}
// Users who can edit categories can see all of them
if (hesk_checkPermission('can_man_cat', 0)) {
return true;
}
/* Compare categories */
foreach ($compare_categories as $catid) {
if (!array_key_exists($catid, $hesk_settings['categories'])) {
@ -591,6 +634,7 @@ function update_user()
$myuser['notify_overdue_unassigned'] = 0;
}
/* Check for duplicate usernames */
$res = hesk_dbQuery("SELECT `id`,`isadmin`,`categories`,`heskprivileges` FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "users` WHERE `user` = '" . hesk_dbEscape($myuser['user']) . "' LIMIT 1");
if (hesk_dbNumRows($res) == 1) {
@ -735,7 +779,7 @@ function hesk_validateUserInfo($pass_required = 1, $redirect_to = './manage_user
}
}
if (strlen($myuser['signature']) > 1000) {
if (hesk_mb_strlen($myuser['signature']) > 1000) {
$hesk_error_buffer .= '<li>' . $hesklang['signature_long'] . '</li>';
}
@ -847,6 +891,7 @@ function remove()
// Revoke manager rights
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "categories` SET `manager` = 0 WHERE `manager` = " . intval($myuser));
/* Un-assign all tickets for this user */
$res = hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `owner`=0 WHERE `owner`='" . intval($myuser) . "'");

View File

@ -1,32 +1,15 @@
<?php
/*******************************************************************************
* Title: Help Desk Software HESK
* Version: 2.6.1 from 26th February 2015
* Author: Klemen Stirn
* Website: https://www.hesk.com
********************************************************************************
* COPYRIGHT AND TRADEMARK NOTICE
* Copyright 2005-2015 Klemen Stirn. All Rights Reserved.
* HESK is a registered trademark of Klemen Stirn.
* The HESK may be used and modified free of charge by anyone
* AS LONG AS COPYRIGHT NOTICES AND ALL THE COMMENTS REMAIN INTACT.
* By using this code you agree to indemnify Klemen Stirn from any
* liability that might arise from it's use.
* Selling the code for this program, in part or full, without prior
* written consent is expressly forbidden.
* Using this code, in part or full, to create derivate work,
* new scripts or products is expressly forbidden. Obtain permission
* before redistributing this software over the Internet or in
* any other medium. In all cases copyright and header must remain intact.
* This Copyright is in full effect in any country that has International
* Trade Agreements with the United States of America or
* with the European Union.
* Removing any of the copyright notices without purchasing a license
* is expressly forbidden. To remove HESK copyright notice you must purchase
* a license for this script. For more information on how to obtain
* a license please visit the page below:
* https://www.hesk.com/buy.php
*******************************************************************************/
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT', 1);
define('HESK_PATH', '../');
@ -76,7 +59,7 @@ if (!$row['autoassign']) {
$category_ok = hesk_okCategory($category, 0);
// Is user allowed to move tickets to this category?
if (!$category_ok && !hesk_checkPermission('can_submit_any_cat', 0)) {
if ( ! $category_ok && ! hesk_checkPermission('can_change_cat', 0) ) {
hesk_process_messages($hesklang['noauth_move'],'admin_main.php');
}
@ -87,8 +70,6 @@ if (hesk_dbNumRows($res) != 1) {
}
$ticket = hesk_dbFetchAssoc($res);
/* Log that ticket is being moved */
$history = sprintf($hesklang['thist1'], hesk_date(), $row['name'], $_SESSION['name'] . ' (' . $_SESSION['user'] . ')');
/* Is the ticket assigned to someone? If yes, check that the user has access to category or change to unassigned */
$need_to_reassign = 0;
@ -109,18 +90,30 @@ if ($ticket['owner']) {
}
/* Reassign automatically if possible */
$autoassign_owner = null;
if ($need_to_reassign || !$ticket['owner']) {
$need_to_reassign = 1;
$autoassign_owner = hesk_autoAssignTicket($category);
if ($autoassign_owner) {
$ticket['owner'] = $autoassign_owner['id'];
$history .= sprintf($hesklang['thist10'], hesk_date(), $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')');
} else {
$ticket['owner'] = 0;
}
}
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `category`='" . intval($category) . "', `owner`='" . intval($ticket['owner']) . "' , `history`=CONCAT(`history`,'" . hesk_dbEscape($history) . "') WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
hesk_dbQuery("UPDATE `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` SET `category`='" . intval($category) . "', `owner`='" . intval($ticket['owner']) . "' WHERE `trackid`='" . hesk_dbEscape($trackingID) . "'");
/* Log that ticket is being moved */
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_moved_category', hesk_date(), array(
0 => $_SESSION['name'] . ' (' . $_SESSION['user'] . ')',
1 => $row['name']
));
if ($autoassign_owner) {
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_autoassigned', hesk_date(), array(
0 => $autoassign_owner['name'] . ' (' . $autoassign_owner['user'] . ')'
));
}
$ticket['category'] = $category;
@ -135,13 +128,13 @@ $info = array(
'trackid' => $ticket['trackid'],
'status' => $ticket['status'],
'name' => $ticket['name'],
'lastreplier' => $ticket['lastreplier'],
'subject' => $ticket['subject'],
'message' => $ticket['message'],
'attachments' => $ticket['attachments'],
'dt' => hesk_date($ticket['dt'], true),
'lastchange' => hesk_date($ticket['lastchange'], true),
'id' => $ticket['id'],
'id' => $ticket['id'],'time_worked' => $ticket['time_worked'],
'last_reply_by' => hesk_getReplierName($ticket),
);
// 2. Add custom fields to the array

View File

@ -113,13 +113,13 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
$hesk_settings['categories'] = array();
if (hesk_checkPermission('can_submit_any_cat', 0)) {
$res = hesk_dbQuery("SELECT `id`, `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."categories` ORDER BY `cat_order` ASC");
$res = hesk_dbQuery("SELECT `id`, `name`, `mfh_description` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."categories` ORDER BY `cat_order` ASC");
} else {
$res = hesk_dbQuery("SELECT `id`, `name` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."categories` WHERE ".hesk_myCategories('id')." ORDER BY `cat_order` ASC");
$res = hesk_dbQuery("SELECT `id`, `name`, `mfh_description` FROM `".hesk_dbEscape($hesk_settings['db_pfix'])."categories` WHERE ".hesk_myCategories('id')." ORDER BY `cat_order` ASC");
}
while ($row = hesk_dbFetchAssoc($res)) {
$hesk_settings['categories'][$row['id']] = $row['name'];
$hesk_settings['categories'][$row['id']] = $row;
}
$number_of_categories = count($hesk_settings['categories']);
@ -147,7 +147,7 @@ $show_quick_help = $show['show'];
<li><a href="admin_main.php"><?php echo $hesk_settings['hesk_title']; ?></a></li>
<?php if ($number_of_categories > 1): ?>
<li><a href="new_ticket.php"><?php echo $hesklang['nti2']; ?></a></li>
<li class="active"><?php echo $hesk_settings['categories'][$category]; ?></li>
<li class="active"><?php echo $hesk_settings['categories'][$category]['name']; ?></li>
<?php else: ?>
<li class="active"><?php echo $hesklang['nti2']; ?></li>
<?php endif; ?>
@ -157,6 +157,11 @@ $show_quick_help = $show['show'];
/* This will handle error, success and notice messages */
hesk_handle_messages();
$service_messages = mfh_get_service_messages('STAFF_SUBMIT_TICKET');
foreach ($service_messages as $sm) {
hesk_service_message($sm);
}
if ($show_quick_help): ?>
<div class="box">
<div class="box-header with-border">
@ -193,21 +198,15 @@ $show_quick_help = $show['show'];
<?php if ($modsForHesk_settings['rich_text_for_tickets']): ?>
<script type="text/javascript">
/* <![CDATA[ */
tinyMCE.init({
mode: "textareas",
editor_selector: "htmlEditor",
elements: "content",
theme: "advanced",
convert_urls: false,
theme_advanced_buttons1: "cut,copy,paste,|,undo,redo,|,formatselect,fontselect,fontsizeselect,|,bold,italic,underline,strikethrough,|,justifyleft,justifycenter,justifyright,justifyfull",
theme_advanced_buttons2: "sub,sup,|,charmap,|,bullist,numlist,|,outdent,indent,insertdate,inserttime,preview,|,forecolor,backcolor,|,hr,removeformat,visualaid,|,link,unlink,anchor,image,cleanup,code",
theme_advanced_buttons3: "",
theme_advanced_toolbar_location: "top",
theme_advanced_toolbar_align: "left",
theme_advanced_statusbar_location: "bottom",
theme_advanced_resizing: true
$(document).ready(function() {
$('.htmlEditor').summernote({
height: 200,
toolbar: [
['style', ['bold', 'italic', 'underline', 'clear']],
['font', ['strikethrough', 'superscript', 'subscript']],
['para', ['ul', 'ol']]
]
});
});
/* ]]> */
</script>
@ -243,7 +242,7 @@ $show_quick_help = $show['show'];
class="important">*</span></label>
<div class="col-sm-9">
<input type="text" class="form-control" name="name" size="40" maxlength="30"
<input type="text" class="form-control" name="name" size="40" maxlength="50"
value="<?php if (isset($_SESSION['as_name'])) {
echo stripslashes(hesk_input($_SESSION['as_name']));
} else if (isset($_GET['name'])) {
@ -380,6 +379,10 @@ $show_quick_help = $show['show'];
</div>';
}
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '
<div class="help-block with-errors"></div>
</div>
@ -388,7 +391,6 @@ $show_quick_help = $show['show'];
/* Select drop-down box */
case 'select':
$cls = in_array($k, $_SESSION['iserror']) ? ' isError' : '';
echo '<div class="form-group' . $cls . '"><label for="' . $v['name'] . '" class="col-sm-3 control-label">' . $v['name'] . ' ' . $v['req'] . '</label>
@ -410,14 +412,23 @@ $show_quick_help = $show['show'];
echo '<option ' . $selected . '>' . $option . '</option>';
}
echo '</select>
<div class="help-block with-errors"></div></div></div>';
echo '</select>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div></div></div>';
break;
/* Checkbox */
case 'checkbox':
$cls = in_array($k, $_SESSION['iserror']) ? ' isError' : '';
$validator = $v['req'] == '<span class="important">*</span>' ? 'data-checkbox="' . $k . '"' : '';
$required_attribute = $validator == '' ? '' : ' data-error="' . $hesklang['this_field_is_required'] . '"';
echo '<div class="form-group' . $cls . '"><label class="col-sm-3 control-label">' . $v['name'] . ' ' . $v['req'] . '</label><div align="left" class="col-sm-9">';
foreach ($v['value']['checkbox_options'] as $option) {
@ -427,7 +438,12 @@ $show_quick_help = $show['show'];
$checked = '';
}
echo '<div class="checkbox"><label><input type="checkbox" name="' . $k . '[]" value="' . $option . '" ' . $checked . $required_attribute . '> ' . $option . '</label></div>';
echo '<div class="checkbox"><label><input ' . $validator . ' type="checkbox" name="' . $k . '[]" value="' . $option . '" ' . $checked . $required_attribute . '> ' . $option . '</label></div>';
}
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '
<div class="help-block with-errors"></div></div></div>';
@ -439,8 +455,13 @@ $show_quick_help = $show['show'];
echo '<div class="form-group' . $cls . '">
<label for="' . $v['name'] . '" class="col-sm-3 control-label">' . $v['name'] . ' ' . $v['req'] . '</label>
<div class="col-sm-9"><textarea class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" rows="' . intval($v['value']['rows']) . '" cols="' . intval($v['value']['cols']) . '" ' . $required_attribute . '>' . $k_value . '</textarea>
<div class="help-block with-errors"></div></div></div>';
<div class="col-sm-9"><textarea class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" rows="' . intval($v['value']['rows']) . '" cols="' . intval($v['value']['cols']) . '" ' . $required_attribute . '>' . $k_value . '</textarea>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div></div></div>';
break;
case 'date':
@ -455,8 +476,13 @@ $show_quick_help = $show['show'];
<label for="' . $v['name'] . '" class="col-sm-3 control-label">' . $v['name'].' '.$v['req'] . '</label>
<div class="col-sm-9">
<input type="text" class="datepicker form-control" placeholder="' . $v['name'] . '" name="' . $k . '" size="40"
value="' . $k_value . '" ' . $required_attribute . '>
<div class="help-block with-errors"></div>
value="' . $k_value . '" ' . $required_attribute . '>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div>
</div>
</div>';
break;
@ -468,8 +494,13 @@ $show_quick_help = $show['show'];
echo '<div class="form-group' . $cls . '">
<label for="' . $v['name'] . '" class="col-sm-3 control-label">' . $v['name'].' '.$v['req'] . '</label>
<div class="col-sm-9">
<input type="text" class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" size="40" value="' . $k_value . '" '.$suggest.$required_attribute.'>
<div class="help-block with-errors"></div>
<input type="text" class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" size="40" value="' . $k_value . '" '.$suggest.$required_attribute.'>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div>
</div>
</div><div id="'.$k.'_suggestions"></div>';
@ -488,8 +519,13 @@ $show_quick_help = $show['show'];
echo '<div class="form-group' . $cls . '">
<label for="' . $v['name'] . '" class="col-sm-3 control-label">' . $v['name'].' '.$v['req'] . '</label>
<div class="col-sm-9">
<input type="text" class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" size="40" maxlength="' . intval($v['value']['max_length']) . '" value="' . $v['value']['default_value'] . '" ' . $cls . $required_attribute . '>
<div class="help-block with-errors"></div>
<input type="text" class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" size="40" maxlength="' . intval($v['value']['max_length']) . '" value="' . $v['value']['default_value'] . '" ' . $cls . $required_attribute . '>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div>
</div>
</div>';
}
@ -536,8 +572,7 @@ $show_quick_help = $show['show'];
if (myMsg == '') {
if (document.form1.mode[1].checked) {
if (useHtmlEditor) {
tinymce.get("message").setContent('');
tinymce.get("message").execCommand('mceInsertRawHTML', false, '');
$("#message").summernote('reset');
}
else {
$('#message').val('');
@ -549,8 +584,8 @@ $show_quick_help = $show['show'];
if (document.getElementById) {
if (document.getElementById('moderep').checked) {
if (useHtmlEditor) {
tinymce.get("message").setContent('');
tinymce.get("message").execCommand('mceInsertRawHTML', false, myMsg);
$("#message").summernote('reset');
$("#message").summernote('editor.insertText', myMsg));
} else {
myMsg = $('<textarea />').html(myMsg).text();
$('#message').val(myMsg).trigger('input');
@ -560,9 +595,9 @@ $show_quick_help = $show['show'];
}
else {
if (useHtmlEditor) {
var oldMsg = tinymce.get("message").getContent();
tinymce.get("message").setContent('');
tinymce.get("message").execCommand('mceInsertRawHTML', false, oldMsg + myMsg);
var oldMsg = $("#message").val();
$("#message").summernote('reset');
$("#message").summernote('editor.insertText', oldMsg + myMsg));
} else {
var oldMsg = document.getElementById('message').value;
var theMsg = $('<textarea />').html(oldMsg + myMsg).text();
@ -662,7 +697,7 @@ $show_quick_help = $show['show'];
?>
</label>
<div class="col-sm-9">
<span id="HeskSub"><input class="form-control" type="text" name="subject" id="subject" size="40" maxlength="40"
<span id="HeskSub"><input class="form-control" type="text" name="subject" id="subject" size="40" maxlength="70"
value="<?php if (isset($_SESSION['as_subject']) || isset($_GET['subject'])) {
echo stripslashes(hesk_input($_SESSION['as_subject']));
} ?>" placeholder="<?php echo htmlspecialchars($hesklang['subject']); ?>"
@ -750,7 +785,9 @@ $show_quick_help = $show['show'];
echo '<div class="radio"><label><input type="radio" name="' . $k . '" value="' . $option . '" ' . $checked . ' ' . $required_attribute . '> ' . $option . '</label></div>';
}
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div></div></div>';
break;
@ -777,12 +814,20 @@ $show_quick_help = $show['show'];
echo '<option ' . $selected . '>' . $option . '</option>';
}
echo '</select><div class="help-block with-errors"></div></div></div>';
echo '</select>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div></div></div>';
break;
/* Checkbox */
case 'checkbox':
$cls = in_array($k, $_SESSION['iserror']) ? ' isError' : '';
$validator = $v['req'] == '<span class="important">*</span>' ? 'data-checkbox="' . $k . '"' : '';
$required_attribute = $validator == '' ? '' : ' data-error="' . $hesklang['this_field_is_required'] . '"';
echo '<div class="form-group' . $cls . '"><label class="col-sm-3 control-label">' . $v['name'].' '.$v['req'] . '</label><div align="left" class="col-sm-9">';
foreach ($v['value']['checkbox_options'] as $option) {
@ -792,7 +837,10 @@ $show_quick_help = $show['show'];
$checked = '';
}
echo '<div class="checkbox"><label><input type="checkbox" name="' . $k . '[]" value="' . $option . '" ' . $checked . ' ' . $required_attribute . '> ' . $option . '</label></div>';
echo '<div class="checkbox"><label><input ' . $validator . ' type="checkbox" name="' . $k . '[]" value="' . $option . '" ' . $checked . $required_attribute .'> ' . $option . '</label></div>';
}
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div></div></div>';
break;
@ -803,8 +851,11 @@ $show_quick_help = $show['show'];
echo '<div class="form-group' . $cls . '">
<label for="' . $v['name'] . '" class="col-sm-3 control-label">' . $v['name'].' '.$v['req'] . '</label>
<div class="col-sm-9"><textarea class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" rows="' . intval($v['value']['rows']) . '" cols="' . intval($v['value']['cols']) . '" ' . $required_attribute . '>' . $k_value . '</textarea>
<div class="help-block with-errors"></div></div>
<div class="col-sm-9"><textarea class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" rows="' . intval($v['value']['rows']) . '" cols="' . intval($v['value']['cols']) . '" ' . $required_attribute . '>' . $k_value . '</textarea>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div></div>
</div>';
break;
@ -820,8 +871,11 @@ $show_quick_help = $show['show'];
<label for="' . $v['name'] . '" class="col-sm-3 control-label">' . $v['name'].' '.$v['req'] . '</label>
<div class="col-sm-9">
<input type="text" class="datepicker form-control" placeholder="' . $v['name'] . '" name="' . $k . '" size="40"
value="' . $k_value . '" ' . $required_attribute . '>
<div class="help-block with-errors"></div>
value="' . $k_value . '" ' . $required_attribute . '>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div>
</div>
</div>';
break;
@ -833,8 +887,11 @@ $show_quick_help = $show['show'];
echo '<div class="form-group">
<label for="' . $v['name'] . '" class="col-sm-3 control-label">' . $v['name'].' '.$v['req'] . '</label>
<div class="col-sm-9">
<input type="text" class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" size="40" value="' . $k_value . '" '.$suggest.' ' . $required_attribute . '>
<div class="help-block with-errors"></div>
<input type="text" class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" size="40" value="' . $k_value . '" '.$suggest.' ' . $required_attribute . '>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div>
</div>
</div><div id="'.$k.'_suggestions"></div>';
@ -852,8 +909,11 @@ $show_quick_help = $show['show'];
echo '<div class="form-group">
<label for="' . $v['name'] . '" class="col-sm-3 control-label">' . $v['name'].' '.$v['req'] . '</label>
<div class="col-sm-9">
<input type="text" class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" size="40" maxlength="' . intval($v['value']['max_length']) . '" value="' . $v['value']['default_value'] . '" ' . $required_attribute . '>
<div class="help-block with-errors"></div>
<input type="text" class="form-control" placeholder="' . $v['name'] . '" name="' . $k . '" size="40" maxlength="' . intval($v['value']['max_length']) . '" value="' . $v['value']['default_value'] . '" ' . $required_attribute . '>';
if (!empty($v['mfh_description'])) {
echo '<div class="help-block">' . $v['mfh_description'] . '</div>';
}
echo '<div class="help-block with-errors"></div>
</div>
</div>';
}
@ -872,7 +932,7 @@ $show_quick_help = $show['show'];
</div>
</div>
<?php
display_dropzone_field($hesk_settings['hesk_url'] . '/internal-api/ticket/upload-attachment.php');
display_dropzone_field(HESK_PATH . 'internal-api/ticket/upload-attachment.php');
}
if (!isset($_SESSION['as_notify'])) {
@ -991,8 +1051,8 @@ if ($modsForHesk_settings['rich_text_for_tickets']) {
$message = hesk_SESSION('as_message', '');
echo "
<script>
tinymce.get('message').setContent('');
tinymce.get('message').execCommand('mceInsertRawHTML', false, '".$message."');
$(\"#message\").summernote('reset');
$(\"#message\").summernote('editor.insertText', '".$message."'));
</script>
";
}
@ -1031,9 +1091,10 @@ function print_select_category($number_of_categories) {
// Print a select box if number of categories is large
if ($number_of_categories > $hesk_settings['cat_show_select'])
{
$firstDescription = null;
?>
<form action="new_ticket.php" method="get">
<select name="category" id="select_category" class="form-control">
<select name="category" id="select_category" class="form-control" onchange="showDescription()">
<?php
if ($hesk_settings['select_cat'])
{
@ -1041,23 +1102,45 @@ function print_select_category($number_of_categories) {
}
foreach ($hesk_settings['categories'] as $k=>$v)
{
echo '<option value="'.$k.'">'.$v.'</option>';
if ($firstDescription === null) {
$firstDescription = $v['mfh_description'];
}
echo '<option value="'.$k.'" data-description="'.$v['mfh_description'].'">'.$v['name'].'</option>';
}
?>
</select>
<?php
$display = ' style="display: none"';
&nbsp;<br />
if (!$hesk_settings['select_cat'] && $firstDescription !== null && trim($firstDescription) !== '') {
$display = '';
}
?>
<span id="category-description"<?php echo $display; ?>>
<b><?php echo $hesklang['description_colon']; ?></b>
<span><?php echo $firstDescription; ?></span>
</span>
<br>
<div style="text-align:center">
<input type="submit" value="<?php echo $hesklang['c2c']; ?>" class="btn btn-default">
</div>
</form>
<script>
function showDescription() {
var $value = $('#select_category').find(':selected');
if ($value.data('description') !== '') {
$('#category-description').show().find('span').text($value.data('description'));
} else {
$('#category-description').hide();
}
}
</script>
<?php
}
// Otherwise print quick links
else
{
// echo '<li><a href="new_ticket.php?a=add&amp;category='.$k.'">&raquo; '.$v.'</a></li>';
$new_row = 1;
foreach ($hesk_settings['categories'] as $k=>$v):
@ -1072,7 +1155,14 @@ function print_select_category($number_of_categories) {
<div class="panel-body">
<div class="row">
<div class="col-xs-12">
<?php echo $v; ?>
<?php
echo $v['name'];
if ($v['mfh_description'] !== null && trim($v['mfh_description']) !== '') {
echo '&nbsp;<i class="fa fa-info-circle" data-toggle="popover"
title="'. $hesklang['description'] .'" data-content="' . $v['mfh_description'] . '"></i>';
}
?>
</div>
</div>
</div>

View File

@ -47,22 +47,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Verify security image
if ($hesk_settings['secimg_use']) {
// Using ReCaptcha?
if ($hesk_settings['recaptcha_use'] == 1) {
require_once(HESK_PATH . 'inc/recaptcha/recaptchalib.php');
$resp = recaptcha_check_answer($hesk_settings['recaptcha_private_key'],
$_SERVER['REMOTE_ADDR'],
hesk_POST('recaptcha_challenge_field', ''),
hesk_POST('recaptcha_response_field', '')
);
if ($resp->is_valid) {
//$_SESSION['img_a_verified']=true;
} else {
$hesk_error_buffer['mysecnum'] = $hesklang['recaptcha_error'];
}
} // Using ReCaptcha API v2?
elseif ($hesk_settings['recaptcha_use'] == 2) {
if ($hesk_settings['recaptcha_use']) {
require(HESK_PATH . 'inc/recaptcha/recaptchalib_v2.php');
$resp = null;
@ -70,7 +55,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// Was there a reCAPTCHA response?
if (isset($_POST["g-recaptcha-response"])) {
$resp = $reCaptcha->verifyResponse($_SERVER["REMOTE_ADDR"], hesk_POST("g-recaptcha-response"));
$resp = $reCaptcha->verifyResponse(hesk_getClientIP(), hesk_POST("g-recaptcha-response"));
}
if ($resp != null && $resp->success) {
@ -121,7 +106,7 @@ if ($_SERVER['REQUEST_METHOD'] == 'POST') {
hesk_process_messages($hesklang['noace'], 'NOREDIRECT');
} else {
$row = hesk_dbFetchAssoc($res);
$hash = sha1(microtime() . $_SERVER['REMOTE_ADDR'] . mt_rand() . $row['id'] . $row['name'] . $row['pass']);
$hash = sha1(microtime() . hesk_getClientIP() . mt_rand() . $row['id'] . $row['name'] . $row['pass']);
// Insert the verification hash into the database
hesk_dbQuery("INSERT INTO `" . hesk_dbEscape($hesk_settings['db_pfix']) . "reset_password` (`user`, `hash`, `ip`) VALUES (" . intval($row['id']) . ", '{$hash}', '" . hesk_dbEscape($_SERVER['REMOTE_ADDR']) . "') ");
@ -215,7 +200,7 @@ elseif (isset($_GET['h'])) {
}
// Tell header to load reCaptcha API if needed
if ($hesk_settings['recaptcha_use'] == 2) {
if ($hesk_settings['recaptcha_use']) {
define('RECAPTCHA', 1);
}
@ -230,7 +215,7 @@ require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
<h4 class="login-box-msg">
<?php echo $hesklang['passr']; ?>
</h4>
<form action="password.php" method="post" name="form1" class="form-horizontal" role="form">
<form action="password.php" method="post" name="form1" id="form1" class="form-horizontal" role="form">
<?php
/* This will handle error, success and notice messages */
hesk_handle_messages();
@ -255,38 +240,13 @@ require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
</div>
</div>
<?php
if ($hesk_settings['secimg_use']) {
if ($hesk_settings['secimg_use'] && $hesk_settings['recaptcha_use'] != 1) {
?>
<div class="form-group">
<div class="col-sm-11 col-sm-offset-1">
<?php
// Should we use Recaptcha?
if ($hesk_settings['recaptcha_use'] == 1) {
?>
<script type="text/javascript">
var RecaptchaOptions = {
theme: '<?php echo ( isset($_SESSION['a_iserror']) && in_array('mysecnum',$_SESSION['a_iserror']) ) ? 'red' : 'white'; ?>',
custom_translations: {
visual_challenge: "<?php echo hesk_slashJS($hesklang['visual_challenge']); ?>",
audio_challenge: "<?php echo hesk_slashJS($hesklang['audio_challenge']); ?>",
refresh_btn: "<?php echo hesk_slashJS($hesklang['refresh_btn']); ?>",
instructions_visual: "<?php echo hesk_slashJS($hesklang['instructions_visual']); ?>",
instructions_context: "<?php echo hesk_slashJS($hesklang['instructions_context']); ?>",
instructions_audio: "<?php echo hesk_slashJS($hesklang['instructions_audio']); ?>",
help_btn: "<?php echo hesk_slashJS($hesklang['help_btn']); ?>",
play_again: "<?php echo hesk_slashJS($hesklang['play_again']); ?>",
cant_hear_this: "<?php echo hesk_slashJS($hesklang['cant_hear_this']); ?>",
incorrect_try_again: "<?php echo hesk_slashJS($hesklang['incorrect_try_again']); ?>",
image_alt_text: "<?php echo hesk_slashJS($hesklang['image_alt_text']); ?>"
}
};
</script>
<?php
require_once(HESK_PATH . 'inc/recaptcha/recaptchalib.php');
echo recaptcha_get_html($hesk_settings['recaptcha_public_key'], null, true);
}
// Use reCaptcha API v2?
elseif ($hesk_settings['recaptcha_use'] == 2)
if ($hesk_settings['recaptcha_use'] == 2)
{
?>
<div class="g-recaptcha"
@ -312,6 +272,14 @@ require_once(HESK_PATH . 'inc/headerAdmin.inc.php');
<input type="submit" value="<?php echo $hesklang['passs']; ?>" class="btn btn-default">
</div>
</div>
<?php
// Use Invisible reCAPTCHA?
if ($hesk_settings['secimg_use'] && $hesk_settings['recaptcha_use'] == 1) {
?>
<div class="g-recaptcha" data-sitekey="<?php echo $hesk_settings['recaptcha_public_key']; ?>" data-bind="recaptcha-submit" data-callback="recaptcha_submitForm"></div>
<?php
}
?>
</form>
</div>
</div>

73
admin/priority.php Normal file
View File

@ -0,0 +1,73 @@
<?php
/**
*
* This file is part of HESK - PHP Help Desk Software.
*
* (c) Copyright Klemen Stirn. All rights reserved.
* https://www.hesk.com
*
* For the full copyright and license agreement information visit
* https://www.hesk.com/eula.php
*
*/
define('IN_SCRIPT',1);
define('HESK_PATH','../');
/* Get all the required files and functions */
require(HESK_PATH . 'hesk_settings.inc.php');
require(HESK_PATH . 'inc/common.inc.php');
require(HESK_PATH . 'inc/admin_functions.inc.php');
hesk_load_database_functions();
hesk_session_start();
hesk_dbConnect();
hesk_isLoggedIn();
/* Check permissions for this feature */
hesk_checkPermission('can_view_tickets');
hesk_checkPermission('can_reply_tickets');
/* A security check */
hesk_token_check('POST');
/* Ticket ID */
$trackingID = hesk_cleanID() or die($hesklang['int_error'].': '.$hesklang['no_trackID']);
$priority = intval( hesk_POST('priority') );
if ($priority < 0 || $priority > 3)
{
hesk_process_messages($hesklang['inpr'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'NOTICE');
}
$options = array(
0 => '<font class="critical">'.$hesklang['critical'].'</font>',
1 => '<font class="important">'.$hesklang['high'].'</font>',
2 => '<font class="medium">'.$hesklang['medium'].'</font>',
3 => $hesklang['low']
);
$plain_options = array(
0 => 'critical',
1 => 'high',
2 => 'medium',
3 => 'low'
);
$ticketRs = hesk_dbQuery("SELECT * FROM `" . hesk_dbEscape($hesk_settings['db_pfix']) . "tickets` WHERE `trackid` = '" . hesk_dbEscape($trackingID) . "'");
$ticket = hesk_dbFetchAssoc($ticketRs);
hesk_dbQuery("UPDATE `".hesk_dbEscape($hesk_settings['db_pfix'])."tickets` SET `priority`='{$priority}' WHERE `trackid`='".hesk_dbEscape($trackingID)."'");
mfh_insert_audit_trail_record($ticket['id'], 'TICKET', 'audit_priority', hesk_date(), array(
0 => $_SESSION['name'].' ('.$_SESSION['user'].')',
1 => $plain_options[$priority]
));
if (hesk_dbAffectedRows() != 1)
{
hesk_process_messages($hesklang['inpr'],'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'NOTICE');
}
hesk_process_messages(sprintf($hesklang['chpri2'],$options[$priority]),'admin_ticket.php?track='.$trackingID.'&Refresh='.mt_rand(10000,99999),'SUCCESS');
?>

View File

@ -166,11 +166,11 @@ function update_profile()
$hesk_error_buffer = '';
$_SESSION['new']['name'] = hesk_input(hesk_POST('name')) or $hesk_error_buffer .= '<li>' . $hesklang['enter_your_name'] . '</li>';
$_SESSION['new']['email'] = hesk_validateEmail(hesk_POST('email'), 'ERR', 0) or $hesk_error_buffer = '<li>' . $hesklang['enter_valid_email'] . '</li>';
$_SESSION['new']['email'] = hesk_validateEmail( hesk_POST('email'), 'ERR', 0) or $hesk_error_buffer .= '<li>' . $hesklang['enter_valid_email'] . '</li>';
$_SESSION['new']['signature'] = hesk_input(hesk_POST('signature'));
/* Signature */
if (strlen($_SESSION['new']['signature']) > 1000) {
if (hesk_mb_strlen($_SESSION['new']['signature']) > 1000) {
$hesk_error_buffer .= '<li>' . $hesklang['signature_long'] . '</li>';
}

View File

@ -249,7 +249,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
(<?php echo $hesklang['m' . date('n')]; ?>)
</option>
<option value="4" <?php echo $selected['time'][4]; ?>><?php echo $hesklang['r4']; ?>
(<?php echo $hesklang['m' . date('n', mktime(0, 0, 0, date('m') - 1, date('d'), date('Y')))]; ?>
(<?php echo $hesklang['m' . date('n', mktime(0, 0, 0, date('m') - 1, 1, date('Y')))]; ?>
)
</option>
<option

File diff suppressed because it is too large Load Diff

View File

@ -89,23 +89,6 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
</div>
</div>
<?php
$hesk_settings['hesk_license']('HMgPSAxOw0KaWYgKGZpbGVfZXhpc3RzKEhFU0tfUEFUSCAuI
CdoZXNrX2xpY2Vuc2UucGhwJykpDQp7DQokaCA9ICghZW1wdHkoJF9TRVJWRVJbJ0hUVFBfSE9TVCddK
SkgPyAkX1NFUlZFUlsnSFRUUF9IT1NUJ10gOiAoKCFlbXB0eSgkX1NFUlZFUlsnU0VSVkVSX05BTUUnX
SkpID8gJF9TRVJWRVJbJ1NFUlZFUl9OQU1FJ10gOiBnZXRlbnYoJ1NFUlZFUl9OQU1FJykpOw0KJGggP
SBzdHJfcmVwbGFjZSgnd3d3LicsJycsc3RydG9sb3dlcigkaCkpOw0KaW5jbHVkZShIRVNLX1BBVEggL
iAnaGVza19saWNlbnNlLnBocCcpOw0KaWYgKGlzc2V0KCRoZXNrX3NldHRpbmdzWydsaWNlbnNlJ10pI
CYmIHN0cnBvcygkaGVza19zZXR0aW5nc1snbGljZW5zZSddLHNoYTEoJGguJ2gzJkZwMiNMYUEmNTkhd
yg4LlpjXSordVI1MTInKSkgIT09IGZhbHNlKQ0Kew0KJHMgPSAwOw0KfQ0KZWxzZQ0Kew0KZWNobyAnP
HAgc3R5bGU9InRleHQtYWxpZ246Y2VudGVyO2NvbG9yOnJlZDsiPklOVkFMSUQgTElDRU5TRSAoTk9UI
FJFR0lTVEVSRUQgRk9SICcuJGguJykhPC9wPic7DQp9DQp9DQppZiAoJHMpDQp7DQplY2hvICc8aHIgL
z48dGFibGUgYm9yZGVyPSIwIiB3aWR0aD0iMTAwJSI+PHRyPjx0ZD48Yj4nLiRoZXNrbGFuZ1sncmVtb
3ZlX3N0YXRlbWVudCddLic8L2I+PC90ZD48dGQgc3R5bGU9InRleHQtYWxpZ246cmlnaHQiPjxhIGhyZ
WY9IkphdmFzY3JpcHQ6dm9pZCgwKSIgb25jbGljaz0iYWxlcnQoXCcnLiRoZXNrbGFuZ1snc3VwcG9yd
F9ub3RpY2UnXS4nXCcpIj4nLiRoZXNrbGFuZ1snc2gnXS4nPC9hPjwvdGQ+PC90cj48L3RhYmxlPjxwP
icuJGhlc2tsYW5nWydzdXBwb3J0X3JlbW92ZSddLicuIDxhIGhyZWY9Imh0dHBzOi8vd3d3Lmhlc2suY
29tL2J1eS5waHAiIHRhcmdldD0iX2JsYW5rIj4nLiRoZXNrbGFuZ1snY2xpY2tfaW5mbyddLic8L2E+P
C9wPic7DQp9DQo=', "\112");
/* Clean unneeded session variables */
hesk_cleanSessionVars('hide');

View File

@ -97,6 +97,7 @@ require_once(HESK_PATH . 'inc/show_admin_nav.inc.php');
<th><?php echo $hesklang['user']; ?></th>
<th><?php echo $hesklang['custom_place']; ?></th>
<th><?php echo $hesklang['message']; ?></th>
<th><?php echo $hesklang['stack_trace_header']; ?></th>
</tr>
</thead>
<tbody></tbody>

7
api/BaseClass.php Normal file
View File

@ -0,0 +1,7 @@
<?php
class BaseClass {
static function clazz() {
return get_called_class();
}
}

7
api/BaseException.php Normal file
View File

@ -0,0 +1,7 @@
<?php
class BaseException extends Exception {
static function clazz() {
return get_called_class();
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace BusinessLogic\Attachments;
class Attachment extends \BaseClass {
/* @var $id int */
public $id;
/* @var $savedName string */
public $savedName;
/* @var $displayName string */
public $displayName;
/* @var $id int */
public $fileSize;
/* @var $downloadCount int */
public $downloadCount;
}

View File

@ -0,0 +1,479 @@
<?php
namespace BusinessLogic\Attachments;
use BusinessLogic\Exceptions\AccessViolationException;
use BusinessLogic\Exceptions\ApiFriendlyException;
use BusinessLogic\Exceptions\ValidationException;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Security\UserPrivilege;
use BusinessLogic\Security\UserToTicketChecker;
use BusinessLogic\Tickets\Attachment;
use BusinessLogic\Tickets\Ticket;
use BusinessLogic\ValidationModel;
use DataAccess\Attachments\AttachmentGateway;
use DataAccess\Files\FileDeleter;
use DataAccess\Files\FileWriter;
use DataAccess\Tickets\TicketGateway;
class AttachmentHandler extends \BaseClass {
/* @var $ticketGateway TicketGateway */
private $ticketGateway;
/* @var $attachmentGateway AttachmentGateway */
private $attachmentGateway;
/* @var $fileWriter FileWriter */
private $fileWriter;
/* @var $fileDeleter FileDeleter */
private $fileDeleter;
/* @var $userToTicketChecker UserToTicketChecker */
private $userToTicketChecker;
function __construct(TicketGateway $ticketGateway,
AttachmentGateway $attachmentGateway,
FileWriter $fileWriter,
UserToTicketChecker $userToTicketChecker,
FileDeleter $fileDeleter) {
$this->ticketGateway = $ticketGateway;
$this->attachmentGateway = $attachmentGateway;
$this->fileWriter = $fileWriter;
$this->userToTicketChecker = $userToTicketChecker;
$this->fileDeleter = $fileDeleter;
}
/**
* @param $createAttachmentModel CreateAttachmentForTicketModel
* @param $userContext UserContext
* @param $heskSettings array
* @return TicketAttachment the newly created attachment
* @throws \Exception
*/
function createAttachmentForTicket($createAttachmentModel, $userContext, $heskSettings) {
$this->validate($createAttachmentModel, $heskSettings);
$decodedAttachment = base64_decode($createAttachmentModel->attachmentContents);
$ticket = $this->ticketGateway->getTicketById($createAttachmentModel->ticketId, $heskSettings);
if ($ticket === null) {
throw new ApiFriendlyException("Ticket {$createAttachmentModel->ticketId} not found", "Ticket Not Found", 404);
}
$extraPermissions = $createAttachmentModel->isEditing
? array(UserPrivilege::CAN_EDIT_TICKETS)
: array();
if (!$this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings, $extraPermissions)) {
throw new AccessViolationException("User does not have access to ticket {$ticket->id} being created / edited!");
}
$cleanedFileName = $this->cleanFileName($createAttachmentModel->displayName);
$fileParts = pathinfo($cleanedFileName);
$ticketAttachment = new TicketAttachment();
$ticketAttachment->savedName = $this->generateSavedName($ticket->trackingId,
$cleanedFileName, $fileParts['extension']);
$ticketAttachment->displayName = $cleanedFileName;
$ticketAttachment->ticketTrackingId = $ticket->trackingId;
$ticketAttachment->type = 0;
$ticketAttachment->downloadCount = 0;
$ticketAttachment->fileSize =
$this->fileWriter->writeToFile($ticketAttachment->savedName, $heskSettings['attach_dir'], $decodedAttachment);
$attachmentId = $this->attachmentGateway->createAttachmentForTicket($ticketAttachment, $heskSettings);
$this->updateAttachmentsOnTicket($ticket, $ticketAttachment, $attachmentId, $heskSettings);
$ticketAttachment->id = $attachmentId;
return $ticketAttachment;
}
/**
* Supports deleting attachments from both ticket messages AND replies
*
* @param $ticketId int The ticket ID
* @param $attachmentId int The attachment ID
* @param $userContext UserContext
* @param $heskSettings array
* @throws ApiFriendlyException
* @throws \Exception
*/
function deleteAttachmentFromTicket($ticketId, $attachmentId, $userContext, $heskSettings) {
$ticket = $this->ticketGateway->getTicketById($ticketId, $heskSettings);
if ($ticket === null) {
throw new ApiFriendlyException("Ticket {$ticketId} not found!", "Ticket Not Found", 404);
}
if (!$this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings, array(UserPrivilege::CAN_EDIT_TICKETS))) {
throw new AccessViolationException("User does not have access to ticket {$ticketId} being created / edited!");
}
$indexToRemove = -1;
$attachmentType = AttachmentType::MESSAGE;
$replyId = -1;
for ($i = 0; $i < count($ticket->attachments); $i++) {
$attachment = $ticket->attachments[$i];
if ($attachment->id === $attachmentId) {
$indexToRemove = $i;
$this->fileDeleter->deleteFile($attachment->savedName, $heskSettings['attach_dir']);
$this->attachmentGateway->deleteAttachment($attachment->id, $heskSettings);
}
}
foreach ($ticket->replies as $reply) {
for ($i = 0; $i < count($reply->attachments); $i++) {
$attachment = $reply->attachments[$i];
if ($attachment->id === $attachmentId) {
$indexToRemove = $i;
$replyId = $reply->id;
$attachmentType = AttachmentType::REPLY;
$this->fileDeleter->deleteFile($attachment->savedName, $heskSettings['attach_dir']);
$this->attachmentGateway->deleteAttachment($attachment->id, $heskSettings);
}
}
}
if ($indexToRemove === -1) {
throw new ApiFriendlyException("Attachment not found for ticket or reply! ID: {$attachmentId}", "Attachment not found", 404);
}
if ($attachmentType == AttachmentType::MESSAGE) {
$attachments = $ticket->attachments;
unset($attachments[$indexToRemove]);
$this->ticketGateway->updateAttachmentsForTicket($ticketId, $attachments, $heskSettings);
} else {
$attachments = $ticket->replies[$replyId]->attachments;
unset($attachments[$indexToRemove]);
$this->ticketGateway->updateAttachmentsForReply($replyId, $attachments, $heskSettings);
}
}
/**
* @param $createAttachmentModel CreateAttachmentForTicketModel
* @param $heskSettings array
* @throws ValidationException
*/
private function validate($createAttachmentModel, $heskSettings) {
$errorKeys = array();
if ($createAttachmentModel->attachmentContents === null ||
trim($createAttachmentModel->attachmentContents) === '') {
$errorKeys[] = 'CONTENTS_EMPTY';
}
if (base64_decode($createAttachmentModel->attachmentContents, true) === false) {
$errorKeys[] = 'CONTENTS_NOT_BASE_64';
}
if ($createAttachmentModel->displayName === null ||
trim($createAttachmentModel->displayName === '')) {
$errorKeys[] = 'DISPLAY_NAME_EMPTY';
}
if ($createAttachmentModel->ticketId === null ||
$createAttachmentModel->ticketId < 1) {
$errorKeys[] = 'TICKET_ID_MISSING';
}
$fileParts = pathinfo($createAttachmentModel->displayName);
if (!isset($fileParts['extension']) || !in_array(".{$fileParts['extension']}", $heskSettings['attachments']['allowed_types'])) {
$errorKeys[] = 'EXTENSION_NOT_PERMITTED';
}
$fileContents = base64_decode($createAttachmentModel->attachmentContents);
if (function_exists('mb_strlen')) {
$fileSize = mb_strlen($fileContents, '8bit');
} else {
$fileSize = strlen($fileContents);
}
if ($fileSize > $heskSettings['attachments']['max_size']) {
$errorKeys[] = 'FILE_SIZE_TOO_LARGE';
}
if (count($errorKeys) > 0) {
$validationModel = new ValidationModel();
$validationModel->errorKeys = $errorKeys;
throw new ValidationException($validationModel);
}
}
private function generateSavedName($trackingId, $displayName, $fileExtension) {
$fileExtension = ".{$fileExtension}";
$useChars = 'AEUYBDGHJLMNPQRSTVWXZ123456789';
$tmp = uniqid();
for ($j = 1; $j < 10; $j++) {
$tmp .= $useChars{mt_rand(0, 29)};
}
return substr($trackingId . '_' . md5($tmp . $displayName), 0, 200) . $fileExtension;
}
/**
* @param $displayName string original file name
* @return string The cleaned file name
*/
private function cleanFileName($displayName) {
$filename = str_replace(array('%20', '+'), '-', $displayName);
$filename = preg_replace('/[\s-]+/', '-', $filename);
$filename = $this->removeAccents($filename);
$filename = preg_replace('/[^A-Za-z0-9\.\-_]/', '', $filename);
$filename = trim($filename, '-_');
return $filename;
}
// The following code has been borrowed from Wordpress, and also from posting_functions.inc.php :P
// Credits: http://wordpress.org
private function removeAccents($string)
{
if (!preg_match('/[\x80-\xff]/', $string)) {
return $string;
}
if ($this->seemsUtf8($string)) {
$chars = array(
// Decompositions for Latin-1 Supplement
chr(194) . chr(170) => 'a', chr(194) . chr(186) => 'o',
chr(195) . chr(128) => 'A', chr(195) . chr(129) => 'A',
chr(195) . chr(130) => 'A', chr(195) . chr(131) => 'A',
chr(195) . chr(132) => 'A', chr(195) . chr(133) => 'A',
chr(195) . chr(134) => 'AE', chr(195) . chr(135) => 'C',
chr(195) . chr(136) => 'E', chr(195) . chr(137) => 'E',
chr(195) . chr(138) => 'E', chr(195) . chr(139) => 'E',
chr(195) . chr(140) => 'I', chr(195) . chr(141) => 'I',
chr(195) . chr(142) => 'I', chr(195) . chr(143) => 'I',
chr(195) . chr(144) => 'D', chr(195) . chr(145) => 'N',
chr(195) . chr(146) => 'O', chr(195) . chr(147) => 'O',
chr(195) . chr(148) => 'O', chr(195) . chr(149) => 'O',
chr(195) . chr(150) => 'O', chr(195) . chr(153) => 'U',
chr(195) . chr(154) => 'U', chr(195) . chr(155) => 'U',
chr(195) . chr(156) => 'U', chr(195) . chr(157) => 'Y',
chr(195) . chr(158) => 'TH', chr(195) . chr(159) => 's',
chr(195) . chr(160) => 'a', chr(195) . chr(161) => 'a',
chr(195) . chr(162) => 'a', chr(195) . chr(163) => 'a',
chr(195) . chr(164) => 'a', chr(195) . chr(165) => 'a',
chr(195) . chr(166) => 'ae', chr(195) . chr(167) => 'c',
chr(195) . chr(168) => 'e', chr(195) . chr(169) => 'e',
chr(195) . chr(170) => 'e', chr(195) . chr(171) => 'e',
chr(195) . chr(172) => 'i', chr(195) . chr(173) => 'i',
chr(195) . chr(174) => 'i', chr(195) . chr(175) => 'i',
chr(195) . chr(176) => 'd', chr(195) . chr(177) => 'n',
chr(195) . chr(178) => 'o', chr(195) . chr(179) => 'o',
chr(195) . chr(180) => 'o', chr(195) . chr(181) => 'o',
chr(195) . chr(182) => 'o', chr(195) . chr(184) => 'o',
chr(195) . chr(185) => 'u', chr(195) . chr(186) => 'u',
chr(195) . chr(187) => 'u', chr(195) . chr(188) => 'u',
chr(195) . chr(189) => 'y', chr(195) . chr(190) => 'th',
chr(195) . chr(191) => 'y', chr(195) . chr(152) => 'O',
// Decompositions for Latin Extended-A
chr(196) . chr(128) => 'A', chr(196) . chr(129) => 'a',
chr(196) . chr(130) => 'A', chr(196) . chr(131) => 'a',
chr(196) . chr(132) => 'A', chr(196) . chr(133) => 'a',
chr(196) . chr(134) => 'C', chr(196) . chr(135) => 'c',
chr(196) . chr(136) => 'C', chr(196) . chr(137) => 'c',
chr(196) . chr(138) => 'C', chr(196) . chr(139) => 'c',
chr(196) . chr(140) => 'C', chr(196) . chr(141) => 'c',
chr(196) . chr(142) => 'D', chr(196) . chr(143) => 'd',
chr(196) . chr(144) => 'D', chr(196) . chr(145) => 'd',
chr(196) . chr(146) => 'E', chr(196) . chr(147) => 'e',
chr(196) . chr(148) => 'E', chr(196) . chr(149) => 'e',
chr(196) . chr(150) => 'E', chr(196) . chr(151) => 'e',
chr(196) . chr(152) => 'E', chr(196) . chr(153) => 'e',
chr(196) . chr(154) => 'E', chr(196) . chr(155) => 'e',
chr(196) . chr(156) => 'G', chr(196) . chr(157) => 'g',
chr(196) . chr(158) => 'G', chr(196) . chr(159) => 'g',
chr(196) . chr(160) => 'G', chr(196) . chr(161) => 'g',
chr(196) . chr(162) => 'G', chr(196) . chr(163) => 'g',
chr(196) . chr(164) => 'H', chr(196) . chr(165) => 'h',
chr(196) . chr(166) => 'H', chr(196) . chr(167) => 'h',
chr(196) . chr(168) => 'I', chr(196) . chr(169) => 'i',
chr(196) . chr(170) => 'I', chr(196) . chr(171) => 'i',
chr(196) . chr(172) => 'I', chr(196) . chr(173) => 'i',
chr(196) . chr(174) => 'I', chr(196) . chr(175) => 'i',
chr(196) . chr(176) => 'I', chr(196) . chr(177) => 'i',
chr(196) . chr(178) => 'IJ', chr(196) . chr(179) => 'ij',
chr(196) . chr(180) => 'J', chr(196) . chr(181) => 'j',
chr(196) . chr(182) => 'K', chr(196) . chr(183) => 'k',
chr(196) . chr(184) => 'k', chr(196) . chr(185) => 'L',
chr(196) . chr(186) => 'l', chr(196) . chr(187) => 'L',
chr(196) . chr(188) => 'l', chr(196) . chr(189) => 'L',
chr(196) . chr(190) => 'l', chr(196) . chr(191) => 'L',
chr(197) . chr(128) => 'l', chr(197) . chr(129) => 'L',
chr(197) . chr(130) => 'l', chr(197) . chr(131) => 'N',
chr(197) . chr(132) => 'n', chr(197) . chr(133) => 'N',
chr(197) . chr(134) => 'n', chr(197) . chr(135) => 'N',
chr(197) . chr(136) => 'n', chr(197) . chr(137) => 'N',
chr(197) . chr(138) => 'n', chr(197) . chr(139) => 'N',
chr(197) . chr(140) => 'O', chr(197) . chr(141) => 'o',
chr(197) . chr(142) => 'O', chr(197) . chr(143) => 'o',
chr(197) . chr(144) => 'O', chr(197) . chr(145) => 'o',
chr(197) . chr(146) => 'OE', chr(197) . chr(147) => 'oe',
chr(197) . chr(148) => 'R', chr(197) . chr(149) => 'r',
chr(197) . chr(150) => 'R', chr(197) . chr(151) => 'r',
chr(197) . chr(152) => 'R', chr(197) . chr(153) => 'r',
chr(197) . chr(154) => 'S', chr(197) . chr(155) => 's',
chr(197) . chr(156) => 'S', chr(197) . chr(157) => 's',
chr(197) . chr(158) => 'S', chr(197) . chr(159) => 's',
chr(197) . chr(160) => 'S', chr(197) . chr(161) => 's',
chr(197) . chr(162) => 'T', chr(197) . chr(163) => 't',
chr(197) . chr(164) => 'T', chr(197) . chr(165) => 't',
chr(197) . chr(166) => 'T', chr(197) . chr(167) => 't',
chr(197) . chr(168) => 'U', chr(197) . chr(169) => 'u',
chr(197) . chr(170) => 'U', chr(197) . chr(171) => 'u',
chr(197) . chr(172) => 'U', chr(197) . chr(173) => 'u',
chr(197) . chr(174) => 'U', chr(197) . chr(175) => 'u',
chr(197) . chr(176) => 'U', chr(197) . chr(177) => 'u',
chr(197) . chr(178) => 'U', chr(197) . chr(179) => 'u',
chr(197) . chr(180) => 'W', chr(197) . chr(181) => 'w',
chr(197) . chr(182) => 'Y', chr(197) . chr(183) => 'y',
chr(197) . chr(184) => 'Y', chr(197) . chr(185) => 'Z',
chr(197) . chr(186) => 'z', chr(197) . chr(187) => 'Z',
chr(197) . chr(188) => 'z', chr(197) . chr(189) => 'Z',
chr(197) . chr(190) => 'z', chr(197) . chr(191) => 's',
// Decompositions for Latin Extended-B
chr(200) . chr(152) => 'S', chr(200) . chr(153) => 's',
chr(200) . chr(154) => 'T', chr(200) . chr(155) => 't',
// Euro Sign
chr(226) . chr(130) . chr(172) => 'E',
// GBP (Pound) Sign
chr(194) . chr(163) => '',
// Vowels with diacritic (Vietnamese)
// unmarked
chr(198) . chr(160) => 'O', chr(198) . chr(161) => 'o',
chr(198) . chr(175) => 'U', chr(198) . chr(176) => 'u',
// grave accent
chr(225) . chr(186) . chr(166) => 'A', chr(225) . chr(186) . chr(167) => 'a',
chr(225) . chr(186) . chr(176) => 'A', chr(225) . chr(186) . chr(177) => 'a',
chr(225) . chr(187) . chr(128) => 'E', chr(225) . chr(187) . chr(129) => 'e',
chr(225) . chr(187) . chr(146) => 'O', chr(225) . chr(187) . chr(147) => 'o',
chr(225) . chr(187) . chr(156) => 'O', chr(225) . chr(187) . chr(157) => 'o',
chr(225) . chr(187) . chr(170) => 'U', chr(225) . chr(187) . chr(171) => 'u',
chr(225) . chr(187) . chr(178) => 'Y', chr(225) . chr(187) . chr(179) => 'y',
// hook
chr(225) . chr(186) . chr(162) => 'A', chr(225) . chr(186) . chr(163) => 'a',
chr(225) . chr(186) . chr(168) => 'A', chr(225) . chr(186) . chr(169) => 'a',
chr(225) . chr(186) . chr(178) => 'A', chr(225) . chr(186) . chr(179) => 'a',
chr(225) . chr(186) . chr(186) => 'E', chr(225) . chr(186) . chr(187) => 'e',
chr(225) . chr(187) . chr(130) => 'E', chr(225) . chr(187) . chr(131) => 'e',
chr(225) . chr(187) . chr(136) => 'I', chr(225) . chr(187) . chr(137) => 'i',
chr(225) . chr(187) . chr(142) => 'O', chr(225) . chr(187) . chr(143) => 'o',
chr(225) . chr(187) . chr(148) => 'O', chr(225) . chr(187) . chr(149) => 'o',
chr(225) . chr(187) . chr(158) => 'O', chr(225) . chr(187) . chr(159) => 'o',
chr(225) . chr(187) . chr(166) => 'U', chr(225) . chr(187) . chr(167) => 'u',
chr(225) . chr(187) . chr(172) => 'U', chr(225) . chr(187) . chr(173) => 'u',
chr(225) . chr(187) . chr(182) => 'Y', chr(225) . chr(187) . chr(183) => 'y',
// tilde
chr(225) . chr(186) . chr(170) => 'A', chr(225) . chr(186) . chr(171) => 'a',
chr(225) . chr(186) . chr(180) => 'A', chr(225) . chr(186) . chr(181) => 'a',
chr(225) . chr(186) . chr(188) => 'E', chr(225) . chr(186) . chr(189) => 'e',
chr(225) . chr(187) . chr(132) => 'E', chr(225) . chr(187) . chr(133) => 'e',
chr(225) . chr(187) . chr(150) => 'O', chr(225) . chr(187) . chr(151) => 'o',
chr(225) . chr(187) . chr(160) => 'O', chr(225) . chr(187) . chr(161) => 'o',
chr(225) . chr(187) . chr(174) => 'U', chr(225) . chr(187) . chr(175) => 'u',
chr(225) . chr(187) . chr(184) => 'Y', chr(225) . chr(187) . chr(185) => 'y',
// acute accent
chr(225) . chr(186) . chr(164) => 'A', chr(225) . chr(186) . chr(165) => 'a',
chr(225) . chr(186) . chr(174) => 'A', chr(225) . chr(186) . chr(175) => 'a',
chr(225) . chr(186) . chr(190) => 'E', chr(225) . chr(186) . chr(191) => 'e',
chr(225) . chr(187) . chr(144) => 'O', chr(225) . chr(187) . chr(145) => 'o',
chr(225) . chr(187) . chr(154) => 'O', chr(225) . chr(187) . chr(155) => 'o',
chr(225) . chr(187) . chr(168) => 'U', chr(225) . chr(187) . chr(169) => 'u',
// dot below
chr(225) . chr(186) . chr(160) => 'A', chr(225) . chr(186) . chr(161) => 'a',
chr(225) . chr(186) . chr(172) => 'A', chr(225) . chr(186) . chr(173) => 'a',
chr(225) . chr(186) . chr(182) => 'A', chr(225) . chr(186) . chr(183) => 'a',
chr(225) . chr(186) . chr(184) => 'E', chr(225) . chr(186) . chr(185) => 'e',
chr(225) . chr(187) . chr(134) => 'E', chr(225) . chr(187) . chr(135) => 'e',
chr(225) . chr(187) . chr(138) => 'I', chr(225) . chr(187) . chr(139) => 'i',
chr(225) . chr(187) . chr(140) => 'O', chr(225) . chr(187) . chr(141) => 'o',
chr(225) . chr(187) . chr(152) => 'O', chr(225) . chr(187) . chr(153) => 'o',
chr(225) . chr(187) . chr(162) => 'O', chr(225) . chr(187) . chr(163) => 'o',
chr(225) . chr(187) . chr(164) => 'U', chr(225) . chr(187) . chr(165) => 'u',
chr(225) . chr(187) . chr(176) => 'U', chr(225) . chr(187) . chr(177) => 'u',
chr(225) . chr(187) . chr(180) => 'Y', chr(225) . chr(187) . chr(181) => 'y',
// Vowels with diacritic (Chinese, Hanyu Pinyin)
chr(201) . chr(145) => 'a',
// macron
chr(199) . chr(149) => 'U', chr(199) . chr(150) => 'u',
// acute accent
chr(199) . chr(151) => 'U', chr(199) . chr(152) => 'u',
// caron
chr(199) . chr(141) => 'A', chr(199) . chr(142) => 'a',
chr(199) . chr(143) => 'I', chr(199) . chr(144) => 'i',
chr(199) . chr(145) => 'O', chr(199) . chr(146) => 'o',
chr(199) . chr(147) => 'U', chr(199) . chr(148) => 'u',
chr(199) . chr(153) => 'U', chr(199) . chr(154) => 'u',
// grave accent
chr(199) . chr(155) => 'U', chr(199) . chr(156) => 'u',
);
$string = strtr($string, $chars);
} else {
// Assume ISO-8859-1 if not UTF-8
$chars['in'] = chr(128) . chr(131) . chr(138) . chr(142) . chr(154) . chr(158)
. chr(159) . chr(162) . chr(165) . chr(181) . chr(192) . chr(193) . chr(194)
. chr(195) . chr(196) . chr(197) . chr(199) . chr(200) . chr(201) . chr(202)
. chr(203) . chr(204) . chr(205) . chr(206) . chr(207) . chr(209) . chr(210)
. chr(211) . chr(212) . chr(213) . chr(214) . chr(216) . chr(217) . chr(218)
. chr(219) . chr(220) . chr(221) . chr(224) . chr(225) . chr(226) . chr(227)
. chr(228) . chr(229) . chr(231) . chr(232) . chr(233) . chr(234) . chr(235)
. chr(236) . chr(237) . chr(238) . chr(239) . chr(241) . chr(242) . chr(243)
. chr(244) . chr(245) . chr(246) . chr(248) . chr(249) . chr(250) . chr(251)
. chr(252) . chr(253) . chr(255);
$chars['out'] = "EfSZszYcYuAAAAAACEEEEIIIINOOOOOOUUUUYaaaaaaceeeeiiiinoooooouuuuyy";
$string = strtr($string, $chars['in'], $chars['out']);
$double_chars['in'] = array(chr(140), chr(156), chr(198), chr(208), chr(222), chr(223), chr(230), chr(240), chr(254));
$double_chars['out'] = array('OE', 'oe', 'AE', 'DH', 'TH', 'ss', 'ae', 'dh', 'th');
$string = str_replace($double_chars['in'], $double_chars['out'], $string);
}
return $string;
}
private function seemsUtf8($str)
{
$length = strlen($str);
for ($i = 0; $i < $length; $i++) {
$c = ord($str[$i]);
if ($c < 0x80) $n = 0; # 0bbbbbbb
elseif (($c & 0xE0) == 0xC0) $n = 1; # 110bbbbb
elseif (($c & 0xF0) == 0xE0) $n = 2; # 1110bbbb
elseif (($c & 0xF8) == 0xF0) $n = 3; # 11110bbb
elseif (($c & 0xFC) == 0xF8) $n = 4; # 111110bb
elseif (($c & 0xFE) == 0xFC) $n = 5; # 1111110b
else return false; # Does not match any model
for ($j = 0; $j < $n; $j++) { # n bytes matching 10bbbbbb follow ?
if ((++$i == $length) || ((ord($str[$i]) & 0xC0) != 0x80))
return false;
}
}
return true;
}
/**
* @param $ticket Ticket
* @param $ticketAttachment TicketAttachment
* @param $attachmentId int
* @param $heskSettings array
*/
private function updateAttachmentsOnTicket($ticket, $ticketAttachment, $attachmentId, $heskSettings) {
$attachments = $ticket->attachments === null ? array() : $ticket->attachments;
$newAttachment = new Attachment();
$newAttachment->savedName = $ticketAttachment->savedName;
$newAttachment->fileName = $ticketAttachment->displayName;
$newAttachment->id = $attachmentId;
$attachments[] = $newAttachment;
$this->ticketGateway->updateAttachmentsForTicket($ticket->id, $attachments, $heskSettings);
}
}

View File

@ -0,0 +1,64 @@
<?php
namespace BusinessLogic\Attachments;
use BusinessLogic\Exceptions\AccessViolationException;
use BusinessLogic\Exceptions\ApiFriendlyException;
use BusinessLogic\Security\UserToTicketChecker;
use DataAccess\Attachments\AttachmentGateway;
use DataAccess\Files\FileReader;
use DataAccess\Tickets\TicketGateway;
class AttachmentRetriever extends \BaseClass {
/* @var $attachmentGateway AttachmentGateway */
private $attachmentGateway;
/* @var $fileReader FileReader */
private $fileReader;
/* @var $ticketGateway TicketGateway */
private $ticketGateway;
/* @var $userToTicketChecker UserToTicketChecker */
private $userToTicketChecker;
function __construct($attachmentGateway, $fileReader, $ticketGateway, $userToTicketChecker) {
$this->attachmentGateway = $attachmentGateway;
$this->fileReader = $fileReader;
$this->ticketGateway = $ticketGateway;
$this->userToTicketChecker = $userToTicketChecker;
}
//-- TODO Test
function getAttachmentContentsForTrackingId($trackingId, $attachmentId, $userContext, $heskSettings) {
$ticket = $this->ticketGateway->getTicketByTrackingId($trackingId, $heskSettings);
if ($ticket === null) {
throw new ApiFriendlyException("Ticket {$trackingId} not found!", "Ticket Not Found", 404);
}
$attachment = $this->attachmentGateway->getAttachmentById($attachmentId, $heskSettings);
return array('meta' => $attachment,
'contents' => $this->fileReader->readFromFile($attachment->savedName, $heskSettings['attach_dir']));
}
function getAttachmentContentsForTicket($ticketId, $attachmentId, $userContext, $heskSettings) {
$ticket = $this->ticketGateway->getTicketById($ticketId, $heskSettings);
if ($ticket === null) {
throw new ApiFriendlyException("Ticket {$ticketId} not found!", "Ticket Not Found", 404);
}
if (!$this->userToTicketChecker->isTicketAccessibleToUser($userContext, $ticket, $heskSettings)) {
throw new AccessViolationException("User does not have access to attachment {$attachmentId}!");
}
$attachment = $this->attachmentGateway->getAttachmentById($attachmentId, $heskSettings);
$contents = base64_encode($this->fileReader->readFromFile(
$attachment->savedName, $heskSettings['attach_dir']));
return $contents;
}
}

View File

@ -0,0 +1,9 @@
<?php
namespace BusinessLogic\Attachments;
class AttachmentType extends \BaseClass {
const MESSAGE = 0;
const REPLY = 1;
}

View File

@ -0,0 +1,9 @@
<?php
namespace BusinessLogic\Attachments;
class CreateAttachmentForTicketModel extends CreateAttachmentModel {
/* @var $ticketId int */
public $ticketId;
}

View File

@ -0,0 +1,21 @@
<?php
namespace BusinessLogic\Attachments;
class CreateAttachmentModel extends \BaseClass {
/* @var $savedName string */
public $savedName;
/* @var $displayName string */
public $displayName;
/* @var $id int */
public $fileSize;
/* @var $attachmentContents string */
public $attachmentContents;
/* @var $isEditing bool */
public $isEditing;
}

View File

@ -0,0 +1,12 @@
<?php
namespace BusinessLogic\Attachments;
class TicketAttachment extends Attachment {
/* @var $ticketTrackingId string */
public $ticketTrackingId;
/* @var $type int [use <code>AttachmentType</code>] */
public $type;
}

View File

@ -0,0 +1,22 @@
<?php
namespace BusinessLogic\Calendar;
class AbstractEvent {
public $id;
public $startTime;
public $title;
public $categoryId;
public $categoryName;
public $backgroundColor;
public $foregroundColor;
public $displayBorder;
}

View File

@ -0,0 +1,15 @@
<?php
namespace BusinessLogic\Calendar;
class BusinessHours {
/* @var $dayOfWeek int */
public $dayOfWeek;
/* @var $startTime string */
public $startTime;
/* @var $endTime string */
public $endTime;
}

View File

@ -0,0 +1,26 @@
<?php
namespace BusinessLogic\Calendar;
use BusinessLogic\Tickets\AuditTrail;
class CalendarEvent extends AbstractEvent {
public $type = 'CALENDAR';
public $endTime;
/* @var $allDay bool */
public $allDay;
public $location;
public $comments;
public $reminderValue;
public $reminderUnits;
/* @var $auditTrail AuditTrail[] */
public $auditTrail = array();
}

View File

@ -0,0 +1,96 @@
<?php
namespace BusinessLogic\Calendar;
use BusinessLogic\DateTimeHelpers;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Tickets\AuditTrailEntityType;
use DataAccess\AuditTrail\AuditTrailGateway;
use DataAccess\Calendar\CalendarGateway;
class CalendarHandler extends \BaseClass {
private $calendarGateway;
private $auditTrailGateway;
public function __construct(CalendarGateway $calendarGateway,
AuditTrailGateway $auditTrailGateway) {
$this->calendarGateway = $calendarGateway;
$this->auditTrailGateway = $auditTrailGateway;
}
public function getEventsForStaff($searchEventsFilter, $heskSettings) {
return $this->calendarGateway->getEventsForStaff($searchEventsFilter, $heskSettings);
}
/**
* @param $calendarEvent CalendarEvent
* @param $userContext UserContext
* @param $heskSettings array
* @return CalendarEvent
* @throws \Exception If more than one event is returned for the given ID
*/
public function updateEvent($calendarEvent, $userContext, $heskSettings) {
$this->calendarGateway->updateEvent($calendarEvent, $userContext, $heskSettings);
$this->auditTrailGateway->insertAuditTrailRecord($calendarEvent->id,
AuditTrailEntityType::CALENDAR_EVENT,
'audit_event_updated',
DateTimeHelpers::heskDate($heskSettings),
array(0 => $userContext->name . ' (' . $userContext->username . ')'), $heskSettings);
$eventFilter = new SearchEventsFilter();
$eventFilter->eventId = $calendarEvent->id;
$eventFilter->reminderUserId = $userContext->id;
$events = $this->calendarGateway->getEventsForStaff($eventFilter, $heskSettings);
if (count($events) !== 1) {
throw new \Exception("Expected exactly 1 event, found: " . count($events));
}
$event = $events[0];
return $event;
}
/**
* @param $calendarEvent CalendarEvent
* @param $userContext UserContext
* @param $heskSettings array
* @return AbstractEvent
* @throws \Exception
*/
public function createEvent($calendarEvent, $userContext, $heskSettings) {
$this->calendarGateway->createEvent($calendarEvent, $userContext, $heskSettings);
$eventFilter = new SearchEventsFilter();
$eventFilter->eventId = $calendarEvent->id;
$eventFilter->reminderUserId = $userContext->id;
$events = $this->calendarGateway->getEventsForStaff($eventFilter, $heskSettings);
if (count($events) !== 1) {
throw new \Exception("Expected exactly 1 event, found: " . count($events));
}
$event = $events[0];
$this->auditTrailGateway->insertAuditTrailRecord($event->id,
AuditTrailEntityType::CALENDAR_EVENT,
'audit_event_created',
DateTimeHelpers::heskDate($heskSettings),
array(0 => $userContext->name . ' (' . $userContext->username . ')'), $heskSettings);
return $event;
}
public function deleteEvent($id, $userContext, $heskSettings) {
$this->calendarGateway->deleteEvent($id, $userContext, $heskSettings);
}
public function getBusinessHours($heskSettings) {
return $this->calendarGateway->getBusinessHours($heskSettings);
}
}

View File

@ -0,0 +1,41 @@
<?php
namespace BusinessLogic\Calendar;
class ReminderUnit {
const MINUTE = 0;
const HOUR = 1;
const DAY = 2;
const WEEK = 3;
static function getByValue($value) {
switch ($value) {
case 0:
return 'MINUTE';
case 1:
return 'HOUR';
case 2:
return 'DAY';
case 3:
return 'WEEK';
default:
return 'UNKNOWN';
}
}
static function getByName($name) {
switch ($name) {
case 'MINUTE':
return self::MINUTE;
case 'HOUR':
return self::HOUR;
case 'DAY':
return self::DAY;
case 'WEEK':
return self::WEEK;
default:
return null;
}
}
}

View File

@ -0,0 +1,33 @@
<?php
namespace BusinessLogic\Calendar;
class SearchEventsFilter {
/* @var $startTime int|null */
public $startTime;
/* @var $endTime int|null */
public $endTime;
/* @var $id int|null */
public $eventId;
/* @var $categories int[]|null */
public $categories;
/* @var $reminderUserId int|null */
public $reminderUserId;
/* @var $includeTickets bool */
public $includeTickets;
/* @var $includeUnassignedTickets bool */
public $includeUnassignedTickets;
/* @var $includeTicketsAssignedToOthers bool */
public $includeTicketsAssignedToOthers;
/* @var $includeTicketsAssignedToMe bool */
public $includeTicketsAssignedToMe;
}

View File

@ -0,0 +1,20 @@
<?php
namespace BusinessLogic\Calendar;
class TicketEvent extends AbstractEvent {
public $type = 'TICKET';
public $trackingId;
public $subject;
public $url;
public $owner;
public $priority;
public $status;
}

View File

@ -0,0 +1,73 @@
<?php
namespace BusinessLogic\Categories;
class Category extends \BaseClass {
/**
* @var int The Categories ID
*/
public $id;
/* @var $name string */
public $name;
/**
* @var int Categories order number
*/
public $catOrder;
/**
* @var bool Tickets autoassigned in this Categories
*/
public $autoAssign;
/**
* @var int The type of Categories (1 = Private, 0 = Public)
*/
public $type;
/**
* @var int The Categories's usage (0 = Tickets and Events, 1 = Tickets, 2 = Events)
*/
public $usage;
/**
* @var string
*/
public $backgroundColor;
/**
* @var string
*/
public $foregroundColor;
/**
* @var bool
*/
public $displayBorder;
/**
* @var int The default Tickets priority
*/
public $priority;
/**
* @var int|null The manager for the Categories, if applicable
*/
public $manager;
/**
* @var bool Indication if the user has access to the Categories
*/
public $accessible;
/**
* @var string
*/
public $description;
/**
* @var int
*/
public $numberOfTickets;
}

View File

@ -0,0 +1,203 @@
<?php
namespace BusinessLogic\Categories;
use BusinessLogic\Exceptions\AccessViolationException;
use BusinessLogic\Exceptions\ValidationException;
use BusinessLogic\Navigation\Direction;
use BusinessLogic\Security\PermissionChecker;
use BusinessLogic\Security\UserPrivilege;
use BusinessLogic\ValidationModel;
use DataAccess\Categories\CategoryGateway;
use DataAccess\Settings\ModsForHeskSettingsGateway;
use DataAccess\Tickets\TicketGateway;
class CategoryHandler extends \BaseClass {
/* @var $categoryGateway CategoryGateway */
private $categoryGateway;
/* @var $ticketGateway TicketGateway */
private $ticketGateway;
/* @var $permissionChecker PermissionChecker */
private $permissionChecker;
/* @var $modsForHeskSettingsGateway ModsForHeskSettingsGateway */
private $modsForHeskSettingsGateway;
function __construct(CategoryGateway $categoryGateway,
TicketGateway $ticketGateway,
PermissionChecker $permissionChecker,
ModsForHeskSettingsGateway $modsForHeskSettingsGateway) {
$this->categoryGateway = $categoryGateway;
$this->ticketGateway = $ticketGateway;
$this->permissionChecker = $permissionChecker;
$this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway;
}
/**
* @param $category Category
* @param $userContext
* @param $heskSettings array
* @return Category The newly created category with ID
* @throws ValidationException When validation fails
* @throws \Exception When the newly created category was not retrieved
*/
//TODO Test
function createCategory($category, $userContext, $heskSettings) {
$modsForHeskSettings = $this->modsForHeskSettingsGateway->getAllSettings($heskSettings);
$validationModel = $this->validate($category, $userContext);
if (count($validationModel->errorKeys) > 0) {
throw new ValidationException($validationModel);
}
$id = $this->categoryGateway->createCategory($category, $heskSettings);
$allCategories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
foreach ($allCategories as $innerCategory) {
if ($innerCategory->id === $id) {
return $innerCategory;
}
}
throw new \BaseException("Newly created category {$id} lost! :O");
}
/**
* @param $category Category
* @param $userContext
* @param $creating bool
* @return ValidationModel
* @throws AccessViolationException
*/
//TODO Test
private function validate($category, $userContext, $creating = true) {
$validationModel = new ValidationModel();
if (!$this->permissionChecker->doesUserHavePermission($userContext, UserPrivilege::CAN_MANAGE_CATEGORIES)) {
throw new AccessViolationException('User cannot manage categories!');
}
if (!$creating && $category->id < 1) {
$validationModel->errorKeys[] = 'ID_MISSING';
}
if ($category->backgroundColor === null || trim($category->backgroundColor) === '') {
$validationModel->errorKeys[] = 'BACKGROUND_COLOR_MISSING';
}
if ($category->foregroundColor === null || trim($category->foregroundColor) === '') {
$validationModel->errorKeys[] = 'FOREGROUND_COLOR_MISSING';
}
if ($category->name === null || trim($category->name) === '') {
$validationModel->errorKeys[] = 'NAME_MISSING';
}
if ($category->priority === null || intval($category->priority) < 0 || intval($category->priority) > 3) {
$validationModel->errorKeys[] = 'INVALID_PRIORITY';
}
if ($category->autoAssign === null || !is_bool($category->autoAssign)) {
$validationModel->errorKeys[] = 'INVALID_AUTOASSIGN';
}
if ($category->displayBorder === null || !is_bool($category->displayBorder)) {
$validationModel->errorKeys[] = 'INVALID_DISPLAY_BORDER';
}
if ($category->type === null || (intval($category->type) !== 0 && intval($category->type) !== 1)) {
$validationModel->errorKeys[] = 'INVALID_TYPE';
}
return $validationModel;
}
/**
* @param $category Category
* @param $userContext
* @param $heskSettings array
* @return Category
* @throws ValidationException
* @throws \Exception When the category is missing
*/
function editCategory($category, $userContext, $heskSettings) {
$modsForHeskSettings = $this->modsForHeskSettingsGateway->getAllSettings($heskSettings);
$validationModel = $this->validate($category, $userContext, false);
if (count($validationModel->errorKeys) > 0) {
throw new ValidationException($validationModel);
}
$this->categoryGateway->updateCategory($category, $heskSettings);
$this->categoryGateway->resortAllCategories($heskSettings);
$allCategories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
foreach ($allCategories as $innerCategory) {
if ($innerCategory->id === $category->id) {
return $innerCategory;
}
}
throw new \BaseException("Category {$category->id} vanished! :O");
}
function deleteCategory($id, $userContext, $heskSettings) {
if (!$this->permissionChecker->doesUserHavePermission($userContext, UserPrivilege::CAN_MANAGE_CATEGORIES)) {
throw new AccessViolationException('User cannot manage categories!');
}
if ($id === 1) {
throw new \BaseException("Category 1 cannot be deleted!");
}
$this->ticketGateway->moveTicketsToDefaultCategory($id, $heskSettings);
$this->categoryGateway->deleteCategory($id, $heskSettings);
$this->categoryGateway->resortAllCategories($heskSettings);
}
function sortCategory($id, $direction, $heskSettings) {
$modsForHeskSettings = $this->modsForHeskSettingsGateway->getAllSettings($heskSettings);
$categories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
$category = null;
foreach ($categories as $innerCategory) {
if ($innerCategory->id === intval($id)) {
$category = $innerCategory;
break;
}
}
if ($category === null) {
throw new \BaseException("Could not find category with ID {$id}!");
}
if ($direction === Direction::UP) {
$category->catOrder -= 15;
} else {
$category->catOrder += 15;
}
$this->categoryGateway->updateCategory($category, $heskSettings);
$this->categoryGateway->resortAllCategories($heskSettings);
}
function getPublicCategories($heskSettings) {
$allCategories = $this->categoryGateway->getAllCategories($heskSettings, $this->modsForHeskSettingsGateway->getAllSettings($heskSettings));
$publicCategories = array();
foreach ($allCategories as $category) {
if ($category->type === 0) {
$publicCategories[] = $category;
}
}
return $publicCategories;
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace BusinessLogic\Categories;
use BusinessLogic\Security\UserContext;
use DataAccess\Categories\CategoryGateway;
use DataAccess\Settings\ModsForHeskSettingsGateway;
class CategoryRetriever extends \BaseClass {
/**
* @var CategoryGateway
*/
private $categoryGateway;
/**
* @var ModsForHeskSettingsGateway
*/
private $modsForHeskSettingsGateway;
function __construct(CategoryGateway $categoryGateway,
ModsForHeskSettingsGateway $modsForHeskSettingsGateway) {
$this->categoryGateway = $categoryGateway;
$this->modsForHeskSettingsGateway = $modsForHeskSettingsGateway;
}
/**
* @param $heskSettings array
* @param $userContext UserContext
* @return array
*/
function getAllCategories($heskSettings, $userContext) {
$modsForHeskSettings = $this->modsForHeskSettingsGateway->getAllSettings($heskSettings);
$categories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
foreach ($categories as $category) {
$category->accessible = $userContext->admin ||
in_array($category->id, $userContext->categories);
}
return $categories;
}
}

View File

@ -0,0 +1,19 @@
<?php
namespace BusinessLogic;
class DateTimeHelpers {
static function heskDate($heskSettings, $dt = '', $isStr = true, $return_str = true) {
if (!$dt) {
$dt = time();
} elseif ($isStr) {
$dt = strtotime($dt);
}
// Return formatted date
return $return_str ? date($heskSettings['timeformat'], $dt) : $dt;
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace BusinessLogic\Emails;
class Addressees extends \BaseClass {
/**
* @var $to string[]
*/
public $to;
/**
* @var $cc string[]|null
*/
public $cc = array();
/**
* @var $bcc string[]|null
*/
public $bcc = array();
}

View File

@ -0,0 +1,84 @@
<?php
namespace BusinessLogic\Emails;
use BusinessLogic\Tickets\Attachment;
use BusinessLogic\Tickets\Ticket;
use PHPMailer;
class BasicEmailSender extends \BaseClass implements EmailSender {
function sendEmail($emailBuilder, $heskSettings, $modsForHeskSettings, $sendAsHtml) {
$toEmails = implode(',', $emailBuilder->to);
if (preg_match("/\n|\r|\t|%0A|%0D|%08|%09/", $toEmails . $emailBuilder->subject)) {
return false;
}
$mailer = new PHPMailer();
if ($heskSettings['smtp']) {
$mailer->isSMTP();
$mailer->SMTPAuth = true;
//-- We'll set this explicitly below if the user has it enabled.
$mailer->SMTPAutoTLS = false;
if ($heskSettings['smtp_ssl']) {
$mailer->SMTPSecure = "ssl";
} elseif ($heskSettings['smtp_tls']) {
$mailer->SMTPSecure = "tls";
}
$mailer->Host = $heskSettings['smtp_host_name'];
$mailer->Port = $heskSettings['smtp_host_port'];
$mailer->Username = $heskSettings['smtp_user'];
$mailer->Password = $heskSettings['smtp_password'];
}
$mailer->FromName = $heskSettings['noreply_name'] !== null &&
$heskSettings['noreply_name'] !== '' ? $heskSettings['noreply_name'] : '';
$mailer->From = $heskSettings['noreply_mail'];
if ($emailBuilder->to !== null) {
foreach ($emailBuilder->to as $to) {
$mailer->addAddress($to);
}
}
if ($emailBuilder->cc !== null) {
foreach ($emailBuilder->cc as $cc) {
$mailer->addCC($cc);
}
}
if ($emailBuilder->bcc !== null) {
foreach ($emailBuilder->bcc as $bcc) {
$mailer->addBCC($bcc);
}
}
$mailer->Subject = $emailBuilder->subject;
if ($sendAsHtml) {
$mailer->Body = $emailBuilder->htmlMessage;
$mailer->AltBody = $emailBuilder->message;
} else {
$mailer->Body = $emailBuilder->message;
$mailer->isHTML(false);
}
$mailer->Timeout = $heskSettings['smtp_timeout'];
if ($emailBuilder->attachments !== null) {
foreach ($emailBuilder->attachments as $attachment) {
$mailer->addAttachment(__DIR__ . '/../../../' . $heskSettings['attach_dir'] . '/' . $attachment->savedName,
$attachment->fileName);
}
}
if ($mailer->send()) {
return true;
}
return $mailer->ErrorInfo;
}
}

View File

@ -0,0 +1,43 @@
<?php
namespace BusinessLogic\Emails;
use BusinessLogic\Tickets\Attachment;
class EmailBuilder extends \BaseClass {
/**
* @var $to string[]
*/
public $to;
/**
* @var $cc string[]
*/
public $cc;
/**
* @var $bcc string[]
*/
public $bcc;
/**
* @var $subject string
*/
public $subject;
/**
* @var $message string
*/
public $message;
/**
* @var $htmlMessage string
*/
public $htmlMessage;
/**
* @var $attachments Attachment[]
*/
public $attachments;
}

View File

@ -0,0 +1,21 @@
<?php
namespace BusinessLogic\Emails;
use BusinessLogic\Tickets\Attachment;
use BusinessLogic\Tickets\Ticket;
use PHPMailer;
interface EmailSender {
/**
* Use to send emails
*
* @param $emailBuilder EmailBuilder
* @param $heskSettings array
* @param $modsForHeskSettings array
* @param $sendAsHtml bool
* @return bool|string|\stdClass true if message sent successfully, string for PHPMail/Smtp error, stdClass for Mailgun error
*/
function sendEmail($emailBuilder, $heskSettings, $modsForHeskSettings, $sendAsHtml);
}

View File

@ -0,0 +1,76 @@
<?php
namespace BusinessLogic\Emails;
use BusinessLogic\Tickets\Ticket;
class EmailSenderHelper extends \BaseClass {
/**
* @var $emailTemplateParser EmailTemplateParser
*/
private $emailTemplateParser;
/**
* @var $basicEmailSender BasicEmailSender
*/
private $basicEmailSender;
/**
* @var $mailgunEmailSender MailgunEmailSender
*/
private $mailgunEmailSender;
function __construct(EmailTemplateParser $emailTemplateParser,
BasicEmailSender $basicEmailSender,
MailgunEmailSender $mailgunEmailSender) {
$this->emailTemplateParser = $emailTemplateParser;
$this->basicEmailSender = $basicEmailSender;
$this->mailgunEmailSender = $mailgunEmailSender;
}
/**
* @param $templateId int the EmailTemplateRetriever::TEMPLATE_NAME
* @param $language string the language name
* @param $addressees Addressees the addressees. **cc and bcc addresses from custom fields will be added here!**
* @param $ticket Ticket
* @param $heskSettings array
* @param $modsForHeskSettings array
*/
function sendEmailForTicket($templateId, $language, $addressees, $ticket, $heskSettings, $modsForHeskSettings) {
$languageCode = $heskSettings['languages'][$language]['folder'];
$parsedTemplate = $this->emailTemplateParser->getFormattedEmailForLanguage($templateId, $languageCode,
$ticket, $heskSettings, $modsForHeskSettings);
$emailBuilder = new EmailBuilder();
$emailBuilder->subject = $parsedTemplate->subject;
$emailBuilder->message = $parsedTemplate->message;
$emailBuilder->htmlMessage = $parsedTemplate->htmlMessage;
$emailBuilder->to = $addressees->to;
$emailBuilder->cc = $addressees->cc;
$emailBuilder->bcc = $addressees->bcc;
foreach ($heskSettings['custom_fields'] as $k => $v) {
$number = intval(str_replace('custom', '', $k));
if ($v['use'] && $v['type'] == 'email' && !empty($ticket->customFields[$number])) {
if ($v['value']['email_type'] == 'cc') {
$emailBuilder->cc[] = $ticket->customFields[$number];
} elseif ($v['value']['email_type'] == 'bcc') {
$emailBuilder->bcc[] = $ticket->customFields[$number];
}
}
}
if ($modsForHeskSettings['attachments']) {
$emailBuilder->attachments = $ticket->attachments;
}
if ($modsForHeskSettings['use_mailgun']) {
$this->mailgunEmailSender->sendEmail($emailBuilder, $heskSettings, $modsForHeskSettings, $modsForHeskSettings['html_emails']);
} else {
$this->basicEmailSender->sendEmail($emailBuilder, $heskSettings, $modsForHeskSettings, $modsForHeskSettings['html_emails']);
}
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace BusinessLogic\Emails;
class EmailTemplate extends \BaseClass {
/**
* @var $languageKey string
*/
public $languageKey;
/**
* @var $fileName string
*/
public $fileName;
/**
* @var $forStaff bool
*/
public $forStaff;
function __construct($forStaff, $fileName, $languageKey = null) {
$this->languageKey = $languageKey === null ? $fileName : $languageKey;
$this->fileName = $fileName;
$this->forStaff = $forStaff;
}
}

View File

@ -0,0 +1,385 @@
<?php
namespace BusinessLogic\Emails;
use BusinessLogic\Exceptions\EmailTemplateNotFoundException;
use BusinessLogic\Exceptions\InvalidEmailTemplateException;
use BusinessLogic\Helpers;
use BusinessLogic\Security\UserContext;
use BusinessLogic\Statuses\DefaultStatusForAction;
use BusinessLogic\Tickets\Ticket;
use Core\Constants\Priority;
use DataAccess\Categories\CategoryGateway;
use DataAccess\Logging\LoggingGateway;
use DataAccess\Security\UserGateway;
use DataAccess\Statuses\StatusGateway;
class EmailTemplateParser extends \BaseClass {
/**
* @var $statusGateway StatusGateway
*/
private $statusGateway;
/**
* @var $categoryGateway CategoryGateway
*/
private $categoryGateway;
/**
* @var $userGateway UserGateway
*/
private $userGateway;
/**
* @var $emailTemplateRetriever EmailTemplateRetriever
*/
private $emailTemplateRetriever;
/**
* @var $logger LoggingGateway
*/
private $logger;
function __construct(StatusGateway $statusGateway,
CategoryGateway $categoryGateway,
UserGateway $userGateway,
EmailTemplateRetriever $emailTemplateRetriever,
LoggingGateway $loggingGateway) {
$this->statusGateway = $statusGateway;
$this->categoryGateway = $categoryGateway;
$this->userGateway = $userGateway;
$this->emailTemplateRetriever = $emailTemplateRetriever;
$this->logger = $loggingGateway;
}
/**
* @param $templateId int
* @param $languageCode string
* @param $ticket Ticket
* @param $heskSettings array
* @param $modsForHeskSettings array
* @return ParsedEmailProperties
* @throws InvalidEmailTemplateException
* @throws \Exception
*/
function getFormattedEmailForLanguage($templateId, $languageCode, $ticket, $heskSettings, $modsForHeskSettings) {
global $hesklang;
$emailTemplate = $this->emailTemplateRetriever->getTemplate($templateId);
if ($emailTemplate === null) {
throw new InvalidEmailTemplateException($templateId);
}
$template = self::getFromFileSystem($emailTemplate->fileName, $languageCode, false);
$htmlTemplate = self::getFromFileSystem($emailTemplate->fileName, $languageCode, true);
$subject = $hesklang[$emailTemplate->languageKey];
$fullLanguageName = null;
foreach ($heskSettings['languages'] as $key => $value) {
if ($value['folder'] === $languageCode) {
$fullLanguageName = $key;
break;
}
}
if ($fullLanguageName === null) {
throw new \BaseException("Language code {$languageCode} did not return any valid HESK languages!");
}
$subject = $this->parseSubject($subject, $ticket, $fullLanguageName, $heskSettings, $modsForHeskSettings);
$message = $this->parseMessage($template, $ticket, $fullLanguageName, $emailTemplate->forStaff, $heskSettings, $modsForHeskSettings, false);
$htmlMessage = $this->parseMessage($htmlTemplate, $ticket, $fullLanguageName, $emailTemplate->forStaff, $heskSettings, $modsForHeskSettings, true);
return new ParsedEmailProperties($subject, $message, $htmlMessage);
}
/**
* @param $template string
* @param $language string
* @param $html bool
* @return string The template
* @throws EmailTemplateNotFoundException If the template was not found in the filesystem for the provided language
*/
private function getFromFileSystem($template, $language, $html)
{
$htmlFolder = $html ? 'html/' : '';
/* Get email template */
$file = "language/{$language}/emails/{$htmlFolder}{$template}.txt";
$absoluteFilePath = __DIR__ . '/../../../' . $file;
if (file_exists($absoluteFilePath)) {
return file_get_contents($absoluteFilePath);
} else {
throw new EmailTemplateNotFoundException($template, $language);
}
}
/**
* @param $subjectTemplate string
* @param $ticket Ticket
* @param $language string
* @param $heskSettings array
* @return string
* @throws \Exception if common.inc.php isn't loaded
*/
private function parseSubject($subjectTemplate, $ticket, $language, $heskSettings, $modsForHeskSettings) {
global $hesklang;
if (!function_exists('hesk_msgToPlain')) {
throw new \BaseException("common.inc.php not loaded!");
}
if ($ticket === null) {
return $subjectTemplate;
}
// Status name and category name
$defaultStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::NEW_TICKET, $heskSettings);
if (key_exists($language, $defaultStatus->localizedNames)) {
$statusName = $defaultStatus->localizedNames[$language];
} elseif (key_exists('English', $defaultStatus->localizedNames)) {
$statusName = $defaultStatus->localizedNames['English'];
$this->logger->logWarning('EmailTemplateParser', "No localized status found for status '{$defaultStatus->id}' and language '{$language}'. Defaulted to English.", "", new UserContext(), $heskSettings);
} else {
$statusName = "[ERROR: No localized status found for status '{$defaultStatus->id}']";
$this->logger->logError('EmailTemplateParser', "No localized status found for status '{$defaultStatus->id}'", "", new UserContext(), $heskSettings);
}
$categories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
$category = null;
foreach ($categories as $innerCategory) {
if ($innerCategory->id === $ticket->categoryId) {
$category = $innerCategory;
break;
}
}
switch ($ticket->priorityId) {
case Priority::CRITICAL:
$priority = $hesklang['critical'];
break;
case Priority::HIGH:
$priority = $hesklang['high'];
break;
case Priority::MEDIUM:
$priority = $hesklang['medium'];
break;
case Priority::LOW:
$priority = $hesklang['low'];
break;
default:
$priority = 'PRIORITY NOT FOUND';
break;
}
// Special tags
$subject = str_replace('%%SUBJECT%%', $ticket->subject, $subjectTemplate);
$subject = str_replace('%%TRACK_ID%%', $ticket->trackingId, $subject);
$subject = str_replace('%%CATEGORY%%', $category->id, $subject);
$subject = str_replace('%%PRIORITY%%', $priority, $subject);
$subject = str_replace('%%STATUS%%', $statusName, $subject);
return $subject;
}
/**
* @param $messageTemplate string
* @param $ticket Ticket
* @param $language string
* @param $heskSettings array
* @return string
* @throws \Exception if common.inc.php isn't loaded
*/
private function parseMessage($messageTemplate, $ticket, $language, $admin, $heskSettings, $modsForHeskSettings, $html) {
global $hesklang;
if (!function_exists('hesk_msgToPlain')) {
throw new \BaseException("common.inc.php not loaded!");
}
if ($ticket === null) {
return $messageTemplate;
}
$heskSettings['site_title'] = hesk_msgToPlain($heskSettings['site_title'], 1);
// Is email required to view ticket (for customers only)?
$heskSettings['e_param'] = $heskSettings['email_view_ticket'] ? '&e=' . rawurlencode(implode(';', $ticket->email)) : '';
/* Generate the ticket URLs */
$trackingURL = $heskSettings['hesk_url'];
$trackingURL .= $admin ? '/' . $heskSettings['admin_dir'] . '/admin_ticket.php' : '/ticket.php';
$trackingURL .= '?track=' . $ticket->trackingId . ($admin ? '' : $heskSettings['e_param']) . '&Refresh=' . rand(10000, 99999);
// Status name and category name
$defaultStatus = $this->statusGateway->getStatusForDefaultAction(DefaultStatusForAction::NEW_TICKET, $heskSettings);
$statusName = hesk_msgToPlain($defaultStatus->localizedNames[$language]);
$categories = $this->categoryGateway->getAllCategories($heskSettings, $modsForHeskSettings);
$category = null;
foreach ($categories as $innerCategory) {
if ($innerCategory->id === $ticket->categoryId) {
$category = $innerCategory;
break;
}
}
$category = hesk_msgToPlain($category->name);
$owner = $this->userGateway->getUserById($ticket->ownerId, $heskSettings);
$ownerName = $owner === null ? $hesklang['unas'] : hesk_msgToPlain($owner->name);
switch ($ticket->priorityId) {
case Priority::CRITICAL:
$priority = $hesklang['critical'];
break;
case Priority::HIGH:
$priority = $hesklang['high'];
break;
case Priority::MEDIUM:
$priority = $hesklang['medium'];
break;
case Priority::LOW:
$priority = $hesklang['low'];
break;
default:
$priority = 'PRIORITY NOT FOUND';
break;
}
// Special tags
$msg = str_replace('%%NAME%%', $ticket->name, $messageTemplate);
$msg = str_replace('%%SUBJECT%%', $ticket->subject, $msg);
$msg = str_replace('%%TRACK_ID%%', $ticket->trackingId, $msg);
$msg = str_replace('%%TRACK_URL%%', $trackingURL, $msg);
$msg = str_replace('%%SITE_TITLE%%', $heskSettings['site_title'], $msg);
$msg = str_replace('%%SITE_URL%%', $heskSettings['site_url'], $msg);
$msg = str_replace('%%FIRST_NAME%%', Helpers::fullNameToFirstName($ticket->name), $msg);
$msg = str_replace('%%CATEGORY%%', $category, $msg);
$msg = str_replace('%%PRIORITY%%', $priority, $msg);
$msg = str_replace('%%OWNER%%', $ownerName, $msg);
$msg = str_replace('%%STATUS%%', $statusName, $msg);
$msg = str_replace('%%EMAIL%%', implode(';', $ticket->email), $msg);
$msg = str_replace('%%CREATED%%', $ticket->dateCreated, $msg);
$msg = str_replace('%%UPDATED%%', $ticket->lastChanged, $msg);
$msg = str_replace('%%ID%%', $ticket->id, $msg);
$msg = str_replace('%%TIME_WORKED%%', $ticket->timeWorked, $msg);
$lastReplyBy = '';
// Get the last reply by
if (!empty($ticket->lastReplier)) {
$lastReplyBy = $ticket->lastReplier;
} else {
$lastReplyBy = $ticket->name;
}
$msg = str_replace('%%LAST_REPLY_BY%%', $lastReplyBy, $msg);
/* All custom fields */
for ($i=1; $i<=50; $i++) {
$k = 'custom'.$i;
if (isset($heskSettings['custom_fields'][$k]) && isset($ticket->customFields[$i])) {
$v = $heskSettings['custom_fields'][$k];
switch ($v['type']) {
case 'checkbox':
$ticket->customFields[$i] = str_replace("<br>","\n",$ticket->customFields[$i]);
break;
case 'date':
$ticket->customFields[$i] = hesk_custom_date_display_format($ticket->customFields[$i], $v['value']['date_format']);
break;
}
$msg = str_replace('%%'.strtoupper($k).'%%',stripslashes($ticket->customFields[$i]),$msg);
} else {
$msg = str_replace('%%'.strtoupper($k).'%%','',$msg);
}
}
// Is message tag in email template?
if (strpos($msg, '%%MESSAGE%%') !== false) {
// Replace message
if ($html) {
$htmlMessage = html_entity_decode($ticket->message);
$htmlMessage = nl2br($htmlMessage);
$msg = str_replace('%%MESSAGE%%', $htmlMessage, $msg);
} else {
$plainTextMessage = $ticket->message;
$messageHtml = $ticket->usesHtml;
if (count($ticket->replies) > 0) {
$lastReply = end($ticket->replies);
$messageHtml = $lastReply->usesHtml;
}
if ($messageHtml) {
if (!function_exists('convert_html_to_text')) {
require(__DIR__ . '/../../../inc/html2text/html2text.php');
}
$plainTextMessage = convert_html_to_text($plainTextMessage);
$plainTextMessage = fix_newlines($plainTextMessage);
}
$msg = str_replace('%%MESSAGE%%', $plainTextMessage, $msg);
}
// Add direct links to any attachments at the bottom of the email message
if ($heskSettings['attachments']['use'] && isset($ticket->attachments) && count($ticket->attachments) > 0) {
if (!$modsForHeskSettings['attachments']) {
if ($html) {
$msg .= "<br><br><br>" . $hesklang['fatt'];
} else {
$msg .= "\n\n\n" . $hesklang['fatt'];
}
foreach ($ticket->attachments as $attachment) {
if ($html) {
$msg .= "<br><br>{$attachment->fileName}<br>";
} else {
$msg .= "\n\n{$attachment->fileName}\n";
}
$msg .= "{$heskSettings['hesk_url']}/download_attachment.php?att_id={$attachment->id}&track={$ticket->trackingId}{$heskSettings['e_param']}";
}
}
}
// For customer notifications: if we allow email piping/pop 3 fetching and
// stripping quoted replies add an "reply above this line" tag
if (!$admin && ($heskSettings['email_piping'] || $heskSettings['pop3']) && $heskSettings['strip_quoted']) {
$msg = $hesklang['EMAIL_HR'] . "\n\n" . $msg;
}
} elseif (strpos($msg, '%%MESSAGE_NO_ATTACHMENTS%%') !== false) {
if ($html) {
$htmlMessage = nl2br($ticket->message);
$msg = str_replace('%%MESSAGE_NO_ATTACHMENTS%%', $htmlMessage, $msg);
} else {
$plainTextMessage = $ticket->message;
$messageHtml = $ticket->usesHtml;
if (count($ticket->replies) > 0) {
$lastReply = end($ticket->replies);
$messageHtml = $lastReply->usesHtml;
}
if ($messageHtml) {
if (!function_exists('convert_html_to_text')) {
require(__DIR__ . '/../../../inc/html2text/html2text.php');
}
$plainTextMessage = convert_html_to_text($plainTextMessage);
$plainTextMessage = fix_newlines($plainTextMessage);
}
$msg = str_replace('%%MESSAGE_NO_ATTACHMENTS%%', $plainTextMessage, $msg);
}
}
return $msg;
}
}

View File

@ -0,0 +1,65 @@
<?php
namespace BusinessLogic\Emails;
class EmailTemplateRetriever extends \BaseClass {
/**
* @var $validTemplates EmailTemplate[]
*/
private $validTemplates;
function __construct() {
$this->validTemplates = array();
$this->initializeArray();
}
const FORGOT_TICKET_ID = 0;
const NEW_REPLY_BY_STAFF = 1;
const NEW_TICKET = 2;
const VERIFY_EMAIL = 3;
const TICKET_CLOSED = 4;
const CATEGORY_MOVED = 5;
const NEW_REPLY_BY_CUSTOMER = 6;
const NEW_TICKET_STAFF = 7;
const TICKET_ASSIGNED_TO_YOU = 8;
const NEW_PM = 9;
const NEW_NOTE = 10;
const RESET_PASSWORD = 11;
const CALENDAR_REMINDER = 12;
const OVERDUE_TICKET = 13;
function initializeArray() {
if (count($this->validTemplates) > 0) {
//-- Map already built
return;
}
$this->validTemplates[self::FORGOT_TICKET_ID] = new EmailTemplate(false, 'forgot_ticket_id');
$this->validTemplates[self::NEW_REPLY_BY_STAFF] = new EmailTemplate(false, 'new_reply_by_staff');
$this->validTemplates[self::NEW_TICKET] = new EmailTemplate(false, 'new_ticket', 'ticket_received');
$this->validTemplates[self::VERIFY_EMAIL] = new EmailTemplate(false, 'verify_email');
$this->validTemplates[self::TICKET_CLOSED] = new EmailTemplate(false, 'ticket_closed');
$this->validTemplates[self::CATEGORY_MOVED] = new EmailTemplate(true, 'category_moved');
$this->validTemplates[self::NEW_REPLY_BY_CUSTOMER] = new EmailTemplate(true, 'new_reply_by_customer');
$this->validTemplates[self::NEW_TICKET_STAFF] = new EmailTemplate(true, 'new_ticket_staff');
$this->validTemplates[self::TICKET_ASSIGNED_TO_YOU] = new EmailTemplate(true, 'ticket_assigned_to_you');
$this->validTemplates[self::NEW_PM] = new EmailTemplate(true, 'new_pm');
$this->validTemplates[self::NEW_NOTE] = new EmailTemplate(true, 'new_note');
$this->validTemplates[self::RESET_PASSWORD] = new EmailTemplate(true, 'reset_password');
$this->validTemplates[self::CALENDAR_REMINDER] = new EmailTemplate(true, 'reset_password');
$this->validTemplates[self::OVERDUE_TICKET] = new EmailTemplate(true, 'overdue_ticket');
}
/**
* @param $templateId
* @return EmailTemplate|null
*/
function getTemplate($templateId) {
if (isset($this->validTemplates[$templateId])) {
return $this->validTemplates[$templateId];
}
return null;
}
}

View File

@ -0,0 +1,73 @@
<?php
namespace BusinessLogic\Emails;
use BusinessLogic\Tickets\Attachment;
use BusinessLogic\Tickets\Ticket;
use Mailgun\Mailgun;
class MailgunEmailSender extends \BaseClass implements EmailSender {
function sendEmail($emailBuilder, $heskSettings, $modsForHeskSettings, $sendAsHtml) {
$mailgunArray = array();
$mailgunArray['from'] = $heskSettings['noreply_mail']; // Email Address
if ($heskSettings['noreply_name'] !== null && $heskSettings['noreply_name'] !== '') {
$mailgunArray['from'] = "{$heskSettings['noreply_name']} <{$heskSettings['noreply_mail']}>"; // Name and address
}
$mailgunArray['to'] = implode(',', $emailBuilder->to);
if ($emailBuilder->cc !== null && count($emailBuilder->cc) > 0) {
$mailgunArray['cc'] = implode(',', $emailBuilder->cc);
}
if ($emailBuilder->bcc !== null && count($emailBuilder->bcc) > 0) {
$mailgunArray['bcc'] = implode(',', $emailBuilder->bcc);
}
$mailgunArray['subject'] = $emailBuilder->subject;
$mailgunArray['text'] = $emailBuilder->message;
if ($sendAsHtml) {
$mailgunArray['html'] = $emailBuilder->htmlMessage;
}
$mailgunAttachments = array();
if ($emailBuilder->attachments !== null) {
foreach ($emailBuilder->attachments as $attachment) {
$mailgunAttachments[] = array(
'remoteName' => $attachment->fileName,
'filePath' => __DIR__ . '/../../../' . $heskSettings['attach_dir'] . '/' . $attachment->savedName
);
}
}
$result = $this->sendMessage($mailgunArray, $mailgunAttachments, $modsForHeskSettings);
if (isset($result->http_response_code)
&& $result->http_response_code === 200) {
return true;
}
return $result;
}
private function sendMessage($mailgunArray, $attachments, $modsForHeskSettings) {
$ssl = !defined('NO_MAILGUN_SSL');
$messageClient = new Mailgun($modsForHeskSettings['mailgun_api_key'], 'api.mailgun.net', 'v2', $ssl);
$mailgunAttachments = array();
if (count($attachments) > 0) {
$mailgunAttachments = array(
'attachment' => $attachments
);
}
$result = $messageClient->sendMessage($modsForHeskSettings['mailgun_domain'], $mailgunArray, $mailgunAttachments);
return $result;
}
}

View File

@ -0,0 +1,27 @@
<?php
namespace BusinessLogic\Emails;
class ParsedEmailProperties extends \BaseClass {
function __construct($subject, $message, $htmlMessage) {
$this->subject = $subject;
$this->message = $message;
$this->htmlMessage = $htmlMessage;
}
/**
* @var $subject string
*/
public $subject;
/**
* @var $message string
*/
public $message;
/**
* @var $htmlMessage string
*/
public $htmlMessage;
}

View File

@ -0,0 +1,10 @@
<?php
namespace BusinessLogic\Exceptions;
class AccessViolationException extends ApiFriendlyException {
function __construct($message) {
parent::__construct($message, 'Access Exception', 403);
}
}

View File

@ -0,0 +1,25 @@
<?php
namespace BusinessLogic\Exceptions;
use Exception;
class ApiFriendlyException extends \BaseException {
public $title;
public $httpResponseCode;
/**
* ApiFriendlyException constructor.
* @param string $message
* @param string $title
* @param int $httpResponseCode
*/
function __construct($message, $title, $httpResponseCode) {
$this->title = $title;
$this->httpResponseCode = $httpResponseCode;
parent::__construct($message);
}
}

View File

@ -0,0 +1,17 @@
<?php
/**
* Created by PhpStorm.
* User: mkoch
* Date: 2/22/2017
* Time: 10:00 PM
*/
namespace BusinessLogic\Exceptions;
class EmailTemplateNotFoundException extends ApiFriendlyException {
function __construct($emailTemplate, $language) {
parent::__construct(sprintf("The email template '%s' was not found for the language '%s'", $emailTemplate, $language),
'Email Template Not Found!', 400);
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace BusinessLogic\Exceptions;
class InternalUseOnlyException extends ApiFriendlyException {
function __construct() {
parent::__construct("This endpoint can only be used internally", "Internal Use Only", 401);
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace BusinessLogic\Exceptions;
class InvalidAuthenticationTokenException extends ApiFriendlyException {
public function __construct() {
parent::__construct('The X-Auth-Token is invalid. The token must be for an active helpdesk user.',
'Security Exception',
401);
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* Created by PhpStorm.
* User: mkoch
* Date: 2/23/2017
* Time: 8:13 PM
*/
namespace BusinessLogic\Exceptions;
class InvalidEmailTemplateException extends ApiFriendlyException {
function __construct($template) {
parent::__construct(sprintf("The email template '%s' is invalid", $template), 'Invalid Email Template', 400);
}
}

View File

@ -0,0 +1,11 @@
<?php
namespace BusinessLogic\Exceptions;
class MissingAuthenticationTokenException extends ApiFriendlyException {
function __construct() {
parent::__construct("An 'X-Auth-Token' is required for this request",
'Security Exception',
401);
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* Created by PhpStorm.
* User: cokoch
* Date: 5/2/2017
* Time: 12:28 PM
*/
namespace BusinessLogic\Exceptions;
class SessionNotActiveException extends ApiFriendlyException {
function __construct() {
parent::__construct("You must be logged in to call internal API methods", "Authentication Required", 401);
}
}

View File

@ -0,0 +1,21 @@
<?php
namespace BusinessLogic\Exceptions;
use BusinessLogic\ValidationModel;
use Exception;
class ValidationException extends ApiFriendlyException {
/**
* ValidationException constructor.
* @param ValidationModel $validationModel The validation model
* @throws Exception If the validationModel's errorKeys is empty
*/
function __construct($validationModel) {
if (count($validationModel->errorKeys) === 0) {
throw new Exception('Tried to throw a ValidationException, but the validation model was valid or had 0 error keys!');
}
parent::__construct(implode(",", $validationModel->errorKeys), "Validation Failed. Error keys are available in the message section.", 400);
}
}

View File

@ -0,0 +1,244 @@
<?php
namespace BusinessLogic;
class Helpers extends \BaseClass {
static function getHeader($key) {
$headers = getallheaders();
$uppercaseHeaders = array();
foreach ($headers as $header => $value) {
$uppercaseHeaders[strtoupper($header)] = $value;
}
return isset($uppercaseHeaders[$key])
? $uppercaseHeaders[$key]
: NULL;
}
static function hashToken($token) {
return hash('sha512', $token);
}
static function safeArrayGet($array, $key) {
return $array !== null && array_key_exists($key, $array)
? $array[$key]
: null;
}
static function boolval($val) {
return $val == true;
}
static function heskHtmlSpecialCharsDecode($in) {
return str_replace(array('&amp;', '&lt;', '&gt;', '&quot;'), array('&', '<', '>', '"'), $in);
}
static function heskMakeUrl($text, $class = '', $shortenLinks = true) {
if (!defined('MAGIC_URL_EMAIL')) {
define('MAGIC_URL_EMAIL', 1);
define('MAGIC_URL_FULL', 2);
define('MAGIC_URL_LOCAL', 3);
define('MAGIC_URL_WWW', 4);
}
$class = ($class) ? ' class="' . $class . '"' : '';
// matches a xxxx://aaaaa.bbb.cccc. ...
$text = preg_replace_callback(
'#(^|[\n\t (>.])(' . "[a-z][a-z\d+]*:/{2}(?:(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+|[0-9.]+|\[[a-z0-9.]+:[a-z0-9.]+:[a-z0-9.:]+\])(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#iu',
function($matches) use ($class, $shortenLinks) {
return self::makeClickableCallback(MAGIC_URL_FULL, $matches[1], $matches[2], '', $class, $shortenLinks);
},
$text
);
// matches a "www.xxxx.yyyy[/zzzz]" kinda lazy URL thing
$text = preg_replace_callback(
'#(^|[\n\t (>])(' . "www\.(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})+(?::\d*)?(?:/(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@|]+|%[\dA-F]{2})*)*(?:\?(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?(?:\#(?:[^\p{C}\p{Z}\p{S}\p{P}\p{Nl}\p{No}\p{Me}\x{1100}-\x{115F}\x{A960}-\x{A97C}\x{1160}-\x{11A7}\x{D7B0}-\x{D7C6}\x{20D0}-\x{20FF}\x{1D100}-\x{1D1FF}\x{1D200}-\x{1D24F}\x{0640}\x{07FA}\x{302E}\x{302F}\x{3031}-\x{3035}\x{303B}]*[\x{00B7}\x{0375}\x{05F3}\x{05F4}\x{30FB}\x{002D}\x{06FD}\x{06FE}\x{0F0B}\x{3007}\x{00DF}\x{03C2}\x{200C}\x{200D}\pL0-9\-._~!$&'(*+,;=:@/?|]+|%[\dA-F]{2})*)?" . ')#iu',
function($matches) use ($class, $shortenLinks) {
return self::makeClickableCallback(MAGIC_URL_WWW, $matches[1], $matches[2], '', $class, $shortenLinks);
},
$text
);
// matches an email address
$text = preg_replace_callback(
'/(^|[\n\t (>])(' . '((?:[\w\!\#$\%\&\'\*\+\-\/\=\?\^\`{\|\}\~]+\.)*(?:[\w\!\#$\%\'\*\+\-\/\=\?\^\`{\|\}\~]|&amp;)+)@((((([a-z0-9]{1}[a-z0-9\-]{0,62}[a-z0-9]{1})|[a-z])\.)+[a-z]{2,63})|(\d{1,3}\.){3}\d{1,3}(\:\d{1,5})?)' . ')/iu',
function($matches) use ($class, $shortenLinks) {
return self::makeClickableCallback(MAGIC_URL_EMAIL, $matches[1], $matches[2], '', $class, $shortenLinks);
},
$text
);
return $text;
}
static function makeClickableCallback($type, $whitespace, $url, $relative_url, $class, $shortenLinks)
{
global $hesk_settings;
$orig_url = $url;
$orig_relative = $relative_url;
$append = '';
$url = htmlspecialchars_decode($url);
$relative_url = htmlspecialchars_decode($relative_url);
// make sure no HTML entities were matched
$chars = array('<', '>', '"');
$split = false;
foreach ($chars as $char) {
$next_split = strpos($url, $char);
if ($next_split !== false) {
$split = ($split !== false) ? min($split, $next_split) : $next_split;
}
}
if ($split !== false) {
// an HTML entity was found, so the URL has to end before it
$append = substr($url, $split) . $relative_url;
$url = substr($url, 0, $split);
$relative_url = '';
} else if ($relative_url) {
// same for $relative_url
$split = false;
foreach ($chars as $char) {
$next_split = strpos($relative_url, $char);
if ($next_split !== false) {
$split = ($split !== false) ? min($split, $next_split) : $next_split;
}
}
if ($split !== false) {
$append = substr($relative_url, $split);
$relative_url = substr($relative_url, 0, $split);
}
}
// if the last character of the url is a punctuation mark, exclude it from the url
$last_char = ($relative_url) ? $relative_url[strlen($relative_url) - 1] : $url[strlen($url) - 1];
switch ($last_char) {
case '.':
case '?':
case '!':
case ':':
case ',':
$append = $last_char;
if ($relative_url) {
$relative_url = substr($relative_url, 0, -1);
} else {
$url = substr($url, 0, -1);
}
break;
// set last_char to empty here, so the variable can be used later to
// check whether a character was removed
default:
$last_char = '';
break;
}
$short_url = ($hesk_settings['short_link'] && strlen($url) > 70 && $shortenLinks) ? substr($url, 0, 54) . ' ... ' . substr($url, -10) : $url;
switch ($type) {
case MAGIC_URL_LOCAL:
$tag = 'l';
$relative_url = preg_replace('/[&?]sid=[0-9a-f]{32}$/', '', preg_replace('/([&?])sid=[0-9a-f]{32}&/', '$1', $relative_url));
$url = $url . '/' . $relative_url;
$text = $relative_url;
// this url goes to http://domain.tld/path/to/board/ which
// would result in an empty link if treated as local so
// don't touch it and let MAGIC_URL_FULL take care of it.
if (!$relative_url) {
return $whitespace . $orig_url . '/' . $orig_relative; // slash is taken away by relative url pattern
}
break;
case MAGIC_URL_FULL:
$tag = 'm';
$text = $short_url;
break;
case MAGIC_URL_WWW:
$tag = 'w';
$url = 'http://' . $url;
$text = $short_url;
break;
case MAGIC_URL_EMAIL:
$tag = 'e';
$text = $short_url;
$url = 'mailto:' . $url;
break;
}
$url = htmlspecialchars($url);
$text = htmlspecialchars($text);
$append = htmlspecialchars($append);
$html = "$whitespace<a href=\"$url\" target=\"blank\" $class>$text</a>$append";
return $html;
} // END make_clickable_callback()
static function fullNameToFirstName($full_name) {
$name_parts = explode(' ', $full_name);
// Only one part, return back the original
if (count($name_parts) < 2){
return $full_name;
}
$first_name = self::heskMbStrToLower($name_parts[0]);
// Name prefixes without dots
$prefixes = array('mr', 'ms', 'mrs', 'miss', 'dr', 'rev', 'fr', 'sr', 'prof', 'sir');
if (in_array($first_name, $prefixes) || in_array($first_name, array_map(function ($i) {return $i . '.';}, $prefixes))) {
if(isset($name_parts[2])) {
// Mr James Smith -> James
$first_name = $name_parts[1];
} else {
// Mr Smith (no first name given)
return $full_name;
}
}
// Detect LastName, FirstName
if (self::heskMbSubstr($first_name, -1, 1) == ',') {
if (count($name_parts) == 2) {
$first_name = $name_parts[1];
} else {
return $full_name;
}
}
// If the first name doesn't have at least 3 chars, return the original
if(self::heskMbStrlen($first_name) < 3) {
return $full_name;
}
// Return the name with first character uppercase
return self::heskUcfirst($first_name);
}
static function heskMbStrToLower($in) {
return function_exists('mb_strtolower') ? mb_strtolower($in) : strtolower($in);
}
static function heskMbStrlen($in) {
return function_exists('mb_strlen') ? mb_strlen($in, 'UTF-8') : strlen($in);
}
static function heskMbSubstr($in, $start, $length) {
return function_exists('mb_substr') ? mb_substr($in, $start, $length, 'UTF-8') : substr($in, $start, $length);
}
static function heskUcfirst($in) {
return function_exists('mb_convert_case') ? mb_convert_case($in, MB_CASE_TITLE, 'UTF-8') : ucfirst($in);
}
}

View File

@ -0,0 +1,30 @@
<?php
namespace BusinessLogic\Navigation;
class CustomNavElement extends \BaseClass {
/* @var $id int*/
public $id;
/* @var $text string[] */
public $text;
/* @var $subtext string[]|null */
public $subtext;
/* @var $imageUrl string|null */
public $imageUrl;
/* @var $fontIcon string|null */
public $fontIcon;
/* @var $place int */
public $place;
/* @var $url string */
public $url;
/* @var $sort int */
public $sort;
}

View File

@ -0,0 +1,70 @@
<?php
namespace BusinessLogic\Navigation;
// TODO Test!
use BusinessLogic\Exceptions\ApiFriendlyException;
use DataAccess\Navigation\CustomNavElementGateway;
class CustomNavElementHandler extends \BaseClass {
/* @var $customNavElementGateway CustomNavElementGateway */
private $customNavElementGateway;
function __construct(CustomNavElementGateway $customNavElementGateway) {
$this->customNavElementGateway = $customNavElementGateway;
}
function getAllCustomNavElements($heskSettings) {
return $this->customNavElementGateway->getAllCustomNavElements($heskSettings);
}
function getCustomNavElement($id, $heskSettings) {
$elements = $this->getAllCustomNavElements($heskSettings);
foreach ($elements as $element) {
if ($element->id === intval($id)) {
return output($element);
}
}
throw new ApiFriendlyException("Custom nav element {$id} not found!", "Element Not Found", 404);
}
function deleteCustomNavElement($id, $heskSettings) {
$this->customNavElementGateway->deleteCustomNavElement($id, $heskSettings);
$this->customNavElementGateway->resortAllElements($heskSettings);
}
function saveCustomNavElement($element, $heskSettings) {
$this->customNavElementGateway->saveCustomNavElement($element, $heskSettings);
}
function createCustomNavElement($element, $heskSettings) {
$element = $this->customNavElementGateway->createCustomNavElement($element, $heskSettings);
$this->customNavElementGateway->resortAllElements($heskSettings);
return $element;
}
function sortCustomNavElement($elementId, $direction, $heskSettings) {
/* @var $element CustomNavElement */
$elements = $this->customNavElementGateway->getAllCustomNavElements($heskSettings);
$elementToChange = null;
foreach ($elements as $element) {
if ($element->id === intval($elementId)) {
$elementToChange = $element;
}
}
if ($direction === Direction::UP) {
$elementToChange->sort -= 15;
} else {
$elementToChange->sort += 15;
}
$this->customNavElementGateway->saveCustomNavElement($elementToChange, $heskSettings);
$this->customNavElementGateway->resortAllElements($heskSettings);
}
}

View File

@ -0,0 +1,10 @@
<?php
namespace BusinessLogic\Navigation;
class CustomNavElementPlace extends \BaseClass {
const HOMEPAGE_BLOCK = 1;
const CUSTOMER_NAVIGATION = 2;
const ADMIN_NAVIGATION = 3;
}

View File

@ -0,0 +1,9 @@
<?php
namespace BusinessLogic\Navigation;
class Direction extends \BaseClass {
const UP = 'up';
const DOWN = 'down';
}

View File

@ -0,0 +1,52 @@
<?php
namespace BusinessLogic\Security;
use DataAccess\Security\BanGateway;
class BanRetriever extends \BaseClass {
/**
* @var BanGateway
*/
private $banGateway;
function __construct(BanGateway $banGateway) {
$this->banGateway = $banGateway;
}
/**
* @param $email
* @param $heskSettings
* @return bool
*/
function isEmailBanned($email, $heskSettings) {
$bannedEmails = $this->banGateway->getEmailBans($heskSettings);
foreach ($bannedEmails as $bannedEmail) {
if ($bannedEmail->email === $email) {
return true;
}
}
return false;
}
/**
* @param $ip int the IP address, converted beforehand using ip2long()
* @param $heskSettings
* @return bool
*/
function isIpAddressBanned($ip, $heskSettings) {
$bannedIps = $this->banGateway->getIpBans($heskSettings);
foreach ($bannedIps as $bannedIp) {
if ($bannedIp->ipFrom <= $ip && $bannedIp->ipTo >= $ip) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,26 @@
<?php
namespace BusinessLogic\Security;
class BannedEmail extends \BaseClass {
/**
* @var int
*/
public $id;
/**
* @var string
*/
public $email;
/**
* @var int|null The user who banned the email, or null if the user was deleted
*/
public $bannedById;
/**
* @var string
*/
public $dateBanned;
}

View File

@ -0,0 +1,36 @@
<?php
namespace BusinessLogic\Security;
class BannedIp extends \BaseClass {
/**
* @var int
*/
public $id;
/**
* @var int the lower bound of the IP address range
*/
public $ipFrom;
/**
* @var int the upper bound of the IP address range
*/
public $ipTo;
/**
* @var string the display of the IP ban to be shown to the user
*/
public $ipDisplay;
/**
* @var int|null The user who banned the IP, or null if the user was deleted
*/
public $bannedById;
/**
* @var string
*/
public $dateBanned;
}

View File

@ -0,0 +1,23 @@
<?php
namespace BusinessLogic\Security;
class PermissionChecker extends \BaseClass {
/**
* @param $userContext UserContext
* @param $permission string
* @return bool
*/
function doesUserHavePermission($userContext, $permission) {
if ($userContext->admin) {
return true;
}
if (in_array($permission, $userContext->permissions)) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,131 @@
<?php
namespace BusinessLogic\Security;
use BusinessLogic\Helpers;
class UserContext extends \BaseClass {
/* @var $id int */
public $id;
/* @var $username string */
public $username;
/* @var $admin bool */
public $admin;
/* @var $name string */
public $name;
/* @var $email string */
public $email;
/* @var $signature string */
public $signature;
/* @var $language string|null */
public $language;
/* @var $categories int[] */
public $categories;
/* @var $permissions string[] */
public $permissions;
/* @var UserContextPreferences */
public $preferences;
/* @var UserContextNotifications */
public $notificationSettings;
/* @var $autoAssign bool */
public $autoAssign;
/* @var $ratingNegative int */
public $ratingNegative;
/* @var $ratingPositive int */
public $ratingPositive;
/* @var $rating float */
public $rating;
/* @var $totalNumberOfReplies int */
public $totalNumberOfReplies;
/* @var $active bool */
public $active;
function isAnonymousUser() {
return $this->id === -1;
}
static function buildAnonymousUser() {
$userContext = new UserContext();
$userContext->id = -1;
$userContext->username = "API - ANONYMOUS USER"; // Usernames can't have spaces, so no one will take this username
$userContext->admin = false;
$userContext->name = "ANONYMOUS USER";
$userContext->email = "anonymous-user@example.com";
$userContext->categories = array();
$userContext->permissions = array();
$userContext->autoAssign = false;
$userContext->active = true;
return $userContext;
}
/**
* Builds a user context based on the current session. **The session must be active!**
* @param $dataRow array the $_SESSION superglobal or the hesk_users result set
* @return UserContext the built user context
*/
static function fromDataRow($dataRow) {
$userContext = new UserContext();
$userContext->id = intval($dataRow['id']);
$userContext->username = $dataRow['user'];
$userContext->admin = Helpers::boolval($dataRow['isadmin']);
$userContext->name = $dataRow['name'];
$userContext->email = $dataRow['email'];
$userContext->signature = $dataRow['signature'];
$userContext->language = $dataRow['language'];
if (is_array($dataRow['categories'])) {
$userContext->categories = $dataRow['categories'];
} else {
$userContext->categories = explode(',', $dataRow['categories']);
}
$userContext->permissions = explode(',', $dataRow['heskprivileges']);
$userContext->autoAssign = Helpers::boolval($dataRow['autoassign']);
$userContext->ratingNegative = intval($dataRow['ratingneg']);
$userContext->ratingPositive = intval($dataRow['ratingpos']);
$userContext->rating = floatval($dataRow['rating']);
$userContext->totalNumberOfReplies = intval($dataRow['replies']);
$userContext->active = Helpers::boolval($dataRow['active']);
$preferences = new UserContextPreferences();
$preferences->afterReply = intval($dataRow['afterreply']);
$preferences->autoStartTimeWorked = Helpers::boolval($dataRow['autostart']);
$preferences->autoreload = intval($dataRow['autoreload']);
$preferences->defaultNotifyCustomerNewTicket = Helpers::boolval($dataRow['notify_customer_new']);
$preferences->defaultNotifyCustomerReply = Helpers::boolval($dataRow['notify_customer_reply']);
$preferences->showSuggestedKnowledgebaseArticles = Helpers::boolval($dataRow['show_suggested']);
$preferences->defaultCalendarView = intval($dataRow['default_calendar_view']);
$preferences->defaultTicketView = $dataRow['default_list'];
$userContext->preferences = $preferences;
$notifications = new UserContextNotifications();
$notifications->newUnassigned = Helpers::boolval($dataRow['notify_new_unassigned']);
$notifications->newAssignedToMe = Helpers::boolval($dataRow['notify_new_my']);
$notifications->replyUnassigned = Helpers::boolval($dataRow['notify_reply_unassigned']);
$notifications->replyToMe = Helpers::boolval($dataRow['notify_reply_my']);
$notifications->ticketAssignedToMe = Helpers::boolval($dataRow['notify_assigned']);
$notifications->privateMessage = Helpers::boolval($dataRow['notify_pm']);
$notifications->noteOnTicketAssignedToMe = Helpers::boolval($dataRow['notify_note']);
$notifications->noteOnTicketNotAssignedToMe = Helpers::boolval($dataRow['notify_note_unassigned']);
$notifications->overdueTicketUnassigned = Helpers::boolval($dataRow['notify_overdue_unassigned']);
$userContext->notificationSettings = $notifications;
return $userContext;
}
}

View File

@ -0,0 +1,87 @@
<?php
namespace BusinessLogic\Security;
use BusinessLogic\Exceptions\InvalidAuthenticationTokenException;
use BusinessLogic\Exceptions\MissingAuthenticationTokenException;
use BusinessLogic\Helpers;
use DataAccess\Security\UserGateway;
class UserContextBuilder extends \BaseClass {
/**
* @var UserGateway
*/
private $userGateway;
function __construct(UserGateway $userGateway) {
$this->userGateway = $userGateway;
}
function buildUserContext($authToken, $heskSettings) {
$NULL_OR_EMPTY_STRING = 'cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e';
$hashedToken = Helpers::hashToken($authToken);
if ($hashedToken === $NULL_OR_EMPTY_STRING) {
throw new MissingAuthenticationTokenException();
}
$userRow = $this->userGateway->getUserForAuthToken($hashedToken, $heskSettings);
if ($userRow === null) {
throw new InvalidAuthenticationTokenException();
}
return UserContext::fromDataRow($userRow);
}
/**
* Builds a user context based on the current session. **The session must be active!**
* @param $dataRow array the $_SESSION superglobal or the hesk_users result set
* @return UserContext the built user context
*/
function fromDataRow($dataRow) {
$userContext = new UserContext();
$userContext->id = $dataRow['id'];
$userContext->username = $dataRow['user'];
$userContext->admin = $dataRow['isadmin'];
$userContext->name = $dataRow['name'];
$userContext->email = $dataRow['email'];
$userContext->signature = $dataRow['signature'];
$userContext->language = $dataRow['language'];
$userContext->categories = explode(',', $dataRow['categories']);
$userContext->permissions = explode(',', $dataRow['heskprivileges']);
$userContext->autoAssign = $dataRow['autoassign'];
$userContext->ratingNegative = $dataRow['ratingneg'];
$userContext->ratingPositive = $dataRow['ratingpos'];
$userContext->rating = $dataRow['rating'];
$userContext->totalNumberOfReplies = $dataRow['replies'];
$userContext->active = $dataRow['active'];
$preferences = new UserContextPreferences();
$preferences->afterReply = $dataRow['afterreply'];
$preferences->autoStartTimeWorked = $dataRow['autostart'];
$preferences->autoreload = $dataRow['autoreload'];
$preferences->defaultNotifyCustomerNewTicket = $dataRow['notify_customer_new'];
$preferences->defaultNotifyCustomerReply = $dataRow['notify_customer_reply'];
$preferences->showSuggestedKnowledgebaseArticles = $dataRow['show_suggested'];
$preferences->defaultCalendarView = $dataRow['default_calendar_view'];
$preferences->defaultTicketView = $dataRow['default_list'];
$userContext->preferences = $preferences;
$notifications = new UserContextNotifications();
$notifications->newUnassigned = $dataRow['notify_new_unassigned'];
$notifications->newAssignedToMe = $dataRow['notify_new_my'];
$notifications->replyUnassigned = $dataRow['notify_reply_unassigned'];
$notifications->replyToMe = $dataRow['notify_reply_my'];
$notifications->ticketAssignedToMe = $dataRow['notify_assigned'];
$notifications->privateMessage = $dataRow['notify_pm'];
$notifications->noteOnTicketAssignedToMe = $dataRow['notify_note'];
$notifications->noteOnTicketNotAssignedToMe = $dataRow['notify_note_unassigned'];
$notifications->overdueTicketUnassigned = $dataRow['notify_overdue_unassigned'];
$userContext->notificationSettings = $notifications;
return $userContext;
}
}

View File

@ -0,0 +1,16 @@
<?php
namespace BusinessLogic\Security;
class UserContextNotifications extends \BaseClass {
public $newUnassigned;
public $newAssignedToMe;
public $replyUnassigned;
public $replyToMe;
public $ticketAssignedToMe;
public $privateMessage;
public $noteOnTicketAssignedToMe;
public $noteOnTicketNotAssignedToMe;
public $overdueTicketUnassigned;
}

View File

@ -0,0 +1,15 @@
<?php
namespace BusinessLogic\Security;
class UserContextPreferences extends \BaseClass {
public $afterReply;
public $autoStartTimeWorked;
public $autoreload;
public $defaultNotifyCustomerNewTicket;
public $defaultNotifyCustomerReply;
public $showSuggestedKnowledgebaseArticles;
public $defaultCalendarView;
public $defaultTicketView;
}

View File

@ -0,0 +1,23 @@
<?php
/**
* Created by PhpStorm.
* User: mkoch
* Date: 3/12/2017
* Time: 12:11 PM
*/
namespace BusinessLogic\Security;
class UserPrivilege extends \BaseClass {
const CAN_VIEW_TICKETS = 'can_view_tickets';
const CAN_REPLY_TO_TICKETS = 'can_reply_tickets';
const CAN_EDIT_TICKETS = 'can_edit_tickets';
const CAN_DELETE_TICKETS = 'can_del_tickets';
const CAN_MANAGE_CATEGORIES = 'can_man_cat';
const CAN_VIEW_ASSIGNED_TO_OTHER = 'can_view_ass_others';
const CAN_VIEW_UNASSIGNED = 'can_view_unassigned';
const CAN_VIEW_ASSIGNED_BY_ME = 'can_view_ass_by';
const CAN_MANAGE_SERVICE_MESSAGES = 'can_service_msg';
const CAN_CHANGE_DUE_DATE = 'can_change_due_date';
}

View File

@ -0,0 +1,55 @@
<?php
namespace BusinessLogic\Security;
use BusinessLogic\Tickets\Ticket;
use DataAccess\Security\UserGateway;
class UserToTicketChecker extends \BaseClass {
/* @var $userGateway UserGateway */
private $userGateway;
function __construct(UserGateway $userGateway) {
$this->userGateway = $userGateway;
}
/**
* @param $user UserContext
* @param $ticket Ticket
* @param $heskSettings array
* @param $extraPermissions UserPrivilege[] additional privileges the user needs besides CAN_VIEW_TICKETS (if not an admin)
* for this to return true
* @return bool
*/
function isTicketAccessibleToUser($user, $ticket, $heskSettings, $extraPermissions = array()) {
if ($user->admin === true) {
return true;
}
if (in_array(UserPrivilege::CAN_VIEW_ASSIGNED_BY_ME, $user->permissions) &&
$ticket->assignedBy === $user->id) {
return true;
}
if (!in_array($ticket->categoryId, $user->categories)) {
return false;
}
$categoryManager = $this->userGateway->getManagerForCategory($ticket->categoryId, $heskSettings);
if ($categoryManager !== null && $user->id === $categoryManager->id) {
return true;
}
$extraPermissions[] = UserPrivilege::CAN_VIEW_TICKETS;
foreach ($extraPermissions as $permission) {
if (!in_array($permission, $user->permissions)) {
return false;
}
}
return true;
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace BusinessLogic\ServiceMessages;
class GetServiceMessagesFilter {
/* @var $includeStaffServiceMessages bool */
public $includeStaffServiceMessages = true;
/* @var $includeDrafts bool */
public $includeDrafts = true;
}

View File

@ -0,0 +1,39 @@
<?php
namespace BusinessLogic\ServiceMessages;
class ServiceMessage extends \BaseClass {
/* @var $id int */
public $id;
/* @var $dateCreated string */
public $dateCreated;
/* @var $createdBy int */
public $createdBy;
/* @var $title string */
public $title;
/* @var $message string */
public $message;
/* @var $style string */
public $style;
/* @var $published bool */
public $published;
/* @var $order int */
public $order;
/* @var $icon string */
public $icon;
/* @var $locations string[] */
public $locations;
/* @var $language string */
public $language;
}

Some files were not shown because too many files have changed in this diff Show More