Compare commits

..

2400 Commits

Author SHA1 Message Date
JediKev
8d38b06196 Add Release Notes for v1.18.4 2026-06-17 22:01:48 +00:00
JediKev
93c2d125e2 Merge branch '1.17.x' into develop 2026-06-17 22:00:04 +00:00
JediKev
a1114e5298 Add Release Notes for v1.17.8 2026-06-17 21:55:42 +00:00
JediKev
13122d1ec9 Merge pull request #6959 from JediKev/security/latest-patches-06-2026
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-06-17 16:48:29 -05:00
JediKev
6558b33225 security: FAQ Print
This addresses a report submitted by Michael Bommarito in regards to
external image handling in FAQ PDF exports.
2026-06-17 16:13:23 -05:00
JediKev
2a0c388fc8 security: User AJAX
This addresses a report submitted by LXY in regards to user profile and
preview access through staff AJAX.
2026-06-17 16:13:23 -05:00
JediKev
b4ede885cc security: Thread Entry Reuse
This addresses a report submitted by LXY in regards to thread entry reuse in
new-ticket workflows.
2026-06-17 16:13:23 -05:00
JediKev
119cefe516 security: Thread Actions
This addresses a report submitted by LXY in regards to thread action
authorization for ticket and task operations.
2026-06-17 16:13:23 -05:00
JediKev
5ff9795ef3 security: User Org AJAX
This addresses a report submitted by LXY in regards to user organization
updates through staff AJAX.
2026-06-17 16:13:23 -05:00
JediKev
5600f94962 security: Pwreset Token Expiration
This addresses a report submitted by Charton93 in regards to password reset
token expiration window handling.
2026-06-17 16:13:23 -05:00
JediKev
d457c146a5 security: Template Vars
This addresses a report submitted by luke.hebenstreit@outlook.com in regards
to template variable resolution for sensitive object values.
2026-06-17 16:13:23 -05:00
JediKev
b4cc0925c2 security: Login-Required Policy
This addresses a privately reported issue in regards to enforcing
login-required policy before ticket creation.
2026-06-17 16:13:23 -05:00
JediKev
eaebe0176e security: Note AJAX
This addresses a report submitted by sliao25@m.fudan.edu.cn in regards to
Note AJAX authorization.
2026-06-17 16:13:23 -05:00
JediKev
d590a9770d security: Ticket Field View
This addresses a report submitted by Juan Felipe Oz (@JF0x0r) in regards to
ticket field view authorization.
2026-06-17 16:13:23 -05:00
JediKev
596379768a security: Hash Comparison
This addresses a report submitted by Nozomu Sasaki (Paul) in regards to
session validation hash comparison.
2026-06-17 16:13:23 -05:00
JediKev
b535782a0a security: CSRF
This addresses a report submitted by Khaled M. Alshammri (@ik0z) in regards
to CSRF enforcement for state-changing request methods.
2026-06-17 16:13:23 -05:00
JediKev
580e1c87ec security: API Key Logging
This addresses a report submitted by Khaled M. Alshammri (@ik0z) in regards
to API key handling in system logs.
2026-06-17 16:13:23 -05:00
JediKev
ba6217a718 security: Staff Password Reset
This addresses a report submitted by Khaled M. Alshammri (@ik0z) in regards
to staff password reset response handling.
2026-06-17 16:13:23 -05:00
JediKev
7bbd8ab209 security: Request Method
This addresses a report submitted by Khaled M. Alshammri (@ik0z) in regards
to method override handling for state-changing routes.
2026-06-17 16:13:23 -05:00
JediKev
fd96bbabc9 security: Recipient Name
This addresses a report submitted by Khaled M. Alshammri (@ik0z) in regards
to collaborator and recipient name rendering.
2026-06-17 16:13:23 -05:00
JediKev
e52e01005b security: File Exception Handling
This addresses a report submitted by Khaled M. Alshammri (@ik0z) in regards
to file error handling and diagnostic output.
2026-06-17 16:13:23 -05:00
JediKev
98abb059b1 security: File URL Signatures
This addresses a report submitted by Khaled M. Alshammri (@ik0z) in regards
to file URL signature validation.
2026-06-17 16:13:23 -05:00
JediKev
078516ed03 security: Inline SVGs
This addresses a report submitted by Khaled M. Alshammri (@ik0z) in regards
to inline handling of SVG attachments.
2026-06-17 16:13:23 -05:00
JediKev
6eb6b98996 security: HTTP_REFERER Typo
This addresses a report submitted by Anindya Sankar Roy (fr3ak) in regards
to staff login referrer handling.
2026-06-17 16:13:23 -05:00
JediKev
feccb6a3a9 security: API Keys
This addresses a report submitted by Anindya Sankar Roy (fr3ak) in regards
to API key generation.
2026-06-17 16:13:23 -05:00
JediKev
1e39bf1cf7 security: Thread Entry Titles
This addresses hardening identified from a report submitted by Anindya
Sankar Roy (fr3ak) in regards to thread entry title rendering.
2026-06-17 16:13:23 -05:00
JediKev
c54a6ac79d security: Email Display Names
This addresses a report submitted by Anindya Sankar Roy (fr3ak) in regards
to rendering email display names in thread entries.
2026-06-17 16:13:23 -05:00
JediKev
5afdf5450f security: Bootstrap Tooltip
This addresses a report submitted by frgranier@deloitte.fr in regards to
tooltip behavior and data attributes in sanitized content.
2026-06-17 16:13:23 -05:00
JediKev
52c366f57b security: Full-Text Search
This addresses a report submitted by Huseyn (meKhatai) Gadashov in regards
to full-text search mode handling for user-crafted search terms.
2026-06-17 16:13:23 -05:00
JediKev
2570d69892 Add Release Notes for v1.18.3 2026-01-15 17:17:15 +00:00
JediKev
51f9249b8a Merge branch '1.17.x' into develop 2026-01-15 17:14:32 +00:00
JediKev
a18df93cdb Add Release Notes for v1.17.7 2026-01-15 17:12:24 +00:00
JediKev
c3819e4d21 Revert "issue: Guest Session TTL"
This reverts commit 416b548bd8.
2026-01-15 17:04:39 +00:00
JediKev
c59b067dbf Merge pull request #6911 from JediKev/security/latest-patches-01-2026
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 11:01:28 -06:00
JediKev
d51301dbcb Merge pull request #6910 from JediKev/htmlawed/upgrade-to-1.2.15
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 10:56:59 -06:00
JediKev
d832f24332 security: Pwreset Hardening
This mitigates a report submitted by Ruben Ferreira of CSA Cyber in
regards to password reset.
2026-01-15 10:44:00 -06:00
JediKev
0e599be671 Merge pull request #6909 from JediKev/issue/regex-or-operator-2
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:55:00 -06:00
JediKev
0ce88a7f0e Merge pull request #6908 from JediKev/rebase/pull-6034
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:54:39 -06:00
JediKev
6caaa640a2 Merge pull request #6878 from nicoletta-maia/1.17.x-banlist
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:54:18 -06:00
JediKev
914474f8cd Merge pull request #6906 from JediKev/rebase/pull-6861
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:54:00 -06:00
JediKev
a923946c75 Merge pull request #6904 from JediKev/rebase/pull-6872
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:53:41 -06:00
JediKev
ef6ed9a4d4 Merge pull request #6903 from JediKev/rebase/pull-6883
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:52:40 -06:00
JediKev
dbebe9d043 Merge pull request #6902 from JediKev/issue/empty-dept-error-on-topic-update
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:52:23 -06:00
JediKev
84b8baee1e Merge pull request #6901 from JediKev/issue/pgp-smime-mail-parsing
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:52:10 -06:00
JediKev
0d6cb83bab Merge pull request #6900 from JediKev/issue/microsoft-utf8-bom
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:51:55 -06:00
JediKev
fbe4bb99ef Merge pull request #6899 from JediKev/issue/trim-user-name
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:51:30 -06:00
JediKev
a0a7a3f3a8 Merge pull request #6898 from JediKev/issue/date-column-interval
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:51:10 -06:00
JediKev
0008042ce9 Merge pull request #6887 from JediKev/issue/pop-oauth2-error-regex
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:50:50 -06:00
JediKev
baf1e0a226 Merge pull request #6874 from JediKev/issue/svg-mime-type
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:50:28 -06:00
JediKev
ea7ecbb6e1 Merge pull request #6897 from JediKev/mpdf/upgrade-to-v8.2.7
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:50:00 -06:00
JediKev
36dee625f1 Merge pull request #6896 from JediKev/rebase/pull-6868
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:43:21 -06:00
JediKev
b46099431e Merge pull request #6865 from JediKev/mail/smtputf8-backwards-compatibility
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:42:52 -06:00
JediKev
2f17b02376 Merge pull request #6895 from JediKev/rebase/pull-6857
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:41:46 -06:00
JediKev
444fd2d013 Merge pull request #6894 from JediKev/issue/kazakh-flag-css
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:41:23 -06:00
JediKev
b53bd4316b Merge pull request #6893 from JediKev/rebase/pull-6851
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 09:40:58 -06:00
JediKev
331ca48d8d issue: Regex OR Operator
This addresses issue 6817 where when using an OR operator in the Regular
Expression validation textbox for a Short Answer field it gets removed
without warning. This is due to a malformed Regex statement within the
`Format::strip_emoticons()` function. This simply removes the brackets
from the OR comparison as brackets are only used for range comparisons
(eg. `/[\x{2310}-\x{231F}]/u`). Additionally, this replaces the
duplicated Copyright symbol with the "masculine" version of degree to
cover both types of degree symbols. There are more but these are the
most common.
2026-01-15 09:37:11 -06:00
JediKev
1552cfa3fa security: Request Handling
This tightens request handling in regards to a report submitted by
Khodor Barakat.
2026-01-15 09:29:21 -06:00
JediKev
9ce7d54ed0 Merge pull request #6808 from JediKev/issue/content-management-errors
Reviewed-By: JediKev <kevin@enhancesoft.com>
2026-01-15 08:58:52 -06:00
Thomas Oster
81ec256263 join cdata table earlier 2026-01-15 08:45:46 -06:00
JediKev
8db4d3778e security: HTML/PDF Hardening
This adds hardening in HTML sanitization and PDF rendering in regards to
reports submitted by Naveen Sunkavally at Horizon3.ai.
2026-01-14 15:03:35 -06:00
JediKev
6852e7197e issue: Ensure User Login Name
This ensures the actor's login name is of an acceptable format before
attempting authentication. This also updates `is_userid()` to accept a
new param of `$verify` that is passed through to `is_email()`.
2026-01-14 15:03:35 -06:00
JediKev
d1b634a9e7 security: mPDF Print
This addresses a report submitted by Naveen Sunkavally at Horizon3 in
regards to stream wrappers, and regex.
2026-01-14 15:03:08 -06:00
JediKev
877adf564a htmLawed: Upgrade To 1.2.15
This upgrades htmLawed to 1.2.15 (latest).
2026-01-14 14:18:25 -06:00
CKeckNorthIO
1425fe1e4f Update class.file.php
Added support for WEBP file format
2026-01-14 10:50:58 -06:00
Jamie Burchell
ca13d88887 Fixes for Implicitly marking parameters as nullable 2026-01-13 16:20:48 -06:00
ololukaszuk
ae4344189d Fix typo in 'Add New Instance' title
Fixed simple typo line 8
2026-01-13 16:18:06 -06:00
JediKev
f1ba934bd9 issue: Empty Dept Error On Topic Update
This addresses an issue where when updating a Help Topic and having a
disabled Department set for example, the system will return a generic
error stating to address the errors below; but none are shown. This is
due to a missing error div that displays the Department errors. This
simply adds the div so Department errors are visible.
2026-01-13 16:13:28 -06:00
JediKev
5074c0321f issue: Microsoft UTF-8 BOM
This addresses an issue where MS started adding UTF-8 BOM to beginning
of some content which causes parsing issues and errors. This removes the
UTF-8 BOM before using it in laminas to avoid parsing issues and errors.
2026-01-13 16:09:49 -06:00
JediKev
0fbafda14a issue: Trim User Name
This adds `trim()` around the user's name when saving and updating to
avoid errant spaces.
2026-01-13 16:08:41 -06:00
JediKev
c646c8cb86 security: Ensure Session ID
This ensures the session ID is of an acceptable format before sending to
`create()`.
2026-01-13 15:51:11 -06:00
JediKev
9aff6b0317 issue: PGP + S/MIME Mail Parsing
This addresses an issue with PGP and S/MIME mail parsing where sometimes
the content is completely empty or malformed. This is due to an old PGP
block that was added back to the code after a Pear upgrade. This removes
the block to allow PGP and S/MIME mail to be parsed correctly.
2026-01-13 15:41:29 -06:00
JediKev
1e38901e79 issue: Date Column Interval
This addresses an issue where having multiple Interval values for a
single Date column (like DueDate) throws a fatal error. This is due to
the system expecting the interval to be a string not an array. This adds
a cast to each place we use the interval to ensure it's a string to
avoid fatal errors.
2026-01-13 14:49:34 -06:00
JediKev
39cdd2b1fb mPDF: Upgrade To v8.2.7
This upgrades the entire mPDF/mPDF package to the latest (v8.2.7) to
support latest PHP, etc.
2026-01-13 14:29:41 -06:00
Jamie Burchell
573e849631 Fixes for Implicitly marking parameters as nullable 2026-01-13 13:41:50 -06:00
ntozier
8b6a0f05fd Update class.setup.php
/download/ page indicates that 1.18.2 needs 8.2+.
This updates this value to match
2026-01-13 13:35:13 -06:00
Sebastián Santisi
924380a970 Fixing Argentinian flag
On commit 3ee111122b the Argentinian flag was wrongly replaced by the Palestinian flag.
2026-01-13 13:29:44 -06:00
JediKev
624c71716c issue: Kazakh Flag CSS
This simply adds the missing Kazakh flag coordinates.
2026-01-13 13:25:13 -06:00
JediKev
10f38bd0cf issue: POP OAuth2 Error REGEX
This addresses an issue with POP OAuth2 error parsing where errors are
blank on screen. This is due to using `$matches[2]` (which doesn't
exist) vs `$matches[1]`. This updates the code to use the correct match
so that errors are correctly shown on screen.
2025-12-16 10:12:38 -06:00
Nicoletta Maia
a7f14bf241 Fix Banlist permission check 2025-11-11 13:37:41 +01:00
JediKev
a6309e2224 issue: SVG MIME Type
This addresses 6873 where SVG Image uploads are failing even with strict
MIME checking disabled. This is due to the `exif_imagetype()` call that
checks an image MIME type. This method does not work well with SVGs as
it only checks the first few bytes. This adds a specific SVG check using
`mime_content_type()` that can handle SVG MIME type checks.
2025-10-22 09:58:16 -05:00
JediKev
05b87199ac mail: SMTPUTF8 Backwards Compatibility
This adds backwards compatibility support for legacy mail servers that
don’t support SMTPUTF8 or ones that simply refuse to support it (get
with the times old man!). When the system adds an attachment or adds an
inline image to outbound mail we add the raw UTF-8 filename to the
`filename=` parameter contained within the `Content-Disposition` header.
This can be problematic with legacy mail servers or servers that refuse
to support SMTPUTF8 as non-ASCII characters contained within the
`filename=` parameter of the `Content-Disposition` header triggers
SMTPUTF8 requirement. If the server doesn’t support it but it’s required
then it bounces the mail, typically with an error message stating such.

This updates the `Message::addInlineImage()` and
`Message::addAttachment()` methods to not only provide an ASCII-safe
filename but to also utilize a new MIME Part `Rfc2231Part` (discussed
momentarily). To generate said ASCII-safe filenames for both inline
images and any attached files this adds a new method called
`Message::asciiFallback()` that converts raw UTF-8 filenames to ASCII as
well as removes any non-header safe characters. In addition, this adds a
new MIME utility namespace `osTicket\Mime` that houses a new MIME
utility called `Rfc2231Part`. This class extends `Laminas\Mime\Part` to
essentially modify the `Content-Disposition` header and tack on the
original UTF-8 filename using the `filename*=UTF-8''` parameter but
encoded with `rawurlencode()` to make it ASCII-safe.

In summary, this adds an ASCII-safe `filename=` parameter to the
`Content-Disposition` header to prevent legacy servers from triggering
SMTPUTF8 requirement whilst utilizing `Rfc2231Part` to additionally
provide an (ASCII-safe) UTF-8 `filename*=UTF-8''` parameter for modern
mail servers (preserving the original filename).
2025-10-14 14:49:04 -05:00
JediKev
2a4fe6ad4f issue: Content Management Errors
This addresses an issue where if you update the User Account
Confirmation Email template for example and it has validation errors the
system will throw a fatal error. This is due to a missing `$langs`
variable and a missing `$cfg` global. This adds the missing variable and
global back to avoid fatal errors.
2025-02-13 13:28:25 -06:00
JediKev
53339df0f5 Add Release Notes for v1.18.2 2025-02-04 09:57:30 -06:00
JediKev
b3d9e39a5d Merge branch '1.17.x' into develop 2025-02-04 09:46:36 -06:00
JediKev
3ff35ad534 Add Release Notes for v1.17.6 2025-02-04 09:36:50 -06:00
JediKev
06c893a5b1 Merge pull request #6802 from JediKev/security/latest-vulns-01-2025
Reviewed-By: JediKev <kevin@enhancesoft.com>
2025-02-04 09:34:49 -06:00
JediKev
dfb1d31fae Merge pull request #6801 from protich/1.17.x
Reviewed-By: JediKev <kevin@enhancesoft.com>
2025-02-04 08:44:37 -06:00
Peter Rotich
ec76a2032e Revert part of 0784359 commit
This commit reverts part of 0784359876
commit. Specifically the wrong / invalid test.
2025-02-04 01:17:43 -08:00
Peter Rotich
a8792c3db9 Merge pull request #6800 from JediKev/issue/plain-text-base64
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-03 23:01:57 +03:00
Peter Rotich
3a77257f50 Merge pull request #6799 from JediKev/issue/transfer-empty-comments-var
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-03 23:01:25 +03:00
Peter Rotich
8d63aa0cc0 Merge pull request #6798 from JediKev/field/variable-name-validation
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-03 23:00:36 +03:00
Peter Rotich
4858f93c2d Merge pull request #6797 from JediKev/issue/canned-response-access
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-03 22:59:42 +03:00
Peter Rotich
8b5b831430 Merge pull request #6796 from JediKev/issue/iframe-logins
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-03 22:58:35 +03:00
JediKev
c4b85fab1f Merge pull request #6766 from JediKev/patches/latest-11-18-2024
Reviewed-By: protich <peter@osticket.com>, JediKev <kevin@enhancesoft.com>
2025-02-03 13:17:42 -06:00
JediKev
245e755462 issue: Random Print
This removes a random `print $emails` from the `emailtest.php` page.
Looks like it was there by mistake all this time.
2025-02-03 13:16:56 -06:00
JediKev
416b548bd8 issue: Guest Session TTL
This addresses an issue where Guest User sessions would quickly timeout
even though the User session was configured for say 24 hours. This was
due to a chuck of code that used `min()` to get the minimum value from
the various TTL. This removes the `min()` part so it uses the `$ttl` if
available else defaults to `$maxlife`/`SESSION_TTL`.
2025-02-03 13:16:46 -06:00
JediKev
9f27584f97 Merge pull request #6724 from JediKev/issue/mimeDecode-eml-attachments
Reviewed-By: protich <peter@osticket.com>, JediKev <kevin@enhancesoft.com>
2025-02-03 13:15:39 -06:00
JediKev
7fc3d8c2ee issue: mimeDecode .eml Attachments
This reapplies a missing patch `af1c4a6` that added `message/rfc822`
attachment support.
2025-02-03 13:14:52 -06:00
JediKev
ab6672faa0 security: Syslog AJAX
This addresses a vulnerability reported by Muhammad Umer Adeem
(@UmerAdeemCheema) where normal Agents can potentially view system logs.
This also addresses additional access vulns with AJAX Content.
2025-02-03 13:09:10 -06:00
Peter Rotich
193f5fe007 Sanitize query to prevent SQL injection via parameter markers
The previous implementation used the regex `/:(\d+)/i` to remove a
single colon preceding digits. However, this approach did not handle
cases with multiple colons (e.g., "::1"), which could potentially allow
for injection attempts.

This commit updates the regex to `/:+(\d+)/` to match one or more colons
before the digits and replaces them with just the captured number. This
change ensures that all leading colons are removed, effectively
neutralizing any parameter marker injection while preserving the
intended numeric value.
2025-02-03 13:04:14 -06:00
JediKev
3a5da66bf6 issue: iFrame Logins
This addresses an issue with iFrame logins where the site simply would
refuse to honor cross site cookies. This adds a new check to see if the
system allows iFrames. If so, it will set the `samesite` for the cookie
to `None` which allows the cookie to be sent in all contexts. If the
site does not allow iFrames it will default to `Strict` for security
reasons.
2025-02-03 12:55:50 -06:00
JediKev
6ba1de123c Merge pull request #6795 from JediKev/i18n/crowdin-api-v2
Reviewed-By: protich <peter@osticket.com>, JediKev <kevin@enhancesoft.com>
2025-02-03 09:52:49 -06:00
JediKev
f57fc3f7c4 Merge pull request #6789 from JediKev/issue/excessive-fetching-errors
Reviewed-By: protich <peter@osticket.com>, JediKev <kevin@enhancesoft.com>
2025-02-03 09:52:09 -06:00
Peter Rotich
b1da571fed Merge pull request #6788 from JediKev/php/8.4-support
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:48:11 +03:00
Peter Rotich
6eb9bc2388 Merge branch '1.17.x' into php/8.4-support 2025-02-01 11:47:04 +03:00
Peter Rotich
6fb48cdec3 Merge pull request #6785 from JediKev/issue/referred-tickets-incorrect-queue-counts
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:42:45 +03:00
Peter Rotich
0176ef97d9 Merge pull request #6773 from remram44/fix-setting-force_https
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:32:52 +03:00
Peter Rotich
a8008b73f2 Merge pull request #6770 from JediKev/issue/dept-field-user-import
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:26:51 +03:00
Peter Rotich
28af87ef03 Merge pull request #6768 from JediKev/issue/user-lookup-umlaut
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:25:39 +03:00
Peter Rotich
3a519bd710 Merge pull request #6767 from JediKev/update/php-deprecations-and-warnings
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:24:22 +03:00
Peter Rotich
68fd23aaf3 Merge pull request #6765 from JediKev/issue/client-acl-staff-file-download
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:15:48 +03:00
Peter Rotich
3326138a52 Merge pull request #6763 from JediKev/queue/getTotal-incorrect-counts
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:14:06 +03:00
Peter Rotich
1b9fb37d05 Merge pull request #6762 from JediKev/issue/latest-sql-warnings
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:10:32 +03:00
Peter Rotich
587a97c2b9 Merge pull request #6761 from JediKev/update/composer-symfony-process
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:08:25 +03:00
Peter Rotich
c466519e48 Merge pull request #6753 from protich/feature/oauth2-strict-mode
OAuth2: Show Scopes and Enforce Strict Mode
2025-02-01 11:07:33 +03:00
Peter Rotich
61b0d6af09 Merge pull request #6751 from JediKev/api/duedate-and-other-errors
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:06:00 +03:00
Peter Rotich
ede9c01b38 Merge pull request #6742 from JediKev/user/list-import
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:03:35 +03:00
Peter Rotich
81d84b0c2f Merge pull request #6741 from JediKev/issue/image-annotation
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:02:30 +03:00
Peter Rotich
241c1af156 Merge pull request #6733 from JediKev/issue/multiselect-list-export
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 11:00:45 +03:00
Peter Rotich
8eb2dfae26 Merge pull request #6732 from JediKev/issue/safari-response-content-disposition
issue: Safari Response Content Disposition
2025-02-01 10:51:05 +03:00
Peter Rotich
9ce6e5c90a Merge pull request #6730 from JediKev/issue/email-remote-bk-name
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 10:48:44 +03:00
Peter Rotich
4b4fc10842 Merge pull request #6729 from dkrotich/feature/vscode_workspace
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 10:47:26 +03:00
Peter Rotich
0355664f6d Merge pull request #6727 from JediKev/php/iconv-recommendation
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 10:46:32 +03:00
Peter Rotich
ff331e9f8d Merge pull request #6725 from JediKev/mail/reapply-memory-optimization
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 10:45:20 +03:00
Peter Rotich
a9bd930217 Merge pull request #6722 from JediKev/issue/basic-search-selector
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 10:35:15 +03:00
Peter Rotich
ea1bdbbc27 Merge pull request #6721 from JediKev/issue/ticket-relations
Reviewed-By: Peter Rotich <peter@osticket.com>
2025-02-01 10:32:45 +03:00
JediKev
0ec6670d19 i18n: Crowdin API v2
This makes the changes needed to fully support Crowdin's latest API v2.
The main changes are the endpoints and the response types. Previously
the base URL was structured like `/api/project/{project}/{command}`
however now it is structured like
`/api/v2/projects/{project_id}/{command}`. Also previously the response
types were XML whereas now they are all JSON. There are other small
changes however their is a new function added called `getBranchId()`
that retrieves the given Branch's ID (to be used in URLs and the build
stage).
2025-01-30 10:26:41 -06:00
JediKev
216ded32ec issue: Plain-text Base64
This addresses an issue where Base64 encoding plain-text content leads
to raw encoded data being displayed in the mail client. This removes the
Base64 encoding from plain-text emails so the content displays properly.
To note, when you look at providers like Gmail, etc. they do not Base64
encode Plain-text nor HTML content.
2025-01-27 14:28:28 -06:00
JediKev
c546a16729 issue: Excessive Fetching Errors
This addresses issue 6647 where in certain scenarios/setups the system
throws the infamous `Excessive errors processing emails for` error. As
per the information from the referenced issue the main cause is a fatal
error where `json_decode()` is receiving an array instead of the
expected string. This adds a check on `$fieldClean[0]` to see if it's a
string and if so uses the `json_decode()` otherwise it uses itself.
2025-01-17 09:19:07 -06:00
JediKev
b930a68b70 issue: Canned Response Access
This addresses issue 6772 where you can access a Canned Response with a
Department set even if you don’t have the Premade Role Permission for
the Canned Response's Department. This is due to not checking access
before displaying the Canned Response. This adds a new function called
`staffCanAccess()` to class Canned that checks to see if the Canned
Response has a Department and if so ensures the Agent has a Role in that
Department and that the Role contains the Premade Permission. This adds
a new `if()` statement that calls `staffCanAccess()` if a Canned
Response is found.
2025-01-16 14:20:40 -06:00
JediKev
fb9a39ba3d update: README PHP Version
This updates the PHP version in the Requirements section from `8.1 - 8.3
(8.3 recommended)` to `8.1 - 8.4 (8.4 recommended)`.
2025-01-16 13:27:39 -06:00
JediKev
5e5a9ff5da deprecation: fgetcsv/fputcsv Default Escape Param
This addresses the deprecation of using the default value for the
`escape` parameter for both `fputcsv()` and `fgetcsv()`. Essentially,
you can no longer use the default value and instead have to explicitly
pass it in. This adds the needed defaults for `escape` as well as
`separator` and `enclosure` where needed to avoid warnings and errors.

References:
https://www.php.net/manual/en/migration84.deprecated.php#migration84.deprecated.standard
https://www.php.net/manual/en/function.fgetcsv.php#refsect1-function.fgetcsv-parameters
2025-01-16 12:55:45 -06:00
JediKev
b4938b9905 deprecation: E_STRICT Constant
This addresses the deprecation of the `E_STRICT` constant. The upstream
error level has been removed and now the constant is being deprecated.
Since we don't support PHP 5.x any longer and this is now
deprecated/removed this fully removes the last mention of the `E_STRICT`
constant. So long and farewell my friend.

Reference:
https://www.php.net/manual/en/errorfunc.constants.php#constant.e-strict
2025-01-16 12:37:58 -06:00
JediKev
a4c0f674ee deprecated: Implicitly Nullable Parameter
This addresses the deprecation of an implicitly nullable parameter
followed by a mandatory parameter in the old suggested format. This
updates the old suggested format of `function name(?string $var=null,
$var2)` to the newly suggested format of `function name(?string $var,
$var2)`. This is to avoid warnings but to also avoid errors in the
future.

Reference:
https://www.php.net/manual/en/migration84.deprecated.php#migration84.deprecated.core.implicitly-nullable-parameter
2025-01-16 12:35:11 -06:00
JediKev
b42cad6fe8 issue: Referred Tickets Incorrect Queue Counts
This addresses an issue where having a Ticket Referred to you and one of
your Departments increases the Queue count erroneously. In the
`getTicketsVisibility()` function the system adds criteria to find
Tickets referred to the Agent and then later adds separate criteria to
find Tickets referred to the Agent’s Department(s). The problem is the
two separate criteria will make the same Ticket appear twice in the
results. To fix the issue we simply need to make the results distinct
via `ticket_id`. Since `getTicketsVisibility()` is essentially
generating an array of criteria we can’t add the distinction there.
Plus, it could be used for things other than counts. So we move on to
`applyVisibility()` where we use the criteria and add the distinction
there. To note, this function is only used in `SavedQueue::counts()` and
`SavedQueue::getTotal()` which would only affect counts; just what we
want.
2025-01-13 13:25:32 -06:00
JediKev
4f137dc2bd queue: getTotal Incorrect Counts
This addresses an issue where when using `getTotal()` to get the total
counts for a Queue it mistakenly includes Children Tickets. This causes
a discrepancy between the number of Tickets shown within the Queue vs
the total shown for the count. Since we ignore Children Tickets within
the Queues themselves (due to them being merged into a Parent) we should
also ignore Children within the Queue Counts. This adds a new filter to
the `$query` in `getTotal()` that filters Tickets with `ticket_pid`
equal to `NULL` or Tickets with `flags` containing `Ticket::FLAG_LINKED`
(ie. it is a Link not Merge).
2025-01-07 14:30:47 -06:00
Remi Rampin
3805bbfdf3 Fix force_https auto-enabling on settings page 2024-12-09 14:12:32 -05:00
JediKev
5c2b6a5d2e issue: Department Field User Import
This addresses an issue where if you are importing Users via CSV,
one of the Users already exists in the system, their profile has a
Department Field with a current value set, and the CSV row for their
account has a Department Field value the system will fail with an error
of `Cannot access offset of type string on string`. This is due to
blindly assuming the `$value` is an array. This adds a check to see if
the value is an array, if so it will use the `$id` otherwise it defaults
to the `$value`.
2024-11-22 10:18:04 -06:00
JediKev
504b0bfb4f issue: User Lookup Umlaut
This addresses osTicket/osTicket-plugins#293 where attempting to lookup
and select a User from an external source like LDAP with an umlaut in
their name causes an error of "User not found". This is because the URL
is encoded with `htmlentities()` which makes the umlaut character
unrecognizable. This wraps the lookup string with `html_entity_decode()`
so that the umlaut is preserved and lookup succeeds.
2024-11-20 16:02:32 -06:00
JediKev
84c14ace46 update: PHP Deprecations & Warnings
This addresses 6574 and other deprecations and warnings encountered
during testing with `error_reporting` set to `E_ALL` and both
`display_errors` and `display_startup_errors` enabled. This includes
defining optional parameters before required parameters and function
return types not matching their parent.
2024-11-20 14:35:03 -06:00
JediKev
8255b2e721 issue: Client ACL Staff File Download
This addresses 6758 where enabling the ACL for Clients and attempting to
download a file as an Agent throws an Access Denied error. This adds a
check in the `check_acl` function to see if the backend is set to Client
Portal and if the current authenticated person is an Agent. If so, it
will skip the ACL check; otherwise it will enforce the check.
2024-11-18 14:26:13 -06:00
JediKev
59f2591809 update: Composer symfony/process
This is a rewrite of 6757 that updates the `symfony/process` package to
address a recent security advisory (11/2024). Both osTicket and
laminas-mail does not use this package in production (only in dev mode)
so this only updates the `require-dev` section of the main
`composer.json` file as well as the `composer.lock` file. This is so
that if anyone uses it in dev mode they will be using the latest patched
version of `symfony/process`.

Since this package is not in-use below are the specific instructions used to
update it without installing it:
```
cd include/laminas-mail/
composer require --dev --no-update symfony/process
vim composer.lock
  -- Update symfony/process version to latest (v6.4.14)
  -- Update the `reference` for the source and distribution to commit hash
  -- Update the `time`
composer update --no-install --lock
```
2024-11-14 10:39:55 -06:00
JediKev
ed87b25759 issue: Transfer Empty Comments Var
This addresses an issue where the `comments` variable is not replaced in
the Ticket Transfer Alert if there is no comment provided. This adds a
ternary operator to the `comments` variable assignment to see if there
is a value. If so it will use the value if not it will default to an
empty string. This is so the variable can be replaced with nothing which
is the intended end result.
2024-11-07 14:16:59 -06:00
JediKev
0724d1ada2 fields: Variable Name Validation
This addresses an issue where `-` characters are allowed in Field
Variable Names when they shouldn't be. Reason being is dashes are not
allowed in MySQL Column names. Since we use the Field Variable Name as
the Column name in the respective CDATA table we cannot allow the dashes
in the Variable Names.
2024-11-07 13:55:48 -06:00
JediKev
9bdfde5a4b issue: Latest SQL Warnings
This temporarily addresses 6661 where there are a few MariaDB warnings
after `sql_mode` changes. This only includes temporary changes via code
until we enforce defaults via SQL in the next major release. This
accomplishes the following:
- Ensures a `body` is set when creating Drafts
- Ensures a `logger` is set when adding system logs
- Ensures `updated` has a date-time set when creating a new ThreadEntry
- Ensures `staff_id`|`team_id` defaults to `0` if no object ID available
- Ensures the `lock_id` is set to `0` instead of `NULL`
2024-11-07 13:43:30 -06:00
Peter Rotich
390555db36 OAuth2: Add Resource Ownership Strict Mode Check
Enforce Strict Mode when updating / saving OAuth2 credentials. At the
moment we force the check at the plugin level which is not ideal and
will be removed in the near future.

In addition the change include setting the correct error tag so we can
show the error message in context.
2024-10-28 03:43:15 -07:00
Peter Rotich
a77cf535ed Token: Show Authorized Scopes
Show authorized scopes to Token Details tab, it's very useful when
debugging authentication issues.
2024-10-28 03:43:15 -07:00
JediKev
fec70c4ae9 user: List Import
This addresses an issue where attempting to import a User with a value
for a Custom List fails to import the list item. This is due to the
parsed (JSON) value being passed to `SelectionField::parse()` which
doesn't know how to parse it. This pull updates the `if()` statement
that checks if the given value is not an array and adds
`JsonDataParser::parse($value) ?:` before the `array($value)` to see if
we can successfully parse the string. If so, it will use the parsed
array. If not, it falls back to manually converting the value into an
array.
2024-08-13 13:23:11 -05:00
JediKev
aeeb285061 issue: Image Annotation
This addresses an issue where when annotating an image and sending it,
it disappears from the final reply. This is due to REGEX that attempts
to detect inline images and determines if it should strip them or not.
This REGEX statement is greedy which means it will find as many matches
as possible. This is a problem for image annotation as one of the
classes that gets added to the image is `data-orig-annotated-image-src`.
This gets picked up by the REGEX and as a result causes the image to be
rejected since it contains a file URL instead of the expected `cid`.
This pull simply changes the first matching group to "lazy" so that it
stops on the first match. This causes the real `src` value to be picked
up and parsed which contains the expected `cid`.
2024-08-12 14:39:48 -05:00
JediKev
f3bf8553cc issue: Multiselect List Export
This addresses an issue where attempting to export a multiselection List
Field with multiple selected items only shows the first selected item.
This is due to the Item IDs containing spaces (due to the earlier
`explode()` call) so the IDs do not match the available IDs. This adds a
`trim()` around the Item IDs so that they match appropriately.
2024-07-15 09:49:13 -05:00
JediKev
14814ae28a api: DueDate and Other Errors
This addresses an issue where adding a `duedate` to API request payloads
the system simply ignores it. This is due to an _old_ bit of code (1.7 -
circa 2013) that refuses the `duedate` from any source other than
`staff`. This updates the check from `strcasecmp()` to `in_array()` so
it can check for both `staff` and `api`. This will allow a `duedate` to
manually be set from Staff created Tickets as well as API created
Tickets.

In addition, this updates the `getRequestStructure()` function to change
the single `strcasecmp()` for `email` to a `switch {}`. This is so we
can check multiple types other than `email`. This adds the previous
`email` format as a case and adds two new cases for `json` and `xml`
formats. Within these two new cases `duedate`, `slaId`, and `staffId`
are added as available fields. This is so the system doesn’t throw an
`Unexpected data received in API request` error even though these fields
are valid and accepted with JSON and XML payloads.
2024-07-11 13:36:13 -05:00
JediKev
64a5df6881 issue: Safari Response Content Disposition
This addresses an issue where Safari is now refusing to load inline
images stored in S3. Upon investigation it was found the code had an old
check for Safari browser when generating the content disposition
filename string. If Safari was being used it left the filename alone as
"Safari and only Safari can handle the filename as is". Well this may be
true for Safari however S3 cannot handle this. This removes the Safari
specific check and forces even Safari to UTF8 encode the filename for
the content disposition string. This allows Safari to load inline
images from S3 again. Safari still loads other images, etc. just fine as
well.
2024-07-08 15:02:31 -05:00
JediKev
b54dd584b6 issue: Email Remote Backend Name
This addresses an issue reported by JensEB where the wrong remote
backend name was used in a strpos check. This updates the name from
`auth_bk` to the correct `mailbox_auth_bk`.
2024-07-02 11:42:03 -05:00
Dennis Rotich
0da2e0e0f2 Ignore VS Code Workspace Files
This commits adds *.code-workspace to .gitignore file
2024-06-21 17:47:48 +03:00
JediKev
33ecc3a0b9 php: iconv Recommendation
This updates the PHP Prerequisites to include the `iconv` extension.
Iconv methods are used for email parsing (in the pear/Mail_mimeDecode
package) as well as other places internally. This adds the extension to
the installer prerequisites as well as the system information page and
the `README.md`.
2024-06-20 15:05:55 -05:00
JediKev
ab76ffe804 issue: BC Removal
This removes a function called `Mail_mimeDecode` that was added in
`cbd78ac` (originally from pull #6681) for "backwards compatibility".
Upon investigation this is not needed; so it will be removed.
2024-06-18 13:21:33 -05:00
JediKev
eaaa64d9de mail: Reapply Memory Optimization
This reapplies the Memory Optimizations added with `5ae4fe6`, `c1d0b05`,
`2c00654`, `87277dd`, and `c57c22a`. This ensures larger emails are
parsed correctly and as optimal as possible. Without optimizations, the
system typically fails at parsing such large emails.
2024-06-18 13:13:42 -05:00
JediKev
74b8bd0e04 issue: Basic Search Selector
This addresses an issue where if you load the User Directory, click the
Organization tab, go back to the User Directory tab, and attempt a user
lookup via basic-search it attempts to hit the url `undefined?q=xxx`
which is obviously not valid and fails to return results. After
investigation it was found that when clicking through the tabs vs
directly loading them causes the Javascript/jQuery to load in reverse
sequence. This means core `scp/js/scp.js` code was taking precedence
over the inline-jQuery within the Users Staff Template. In most cases
this shouldn't matter however in this particular case the input selector
in the core `scp/js/scp.js` was looking for a generic
`input.basic-search` class. We use this class for all basic searches
however the ones for user lookup and organization lookpup respectively
have their own unique ID in addition that the inline-jQuery is supposed
to select. Since the core is loading after the inline in this case that
means the core takes precedence over the inline code causing wrong URL,
etc. This simply updates the core selector to have `:not([id])` so that
it doesn't try to match an iput with class of `input.basic-search` with
an ID. Tested and working with User/Org lookups and all other
basic-searches.
2024-06-14 10:47:08 -05:00
JediKev
9426b2dd82 issue: Ticket Relations
This addresses an issue where when viewing a Parent/Child Ticket that
also has Tasks and you first click the Tasks tab, then the Related
Tickets tab, then finally click a Related Ticket the browser redirects
to `/scp/ickets.php?=xxx` with URL Not Supported error. This is due to
reusing the class name `tasks` for the related Tickets table. This
changes the `tasks` class to `relations` so that it's unique.
2024-06-14 10:20:09 -05:00
JediKev
bb4c27dfe6 Merge pull request #6709 from JediKev/patches/latest-05-28-2024
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2024-06-13 11:49:39 -05:00
protich
d9fe3adad2 issue: Missing From Address
This addresses an issue where sometimes mail does not have a From Address
which causes issues in `Mail_Parse::parseAddressList()`. First, this adds a
check to see if the from is set in the headers, if not we return. Next, this
adds a check to see if the From header is malformed (ie. missing a bracket),
if so it adds one. Lastly, this continues to call `parseAddressList()` as
before however this time the From should always be set.
2024-06-13 11:49:06 -05:00
protich
854cf47ce5 issue: Quoted Table Name
This addresses an issue where the table name was not properly quoted. This
sends `true` to `quote()` to ensure the table name is properly quoted.
2024-06-13 11:49:06 -05:00
JediKev
36b4c94fb7 issue: Agent Permission Info
This addresses an issue where when exporting Agents and an Agent doesn't
have a Permission or Permission lookp fails the system throws a fatal error.
This is because we try to use `array_keys()` on `null`/`false`. This
updates class Role's `getInfo()` function to return an empty array if
the `perms` are not set/null/etc.
2024-06-13 11:47:15 -05:00
JediKev
4c57bf178e Merge pull request #6697 from JediKev/php/8.3-support
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2024-06-13 11:45:25 -05:00
JediKev
136d372ebc deprecated: assert_options()
This removes a call to a deprecated function `assert_options()` to match
PHP 8.3 changes.
2024-06-13 11:44:42 -05:00
JediKev
387a1c04dd update: System Prerequisites (PHP)
This updates the PHP version in the System Prerequisites (used in the
installer and upgrader) from 8.0 to 8.1. Since upstream PHP dropped support
for it we will too. RIP
2024-06-13 11:44:42 -05:00
JediKev
fea5e1e043 issue: Cannot Redeclare mb_str_pad()
This addresses an issue where in PHP 8.3 our declaration of `mb_str_pad()`
conflicts with the native `mb_str_pad()`. This adds a check to see if the
function already exists or not before declaring it.
2024-06-13 11:43:54 -05:00
JediKev
b38db3725a update: README PHP Version
This updates the PHP version in the Requirements section from `8.0 - 8.2
(8.2 recommended)` to `8.1 - 8.3 (8.3 recommended)`.
2024-06-13 11:43:54 -05:00
JediKev
a3931f4667 deprecation: get_class() No Parameters
In PHP 8.3 they have deprecated the use of `get_class()` with no parameters.
Instead you should use `get_class($this)`, `self::class`, or `__CLASS__`.
This updates all calls in the code to make it 8.3 compliant. These changes
are backwards compatible with PHP 8.1-8.2.
2024-06-13 11:43:54 -05:00
JediKev
a4e088b55e Merge pull request #6694 from JediKev/mailer/sendmail-failure
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2024-06-13 11:40:57 -05:00
JediKev
14e2057b0e mailer: sendmail() Failure
This addresses an issue where passing a full From string (eg. `"osTicket
Alerts" <user@noemail.com>`) as the `$from` parameter for
`Mailer::sendmail()` causes a fatal laminas-mail error. This is due to the
full string being reformatted after it's already been formatted. This
adds a check for `<` and if present we will not reformat; we will
instead use the full string as-is. This also updates one of the calls
and adds a space between the display name and the actual address.
2024-06-13 11:38:18 -05:00
JediKev
73bec0f89f Merge pull request #6720 from JediKev/changyy/develop
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2024-06-13 11:34:45 -05:00
Yuan-Yi Chang
cbd78ac8d6 Upgrade mimeDecode.php from v1.48 to v1.5.6 2016-08-28
Update the mimeDecode.php file, which was originally version 1.48 from 2006/12/03 and has been maintained up to now. Currently, we are directly using version 1.5.6. Adjustments were made to the syntax while retaining the original getHeader() function.

This is to fix #6680 issue.
2024-06-13 11:32:32 -05:00
JediKev
af9de90d0f Merge pull request #6719 from JediKev/ProbablePrime/fix/undelivered-mail-handling
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2024-06-13 11:29:24 -05:00
Richard Fox
0784359876 fix(email): fix case sensitivity in "Action" header retrieval
This fixes a casing issue in the handling of the Action header while
handling bounce notices from mail servers.

Prior to this change, no emails could be flagged as a bounce email
because the Upper-Case version of Action was used. This has been
lowercases to "action".

An accompanying unit test, tests that a bounce email is properly passed
and it's attributes are setup. I have redacted a sample DSN email as
much as I thought was necessary but am happy to re-review this fixture.

As all other header access appears to be lowercase, this just appears to
be a simple typo.

This fixes:
https://forum.osticket.com/d/104433-undelivered-mail-returned-to-sender-processing
too

A huge thank you to: Hikari Akimori from the Resonite community for
their sanity checks.
2024-06-13 11:27:41 -05:00
JediKev
45e29185c8 Merge pull request #6718 from JediKev/nicoletta-maia/issue/linked-icon-annotation
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2024-06-13 11:19:17 -05:00
Nicoletta Maia
6c096cce4b issue: Linked Icon annotation 2024-06-13 11:18:08 -05:00
JediKev
7cc70c8bd9 Merge pull request #6717 from JediKev/changyy/hotfix/FixGetRawEmail
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2024-06-13 11:15:16 -05:00
Yuan-Yi Chang
1eb71197bc Added trim() around headers in the getRawEmail method 2024-06-13 11:13:18 -05:00
Yuan-Yi Chang
c26d840c5f Fix raw mail content generation
Ensure proper splitting of mail headers and mail body using "\r\n\r\n" or "\n\n" as delimiters.
2024-06-13 11:13:02 -05:00
JediKev
c7b2968b24 Merge pull request #6716 from JediKev/upgrade/laminas-mail-2.25.1
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 10:19:02 -05:00
JediKev
ef24ee9e75 Merge pull request #6707 from sergejostir/pr/fix-staff-mobile-field-class
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 10:08:31 -05:00
JediKev
4993ba7de6 Merge pull request #6706 from JediKev/mysql/update-min-version
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 10:06:53 -05:00
JediKev
498ea7f506 Merge pull request #6704 from JediKev/i18n/lang-url-param
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 10:05:04 -05:00
JediKev
5f68020b07 Merge pull request #6703 from JediKev/php/update-prereqs
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 10:03:36 -05:00
JediKev
2a6182bd36 Merge pull request #6702 from JediKev/issue/referred-closed-tickets
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 10:00:50 -05:00
JediKev
3b1334d904 Merge pull request #6700 from JediKev/issue/task-last-respondent
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 10:00:10 -05:00
JediKev
b5a3098c65 Merge pull request #6698 from JediKev/mysqli/multi-host-failure
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 09:59:01 -05:00
JediKev
15b269dd45 Merge pull request #6699 from JediKev/i18n/schedules-getDays
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 09:54:00 -05:00
JediKev
f131c54fe8 Merge pull request #6687 from JediKev/issue/position-styling-again
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 09:31:00 -05:00
JediKev
1affaceb25 Merge pull request #6684 from amiraiman/hotfix/fix-square-brackets-when-print
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 09:29:08 -05:00
JediKev
9a224d6dc0 Merge pull request #6648 from JediKev/issue/checkbox-template-variable
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 09:13:41 -05:00
JediKev
8a01025266 Merge pull request #6630 from JediKev/i18n/tasks-dept-id-missing
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 09:12:29 -05:00
JediKev
dfcd14df1b Merge pull request #6676 from sergejostir/patch-1
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 09:04:25 -05:00
JediKev
d788786b2b Merge pull request #6675 from FlapJac-k/1.17.x
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 09:02:57 -05:00
JediKev
9bef49b672 Merge pull request #6496 from nicorac/develop
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2024-06-13 09:01:40 -05:00
JediKev
f658268d1f upgrade: Laminas-Mail (2.25.1)
This updates the laminas-mail package from 2.23.0 to 2.25.1 to fully support PHP 8.3.
2024-06-12 14:04:51 -05:00
JediKev
939a278cca todo: Remove Custom prepareHeaders()
This removes the custom `prepareHeaders()` method from class Sendmail as
this functionality was added upstream which is now available with the
latest update.
2024-06-12 13:56:43 -05:00
JediKev
c0a74162f0 update: Laminas-Mail
This is a rewrite of 6312 and updates the laminas-mail package from
2.10.1 to 2.23.0. This also remove unused dev dependencies.
2024-06-12 13:56:20 -05:00
JediKev
b843fb1503 issue: Sanitization Updates
This adds a couple of new sanitizations including:
- Replacing unicode spaces with normal spaces
- Stripping the Degrees and Copyright unicode symbols
2024-06-11 17:33:15 +00:00
protich
2d65cb7723 api: XML Array Key
This addresses an issue where if the `ticket` array key is missing in the
`$current` array it will throw a fatal error. This adds an `isset()` check
to ensure the array key exists and is set before using it.
2024-05-28 20:37:04 +00:00
Sergej Oštir
f8455c82ca Fix staff mobile field class 2024-05-25 22:55:19 +02:00
Sergej Oštir
6df6cd984d Fix ajax path for AddRemoteCollaborator 2024-05-25 20:10:45 +02:00
JediKev
317ab96700 mysql: Update Minimum Version
This updates the minimum required MySQL Version from 5.0 to 5.5. We've
stated "5.5 or better" for a while but never actually enforced it in our
installer/upgrader.
2024-05-22 21:20:17 +00:00
JediKev
fece6ff727 i18n: Lang URL Param
This addresses issue 6573 where the `lang` URL param is not sanity checked
and throws a fatal error if it contains anything but a string. This forces
the `lang` param to a string when passing to `strtolower()` to avoid fatal
errors. The `isLanguageInstalled()` function will still behave the same way
as before by returning `false` if passed an invalid `lang` code -or- if the
`lang` code is valid just doesn't exist in the available languages.
2024-05-22 20:24:58 +00:00
JediKev
d331a44c2d php: Update Prerequisites
This updates the PHP Prerequisites to include the `ctype` extension needed
for email fetching as part of the `laminas-mail` package. This adds the
extension to the installer prerequisites as well as the system information
page and the `README.md`. Lastly, this updates the installer prerequisites
wording and structure so they all match and look streamlined.
2024-05-21 19:32:35 +00:00
JediKev
a7b0711d65 issue: Referred Closed Tickets
This addresses an issue where Agents cannot see Referred Tickets in their
Closed Queues. This is due to the `Staff::getTicketsVisibility()` function
blindly using the `open` state instead of looking for `closed` as well. This
updates the function to include the `closed` state in the status condition.
This ensures the referred Tickets are shown in every Queue.
2024-05-20 18:43:42 +00:00
JediKev
f2facda3e6 i18n: Schedules getDays()
This addresses an issue where using a non-english language breaks the Ticket
view page for Tickets with no Due Date, SLA with grace period longer than 41
hours, and the SLA is attached to a Schedule with working days. This is due
to mistakenly translating the day names in `getDays()` function at times we
shouldn't be. PHP only likes English day names during actual date
calculations.  This adds a new method called `getTranslatedDays()` that will
return the translated day names when needed (it also caches the
translations). In addition this updates the existing `getDays()` to strictly
return the native, untranslated day names. Lastly, this updates the calls to
`getDays()` that need to be translated to `getTranslatedDays()`.
2024-05-16 14:58:07 +00:00
JediKev
5277c7ab46 issue: Task Last Respondent
This addresses an issue where `Task::getLastRespondent()` returns the wrong
Agent leading to the wrong people receiving alerts, etc. This updates the
`Task::getLastRespondent()` function to make it limit the last respondent
search to the Task's own Thread Entries rather than searching through all
entries.
2024-05-15 17:57:15 +00:00
JediKev
0a8475fbba mysqli: Multi-Host Failure
This is a rewrite of #6641. This addresses an issue where if PHP has MySQLi
Error Reporting enabled (enabled by default starting with PHP 8.1), there
are multiple configured database hosts, and one host fails to connect the
system throws a fatal error. We previously attempted to silence fatal errors
with `@` suppression however STRICT MySQLi Error Reporting bypasses this and
still throws an error. This updates the `db_connect()` and
`db_select_database()` calls in `bootstrap.php` and wraps them with a
try/catch. If either `db_connect()` or `db_select_database()` throws a fatal
exception we will catch it and set `$ferror` to the exception message. Doing
so ensures the system attempts to connect to all configured hosts without
exiting and only croaks when no hosts are reachable or the database cannot
be selected.
2024-05-15 17:35:20 +00:00
JediKev
7f03a64bd1 issue: Position Styling.. Again
This addresses an issue where the current REGEX for the "position" styling
attribute is causing issues when emails contain legit text like "position:
100 degrees". This updates the REGEX to only look for one of the possible
values instead of looking for seemingly anything.
2024-04-22 19:01:55 +00:00
Amir Aiman
2584403447 Properly set mPdf instance autoScriptToLang property to true
Based on mPdf migration guide: https://mpdf.github.io/installation-setup/installation-v6-x.html
2024-04-14 17:07:11 +08:00
Amir Aiman
872a649210 add mpdf init options to auto convert non-latin characters 2024-04-13 17:22:11 +08:00
Eslam Mohamed
cd4717a10b Fixed mailfetch error message 2024-03-12 11:37:15 +02:00
JediKev
09de958730 issue: Checkbox Template Variable
This addresses an issue where when using a Checkbox on an Email Template the
variable is replaced with `1` if checked and doesn't get replaced at all if
unchecked. This is due to the `BooleanField` class not having an `asVar()`
method so it uses the `FormField::asVar()` method which calls `to_php()`.
This method returns an integer for BooleanField which is not what we want.
This adds a new method called `asVar()` to the `BooleanField` class that
calls `toString()` which will return `Yes` if checked and `No` if unchecked.
2023-12-06 22:14:39 +00:00
JediKev
00bc6b1bf3 i18n: Tasks Department ID Missing
This addresses a small issue where the Department Name is not translated
on the Task Queues. This is due to the Task values missing the
Department ID used to generate the object_hash for the translation
table. This adds the `dept_id` to the Task Values so the translations
are properly found.
2023-10-30 09:22:46 -05:00
JediKev
4689926b2d cli: Class Not Found
This addresses a small issue where the osTicket class could not be found in
manage.php. This moves the boostrap.php include above the osTicket call to
ensure the class is loaded before use.
2023-10-25 15:45:33 +00:00
JediKev
03755768d9 Add Release Notes for v1.18.1 2023-10-25 15:34:06 +00:00
JediKev
0f08e5b0b7 Merge branch '1.17.x' into develop 2023-10-25 15:26:17 +00:00
JediKev
7c2003629d Add Release Notes for v1.17.5 2023-10-25 15:19:29 +00:00
JediKev
f878766863 Merge pull request #6627 from JediKev/format/viewable-images-bug
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2023-10-25 10:06:35 -05:00
JediKev
2a412883ae format: Viewable Images Bug
This addresses a small bug where `Format::viewableImages()` was using
unencoded quotes instead of encoded quotes to replace the `<img src=`
matches. This means when the content is added to a textarea’s
`draft-data-original` attribute the unencoded quotes break the attribute
and displays raw HTML content. This moves the `Format::htmlchars()` call
after the `preg_replace_callback()` so the quotes can be properly
encoded (if needed).
2023-10-25 10:04:01 -05:00
JediKev
4919051817 Merge pull request #6626 from JediKev/issue/user-account-creation
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2023-10-25 10:03:19 -05:00
JediKev
777e6f0b74 issue: User Account Creation
This addresses an issue with User account creation not rotating the
session properly.
2023-10-25 10:02:49 -05:00
JediKev
7c00e398a6 Merge pull request #6625 from JediKev/security/latest-vulns-09-2023
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2023-10-25 10:02:01 -05:00
JediKev
37cf8350ea security: User Ticket Creation
This addresses an issue with Topic ID param abuse on User Ticket
Creation via portal.
2023-10-25 09:59:53 -05:00
JediKev
c4ad48de5d security: Inline Image
This addresses an issue where we needed to harden inline image regex and
localize the inline images before sanitizing.
2023-10-25 09:59:53 -05:00
JediKev
88a87a3346 security: XSS List Properties
This mitigates a vulnerability reported by Vaibhav Kumar Srivastava
where XSS is possible via List Properties.
2023-10-25 09:59:53 -05:00
JediKev
04f4e61110 security: FAQ Manage Permissions
This addresses a vulnerability reported by @lujiefsi where Agents can
potentially bypass the FAQ restrictions.
2023-10-25 09:59:53 -05:00
JediKev
45d70301f6 Merge pull request #6624 from JediKev/issue/csp-headers
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2023-10-25 09:58:53 -05:00
JediKev
6228f640ac issue: CSP Headers
This adds a few more CSP Headers (`script-src`, `object-src`) to better
secure the helpdesk.
2023-10-25 09:57:58 -05:00
JediKev
d4e1c22d4f Merge pull request #6623 from JediKev/issue/canned-resp-inline-images
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2023-10-25 09:57:02 -05:00
JediKev
a503c1600e issue: Canned Response Inline Images
This addresses an issue where saving edits made to a canned response with two
or more inline images either breaks the page or causes 500 error. This is due
to incorrectly formatted array of IDs for the inline images causing further
issues with `$att->file->getId()` on render.

This adds a check in `keepOnlyFileIds()` to see if the `$value` from the array
of IDs is an array itself. If so, we will break apart the `$value` array into
`$id` (File ID) => `$value` (File Name) to match the expected format. If the
`$value` is not an array, it will use the existing format (as before). This is
important as we have two different array formats for the File IDs depending on
what method is called to generate them. We need to be able to account for both
formats. In addition, this adds the file name to the `$attachment` array in
`getAttachmentIds()` so we can save the new attachment name (if different).

Lastly, this fixes an issue where the Canned Response attachment upload field
was blindly including all attachments rather than excluding the inline images.
2023-10-25 09:55:48 -05:00
Peter Rotich
f489dde1b4 Merge pull request #6622 from protich/issue/lint
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-25 09:03:33 -05:00
Peter Rotich
895c7236b5 stubs: Add stubs to pass lint test 2023-10-24 19:12:56 -07:00
Peter Rotich
9be940a835 Merge pull request #6548 from fjf2002/patch-1
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 21:02:28 -05:00
Peter Rotich
6dc77c8cdb Merge pull request #6549 from fjf2002/patch-2
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 20:59:57 -05:00
Peter Rotich
9d0ba875a3 Merge pull request #6578 from JediKev/i18n/flags-position-and-codes
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 20:45:58 -05:00
Peter Rotich
842bc7e873 Merge pull request #6577 from JediKev/i18n/update-signing
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 20:45:16 -05:00
Peter Rotich
e1340dc70c Merge pull request #6566 from JediKev/issue/putenv-disabled
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 20:44:17 -05:00
Peter Rotich
177ece7c2d Merge pull request #6591 from protich/issue/php-cli
CLI: Make sure manage.php util can be executed via php-cgi CLI
2023-10-24 20:42:18 -05:00
Peter Rotich
ee7e6e5b84 Merge pull request #6609 from JediKev/mailer/undefined-smtpaccount-getname
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 20:41:48 -05:00
Peter Rotich
a37de02a16 Merge pull request #6612 from JediKev/faq/category-notes-images
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 20:40:50 -05:00
Peter Rotich
1a3326377e Merge pull request #6614 from JediKev/patches/latest-10-03-2023
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 20:40:09 -05:00
Peter Rotich
2b5fa48590 Merge pull request #6610 from JediKev/issue/systemsessionhandler
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 10:46:17 -05:00
Peter Rotich
3fd1c04fe1 Merge pull request #6611 from JediKev/issue/status-list-overflow
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 10:44:27 -05:00
Peter Rotich
c7657ae536 Merge pull request #6620 from JediKev/issue/choice-selection-field-searches
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 10:43:23 -05:00
Peter Rotich
736f3e8772 Merge pull request #6618 from JediKev/mail/novalidatecert
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 10:27:29 -05:00
Peter Rotich
89edac8cc8 Merge pull request #6616 from fillorkill/develop
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-10-24 09:02:48 -05:00
JediKev
00e22faddc issue: Choice/Selection Field Searches
This addresses a small issue where when searching for a Choice/Selection
Field value using `includes` criteria it sometimes shows records it's
not supposed to. This is due to the REGEX used to find the value. Let's
say you have two different List Options:
1. ID = 2  | Value = List Item 2
2. ID = 22 | Value = List Item 22

Now, let’s say you make a search criteria of `List => Includes => List
Item 2`. The REGEX we use is `\"?2(\"|,|$)` which will essentially match
`*2` instead of just `2`. This means it will include Tickets with with
values of `List Item 22` as it contains a `2` as well.

This updates the REGEX to add `(?<![0-9])` before the ID/Key to ensure
it does not match numbers that contain this ID/Key. Instead it will have
to be an exact match of the ID/Key.
2023-10-20 10:42:12 -05:00
JediKev
d3c140ce35 mail: NoValidateCert
This adds code to disable certificate validation for IMAP/POP3 and SMTP.
2023-10-16 09:39:01 -05:00
Jing Zhang
d4aeada1c5 Update raphael-min.js to 2.3.0
2.1.0 invokes unsafe-eval error and dashboard graph does not display if CSP turned on. This fixes the issue.
2023-10-11 11:59:37 +08:00
JediKev
1775ce7582 schedules: No Holidays
This fixes an issue where sometimes the holidays for schedules can be
empty. This adds checks to see if holidays is empty/not set in the POST
and if so we try to get the Schedule's existing Holidays and if they
don't exist we default to an empty array. This also adds a further check
to see if `$holidays` is set if not then we default to an empty array.
2023-10-04 16:37:51 -05:00
JediKev
070eefcba2 org: Domain Input Length
This is a small patch that increases the Auto Add Members From input max
length from 60 to 256 to allow more domains.
2023-10-04 16:36:16 -05:00
JediKev
64b8c81d09 mysqli: Retry Codes
This adds the concept of Retry Codes so we can attempt to reconnect to
MySQL in the event of certain error codes (2006 and 1213).
2006 - MySQL server has gone away
1213 - Deadlock found when trying to get lock; try restarting
transaction
2023-10-04 16:31:41 -05:00
JediKev
bd034712a5 logs: Email Loop Info
This adds code to append the offending mail headers when an Email Loop
is detected. This will provide more information on what email exactly is
causing the loop.
2023-10-04 16:30:13 -05:00
JediKev
4475e03ebd search: Not Includes No Value
This addresses an issue where sometimes an Agent will add Search
criteria with `!includes` but don't add a value. This adds a check to
make sure there is a value before attempting the search. If there is no
value we simply return without executing the search to avoid errors.
2023-10-04 16:28:22 -05:00
JediKev
a8d42a9de2 api: Data Array
This addresses an issue where sometimes the returned `$data` from the
parser can be a type other than an array. We expect the data to be an
array so to avoid issues/errors this adds a check to ensure `$data` is
an array before we use it.
2023-10-04 16:25:33 -05:00
JediKev
48e8501dd0 api: Check Attachments
This addresses an issue where sometimes attachments can sometimes not be
set in the `$data` array. This adds a check to ensure attachments key
isset in the `$data` array before attempting to use it.
2023-10-04 16:23:32 -05:00
JediKev
65e12297fa search: Store Saved Search Count
This adds code to store a Saved Search count on creation.
2023-10-04 16:21:29 -05:00
JediKev
ccca0f5954 faq: Category Notes Images
This addresses an issue where inline images were being broken in FAQ
Category Notes. This ensures we call `Format::viewableImages()` on both
the Category Description and Notes to ensure they are sanitized and
properly formatted.
2023-09-29 15:17:02 -05:00
JediKev
1deee342a5 issue: Status List Overflow
This addresses an issue where having more than 20 ticket statuses run
off the page when selecting ticket statuses from Changes Status action
button. This adds a check for how many status you have an if more than
20 we add styling so the list is scrollable.
2023-09-29 14:57:17 -05:00
JediKev
7e17daa68b issue: SystemSessionHandler
This addresses an issue where if using an old database such as v1.6 ST
and attempting to upgrade you get a fatal error of
`osTicket\Session\SystemSessionHandler: must implement
osTicket\Session\AbstractSessionhandler`. This is because the
`SystemSessionHandler` class does not extend `AbstractSessionHandler`
(rightfully so). We seemingly force `AbstractSessionHandler` without
taking the `SystemSessionHandler` into account. This adds a check to see
if using `SystemSessionHandler` and if so sets `$impl` as such; allowing
the check to pass and the session to be initiated. This also updates the
capitalization of the `AbstractSessionhandler` class in two places.
2023-09-29 14:48:12 -05:00
JediKev
560a4f1d63 mailer: Undefined SmtpAccount::getName()
This addresses an issue where when attempting to send mail from an
SmtpAccount we attempt to get the From name with `getName()` which
throws a fatal error. This updates class EmailAccount and adds a new
`getName()` method that gets the From name from the associated email
relation. This provides the needed name and prevents fatal error from
being thrown. In addition, this adds a further fail-safe where if no
name is returned we will use the email address as the name.
2023-09-29 14:07:42 -05:00
Peter Rotich
0caf58648f CLI: Make sure manage util can be executed via CLI
This commit changes manage.php util to use unified cli detection
routine. This ensures that cgi based CLI binaries execute the util.
2023-07-31 13:42:17 -07:00
JediKev
fcdeb542ab Merge pull request #6579 from JediKev/update/php-requirements-1.18.x
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-07-18 13:34:57 -05:00
JediKev
1c0c670b11 update: PHP Requirements 1.18.x
This updates the PHP requirements to match 1.18.x requirements.
2023-07-18 13:30:29 -05:00
JediKev
3079040e6b Merge branch '1.17.x' into develop 2023-07-18 13:25:25 -05:00
JediKev
3dd2ed35f3 Merge pull request #6562 from JediKev/update/readme-php-and-laminas
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-07-18 13:24:31 -05:00
Tinnitus97
30a4a6e900 update: External Project Links
This updates the links to all external projects used in osTicket.
2023-07-18 13:00:34 -05:00
JediKev
45f5b5b4c5 i18n: Flags Codes
This updates the `include/class.i18n.php` file to fix issues with lang
codes. When building packs for languages with codes that have locales
(eg. `sv-SE`) the pack name use underscores, not dashes. This updates
the places we lookup by lang code and replaces `-` with `_` so they are
found correctly.
2023-07-13 15:44:38 -05:00
JediKev
3ee111122b i18n: Flags Position
This updates the `css/flags.css` to correct the positioning of some
flags. This also adds `fil` code to the `include/i18n/langs.php` file to
account for Filipino language.
2023-07-13 15:42:48 -05:00
JediKev
776c0f2791 i18n: Build MANIFEST.php
This updates the code to fix issues with the `Phrases-Version`,
`Language`, `Last-Revision`, and `Version` not being added properly in
the `MANIFEST.php` file on build. This is due to importing the wrong
class as well as incorrect key names. This updates the include_once
statement as well as the key names.
2023-07-13 15:34:36 -05:00
JediKev
9870627423 i18n: Update Signing
This updates the i18n signing code to reflect the new aws-sdk-php v3
standards. This also rearranges the code to look a little nicer.
2023-07-10 15:19:07 -05:00
JediKev
88294e2d87 update: Upgrade Section & Extensions
This is a partial rewrite of 6365. This moves the Upgrade section to the
`UPGRADING.txt` file and updates the verbiage to link to the Upgrade
Guide in the docs as well as the `UPGRADING.txt` file. In addition this
updates the recommended extensions for PHP to reflect what's shown in
Admin Panel > Dashboard > Information. Lastly, this updates various
links in the `README.md` and `UPGRADING.txt` files.
2023-06-13 16:32:37 -05:00
JediKev
555c4a74b6 update: Crowdin Localization Badge
It's time we updated from the static localization badege to a more
real-time badge.
2023-06-13 16:02:57 -05:00
JediKev
3c0d5f477a issue: putenv() Disabled
This addresses issue 6564 where `putenv()` may be disabled on some
hosts. This adds a check to make sure the function exists before calling
it to avoid fatal errors.
2023-06-13 15:46:32 -05:00
JediKev
4baf9dc859 update: README.md PHP & Laminas
This updates the `README.md` file to include the newly supported PHP 8.2
as well as an update to add more verbiage to supported MySQL versions.
This also adds credit to `laminas-mail` in the OS projects listings.
2023-06-12 14:52:11 -05:00
JediKev
8f6c2ec794 Merge branch '1.18.x' into develop 2023-06-12 18:15:07 +00:00
JediKev
724de4563e Add Release Notes for v1.18 2023-06-12 18:11:05 +00:00
JediKev
3eac42e55f update: MAJOR_VERSION
This updates MAJOR_VERSION from 1.17 to 1.18.
2023-06-12 18:08:57 +00:00
JediKev
104b4bfc70 Add Release Notes for v1.18 2023-06-12 17:58:18 +00:00
JediKev
ee39fd796e Merge branch 'develop' into 1.18.x 2023-06-12 17:45:36 +00:00
JediKev
11b298680c Merge branch '1.17.x' into develop 2023-06-12 17:45:10 +00:00
JediKev
ea462cb1e6 Add Release Notes for v1.17.4 2023-06-12 17:40:33 +00:00
JediKev
39f1a4f480 Merge branch '1.17.x-develop' into 1.17.x 2023-06-12 17:22:55 +00:00
JediKev
7d60207bd0 Merge branch '1.17.x-1.16.x' into 1.17.x 2023-06-12 17:22:45 +00:00
JediKev
a22ff3b766 issue: iFrame Domain Bypass
This mitigates a vulnerability repoted by @endansdto where iFrame domain
can be bypassed due to bad regex. This updates the regex to ensure
proper filtering and checks.
2023-06-12 17:22:35 +00:00
JediKev
ca30637645 issue: XSS Image Caption
This mitigates a vulnerability reported by @cupc4k3 where XSS is possible
via image caption. This removes the possibilty for captions altogether.
2023-06-12 17:22:35 +00:00
JediKev
cecda2f2c0 issue: Multiple File Upload
This mitigates a vulnerability reported by @ManuelHu where files can
bypass checks if sent in the same request behind a valid file. This also
adds a space to fix an annoyance in the JS errors.
2023-06-12 17:22:35 +00:00
JediKev
d1f8cd0a6c issue: Draft & Inline Images
This is a two-part commit that includes a fix for inline images on
display and a patch for a possible vulnerability for Drafts. This
restructures the way we call Format::viewableImages() so that we call it
when displaying after we sanitize the data to ensure the images are not
broken. Secondly, this ensures Drafts do not skip the
`Format::htmlchars()` sanitization at all. This is a rewrite of #6511.
2023-06-12 17:22:35 +00:00
JediKev
7bbe0762d7 issue: Password Length
This addresses an issue reported by @manavparekh where allowing
excessively lengthy passwords is not a good idea. CVE-2023-30082
2023-06-12 17:22:35 +00:00
protich
f7dd4a7c24 installer: Change Email
This updates the email included in the intial installation Ticket to
`feedback@osticket.com`. This also updates the Ticket information to
include details about the documentation site.
2023-06-12 17:22:34 +00:00
JediKev
34b744b5ea issue: Email Only Attachment
This addresses an issue where emails that contain only attachment(s)
fail to process correctly. This is due to there being no `parts` for
`$part`. This adds a check for `!$part->parts` and if true (no parts) we
call `getAttachments()` on just the `$part` itself.
2023-06-12 17:22:34 +00:00
JediKev
c89454067c issue: glob() Empty Array
With PHP 8.2 `glob()` now returns an empty array if all paths are
restricted instead of `false`. This updates the only check we have on
this to check for empty array instead.
2023-06-12 17:22:34 +00:00
JediKev
544689d72b jquery: Update To 3.7.0
This updates jQuery to the latest stable release of 3.7.0.
2023-06-12 17:22:34 +00:00
JediKev
9c3ac48755 issue: strftime() Deprecation
This replaces the now deprecated `strftime()` with `date()`. This also
adds a TODO to class Format to replace an instance there. It will need
some refactoring though so we are leaving it out of this commit.
2023-06-12 17:22:34 +00:00
JediKev
8b12cfa96f issue: Relocate Typeahead JS/CSS Files
This is a rewrite of 2401 that relocates the Typeahead JS/CSS files for
people with setups that have things like HTTP Auth enabled.
2023-06-12 17:22:34 +00:00
JediKev
a0ba67febd issue: Duplicate User Copy/Paste Import
This addresses an issue where the Copy/Paste Import feature for Users
sometimes creates a duplicate account for an existing User. This occurs
when using a string like `User Name, email@domain.tld`, however, does
not occur when using a string like `User Name,email@domain.tld`. This is
due to the extra space after the comma as we are not trimming extra
spaces correctly. This adds `trim()` to the values before they are used
so that they correctly match existing values and avoids duplicates.
2023-06-12 17:22:34 +00:00
Peter Rotich
039a902252 FileUploadField: Custom File Upload Field
This commit fixes a bug where generic (ticket/task) file upload
configuration is mistakenly used on custom field file upload.
2023-06-12 17:21:30 +00:00
Peter Rotich
7fdc9949d6 File: Strict Mime Type Check
This commit adds config setting to FileUploadField to enable strict mime
type check when uploading files.
2023-06-12 17:21:30 +00:00
JediKev
b5b9e2b4a6 issue: File Upload Type
This addresses an issue where uploading a file throws an Invalid File
error even though the file is valid and there are no file restrictions.
This is due to doing `strcasecmp()` on a variable that is some times
empty. This adds a check to see if that variable has a value before
doing the comparison to avoid false positives. In addition, this adds a
new paramter called `$strict` that if true we run the mime type check.
By default `$strict` is false which skips the check. We will eventually
add a configurable setting to enable strict mime type check if preferred.
2023-06-12 17:21:30 +00:00
JediKev
2ed8adaef6 issue: i18n Audit Exports
This addresses an issue where attempting to use `All` Event type in any
other language than English the export will fail. This removes the
translation method from `All` so that the English version is used for
the option's `key`. This doesn't affect the visible word as it gets
translated downstream.
2023-06-12 17:21:30 +00:00
JediKev
8b1cd53ff1 Merge pull request #6561 from JediKev/security/latest-vulns-06-2023
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-06-12 12:14:11 -05:00
JediKev
9bb6c04464 Merge pull request #6560 from JediKev/installer/change-email
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-06-12 11:55:23 -05:00
JediKev
10e779b77d Merge pull request #6559 from JediKev/issue/email-only-attachment
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-06-12 11:55:11 -05:00
protich
a11aee294d installer: Change Email
This updates the email included in the intial installation Ticket to
`feedback@osticket.com`. This also updates the Ticket information to
include details about the documentation site.
2023-06-12 11:52:38 -05:00
JediKev
9e45f3fa95 issue: Email Only Attachment
This addresses an issue where emails that contain only attachment(s)
fail to process correctly. This is due to there being no `parts` for
`$part`. This adds a check for `!$part->parts` and if true (no parts) we
call `getAttachments()` on just the `$part` itself.
2023-06-12 11:47:48 -05:00
JediKev
0cfbc907b7 Merge pull request #6530 from empty88/patch-8
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-06-12 11:32:15 -05:00
JediKev
81cd39c84f Merge pull request #6557 from JediKev/php/8.2-support
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2023-06-12 10:48:36 -05:00
JediKev
e4bfb00de1 issue: iFrame Domain Bypass
This mitigates a vulnerability repoted by @endansdto where iFrame domain
can be bypassed due to bad regex. This updates the regex to ensure
proper filtering and checks.
2023-06-12 10:09:06 -05:00
JediKev
ae37925598 issue: XSS Image Caption
This mitigates a vulnerability reported by @cupc4k3 where XSS is possible
via image caption. This removes the possibilty for captions altogether.
2023-06-12 10:08:54 -05:00
JediKev
73b997a9de issue: Multiple File Upload
This mitigates a vulnerability reported by @ManuelHu where files can
bypass checks if sent in the same request behind a valid file. This also
adds a space to fix an annoyance in the JS errors.
2023-06-12 10:08:39 -05:00
JediKev
6924417599 issue: Draft & Inline Images
This is a two-part commit that includes a fix for inline images on
display and a patch for a possible vulnerability for Drafts. This
restructures the way we call Format::viewableImages() so that we call it
when displaying after we sanitize the data to ensure the images are not
broken. Secondly, this ensures Drafts do not skip the
`Format::htmlchars()` sanitization at all. This is a rewrite of #6511.
2023-06-12 10:08:03 -05:00
JediKev
86c2ba0220 issue: Password Length
This addresses an issue reported by @manavparekh where allowing
excessively lengthy passwords is not a good idea. CVE-2023-30082
2023-06-12 10:07:27 -05:00
JediKev
c64a2611b7 issue: glob() Empty Array
With PHP 8.2 `glob()` now returns an empty array if all paths are
restricted instead of `false`. This updates the only check we have on
this to check for empty array instead.
2023-06-12 09:30:54 -05:00
Peter Rotich
848d3bcf69 Merge remote-tracking branch 'upstream/develop' into 1.18.x 2023-06-07 09:16:17 -07:00
Peter Rotich
781dbe551b Merge pull request #6540 from JediKev/jquery/update-to-3.7.0
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-06-06 11:04:32 -05:00
Peter Rotich
e5cf0109cd Merge pull request #6553 from JediKev/issue/strftime-deprecation
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-06-06 10:55:02 -05:00
Peter Rotich
aac546d0db Database: Change Plugin Name to varchar(255)
This commit modifies name field in Plugin and Plugin Instance table to
varchar(255). This is necessary since plugin can have long arse
names.
2023-06-06 08:35:53 -07:00
JediKev
3fe132c452 issue: strftime() Deprecation
This replaces the now deprecated `strftime()` with `date()`. This also
adds a TODO to class Format to replace an instance there. It will need
some refactoring though so we are leaving it out of this commit.
2023-06-05 14:10:43 -05:00
Peter Rotich
f58bcc9bd7 Merge remote-tracking branch 'upstream/develop' into develop 2023-06-05 11:48:40 -07:00
Peter Rotich
f1d28b1c6d Merge pull request #6541 from JediKev/issue/relocate-typeahead-js-css-files
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-06-05 13:18:10 -05:00
Peter Rotich
32b0ed8cd8 Merge pull request #6543 from JediKev/update/laminas-mail
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-06-05 13:16:52 -05:00
Peter Rotich
6b53ff7950 Merge remote-tracking branch 'upstream/develop' into develop 2023-06-03 07:54:56 -07:00
fjf2002
8c8a7fd120 Update upgrade.inc.php
fix typo
2023-06-02 15:28:41 +02:00
fjf2002
9fd83eba3a Update upgrade.php
fix typo
2023-06-02 15:26:48 +02:00
Peter Rotich
9fd3cf5ffd Merge pull request #6520 from JediKev/issue/dup-user-copy-paste-import
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-05-30 17:36:30 -05:00
Peter Rotich
b7b31e721d Merge pull request #6542 from JediKev/issue/remove-old-login-code
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-05-30 17:34:37 -05:00
JediKev
bb45d37a54 todo: Remove Custom prepareHeaders()
This removes the custom `prepareHeaders()` method from class Sendmail as
this functionality was added upstream which is now available with the
latest update.
2023-05-30 17:22:41 -05:00
JediKev
66fa10af51 update: Laminas-Mail
This is a rewrite of 6312 and updates the laminas-mail package from
2.10.1 to 2.23.0. This also remove unused dev dependencies.
2023-05-30 17:22:36 -05:00
JediKev
e17ad463ec issue: Remove Old Login Code
This removes old and tired code from the login pages where we throw
`Http::response(422);` to "prevent browsers from suggesting saving the
username and password". This is no longer the case as browsers no longer
play by these rules. The only way to properly do this nowadays is to set
an attribute on the form tag to disable autocomplete. We don't want to
do this either as that would prevent password managers from autofilling
the auth info.

Throwing a 422 code prevents some setups from accepting logins due to
4XX codes being error codes in nature. Removing this code seemingly has
no negative impact whatsoever.

A short backstory, this was [originally a 401
code](a99b9ce81e)
to prevent browsers from suggesting saving the auth info. Later it was
[changed to a 422
code](772d5c59a9)
to make IE play nice.
2023-05-25 13:55:48 -05:00
JediKev
62cd40648b issue: Relocate Typeahead JS/CSS Files
This is a rewrite of 2401 that relocates the Typeahead JS/CSS files for
people with setups that have things like HTTP Auth enabled.
2023-05-25 13:46:03 -05:00
JediKev
ffa23dad20 jquery: Update To 3.7.0
This updates jQuery to the latest stable release of 3.7.0.
2023-05-22 12:47:20 -05:00
JediKev
b304cdbd9c issue: Duplicate User Copy/Paste Import
This addresses an issue where the Copy/Paste Import feature for Users
sometimes creates a duplicate account for an existing User. This occurs
when using a string like `User Name, email@domain.tld`, however, does
not occur when using a string like `User Name,email@domain.tld`. This is
due to the extra space after the comma as we are not trimming extra
spaces correctly. This adds `trim()` to the values before they are used
so that they correctly match existing values and avoids duplicates.
2023-05-11 13:32:29 -05:00
JediKev
4493b1267b issue: Inline-Images Canned Responses
This addresses an issue where inline images only used in canned
responses and saved before a draft could be generated would erroneously
be deleted by the orphan file cleanup routine. This caused the inline
images to appear broken on use as they no longer exist. This is due to a
check for a `draft_id` before creating an attachment record for each
inline file. We do not need to check for a `draft_id` as we always have
a `response` in the POST with the most current data (eg. there might be
content added before a new draft can be saved). This removes the checks
in both `create` and `update` cases so that attachment records can be
created (with `inline = 1`) to avoid being deleted by file cleanup.
2023-05-11 13:27:20 -05:00
Peter Rotich
41c1edd940 Merge remote-tracking branch 'upstream/develop' into develop 2023-05-11 08:42:53 -07:00
Peter Rotich
6c8b151ae3 Merge remote-tracking branch 'upstream/1.17.x' into develop 2023-05-11 08:42:47 -07:00
eMpTy
1105cde711 Make string translatable 2023-05-02 10:36:49 +02:00
Claudio Nicora
7805cd9428 Fix PR #6283: DB column value of "local backend" is 'client' and not 'local' 2023-03-21 12:04:54 +01:00
Peter Rotich
4e570b53d2 Merge pull request #6494 from JediKev/oauth2/strict-matching-bug
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-03-16 20:09:38 -05:00
JediKev
e014ffd24c oauth2: Strict Matching Bug
This addresses an issue where we were checking strict matching when
using basic authentication. This is due to a small oversight in the smtp
save checks. This adds a line to check if auth_bk is set to oauth2
before checking strict matching.
2023-03-16 15:23:19 -05:00
Peter Rotich
ef25ee7607 Merge pull request #6493 from JediKev/issue/thread-entry-actions-z-index
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-03-16 11:52:42 -05:00
JediKev
215a0ce262 issue: Thread Entry Actions z-index
This addresses a small annoyance where the thread entry actions dropdown
always appears below the subsequent thread entry. This can be very
annoying and even hide some of the options. This adds `z-index` of
`auto` to the `thread-entry` div so that the dropdown always appears on
top.
2023-03-16 11:03:41 -05:00
JediKev
8bd22d0942 Add Release Notes for v1.17.3 2023-03-08 19:58:52 +00:00
JediKev
ca95150105 Merge branch '1.16.x' into develop 2023-03-08 19:53:07 +00:00
JediKev
30ef1cc2ae Add Release Notes for v1.16.6 2023-03-08 19:46:13 +00:00
JediKev
402992f385 Merge pull request #6485 from JediKev/issue/getRealPath-stub
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2023-03-08 13:43:46 -06:00
JediKev
32a229aa98 issue: getRealPath() Stub
This addresses an issue where lint tests fails due to `getRealPath()`
not being defined. This is from SplFileObject so we just need to add a
stub to ignore it in the tests.
2023-03-08 13:41:40 -06:00
JediKev
ead4f742ba Merge pull request #6484 from JediKev/security/latest-patches-03-2023
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-08 13:27:30 -06:00
JediKev
263f71a38e security: Search Params
This mitigates a vulnerability with search params.
2023-03-08 13:22:20 -06:00
Peter Rotich
731be08600 Merge remote-tracking branch 'upstream/develop' into develop 2023-03-08 09:20:02 -08:00
Peter Rotich
55b4bde204 Merge remote-tracking branch 'upstream/1.16.x' into develop 2023-03-08 09:19:49 -08:00
JediKev
ee7ce3d9c3 plugins: Path Manipulation
This mitigates a vulnerability reported by xxx where path manipulation
is possible via Plugins.
2023-03-08 10:56:30 -06:00
JediKev
e2c8f7992c xss: Email Templates
This mitigates a vulnerability reported by xxx where XSS is possible via
Email Templates.
2023-03-08 10:56:04 -06:00
JediKev
8a55c29f87 xss: Queues
This mitigates a vulnerability reported by indevi0us where XSS is
possible via Queue conditions.
2023-03-08 10:54:19 -06:00
JediKev
343a2b47e1 xss: AJAX Paths
This mitigates a vulnerability reported by indevi0us where XSS is
possible via some AJAX paths.
2023-03-08 10:53:55 -06:00
JediKev
619ce0f620 xss: Dashboard period
This mitigates a vulnerability reported by @indevi0us where XSS is
possible via the `period` parameter. This sanitizes the parameter values
before using them anywhere.
2023-03-08 10:50:47 -06:00
JediKev
9fb01bc12f xss: Roles
This mitigates a vulnerability reported by indevi0us where XSS is
possible via the `name` parameter for Roles.
2023-03-08 10:50:07 -06:00
JediKev
daee20fdd8 xss: Organization Search q
This mitigates a vulnerability reported by @indevi0us where XSS is
possible via the `q` parameter in organization lookups. This sanitizes
the parameter value before use as well as htmlchars it before adding to
JSON output.
2023-03-08 10:36:28 -06:00
JediKev
ec6043935b xss: Search parent_id
This mitigates a vulnerability reported by @indevi0us where XSS is
possible via the parent_id parameter. This forces the parameter to an
INT so that there is no chance of XSS.
2023-03-08 10:35:56 -06:00
JediKev
091ddba965 xss: System Email
This mitigates a vulnerability reported by @edr4 where XSS is possible
via System Email. This adds sanitization to the email before
saving/displaying. This also forces the other options (topic,
department, etc.) to int so there is no chance of XSS.
2023-03-08 10:35:10 -06:00
JediKev
86f9693dc6 xss: Draft Files
This mitigates an XSS vulnerability with files uploaded through drafts.
2023-03-08 10:31:12 -06:00
Peter Rotich
5290e4997a Merge pull request #6482 from protich/issue/mailer+attachments
Reviewed-By: Jedikev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2023-03-08 09:51:11 -06:00
Peter Rotich
e43cc799f0 Merge pull request #6483 from JediKev/issue/mPDF-font-files
Reviewed-By: Jedikev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2023-03-08 09:50:53 -06:00
Peter Rotich
8c137fb700 Merge pull request #6386 from bestlong/patch-1
Reviewed-By: Jedikev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2023-03-08 09:42:12 -06:00
Peter Rotich
516b6e71ec Merge pull request #6437 from JediKev/issue/file-upload-false
Reviewed-By: Jedikev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2023-03-08 09:40:50 -06:00
Peter Rotich
a09a23e355 Merge pull request #6469 from protich/JediKev/oauth2/strict-matching
Reviewed-By: Jedikev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2023-03-08 09:39:50 -06:00
JediKev
8dd2ab61df issue: FileUpload False
This addresses an issue where when doing full Ticket edit with a
FileUpload field and you don't supply a file the form_entry_value for
the corresponding field updates to `false`. This causes an issue with IS
NULL criteria so this adds a check to see if a value is present, if not,
then we return `NULL` instead of JSON encoding a `false` string value.
2023-03-08 09:37:03 -06:00
JediKev
427a8aa628 issue: mPDF Font Files
This addresses an issue where some of the mPDF font files don't get
included due to the way we use the `preg_split()`. This adds the
remaining path parts to the `list()` and adds statements to update the
`$path` if such parts exist.
2023-03-08 09:20:37 -06:00
Peter Rotich
64a8abf375 lint: Fix Case Mismatch 2023-03-07 17:53:26 -08:00
Peter Rotich
8815d0874f mailer: Inline Attachments
This commit addresses an issue where inline images also gets attached as
files.
2023-03-07 17:53:26 -08:00
Peter Rotich
7efbdfd2a3 Add FileObject Interface
This commit adds File Object Interface to force uniformity when using
mixed file types like AttachmentFile and FileObject
2023-03-07 17:53:26 -08:00
Peter Rotich
ca6c1778e5 Merge remote-tracking branch 'upstream/develop' into develop 2023-03-07 12:53:02 -08:00
Peter Rotich
5c239adb57 oauth2: Support Alias/Shared Mailboxes
This commit add logic to Mail Protocol to support shared / aliased
mailboxes by setting token User.
2023-03-07 12:29:22 -08:00
JediKev
76149d65ef Merge pull request #6466 from JediKev/oauth2/strict-matching
Reviewed-By: protich <peter@osticket.com>, JediKev <kevin@enhancesoft.com>
2023-03-07 12:48:49 -06:00
JediKev
e76e91a8ee Merge pull request #6462 from JensEB/patch-2
Reviewed-By: protich <peter@osticket.com>, JediKev <kevin@enhancesoft.com>
2023-03-07 12:46:21 -06:00
JediKev
cf83b3ad38 Merge pull request #6435 from JediKev/issue/queue-counts-incorrect
Reviewed-By: protich <peter@osticket.com>, JediKev <kevin@enhancesoft.com>
2023-03-07 12:21:25 -06:00
JediKev
23719a232f Merge pull request #6427 from JediKev/issue/does-not-have-a-value
Reviewed-By: protich <peter@osticket.com>, JediKev <kevin@enhancesoft.com>
2023-03-07 12:17:51 -06:00
JediKev
ce8e0b70e4 Merge pull request #6423 from empty88/patch-2
Reviewed-By: protich <peter@osticket.com>, JediKev <kevin@enhancesoft.com>
2023-03-07 12:12:58 -06:00
JediKev
13e75be91b Merge pull request #6421 from empty88/patch-6
Reviewed-By: protich <peter@osticket.com>, JediKev <kevin@enhancesoft.com>
2023-03-07 12:10:05 -06:00
JediKev
34d978a972 Merge pull request #6395 from protich/feature/dbproxies
Reviewed-By: protich <peter@osticket.com>, JediKev <kevin@enhancesoft.com>
2023-03-07 12:04:23 -06:00
JediKev
b20a2ba861 Merge pull request #6440 from JediKev/jquery/update-to-3.6.3
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-07 09:48:43 -06:00
JediKev
8d39a4cc59 jquery: Update To 3.6.3
This updates jQuery to the latest stable release of v3.6.3.
2023-03-07 09:47:48 -06:00
JediKev
58c6c2246b Merge pull request #6439 from JediKev/jquery/update-jquery-ui-1.13.2
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-07 09:43:33 -06:00
JediKev
37f6a3f970 Merge pull request #6434 from JediKev/session/user-logged-out
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-07 09:41:12 -06:00
JediKev
34f913c084 Merge pull request #6428 from JediKev/issue/disabled-queues-run-counts
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-07 09:39:23 -06:00
JediKev
bab98e3090 Merge pull request #6426 from JediKev/print/hidden-thread-events
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-07 09:38:39 -06:00
JediKev
e15e1d2929 Merge pull request #6410 from JediKev/issue/featured-faqs
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-07 09:37:37 -06:00
JediKev
1c316688a1 Merge pull request #6409 from JediKev/issue/ticketdenied-errno
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-07 09:36:51 -06:00
JediKev
2e0e768f1d Merge pull request #6408 from JediKev/issue/static-forTask
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-07 09:35:59 -06:00
JediKev
a9f3d9145c Merge pull request #6403 from JediKev/issue/ldap-multi-instance-fatal-error
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-07 09:35:18 -06:00
JediKev
41af1ab738 Merge pull request #6400 from protich/issue/mailfetch+default-dept
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-07 09:33:27 -06:00
JediKev
ea343b7cce Merge pull request #6399 from protich/issue/misc
Reviewed-By: JediKev <kevin@enhancesoft.com>
2023-03-07 09:32:40 -06:00
Peter Rotich
1a824770e1 Merge pull request #6477 from JediKev/i18n/make-pot
Peter Rotich <peter@enhancesoft.com>
2023-03-04 13:34:22 -06:00
Peter Rotich
96794feac8 Merge pull request #6480 from JediKev/issue/dept-export
Reviewed-By: Peter Rotich <peter@osticket.com>
2023-03-04 13:32:05 -06:00
Peter Rotich
607264dea9 Merge pull request #6481 from JediKev/update/readme-php-version
Reviewed-By:  Peter Rotich <peter@osticket.com>
2023-03-04 13:31:00 -06:00
JediKev
6087bc550c update: README PHP Version
This updates the PHP version in the Requirements section from `8.0` to
`8.0 - 8.1 (8.1 recommended)` to avoid confusion with the newly released
`8.2`.
2023-03-02 14:52:32 -06:00
JediKev
5418cf2092 issue: Department Export
This addresses a small issue where when attempting to export Agents in
any Department you get a fatal error of calling non-static method
statically. This updates the export method for the Department class to
static so that exports will function and no errors are thrown.
2023-03-02 09:51:02 -06:00
JediKev
74274b5cb1 i18n: make-pot
This addresses an issue where `make-pot` command is not working
properly. This is due to PHP 8 changes that were never fully resolved.
We had to move away from the now deprecated `each()` so we switched to
`foreach()`. However, `foreach()` does not keep current position in the
iteration which we rely on for the `make-pot` command. However, you can
get around this by using `while($var = current())` and passing by
reference which keeps the current position.
2023-02-27 15:40:40 -06:00
JediKev
c0cd8b16d0 oauth2: Delete Token Banner
This updates the Delete Token functionality to show a success/error
banner when deleting the token. If successful it will delete the Token
tab and content, load the IdP tab, and show a success banner with the
JSON content. On error it will simply show an error banner with the JSON
content.
2023-02-22 16:36:37 -06:00
JediKev
f531718a56 oauth2: Strict Matching Default True
This changes the default for Strict Matching from `false` to `true` so
that new emails are strict unless explicitly set otherwise. This also
adds some descriptive comments to the getter and setter.
2023-02-16 15:41:46 -06:00
JediKev
cb3625e875 oauth2: Bug Fixes
This addresses some bugs found during testing. This adds a check to
`SmtpAccount::getConfig()` that ensures we have an email and
MailboxAccount before attempting to call `getConfig()` and adds
descriptive comments. This also removes the `isActive()` check from the
SmtpAccount `save()` method as we only care about if it's currently set to
active. Lastly, this changes the variable name for the email address
from `$email` to `$addr` so it doesn't conflict with the original
`$email` variable.
2023-02-16 15:34:54 -06:00
JediKev
ca913ba29f oauth2: Delete Token
It's about damn time.. that we add ability to delete the OAuth2 Token.
This adds a new button to the Token tab that will allow you to delete
the current Token.
2023-02-16 15:30:37 -06:00
JediKev
b7718be42d oauth2: Add Strict To Backend ID
This adds the Strict Matching value to the Backend ID for now until we
add a column for it in the database (1.18.x).
2023-02-14 15:51:11 -06:00
JediKev
7275d67bc7 oauth2: Strict Matching
This is a rewrite of osTicket/osTicket-plugins#263 where it was
attempting to implement Strict Matching. This fully implements Strict
Matching and adds functionality to check for this when retrieving a
token and when saving SMTP with Same As Remote Mailbox. This also adds a
new disabled field to the General Settings to show what email will be
used as well as a help tip that further explains Strict Matching.
2023-02-14 14:53:27 -06:00
JensEB
af83896d92 Uncaught Error: Call to a member function getId() on bool in /.../include/class.session.php:314
To prevent following error:
PHP Fatal error: Uncaught Error: Call to a member function getId() on bool in /.../include/class.session.php:314

Logged back trace:

PHP Fatal error: Uncaught Error: Call to a member function getId() on bool in /.../include/class.session.php:314
Stack trace:
#0 /.../include/class.session.php(336): osTicket\\Session\\AbstractSessionStorageBackend->getRecord()
#1 /.../include/class.session.php(281): osTicket\\Session\\AbstractSessionStorageBackend->update()
#2 [internal function]: osTicket\\Session\\AbstractSessionHandler->write()
#3 [internal function]: session_write_close()
2023-02-03 12:55:23 +01:00
JediKev
d47fc2b1cc issue: Does Not Have A Value
This addresses an issue where using the `Does Not Have A Value` criteria
on things like Short Answer Fields shows incorrect results. In fact, it
shows all Tickets with and without values for the Field. This is due to
using an overall negative filter (`column IS NULL` or `NOT column IS NOT
NULL`) on a column from a LEFT JOIN causing the backend to return NULL
for all values in that column. This adds a new variable called
`$nullable` that is set to `false` if the `$method` is `nset`. This then
passes `$nullable` to `getOrmPath()` so it can determine wether or not
to force a normal JOIN instead of LEFT JOIN so that `xxx IS NULL`/`NOT
xxx IS NOT NULL` will return the proper results. If the search method is
not `nset` then it will use LEFT JOIN as before.
2023-01-19 13:35:20 -06:00
JediKev
b896f70de6 jquery: Update jQueryUI 1.13.2
This updates jQueryUI from `1.13.1` to `1.13.2`. This also includes the
updated CSS for jQueryUI `1.13.2`.
2023-01-18 16:20:52 -06:00
JediKev
2428cc5823 issue: Queue Counts Incorrect
This addresses an issue where when a Queue is filtering by a specific
field the counts are incorrect. This is due to using only the
`constraints` instead of both `constraints` and `path_constraints`. This
updates the `counts()` method to include the `path_constraints` if set
so that the counts are properly calculated.
2023-01-11 15:41:04 -06:00
JediKev
00d409d30e session: User Logged Out
This addresses an issue where Users login, do something, and get
randomly shown the login screen. If they refresh the page it shows
them authenticated as normal again. This is due to a Session ID mismatch
in `isvalidSession()`. When `refreshSession()` calls
`regenerateSession()` it's supposed regenerate the session and update
the session ID however it updates the local ID which `refreshSession()`
later does. This updates `regenerateSession()` to where it updates the
session ID and allows `refreshSession()` to update the local ID. This
deduplicates the local ID update and corrects the ID mismatch.
2023-01-09 14:38:55 -06:00
JediKev
3ff3ce93aa issue: Disabled Queues Run Counts
This addresses an issue where Disabled Queues are still being used in
counts. This is due to grabbing any CustomQueue that has the
`FLAG_QUEUE` flag and/or having `staff_id` equal to the current Staff
member's ID. This adds another filter `Q::not(…'flags__hasbit' =>
CustomQueue::FLAG_DISABLED,` that will ensure the Queue is not Disabled
before using in counts.
2023-01-04 11:19:36 -06:00
JediKev
f63fc67d23 print: Hidden Thread Events
This addresses an issue reported on the Forum where when a field is set
to not visible to Users it is hidden from the Staff Ticket Print PDF.
This is due to the ThreadEvent MODE that is being used (MODE_CLIENT).
This uses the User Ticket Print template instead of the Staff Ticket
Print template which hides some thread events and other data. This
updates the utilized MODE to MODE_STAFF so that the appropriate data is
printed. This also addresses an issue where if the Staff has Relative
time configured it shows in the Ticket Print which should not happen.
This adds a check for `$_REQUEST['a']` and if it's set we make sure it’s
not `print` to avoid printing relative times.
2023-01-03 13:50:52 -06:00
eMpTy
46c005a02b add translation for task status 2022-12-29 11:01:06 +01:00
eMpTy
cb52804450 Add translation for "last resort" standard column labels 2022-12-28 15:29:32 +01:00
JediKev
8df095817f issue: Featured FAQs
This addresses a small logic issue where we are adding Public and
Featured FAQs in the Featured sidebar when it should only be Featured
ones. This updates the ORM statement to only show FAQs that are set to
Featured and belong to a Public or Featured Category.
2022-12-13 15:12:41 -06:00
JediKev
6de7cf4c2c issue: TicketDenied errno
This addresses an issue where emails being rejected by Banlist is
causing excessive processing errors and refuses to move the mail. This
is due to our logic expecting `403` exception code for TicketDenied but
we are using `500` in `TicketApiController::createTicket()`. This
updates the `exerr()` line to use the `$errors['errno']` if it exists
otherwise default to `500`.
2022-12-13 13:33:24 -06:00
JediKev
1079011fc0 issue: Static forTask()
This addresses an issue where printing a Ticket with Tasks or printing a
Task itself will throw a fatal error of `Non-static method
DynamicFormEntry::forTask() cannot be called statically`. This updates
the `forTask()` method to be static to avoid fatal errors.
2022-12-12 12:10:37 -06:00
JediKev
f64860441e issue: LDAP Multi-Instance Fatal Error
This addresses an issue where if you have more than one instance of LDAP
plugin enabled and try to lookup a User it fails with a fatal error of
`Object of class StaffLDAPAuthentication could not be converted to
string`. This is due to using `array_unique()` which can't convert
objects to strings. This updates the method and adds the `SORT_REGULAR`
flag so that it can compare without converting objects to strings.

In addition this addresses an issue where we were using static ID for
StaffLDAPAuthentication backend. We updated the plugin code to reflect
the actual Backend ID but the current AJAX regex for this doesn’t match
this format. This updates the AJAX regex to match the updated format.
2022-12-05 17:09:35 -06:00
Peter Rotich
f410d4ec58 fetcher: Default Department
When fetching a mailbox, osTicket routes fetched emails to a department based
on `To` or `Delivered-To` header entries. This allows for ability to fetch
aliased emails from one primary account and route them based on configured
system emails. On failure to match, the email (ticket) is routed to the
department of the email account being fetched.

With the email backend overhaul in v1.17 - a bug was instroduced where
unmatched emails ended up being routed to default department instead of the
department of the email being fetched.

This commit addresses the issue...
2022-12-04 23:22:25 +00:00
Peter Rotich
389c669728 Merge remote-tracking branch 'upstream/develop' into develop 2022-11-30 08:42:52 +00:00
Peter Rotich
10af29a5d7 email: Account for possible Orphaned SMTP Accounts 2022-11-30 08:42:52 +00:00
Peter Rotich
ebbebaab38 Merge remote-tracking branch 'upstream/1.17.x' into develop 2022-11-30 08:42:52 +00:00
Peter Rotich
eac9960a51 cron: Local Cron as CLI 2022-11-30 08:42:52 +00:00
Peter Rotich
24fd5075d6 logs: System Logs Tooltip
This commit addresses a bug introduced in d4d9c4242 due to conflicting function
names in Api Controler.
2022-11-30 08:42:52 +00:00
Peter Rotich
e6beeb9baf api: API Request Format
This commit addresses a bug introduced by d4d9c4242 by making sure format is
taken into account when processing API Requests.
2022-11-30 08:42:52 +00:00
Peter Rotich
246aaa4dcf mysql: Support Sidecar Database Proxies
When running osTicket in a multi-node cluster setup, it makes sense to connect
to the database via a load balancer or a database proxy (assuming VIP with
failover support). It's great for redundancy -  however - this adds extra time
(miliseconds) because of the extra network hop latency.

To save a few miliseconds - when osTicket (the Application) is also hosted on
the same node or container running the database proxy - then it might make
sense to attempt a local connection first before attempting via via the VIP
(sidecar pattern).

This commit adds multiple database hosts support, comma separated, when defining
DBHOST in osTicket config file (`ost-config.php`). It also adds a new _Database
Option_ to define `DBCONNECT_TIME` used to set `MYSQLI_OPT_CONNECT_TIMEOUT`.
Connection timeout is important with multiple hosts so connection attempts
(done sequencially) can timeout relatively quickly.
2022-11-24 19:09:54 +00:00
JediKev
61263635d9 Merge branch '1.17.x' into develop 2022-11-23 18:33:45 +00:00
JediKev
8d9ab037b3 Merge branch '1.16.x' into 1.17.x 2022-11-23 18:33:35 +00:00
JediKev
460c5fd4a5 Merge pull request #6381 from protich/1.17.x
Reviewed-By: JediKev <kevin@enhancesoft.com>
2022-11-23 12:32:19 -06:00
JediKev
58fd151393 Merge pull request #6379 from protich/issue/session+regenerate
Reviewed-By: JediKev <kevin@enhancesoft.com>
2022-11-23 12:31:37 -06:00
Peter Rotich
3d7b2394be Merge pull request #6385 from JediKev/session/collab-view-ticket
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-11-23 12:27:02 -06:00
Peter Rotich
0a4498b22e Lint Fixes 2022-11-23 18:22:10 +00:00
Shao Yu-Lung (Allen)
a6d4761a85 fix: typo 2022-11-23 18:55:11 +08:00
JediKev
6afe0efa37 session: Collab View Ticket
This addresses an issue where if a Collaborator views a Ticket via the
Check Ticket Status button in the Client Portal and then tries to repeat
the process with an additional Ticket it will redirect to login page.
This is due to when instantiating the session we use `$user->getId()`
which causes a problem when the User is a Collaborator. When
instantiating a session for a Collaborator object `getId()` returns the
Collaborator ID, not the Collaborator's User ID. This updates the call
from `getId()` to `getUserId()` which gets the correct User ID from the
Collaborator object (and others).
2022-11-22 15:51:01 -06:00
Peter Rotich
d4d9c4242f fetcher: Mail Fetcher / Parser Error Handling
Prior to osTicket `v1.17.x` email fetching required and used php-imap module to
decode and parse emails, whereas locally or remotely piped emails (via API
endpoint) used a Raw Email Parser ("Mail Parser").

Using two separate backends meant duplicated code, logic and inconsistent email
processing.

Starting with osTicket `v1.17.0`, we overhauled the Email Backend to OAuth2
support and in the process we switched toxusing a unified Mail Parser for both
fetched and piped emails. To determined how the email got delivered in order to
handle errors for the interfaces accodingly, we relied on `PHP_SAP`I /
`php_sapi_name()`.

That was shortsighted because of the value of `PHP_SAPI` can be different in
the following cases;

1. Email Fetching can be triggered by autocron (Staff Activity) or by a remote
task (API)

2. `PHP_SAPI` cannot be relied on for php installations using php-fpm, php-cgi
or custom binaries for php CLI executable

3. Cron Job / Task entry "user-name" or "command path" might use separate php
executables (related to `#2`)

4. Triggering cron/php via php-fpm socket connection e.g using FastCGI Client

Since emails are fetched in batches - Email Fetching, unlike stateless API
requests, should be considered a CLI operation regardless of how it gets
trigerred, this necessary so the system can gracefully handle fetch and parse
errors.

This commit does just that and a few other minor logic / code cleanup.

~ Peter - with love!
2022-11-18 11:49:12 +00:00
Peter Rotich
d5853245f7 session: Regenerate Session Id
To avoid session fixation, osTicket regenerates Session Id on-login and on
every session timeout set for the User/Agent even with activity.

This commit changes the logic to make sure that the regenerate `TIME BOMB` only
goes off on a GET request - this is necessary so we don't invalidate data
in-flight on a POST request since osTicket Forms API backend uses session_id to
generate form field names as well as CSRF token used on forms.
2022-11-15 22:38:09 +00:00
JediKev
8fbc7eea6a Add Release Notes for v1.17.2 2022-11-14 22:16:50 +00:00
JediKev
f6c8d18495 Merge branch '1.16.x' into 1.17.x 2022-11-14 22:13:08 +00:00
JediKev
b48bf7eb0b Add Release Notes for v1.16.5 2022-11-14 22:08:06 +00:00
JediKev
5ae737b9bb Merge branch 'develop' into 1.16.x 2022-11-14 22:03:32 +00:00
JediKev
9530965f8c Merge pull request #6373 from protich/issue/session+max_ttl
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-14 16:00:20 -06:00
JediKev
7f5f8cb747 Merge pull request #6371 from protich/issue/email_validator
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-14 15:59:39 -06:00
JediKev
d2ae93b540 Merge pull request #6370 from protich/issue/user-create
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-14 15:58:56 -06:00
JediKev
0541faa826 Merge pull request #6369 from protich/issue/email
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-14 15:58:25 -06:00
JediKev
c17aa40852 Merge pull request #6368 from protich/issue/mailparse+filename
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-14 15:58:00 -06:00
JediKev
396d307913 Merge pull request #6366 from protich/1.17.x
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-14 15:56:52 -06:00
JediKev
8f5f563973 Merge pull request #6363 from JediKev/issue/html-typo
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-14 15:56:32 -06:00
JediKev
9c2d65ffe4 Merge pull request #6361 from sajtiii/develop
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-14 15:56:05 -06:00
JediKev
fd4acd4298 Merge pull request #6360 from rinkp/fix/sessiondata
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-14 15:48:22 -06:00
Peter Rotich
133585f8cd mailer: Use Namespaced Mailer
This commit instantiates the mailer using the correct namespace.
2022-11-14 21:24:43 +00:00
Peter Rotich
ea3e03d212 session: Memcache Max TTL
When storing session data in Memchache storage backend we need to make sure
the TTL is not longer than 30 days, maximum allowed.
2022-11-14 15:49:45 +00:00
Peter Rotich
55fbfcb57b user: Make sure User has a valid Email on create
Emailed tickets skips user validation on purpose with the assumption that the
user has at least a valid email. The assumption can be problematic when
osTicket has issues parsing the from address due to invalid format.
2022-11-13 21:43:28 +00:00
Peter Rotich
3c4a20a85f validator: Email Domain Verification
To truly verify an email, osTicket uses DNS lookup by checking MX record, if
that fails it defaults to checking A / AAAA record of the email domain.

This commit handle a case where a domain doesn't have A record.
2022-11-13 20:51:24 +00:00
Peter Rotich
c19a5f03e9 smtp: Only init SMTP if we have credentials 2022-11-13 18:52:37 +00:00
Peter Rotich
de620fe602 email: Clear Last Error On Save 2022-11-13 18:52:37 +00:00
Peter Rotich
c806721298 mailparse: Parse filenames with complex format 2022-11-13 18:36:04 +00:00
JediKev
50dfe93133 issue: Html Typo
This addresses a small typo where the class `Html` was used instead of
`Http`.
2022-11-10 09:23:05 -06:00
sajtiii
04c0bb3a00 Fix trusted proxy wildcard check 2022-11-10 11:28:15 +01:00
rinkp
cf8b8ce721 Fix old reference to SessionData 2022-11-10 11:13:50 +01:00
JediKev
58bf538df9 Add Release Notes for v1.17.1 2022-11-09 21:16:42 +00:00
JediKev
97c50c197b Merge branch 'develop' into 1.17.x 2022-11-09 21:14:00 +00:00
JediKev
1d11ee674f Add Release Notes for v1.16.4 2022-11-09 20:51:24 +00:00
JediKev
f7ab9f42d5 Merge branch 'develop' into 1.16.x 2022-11-09 20:49:10 +00:00
JediKev
095dc0118c Merge pull request #6358 from protich/issue/session_revisited
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-09 14:42:07 -06:00
Peter Rotich
4fc5f5cc17 session: Add routines to get and filter session records
This commit adds the base functions to get session records based on desired
criteria. It also fixes errant error_log as well as a typo.
2022-11-09 05:05:12 +00:00
Peter Rotich
49d91b0551 session: On-demand Session Destroy
This commit adds ability to ask backend to destroy a session by session_id.
Also changes how expire routine works - passing zero ttl results in the session
being destroyed immediately.
2022-11-09 04:39:07 +00:00
JediKev
e1d759c4d5 Merge pull request #6357 from JediKev/security/username-xss
Reviewed-By: JediKev <kevin@enhancesoft.com>
2022-11-08 14:57:27 -06:00
JediKev
5213ff138c security: Username XSS
This mitigates a vulnerability reported by legoclones on
[huntr.dev](https://huntr.dev/) where XSS can be stored/executed via a
User's `username`. If an Agent is redirected to the User Lookup AJAX
response directly it will execute the stored XSS. This adds
`Format::sanitize()` to the `username` before saving to the database so any
potential XSS is sanitized. Additionally, this adds `Format::htmlchars()` to
the `username` before displaying in the UI to help prevent code execution.
2022-11-08 20:54:15 +00:00
JediKev
dc0507e3b8 Merge pull request #6356 from JediKev/security/refresh-url
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>
2022-11-08 14:51:31 -06:00
protich
3702a4fb3f security: Refresh URL
This initially targeted a particular vulnerability with the Advanced
Search Refresh URLs but subsequently evolved into unifying all Refresh
URLs. We decided to create methods that properly encode URLs to prevent
code execution and to ensure they are all uniformly created. This adds
such capabilities and updates current Refresh URL generation to the new
methods. This also adds a method `Format::http_query_string()` that will
filter the query string and remove any unwanted params. Lastly, this
removes the old and tired `Misc::currentURL()` in favor of the new
"hip" (is that what the kids say these days?) method `Http::url()`.
2022-11-08 14:48:29 -06:00
JediKev
2832d44362 Merge pull request #6345 from protich/issue/fetcher+expunge
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-08 14:40:26 -06:00
JediKev
1c42e26a0e Merge pull request #6334 from protich/issue/session++
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-08 14:38:57 -06:00
JediKev
08b5eea771 Merge pull request #6349 from protich/feature/mailparse-error-handling
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-08 14:37:48 -06:00
JediKev
406b06f284 Merge branch '1.17.x' into feature/mailparse-error-handling 2022-11-08 14:36:46 -06:00
JediKev
2d8bd7498f Merge branch '1.17.x' into issue/fetcher+expunge 2022-11-08 14:35:13 -06:00
JediKev
22db3eca53 Merge pull request #6304 from protich/issue/emailaccount-isactive
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-08 14:33:55 -06:00
Peter Rotich
f85f9036a4 mailparse: Misc. Fixes 2022-11-08 19:31:57 +00:00
Peter Rotich
46b7899bc7 mailparse: Thread Entry on Parse Error
Add mail parse error as the Message instead of an empty entry.
2022-11-08 19:31:57 +00:00
Peter Rotich
678098d874 mailparse: FileName On Parse Error
Use subject as a filename if available otherwise default to Message Id
2022-11-08 19:31:57 +00:00
Peter Rotich
30ad9cd477 api: Don't validate email requests
Skip validating the structure of email request - this is important since emails
don't necessarily have all User Information - e.g name and should be failure
resistant.
2022-11-08 19:31:57 +00:00
Peter Rotich
ba2d31cd68 api: Pass Ticket Source to Ticket Create 2022-11-08 19:31:57 +00:00
Peter Rotich
a4e36d399c mailparse: Handle Mail Parse Errors Gracefully
On mail parse error, osTicket typically leaves the email alone and reports it
as a fetch failure - which results in multiple fetch attempts until an admin
manually moves the email out of the Fetch Folder. Most parse errors are caused
by poorly formatted mime message (email) that failes to decode.

This commit adds ability to create a ticket even when osTicket encounters mail
parse error. The entire raw email is attached to the ticket as message/rfc822
(.eml) attachment.
2022-11-08 19:31:57 +00:00
Peter Rotich
75c5cfe91e fetcher: Delayed Mailbox Expunction
As part of post-processing options, when fetching emails, osTicket can archive
(move) or delete (remove) a mail message from the server. When using mail
storage backend like IMAP - both operations requires `expunge` command to truly
commit the changes to the mail server.

That's all good and well, except Laminas Mail (our darling upstream lib)
expunges the mailbox in real-time when a message is moved or deleted. This
creates a problem for osTicket because **expunging causes message sequence
numbers to reset at the server end during the session!!** Which in turn causes
mismatch when we process the next message in the queued sequence. Additionally,
expunging on every message operation cases unnecessary traffic to the mail
server when every second counts.

To resolve the issue - until we switch to using `UIDs` -  this commit simply
bypasses Laminas Mail IMAP's removeMessage function so we can skip expunging on
message move/remove operations. osTicket expunges the mailbox at the end of
fetch session.
2022-11-08 19:22:05 +00:00
Peter Rotich
320981df67 fetcher: Improved Error / Warning Messages and Comments 2022-11-08 19:22:05 +00:00
JediKev
cd3c101246 Merge pull request #6355 from protich/issue/Sendmail+Windows
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-08 12:41:10 -06:00
JediKev
40f16dd2d6 Merge pull request #6350 from protich/issue/SMTP+QUIT
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-08 12:31:11 -06:00
JediKev
6ab019c161 Merge branch '1.17.x' into issue/SMTP+QUIT 2022-11-08 12:29:49 -06:00
JediKev
2b2f0a524e Merge pull request #6344 from protich/feature/fetchorder
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-08 12:25:18 -06:00
JediKev
78c4e5c617 Merge pull request #6307 from protich/issue/setup-session
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-08 12:23:31 -06:00
JediKev
9ab605e699 Merge pull request #6303 from protich/issue/3366
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-08 12:20:00 -06:00
JediKev
c02dce7468 Merge pull request #6302 from protich/feature/mail+plain
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-08 12:14:32 -06:00
JediKev
8c52e042f7 Merge pull request #6301 from protich/issue/mailer++
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-08 12:13:47 -06:00
Peter Rotich
bfccc82057 Merge pull request #6352 from JediKev/issue/mta-typo
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-11-08 11:28:28 -06:00
Peter Rotich
75e111cecc Merge pull request #6308 from JediKev/issue/file-upload-size
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-11-08 11:27:46 -06:00
Peter Rotich
39d7625882 Misc. Typo Fix 2022-11-08 17:23:58 +00:00
Peter Rotich
ac3855a4b5 sendmail: Strip "To" and "Subject" headers
This commit removes "to" and "subject" headers before headers are prepared and
passed to MTA. It's necessary since the headers in question are set directly
via PHP mail() function - leaving them results in duplicate headers.

This is a temp fix needed for Windows installs until we upgrade to the latest
version of Laminas Mail which already has the fix. The version we use currently
doesn't strip the headers on Windows.
2022-11-08 03:59:25 +00:00
JediKev
03eeb8e2b9 issue: MTA Typo
This addresses a small typo (6351) where `l` was being added to each
email string for the Default MTA setting. This removes the `l` so the
emails are displayed properly.
2022-11-07 16:40:21 -06:00
Peter Rotich
977cf9aafb typo: Fix Typo 2022-11-07 22:07:14 +00:00
Peter Rotich
dbeae227de SMTP: Dont send 'QUIT' on __destruct()
This commit attempts to avoid errors / exceptions that cannot be managed from PHP
userspace when an SMTP object is destructed. It also adds a connection timeout
of 5 minutes so old connections can be recreated.
2022-11-07 20:21:45 +00:00
JediKev
45f554adf6 issue: File Upload Size
This addresses an issue where if the Issue Details field or any custom
FileUpload field don't have `configuration` set any file upload to such
fields will fail with `File too large` error. This is due to the
`configuration` not being set so when we check the uploaded file size to
the allowed file `size` from the field's config via `$config['size']` it
fails. This adds a check for the `size` option in the `$config` array
and if not set or set to NULL then we will default to the system setting
`Agent Maximum File Size`.
2022-11-07 13:50:12 -06:00
JediKev
c145b2d8fd Merge pull request #4186 from JediKev/issue/system-timezone-var
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-11-07 11:53:08 -06:00
Peter Rotich
24338c2b5d fetcher: Max Fetch vs. Mail Box Count
This commit addresses a logic bug introduced in commit f1639d4123
2022-11-06 21:45:15 +00:00
JediKev
bc017ecdb5 Merge pull request #6343 from protich/issue/mailfetch_errors
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-03 16:42:16 -05:00
JediKev
268a246b19 Merge pull request #6342 from JediKev/issue/miscellaneous-fixes
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-03 16:41:49 -05:00
JediKev
ca02831c08 Merge pull request #6339 from protich/issue/email-status+upgrader
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-03 16:41:00 -05:00
JediKev
1b4ec3d0e8 Merge pull request #6333 from JediKev/issue/urldecode-dispatcher
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-03 16:40:48 -05:00
JediKev
a1977d9265 Merge pull request #6332 from JediKev/issue/plugin-config-item-exists
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-03 16:40:11 -05:00
JediKev
5c76bd8183 Merge pull request #6329 from JediKev/issue/information-sectionbreak-fields-on-edit
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-03 16:38:51 -05:00
JediKev
7899ae023a Merge pull request #6327 from JediKev/issue/favicons-login-headers
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-03 16:38:32 -05:00
JediKev
5784621fec Merge pull request #6324 from JediKev/issue/schedules-stops_on
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-03 16:38:05 -05:00
JediKev
cecab4a3c4 Merge pull request #6316 from aydreeihn/issue/assign-perm
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-11-03 16:36:42 -05:00
JediKev
5e970061b5 issue: No Ticket For checkStaffPerm()
This addresses an issue where there may be no `$ticket` available which
makes the `checkStaffPerm()` check fatally fail. This adds a check for
`$ticket` before checking the permissions. If no Ticket exists then we
set `Access Denied` error.
2022-11-03 16:09:59 +00:00
JediKev
c2a15b64c7 update: Static isValidFile()
As the name suggests this converts the `FileUploadField::isValidFile()`
method to static. This also updates the relevant calls to static format.
Lastly, this removes the check for `function_exists('exif_imagetype')` as we
now define this if it doesn't exist.
2022-11-03 16:09:59 +00:00
JediKev
9c280b49d6 searchable: Length Param
This adds a minor improvement to the `Format::searchable()` method by adding
a new param called `$length` that will allow you to pass in a specific
length to ensure the text is less than or equal to the supplied length. If
the text length is greater than the supplied length then it will return
`NULL` (ie. not searchable).
2022-11-03 16:09:59 +00:00
JediKev
3568418939 issue: Position CSS
This addresses an issue where some emails contain CSS `position` attributes
that can royally mess up the Ticket View. This adds REGEX to the
`Format::safe_html()` method that will remove any `position` attributes to
avoid rendering issues. This also adds a `position` attribute to the Thread
Entry div to ensure proper rendering.
2022-11-03 16:09:59 +00:00
JediKev
e036fd9a1e issue: Malformed Headers
This addresses an issue where some emails have malformed headers like `From:
"User Name" <email@domain.tld` which causes issues when processing.
This adds a check for malformed headers and if malformed then it will fixup
the header to prevent processing issues.
2022-11-03 16:09:59 +00:00
JediKev
5002bef9f3 issue: SelectionField Typeahead Validation
This addresses an issue where when validating a SelectionField's typeahead
value if there is no `$entry` the check will fail. This ensures `$entry`
exists and is set before using it in the subsequent checks.
2022-11-03 16:09:59 +00:00
Peter Rotich
f1639d4123 fetcher: Mail Fetch Order
osTicket currently fetches messages in LIFO order meaning the most recent messages get
fetched first. This was intentional to avoid possible stalemate when fetched
messages are left in the inbox (Do Nothing Option). However, this can creates
out of order threading issues since subsequest replies can be fetched first.

This commits addresses the issue by changing the logic so we can fetch older
messages first (FIFO order) as long as the numbers of the emails in the folder
being fetched are less than maximum messages to process at a time.
2022-11-03 10:13:56 +00:00
Peter Rotich
c92006e638 mail: moveMessage Return Value
This commit makes sure we're returning the correct result (boolean) when moving
a message. Laminas Mail (upstream) doesn't return a value when moving a message
- success is assumed unless we catch an exception.
2022-11-03 09:42:55 +00:00
Peter Rotich
22edf2b42e mailfetcher: Fetch vs. Archive Folders
This commit removes ambiguity by making it clear which folder we're referencing.
2022-11-03 07:56:56 +00:00
Peter Rotich
384aad1365 mailfetcher: Catch & Log Post Create Errors
This commit adds a try/catch to catch possible exceptions that might happen
post ticket create. This is necessary so we can isolate problematic emails from
segfaulting the entire process (fatal error) or cause it to skip expunging the
mailbox.

The commit also adds debug logging for such errors / exceptions.
2022-11-03 07:56:56 +00:00
JediKev
50bc1a2133 issue: exif_imagetype()
This addresses an issue where if someone doesn't install the PHP `exif`
extension, subsequent calls to `exif_imagetype()` returns `undefined`
errors. This checks to see if the method is defined and if not defines it.
2022-11-02 20:23:02 +00:00
Peter Rotich
aee25d69a5 upgrader: Email Account Status
This commit addresses an issue where we mistakenly disabled email account
status when upgrading to 1.17.x from older versions.

The change makes sure the status is maintained based on what's set on
hashtable.
2022-10-31 21:06:38 +00:00
Peter Rotich
db913bd385 cron: Cleanup Expired Sessions
This commit fixes cron session cleanup to use the new session model
2022-10-28 02:17:44 +00:00
Peter Rotich
c2be4ebf02 Misc. Fixes 2022-10-27 16:23:15 +00:00
Peter Rotich
f2c018409e session: Add onEvent Callback Support
This commit adds ability for session backends to report on certain events,
allowing us to keep app logic out of the session library.

The only event supported at the moment is "onClose"  - triggered right before
the session commits the session data.
2022-10-27 14:59:34 +00:00
Peter Rotich
da6673667e Add Basic Checks for Database Session Record
Make sure User Agent stays same and session id len is 32
2022-10-26 20:42:40 +00:00
Peter Rotich
9ab5b4f18f session: Regenerate session based on Max Idle Time
osTicket renegerates session id 10 seconds after login and that's it. This
commit add a timer to regenerate session id based on user's set max idle timeout
regardless of activity. If session timeout is disabled then it defaults to
every 24 hrs.
2022-10-26 20:17:59 +00:00
JediKev
c00b8e879a issue: urldecode Dispatcher
This addresses an issue where if using a webserver that encodes URLs by
default (like NGINX) some of the AJAX URLs will not resolve. This
ensures the URL is decoded with `urldecode()` before matching and
dispatching.
2022-10-26 14:47:56 -05:00
JediKev
fdf9e4127a issue: Plugin Config Item Exists
This addresses an issue where the Audit Log plugin shows Ticket Views in
the Audit Logs and shows the setting as enabled even when you disable
and save via plugin config. This is due to the current
`Config::exists()` method using the config `->get()` method and checking
the return value to determine `true` or `false`. This is problematic,
especially when values can be `NULL` or `0`. This updates the
`Config::exists()` method to check if the key exists in the session, in
the config array, or in the defaults. If the key does exist then we
return `true` otherwise we return `false`.
2022-10-26 14:45:55 -05:00
Peter Rotich
e2e6c0f436 session: Make Session Name Config Option
This commit adds session name as an option in config file. Also it
adds information about chaining session storage backends.
2022-10-26 19:37:36 +00:00
Peter Rotich
47df2b4409 session: use osTicket\Session Backends
This commit should have probably been broken into smaller commits but the
wholesale change was required since it's an overhaul of how osTicket handles
sessions.
2022-10-26 01:18:21 +00:00
Peter Rotich
f58e1c5d62 session: osTicket Session Backends
This commit adds unified & abstract osTicket Session Handlers / Storage
Backends to make it easy to add and extends storage backends.
2022-10-26 00:21:03 +00:00
JediKev
7b60c57653 issue: Information and SectionBreak Fields On Edit
This addresses an issue where Information and SectionBreak Fields do not
display on Ticket edit for Users and Agents. This is due to no
visibility option for Editable for these field types. Since these field
types don't have Editable visibility when we check for
`isEditableTo[Staff|Users]()` it returns false. This overwrites the two
methods for both field types so that they are visible on Edit if the
field is visible to the respective user-type (User/Agent).
2022-10-24 10:26:13 -05:00
JediKev
61655ec608 issue: Favicons Login Headers
This addresses a small issue where Favicons weren't appearing on the
Staff Login Page. This is due to the Staff Login Page using a different
header than other pages. This adds the Favicons to the Staff Login Page
Headers so that they appear correctly.
2022-10-19 14:48:28 -05:00
JediKev
e2dcbb6991 issue: Schedules stops_on
This addresses a small issue where we were calling `setTimestamp()`
instead of `getTimestamp()` which causes a Fatal Error. We didn't notice
this in previous versions due to pre-PHP 8 it was only a Warning not a
Fatal Error. This updates the line to call the correct method which
avoids any fatal errors.
2022-10-18 14:25:24 -05:00
aydreeihn
b4732b0523 Issue: Agent Permission to Assign Tickets
When we do $thisstaff->getDeptAgents, we are trying to get active agents $thisstaff can assign tickets to. The query done for this groups records in the staff_dept_access table by staff_id, so when we try to do getRoles() for $thisstaff, the only role we can get from staff_dept_access is the first record for $thisstaff.

This commit unsets the dept_access relation so that it can be requeried to get all staff_dept_access records for $thisstaff.
2022-10-13 17:09:55 -05:00
Peter Rotich
b6b63c9916 setup: Use Bootstrap:ini() to initialize session
This commit centralizes sessions init by defering it to Bootstrap:ini() -
when setup scripts needs to start an independent session (e.g cli installer)

Centralized session init is also important because, going forward, it will make it
easy to make changes in one place e.g when changing error_reporting setting
application-wide.
2022-10-10 22:24:44 +00:00
Peter Rotich
48e436f002 setup: Use Bootstrap:ini() to initialize session
This commit centralizes sessions init by defering it to Bootstrap:ini() -
when setup scripts needs to start an independent session (e.g cli installer)

Centralized session init is also important because, going forward, it will make it
easy to make changes in one place e.g when changing error_reporting setting
application-wide.
2022-10-09 22:06:44 +00:00
Peter Rotich
b943a95536 cli: Remove inline noop session handler
This commit removes noop session hadler set by manage.php for cli utils - cli utils generally don't require sessions and are disabled by default.
2022-10-09 21:53:55 +00:00
Peter Rotich
ced0ef4da3 session: Add Noop Session Backend
osTicket support uploading your own logos as well as login backgrounds and
calls logo.php (on both panels) to fetch the image in question. Previously we
didn't care about session data so session handler was set to an inline noop
function as a way to bypass starting a "real" session. The problem with the
approach is; if osTicket is hosted behind a proxy with multiple web severs in the backend,
the proxy needs to send all requests to the same server for specific user
session. To do so session name (OSTSESSID) is used to route requests from the same session
to the same backend server.

This commit adds a noop session backend allowing us to start a session while
still ignoring data writes. Noop backend is used when DISABLE_SESSION is
defined and set to false.
2022-10-09 20:46:40 +00:00
Peter Rotich
a9b5749656 email: Split Auth updates & getters into individual routines
This commit doesn't add anything useful other an splitting Auth updates & getters into individual routines per backend.
2022-10-09 05:24:01 +00:00
Peter Rotich
5efd9f14dd email: Make sure Email Account is Active 4realz!
This commit adds a check to make sure an Email Account has valid credentials
when determining if the account is active. It's necessary so we can detect
deleted credentials or expired refresh token in the case of accounts with
oauth2 backends.
2022-10-09 05:20:23 +00:00
Peter Rotich
b0e5ac83f2 smtp: Use proper name when saying What's Up (HELO/EHLO)
This commit addresses an issue  where outgoing email can get rejected when the
target mail server is tight-assed - requiring a valid host when saying
helo/ehlo.

We were setting the name to null which resulted in localhost being used as the
name. Now we're asking the OS to give us the proper hostname of the server -
hopefully the server admin has the correct hostname and reverse-lookup setup
correctly for better deliverability.
2022-10-09 00:04:37 +00:00
Peter Rotich
7c1b97b306 mail: Add plain:// encryption scheme hint
When configuring an email, starting with osTicket v1.17, the adminstrator can
hint to the desired encryption when using non-stantard ports by prefixing the
`hostname` with an encryption scheme  e.g `tls://` or `ssl://`. Using hints is
much better and less confusing than the old ways of presenting a user with
`IMAP` and `IMAP + SSL` as protocol selections - when infact we could use the
port number, in the backend, to determined the encryption.

This commit adds support for the opposite  - by allowing an admin to force
unencrypted connection even when using standard encryption ports by simply
adding `plain://` as the scheme hint.
2022-10-08 22:14:10 +00:00
Peter Rotich
23a80592e9 mail: Message-Id
This commit adds a routine to get Message-Id and also adds a check for an
invalid Id when trying to set a Message Id.

Please note that invalid ID are silently ignored since the upstram library
generates one.
2022-10-08 19:47:58 +00:00
Peter Rotich
845e500844 mailer: Spoofing & Originator
Spoofing: When an SMTP Account **DOES NOT** allow spoofing then set the Sender
(Envelope FROM) to the account's email address and leave the Header FROM as
set

Originator: When an SMTP account send fails - we now reset the Originator /
Sender to the original From Address, incase spoofing setting changed the
Sender

* Spoofing - when an SMTP Account does NOT allow spoofing then set the Sender
(Envelope FROM) to the account address and leave the Header FROM as set.

* SetOrinator - When an SMTP send mails we now reset the Originator / Sender to the original
From Address just incase spoofing setting had changed the Sender.
2022-10-08 19:42:59 +00:00
Peter Rotich
0564438c9c Merge remote-tracking branch 'upstream/1.17.x' into 1.17.x 2022-10-06 17:52:46 +00:00
Peter Rotich
7ef7dec03c Merge remote-tracking branch 'upstream/develop' into 1.17.x 2022-10-06 17:52:36 +00:00
JediKev
03f8813348 Merge pull request #6292 from JediKev/cli/user-import
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-10-06 12:32:34 -05:00
JediKev
1301db4935 Merge pull request #6297 from JensEB/patch-1
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-10-06 12:27:52 -05:00
JediKev
c431d26bb4 Merge pull request #6296 from protich/issue/Email_Message-Id
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-10-06 12:23:03 -05:00
Peter Rotich
60c8c8841e mailer: Add Sender Header
Sender is equivalent to -f from@address in mail() interface which get used as
envelope FROM address - this is important when header FROM is spoofed.
2022-10-06 16:57:39 +00:00
Peter Rotich
020fa0d3db mailer: Lint Fix
$type is a protected static upstream without a getter!
2022-10-06 16:05:12 +00:00
Peter Rotich
2223877c6a mailer: Add InReplyTo Header Interface
In-Reply-To: Unbreak My Soul
2022-10-06 03:46:08 +00:00
Peter Rotich
00981554be mailer: Add References Header
Use References Header to add references instead of using Generic Headers which might break due encoding
2022-10-06 03:46:08 +00:00
Peter Rotich
aaee6b0fde mailer: Add Return-Path Header Interface
This commits adds Return-Path Header interface to osTicket\Mail\Message
2022-10-06 03:45:59 +00:00
JensEB
ccd8445e97 Update class.mail.php 2022-10-05 20:18:54 +02:00
JensEB
b84547b0b6 POP3 Configration can not saved
First error: abstract functions can not be private. It have to be protected or public...

Second error: the pop3 login function doesn't respond anything on successful login. This will be return false in MailBoxProtocolTrait::basicAuth()
2022-10-05 14:17:09 +02:00
Peter Rotich
c08a8a8a21 mailer: Make Headers Valid Again
Message-Id: osTicket uses encoded message Id to thread emails on reply.
Laminas Mail, the new backend we're mangles up the Message-Id when set as a
generic header. This commits corrects the issue by using MessageId object -
making sure it is ASCII encoded.

Date: Date is auto-added upstream - so we're removing it from Mailer to
avoid double header issues - but if need be, you can overwrite it by setting
your own fake date!
2022-10-05 05:49:06 +00:00
JediKev
4c43e46f68 cli: User Import
This addresses issue 6291 where importing users from CSV via command
line causes a fatal error. This is due to attempting `fclose()` on a
stream that has already been closed. The CsvImporter `__descontruct()`
method already closes the stream so when we get to the end of the import
and attempt to call `fclose()` in the CLI method, it causes a fatal
error as the stream is no longer valid (as it's already been closed).
This adds a check to see if the stream is a valid resource and if so
then we close it, otherwise we skip and continue (as it's already
closed).
2022-10-03 15:34:55 -05:00
JediKev
1d8b79023e Add Release Notes for v1.17 2022-09-30 17:09:42 +00:00
JediKev
1eadd02354 Merge pull request #6290 from protich/issue/plugins-backwards-compatibility
Reviewed-By: aydreeihn <adriane@enhancesoft.com>, JediKev <kevin@enhancesoft.com>
2022-09-30 12:04:08 -05:00
Peter Rotich
3163972b1e plugin: Add getNamespace to Base 2022-09-30 15:30:40 +00:00
Peter Rotich
5787f9ae0d plugin: Add New Instance
This commit fixes a bug where blacklisted plugin cannot add a new instance post install.
2022-09-30 14:57:15 +00:00
Peter Rotich
7b26f6654a plugin: Make Plugin Base Class Nice
This commit addresses backward compatibility issue related to the data sent to
pre_save hook. Older plugins expected clean data whereas the new interface
provided to_db data which might be json formatted for example depending on the
config field database format. Now we will send the clean data to pre_save then
transform the results for database storage via the form / fields.
2022-09-30 14:48:28 +00:00
Peter Rotich
41b19db3f0 Merge pull request #6288 from protich/1.17.x
Reviewed-By: osTicket Devs <devs@osticket.com>
2022-09-29 12:46:21 -05:00
Peter Rotich
1b7f41aab3 Merge pull request #6287 from protich/1.17.x
Reviewed-By: osTicket Devs <devs@osticket.com>
2022-09-29 12:39:45 -05:00
Peter Rotich
65430abe20 Merge pull request #6285 from protich/issue/file-key-lookup
Reviewed-By: osTicket Devs <devs@osticket.com>
2022-09-29 12:39:20 -05:00
Peter Rotich
9ed39d9c95 Merge pull request #6284 from protich/issue/manage-users-password-policy
Reviewed-By: osTicket Devs <devs@osticket.com>
2022-09-29 12:38:37 -05:00
Peter Rotich
06e334fa89 Merge pull request #6283 from JediKev/issue/user-agent-password-reset
Reviewed-By: osTicket Devs <devs@osticket.com>
2022-09-29 12:38:15 -05:00
Peter Rotich
11c3b2e2b4 Merge pull request #6282 from JediKev/issue/imagesx-boolean
Reviewed-By: osTicket Devs <devs@osticket.com>
2022-09-29 12:35:08 -05:00
Peter Rotich
ce2b1ef3d4 Merge pull request #6281 from protich/issue/mailbox-exceptions
Reviewed-By: osTicket Devs <devs@osticket.com>
2022-09-29 12:34:44 -05:00
Peter Rotich
1f0a5ed086 Merge pull request #6279 from protich/issue/form-notice
Reviewed-By: osTicket Devs <devs@osticket.com>
2022-09-29 12:34:23 -05:00
Peter Rotich
08b7a18080 Merge pull request #6280 from protich/issue/misc-v116-fixes
Reviewed-By: osTicket Devs <devs@osticket.com>
2022-09-29 12:33:58 -05:00
Peter Rotich
423a0d74b1 Merge pull request #6278 from protich/issue/email-parse-error
Reviewed-By: osTicket Devs <devs@osticket.com>
2022-09-29 12:33:32 -05:00
Peter Rotich
39319e5b3d Merge branch '1.16.x' into 1.17.x 2022-09-29 17:25:45 +00:00
Peter Rotich
d98bbfcdfe Merge remote-tracking branch 'upstream/develop' into 1.16.x 2022-09-29 17:24:19 +00:00
Peter Rotich
d149ea0d42 v1.17 Misc. Fixes 2022-09-29 16:24:56 +00:00
Peter Rotich
21c71c6ed2 file: Possible Key Collision
This commit is a temporary fix for possible Fatal Crash when file key (hash
lookup) matches more than one object on lookup. See TODO note for more
information.
2022-09-28 22:45:28 +00:00
JediKev
5d06ee4618 issue: imagesx Boolean
This addresses an issue where if `imagecreatefromstring()` fails it
returns false (boolean) and we then pass that to `imagesx()`. This
method only accepts Gdimage (since PHP 8) so this adds a check to see if
`$image` can be set and if so we continue otherwise we skip the `if()`
completely and go straight to sending the data.
2022-09-28 21:36:06 +00:00
Peter Rotich
ebfc1d89f6 bug: Users Password Policy
Use the correct backend id on Users > Password Policy dropdown
2022-09-28 21:22:14 +00:00
JediKev
d3de159915 issue: User/Agent Password Reset
This addresses an issue where password reset is triggered even though the
user/agent doesn’t have a password or the authentication backend is
external.
2022-09-28 21:10:14 +00:00
Peter Rotich
81d5cb351b mail: Catch Possible Exceptions and Errors
This commit adds try/catch to MailBox related routines that shouldn't
necessarily affect email processing on failure.
2022-09-28 19:42:10 +00:00
Peter Rotich
4c0341e232 bug: Fix Sprintf Param placement 2022-09-28 17:40:15 +00:00
Peter Rotich
6e54e8106c forms: Add getNotice func. to DynamicFormEntry
This commit fixes a bug where getNotice was undefined when rendering a dynamic
form entry. It now delegates getting a notice, if any, from the form impl.
2022-09-28 17:33:31 +00:00
Peter Rotich
459520e8ed fetcher: Fail Safely on Email Parse Error
This commit adds ability to log email parse errors. This can happen if the
system fails to fetch complete raw email or when the email content is malformed
somehow.
2022-09-28 17:29:10 +00:00
Peter Rotich
e724ccb927 Merge pull request #6272 from protich/issue/ticket-denied
Reviewed-By: osTicket Team <devs@osticket.com>
2022-09-27 16:41:15 -05:00
Peter Rotich
5c5bd41e37 Merge pull request #6276 from protich/issue/filestoragebackend-errors
Reviewed-By: osTicket Team <devs@osticket.com>
2022-09-27 16:40:59 -05:00
Peter Rotich
1a47825aa6 Merge pull request #6271 from protich/issue/mailer-from-address
Reviewed-By: osTicket Team <devs@osticket.com>
2022-09-27 16:40:45 -05:00
Peter Rotich
b67f0a6e53 Merge pull request #6270 from protich/issue/attachments
Reviewed-By: osTicket Team <devs@osticket.com>
2022-09-27 16:40:26 -05:00
Peter Rotich
e8959f6af3 Merge pull request #6277 from aydreeihn/issue/plugin-inst-blacklist
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-27 16:38:50 -05:00
Peter Rotich
be178da5ca fetcher: Log Last Fetch on attempt
Log last fetch timestamp on login and before processing emails so that the
mailbox can yield to other mailboxes in the fetch queue.

Also catch Throwables instead of just Exceptions
2022-09-27 21:22:00 +00:00
Peter Rotich
e027dcc433 fetcher: Fetch Order based on Last Activity
Sort MailBoxes to fetch based on the last activity in ASC order. This is
necessary to give every mailbox a chance to be fetched.
2022-09-27 21:22:00 +00:00
Peter Rotich
79209144d1 fetcher: Catch Throwable
Catch Generic Exceptions / Errors
2022-09-27 21:21:07 +00:00
Peter Rotich
e685636ebc files: Catch possible Storage Backends Errors
Catch possible throwables (Exceptions and Errors) from file storage backends.
This is necessary so we don't crash while trying to save a file when storage
backend is having issues or bugs. osTicket uses database as fallback storage.
2022-09-27 21:07:20 +00:00
Peter Rotich
6932ea84cf Merge remote-tracking branch 'upstream/develop' into develop 2022-09-27 20:54:54 +00:00
aydreeihn
1ba8d37afc Issue: File Storage Plugins Blacklist
This commit will add the file storage plugins to the multi instance blacklist until we update them to offer multi instance support.
2022-09-27 14:47:28 -05:00
Peter Rotich
58f64e65b0 fetcher: TicketDenied Exception
Address a bug on how TicketDenied Exception is handled
2022-09-27 00:59:02 +00:00
Peter Rotich
75605a3fe9 mailer: Reset FROM Address when SMTP fails
This commit adds ability to reset FROM address when SMTP attempt fails. This is
important becacause of Spoofing Allowed setting.
2022-09-27 00:54:48 +00:00
Peter Rotich
2218aaca75 mailer: Skip Missing Attachment Files
This commit addresses an issue where mailer would crash due to missing
attachment files when sending out emails.
2022-09-26 14:25:25 +00:00
Peter Rotich
557d79f921 Merge pull request #6268 from ChrisTG742/patch-2
Reviwed-By: Peter Rotich <peter@osticket.com>
2022-09-25 23:12:53 -05:00
Chris
12a4cb093b Fix for https://github.com/osTicket/osTicket/issues/6267
Fix for Issue https://github.com/osTicket/osTicket/issues/6267, the order of the vars in line 691 was wrong.
2022-09-24 14:08:39 +02:00
JediKev
40d6ecbdd7 Merge branch 'develop' into 1.17.x 2022-09-23 18:59:18 +00:00
JediKev
edc7993289 Merge pull request #6262 from protich/issue/mailer-invalid-recipients
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-09-23 13:49:51 -05:00
Peter Rotich
d7d37c4cce Mailer: Change FromAddress to EmailAddress object + Spoofing
This commit refactors how FROM address is set and used within the Mailer. It's
now set as EmailAddress object - making it easy to get Email and Name
separately.

We're also removing Spoofing Check when determining possible SMTP accounts to
use for outgoing emails. It's now checked while attempting to send a Message.
If the account in question doesn't allow Spoofing then the FROM header is reset
to the accounts email address.
2022-09-23 07:37:56 +00:00
Peter Rotich
551f786464 email: EmailAddress:__toString()
This commit partially revers 5d799ecd to return Email when EmailAddress is
casted to String instead of Email Address (email+name)
2022-09-23 06:53:27 +00:00
Peter Rotich
046f432765 mailer: Skip Invalid Email Recipients
This commit adds ability for Mailer to skip invalid email recipients when
sending out an email. A Mailer warning with the recipient info (name & email
address) is logged.

For uniformity sake EmailContact interface now requires getEmailAddress() to be
defined downstream. This was necessary because some of the objects (e.g Staff)
return a name when casted to string (__toString) and changing it will affect
variables used in email templates and possibly leak the agents email.
2022-09-23 06:47:44 +00:00
Peter Rotich
b1e5386491 Merge pull request #6261 from JediKev/issue/undefined-var-orm
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-22 14:20:35 -05:00
JediKev
4009881ad8 issue: Undefined Variable ORM
This addresses an issue where a wrong variable was used which caused
undefined variable errors with the built-in tests. This corrects the
variable from `$sql` to `$exec->sql`.
2022-09-22 13:39:30 -05:00
JediKev
f8e6c327f1 Merge pull request #6258 from JediKev/issue/session-cookie-refresh
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-09-22 12:36:21 -05:00
JediKev
1630459a21 issue: Session Cookie Refresh
This addresses an issue where we were not renewing the cookie expired
time correctly when refreshing the session. This updates
`refreshSession()` to accept a `$refreshRate` defaulting to 60
(seconds). This also updates the `if()` statement from a negative to a
postive logic for better readability.
2022-09-22 12:19:31 -05:00
JediKev
d4ec4dd143 Merge pull request #6260 from protich/issue/plugin-instances
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-09-22 09:58:09 -05:00
JediKev
3a486600b4 Merge pull request #6259 from protich/issue/plugins-version
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-09-22 09:54:47 -05:00
JediKev
250f4195d1 Merge pull request #6257 from JediKev/issue/fix-upgrader-session-issues
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-09-22 09:47:12 -05:00
JediKev
9b3cd60bed Merge pull request #6256 from protich/1.17.x
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-09-22 09:43:09 -05:00
Peter Rotich
5607751671 plugins: Multi-Instance Blacklist
Some Plugins DO NOT or SHOULDN'T support multiple instances due design issues
or simply because of the fact that it doesn't make sense to do so.

The blacklist will be removed down the road once plugins are forced to declare
compatiple core osTicket version and if it supports multiple instances.
2022-09-22 02:20:51 +00:00
Peter Rotich
80bcc191d1 plugins: Make Plugins Upgradeable Again!
This adds ability and interface to auto-trigger plugins upgrade or downgrade
when there's a version mismatch on-load.

The base plugin class simply updates the version (for now) - the downstream
Plugins should implement the actual upgrade / downgrade process as needed,
especially if it creates database tables or needs to change stored config info
to match the new version format.
2022-09-22 01:47:09 +00:00
JediKev
311089a62e issue: Fix Upgrader Session Issues
This addresses session issues when upgrading from versions pre-1.7. This
bypasses the DBSessionBackend if `MAJOR_VERSION` is not defined or an
upgrade is pending and the `getDBVersion()` method returns `true` to
default to using the local session storage.
2022-09-21 15:55:15 -05:00
Peter Rotich
21e3a407dd smtp: Fix Crash on SMTP Error
This commit addresses a fatal error when system tries to log an error on SMTP account exception.
2022-09-21 20:32:59 +00:00
Peter Rotich
f3446599ea Merge pull request #6253 from ChrisTG742/patch-1
Reviewed-By: <peter@osticket.com>
2022-09-21 13:03:28 -05:00
Peter Rotich
5d799ecdf4 email: Add getEmail to EmailAddress
This commits adds getEmail to EmailAddress class to provide an interface for
osTicket Mailer to get the email address without the name.
2022-09-21 17:33:19 +00:00
Peter Rotich
6c2ecad220 mail: Fix Namespace Type 2022-09-21 16:52:32 +00:00
Peter Rotich
f10de7af90 Merge pull request #6254 from protich/issue/email_encoding
email: Set Default Email Message Encoding to UTF-8
2022-09-20 19:05:03 -05:00
Peter Rotich
f07d2c07b9 Merge pull request #6251 from protich/issue/mailfetch
Mail Fetcher Fixes
2022-09-20 19:04:50 -05:00
Peter Rotich
8954f05b6a mailer: Make Laminas Mail Happy Again
This commits split email and name to avoid the need for Laminas Mail to parse
the email address parts from a string - saving a couple of CPU cycles.
2022-09-20 14:31:28 +00:00
Peter Rotich
4656cf4cbc email: Set Default Email Message Encoding to UTF-8
This commits sets UTF-8 as the default encoding. It's necessary because - by
default Laminas Mail uses ASCII encoding - which can cause `invalid header
value` exception when an email address of the sender or a recipient has an
accented character.

Please note that individual Mine Parts set thier own encoding as needed - by
default osTicket uses base64 to encode `text/{plain/html}` parts to reduce the
overrall size of the Message - configuratable option to make `quoted-printable`
encoding an option is planned.
2022-09-19 23:49:10 +00:00
Peter Rotich
3decbe7863 Mail Fetcher: Handle Denied Tickets
This commit addresses a bug where the new Mail Fetcher failed to handle Denied
Tickets (via banlist/filter) correctly. In addition, email parsing is now
delagated to Mail Parser utility class.
2022-09-19 17:58:39 +00:00
Peter Rotich
1eebcd6661 email: Get Host Info from Email Account Setting
This commit addresees an issue where mail fetcher crashed when logging a
warning on excessive fetch errors. As part of the fix, Email AccountSetting is
now the single source of truth when it comes to Email Account information.
2022-09-19 17:58:39 +00:00
Chris
d5545b4e82 Update class.mail.php
Fix for typo in function auth(): expect need to be set to 334 instead of 234 here.
2022-09-19 13:29:54 +02:00
JediKev
a1a3d450b7 Merge branch 'develop' into 1.17.x 2022-09-15 19:31:29 +00:00
JediKev
ec331a549f Merge branch 'develop' into 1.16.x 2022-09-15 19:22:07 +00:00
JediKev
365a57ea3c Merge branch '1.15.x' into develop 2022-09-15 19:20:27 +00:00
Peter Rotich
0f81f5f3ac Merge pull request #6176 from JediKev/oops/jquery-ui-images
Reviewed-By:  Peter Rotich <peter@osticket.com>
2022-09-13 08:39:29 -05:00
JediKev
356e156ab2 Add Release Notes for v1.17-rc4 2022-09-12 19:53:59 +00:00
JediKev
6607facb6e Merge pull request #6249 from protich/issue/mail
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-09-12 14:48:13 -05:00
JediKev
1247609af9 Merge pull request #6246 from protich/1.17.x
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-09-12 14:45:48 -05:00
Peter Rotich
c71ddade63 mailer: Dropped Attachments
This commit fixes a bug that caused attachments to be dropped
2022-09-12 17:49:45 +00:00
Peter Rotich
2318714e25 plugin: Disable Multi-intance Support for 2FA plugin
Official 2FA Plugin  doesn't support multiple instances at the moment due to how the
plugin loads config info for versions <= 0.3
2022-09-12 03:11:14 +00:00
Peter Rotich
6de79a0bd4 mail: Mixed Mime Message with mixed multiparts
This commit addresses nesting issue when a message is mixed (with inline images
or attachments) and also has alternate content (plain & html).
2022-09-11 02:59:38 +00:00
Peter Rotich
f8f5d3dd7d 2fa: Fix 2FA Backend Registry
This commit updates 2FA Backend registery to match v1.17.x model
2022-09-08 21:09:39 +00:00
Peter Rotich
abbe1d2d99 Merge pull request #6230 from protich/feature/oauth2
Reviewed-By: osTicket Devs <devs@osticket.com>
2022-09-08 16:03:25 -05:00
Peter Rotich
c6ac4e7452 Merge pull request #6245 from JediKev/issue/dispatcher-include_once
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 16:02:44 -05:00
JediKev
dab490dc27 issue: Dispatcher include_once
This addresses issue 6218 where using `include` for things like
`api.tickets.php` fails with fatal error of `Cannot declare class xxx,
becuase the name is already in use`. This changes `include` to
`include_once` so that we avoid fatal errors and the files still get
included.
2022-09-08 11:20:42 -05:00
Peter Rotich
09197da959 Merge pull request #6241 from JediKev/php/8.1-support
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 11:19:53 -05:00
JediKev
dd2b9a4309 fix: Upgrader Issues
This addresses some various Upgrader issues when attempting to upgrade
from an older version (eg. `v1.6` and `v1.7`). This includes catching
more exception types, making a method static, adding some variable
checks before calling `count()`, checking for session ID before setting
custom handlers in the session class, and last (but not least) a
try-catch statement around `$__db->query()` calls so that we can catch
Excpetions without exiting.
2022-09-08 11:16:02 -05:00
Peter Rotich
eed1b66884 Merge pull request #6232 from jasplin/fix/storage-plugin-unhandledexception
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 10:59:35 -05:00
Peter Rotich
32877dcac0 Merge pull request #6243 from aydreeihn/issue/installer-yaml
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 10:58:12 -05:00
Peter Rotich
1388829286 email: Rename AccountOptions to AccountSetting
Options is a little confusing in the context used.
2022-09-08 08:26:36 +00:00
Peter Rotich
7123403e4f Merge pull request #6240 from JediKev/issue/searching-numbers
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 02:43:52 -05:00
Peter Rotich
774771cd8e Merge pull request #6235 from JediKev/issue/staff-ticket-open-session
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 02:43:07 -05:00
Peter Rotich
8f88a5513a Merge pull request #6239 from JediKev/issue/external-auth-regenerate-session
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 02:42:01 -05:00
Peter Rotich
5b76b887ac Merge pull request #6238 from JediKev/issue/unique-variable-names
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 02:40:46 -05:00
Peter Rotich
42e7b713f3 Merge pull request #6216 from JediKev/mailparse/thread-entry-recipients-to
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 02:39:05 -05:00
Peter Rotich
5717bdd427 Merge pull request #6233 from JediKev/issue/auth-backend-getBkId
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 02:38:31 -05:00
Peter Rotich
9f2ea7b0f9 Merge pull request #6228 from JediKev/installer/checking-existing-install
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 02:37:26 -05:00
Peter Rotich
9cb4408db5 Merge pull request #6234 from JediKev/plugins/audit-enable
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 02:36:39 -05:00
Peter Rotich
8e8d4f4fe1 Merge pull request #6242 from Wyrrrd/reflection
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-09-08 02:35:34 -05:00
Peter Rotich
2fa077aec7 plugins: Plugin Instance Config Class
This commit adds additional enhancements to allow Instances to dynamically set
Config Class. See e4f594c
2022-09-08 07:26:25 +00:00
Peter Rotich
481a047576 email: Validate Basic Auth Credentials
This commit adds validating when settting username and password.
2022-09-08 06:01:36 +00:00
JediKev
c24ee5753e issue: Fix Deprecation Warnings (line_endings)
This fixes the Deprecation warnings when attempting to set INI directive
`ini_set('auto_detect_line_endings', true)`. This directive is no longer
supported so this removes the calls completely.
2022-09-07 10:08:28 -05:00
JediKev
22b599e314 issue: Fix Deprecation Warnings (Serializable)
This addresses the Deprecation warnings when attempting to implement the
Serializable interface without defining the `__serialize()` and
`__unserialize()` methods. This updates the code for each class that
implements Serializable to define these methods and to call the original
methods we have.
2022-09-07 10:08:21 -05:00
Peter Rotich
5e53b1a131 issue: PasswordPolicyBackend
Use plugin getBkId() instead of getId() inline with plugins multi-instance
support.
2022-09-06 16:12:33 +00:00
aydreeihn
6780f29e74 Issue: Installer YAML
This commit fixes an issue where some default data was not being inserted into the database for fresh installs:

1. Sales Department
	The Sales Department was not being created because we were trying to set an sla_id before the SLA table was created.

2. Banlist
	The default Filter Rule and Action for the System Banlist was not being created because the save function now calls the ORM save function, so it is no longer calling save_rules and save_actions for the installer. We also have to change the YAML to refer to the fields as w,h,v instead of what, how, value for them to be recognized correctly.

It also fixes some spacing issues in the Filter class.
2022-09-06 09:51:53 -05:00
Peter Rotich
a706866844 plugins: Fix PluginConfig config load bug
This commit addresses an issue where Password Policy Plugin crashed on login
when password expiration is set to "Never Expire" and php mode set to strict.

This is because v1.17 changed how plugin instances config values are stored to match
the actual field format (using to_db), but on load - PluginConfig mistakenly
defaulted to database value when to_php returned an empty value - which is
indeed correct value when selection was empty option.
2022-09-03 01:10:44 +00:00
Peter Rotich
4ee44d4830 plugin: Fix message typo on instance update 2022-09-02 17:17:11 +00:00
Peter Rotich
76bf772568 email: Check if global error is set already on update failure 2022-09-02 16:59:43 +00:00
Peter Rotich
e4f594c2d3 plugins: Allow Plugin Instances to set Config Form
This is necessary to allow plugin instances to use different config forms as
desired depending on internal logic. For example OAuth2 plugin can have both
Authentication and Authorization instances which require slightly diffrent
fields and validation.
2022-09-02 16:50:24 +00:00
Peter Rotich
246c144513 basic-auth: Use updated PasswordField options
This commit refactors password filed in Basic Authentication form to utilize
the PasswordField correctly.
2022-09-02 16:47:18 +00:00
Peter Rotich
bc154434dd forms: Add ability to disable ChoiceField fields 2022-09-02 16:45:57 +00:00
Peter Rotich
681bea0839 forms: Add ability to add notice (warning) to forms
This commit adds ability to inject and display a warning message on dynamically
rendered forms. This is helpful when various components want to add such
warnings while not having full control of the display logic.
2022-09-02 16:38:03 +00:00
Wyrrrd
55f61390cc Replace hacky way with ReflectionClass 2022-09-01 14:37:56 +00:00
Peter Rotich
e705ff0f6c email: Add ability to stash / restore data
his is adds ability to stash data before doing external redirect when
configuring External Authorization e.g OAuth2
2022-08-29 21:35:53 +00:00
JediKev
e00003f68a issue: Searching Numbers
This updates the ticket search mechanism to check if the supplied keyword is
a number. If the keyword is a number we will only search Ticket Numbers to
improve search performance.
2022-08-29 15:22:56 +00:00
Peter Rotich
3024d7f50c smtp: Fix Configure Mailbox Authentication Error
This commit addreses an error that happens when "Same as Mailbox"
authentication is selected when configuring SMTP Account.
2022-08-29 05:35:54 +00:00
JediKev
8325226046 issue: External Auth Regenerate Session
This addresses an issue where we are rotating the session on each login
to help prevent session fixation. However, this causes an issue when
using an External Authentication Backend such as OAuth2. This remove the
`regenerateSession()` calls from the `login()` methods and instead we
will set a time bomb that will auto regenerate the session a certain
amount of time after login. This way external auth backends will still
function properly and we can still regenerate the session.
2022-08-26 11:38:44 -05:00
JediKev
0dc5a02e4a issue: Unique Variable Names
This addresses an issue where we are not checking the Field Variable
Names with case-insensitive comparison. This causes issues as the
database doesn't care about case and sees the two variables as the same.
This hardens our variable name checks to convert existing names and the
new name(s) to lowercase for case-insensitve comparison. With this
change it will no longer allow duplicate variable names (with a
difference of case).
2022-08-26 11:31:35 -05:00
JediKev
7796d60c1d plugins: Audit enable()
This addresses an issue where the Audit Plugin relies on `enable()`
being called in order to create the `_audit` table required for saving
audit data to the database. This adds the method back temporarily until
we can rewrite the plugin to fit the new standards. This also attempts
to call `enable()` on install so that the table can be created. If the
plugin doesn't have an `enable()` method it defaults to the parent class
Plugin `enable()` which just returns `true`.
2022-08-25 13:59:13 -05:00
JediKev
4f3d3cff7c issue: Staff Ticket Open Session
This addresses an issue where we are not regenerating the session for
Staff members after they've opened a Ticket. This adds
`$thisstaff->regenerateSession()` after creating a Ticket so that the
session is regenerated.
2022-08-25 13:27:31 -05:00
JediKev
29f01c090a issue: AuthenticationBackend getBkId()
This addresses an issue where we are calling `getId()` instead of
`getBkId()` in some places when registering and listing plugin instances. This causes
an issue if a User is auto-created via something like LDAP and the
`backend` is set to something like `ldap.client.p[id]i[id]`. When we get
available/registered backends we are not selecting the appropriate ID so
the backend is considered "not in the list" and does not let the User
authenticate. This changes all the calls to `getBkId()` to ensure we are
selecting the appropriate ID.
2022-08-25 10:42:25 -05:00
John Asplin
ca5932ac6f add try/catch to get inline email image 2022-08-23 17:42:49 +01:00
Peter Rotich
ab9a810181 email: Add routine to log fetch errors 2022-08-23 00:50:56 +00:00
Peter Rotich
bd300c44d3 Basic Auth: Remove Maxlength
This commit removes maxlength restriction of 30 added upstream by default to TextboxField.
2022-08-22 15:35:04 +00:00
JediKev
a3f2e24647 installer: Checking Existing Install
This addresses an issue with PHP 8.1 where on install we run a query to
see if we can select data from the ost_config table to see if there is
already an instance installed to avoid overwriting data. In PHP 8.1 this
will throw a fatal error which kills the installer. This adds a `try {}
catch() {}` statement around the call so that if it does throw an error
it continues without issues. This is what we want anyways, if the query
returns false or an error then we want to continue.
2022-08-19 10:54:03 -05:00
JediKev
34c64f14b4 Add Release Notes for v1.17-rc3 2022-08-05 14:56:56 +00:00
JediKev
e4db87635f Merge pull request #6217 from protich/feature/oauth2
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-08-05 09:49:50 -05:00
Peter Rotich
fdc5b0fa82 oauth2: Verify Config Signature
This commit adds ability to verify config signature when getting Access Token.
2022-08-04 21:04:10 +00:00
Peter Rotich
d9b41f4e5c plugin: Plugin Instance Config Signature
This commit addresses a bug where config signature routine used ksort
incorrectly - resulting in same signature everytime.
2022-08-04 21:04:10 +00:00
Peter Rotich
fa8dc24d0e email: OAuth2 Backend Change
Update OAuth2 backend on update since it could be changed on instance update.
2022-08-04 21:04:04 +00:00
Peter Rotich
265065c1d9 email: Port Password to the new Encryption Scheme 2022-08-04 19:13:30 +00:00
JediKev
a82af69845 mailparse: thread_entry_recipients to
This addresses an issue where some emails don't have a To header which
causes a fatal error when parsing mail. This is due to assuming To is set
and passing it to array_unique which expects the value to be an array. This
adds a check to see if To is set and if so we call array_unique otherwise we
default to an empty array.
2022-08-04 19:13:24 +00:00
JediKev
d821546a1d Add Release Notes for v1.17-rc2 2022-08-02 19:05:37 +00:00
JediKev
ca7d12fc49 Merge remote-tracking branch 'origin/1.17.x' into 1.17.x 2022-08-02 18:58:37 +00:00
JediKev
99e415f7a9 Merge pull request #6211 from protich/feature/oauth2
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-08-02 13:57:40 -05:00
Peter Rotich
4576a6ef07 Merge pull request #6200 from JediKev/issue/manually-sorted-topics
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-08-01 13:15:21 -05:00
Peter Rotich
55f3dd3c04 Merge pull request #6199 from JediKev/i18n/default-ticket-queue
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-08-01 13:14:14 -05:00
Peter Rotich
aef471b10a Merge pull request #6214 from JediKev/issue/queue-export-headings
Reviewed-By: Peter Rotich <peter@osticket.com>
2022-08-01 13:12:41 -05:00
Peter Rotich
4da6fb07a0 email: Don't load Instance Config when Auth is getting reconfigured. 2022-08-01 17:41:30 +00:00
Peter Rotich
90ed880b0b email: Check Auth Backend on Save
Make sure authentication backend is configured when selection is made, even if
the account is disabled.
2022-08-01 17:35:34 +00:00
Peter Rotich
72b2a2492a email: Use full Auth backend string
This commit also adds warning when reconfiguring auth backend.
2022-08-01 17:32:11 +00:00
JediKev
4744975840 issue: Queue Export Headings
This addresses an issue where updating the Queue Export Column Headings
doesn't actually save the changes. This is due to using the previous heading
regardless of the headings being passed in. This adds a check for the column
heading in `$fields` and if exists we use that otherwise we default back to
the previous heading.
2022-07-27 21:24:10 +00:00
Peter Rotich
8a8c1a162b plugin: Plugin Instance Config
This commit addresses an issue where the plugin cached the config of the first
instance loaded. The change delegates config loading to the instance when side
loading on bootstrap.
2022-07-27 18:28:32 +00:00
Peter Rotich
fa6cc0402b email: SMTP Open Relay
This commit addresses an issue where selecting "None - No Authentication" on
STMP setting resulted in a error of "Configure Authentication".
2022-07-27 16:36:15 +00:00
Peter Rotich
97a9b0af10 config: Accept Defaults
This commit makes it possible to pass default config values to Config class on init
2022-07-22 15:29:01 +00:00
JediKev
9f51d4673a Add Release Notes for v1.17-rc1 2022-07-20 18:56:41 +00:00
JediKev
e854a598e9 Merge pull request #6191 from protich/feature/oauth2
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <peter@osticket.com>, aydreeihn <adriane@enhancesoft.com>
2022-07-20 13:50:11 -05:00
Peter Rotich
163c28b56d email: External Auth Redirect
Use  window.location.href to redirect instead of href click
2022-07-20 03:30:57 +00:00
Peter Rotich
c3314a056b Email Delete
Delete email config and plugin instance on delete
2022-07-20 03:28:11 +00:00
Peter Rotich
bfb5b8a1f3 email: Fix Basic Authentication 2022-07-20 03:24:21 +00:00
Peter Rotich
d1ca71e5cb mailfetch: Fix email fetch bugs
This commit addresses email fetch bugs - thanks to @kevin
2022-07-20 03:17:30 +00:00
Peter Rotich
bfb808d6c6 email: Support Encrypting/Decrypting Credentials Secrets 2022-07-19 04:29:49 +00:00
Peter Rotich
47cb6a7b6f PluginInstance: Update signature routine
With the config moved to central config it's necessary to sort, platten the
array to json before getting md5 value.

Signature is used to detect configuratuion changes.
2022-07-19 04:24:28 +00:00
Peter Rotich
8367a03277 PluginConfig: Cache transcoded values locally
This is necessary for fields that chance e.g PasswordField getting decrypted.
Using upstream config store can result in decoded/decrypted values being saved
by mistake.
2022-07-19 04:21:14 +00:00
Peter Rotich
c1c7560305 forms: Change PasswordField encryption sub-key key
This commit also changes the length of the password placeholder to match the
actual length of the input/password.
2022-07-19 04:17:50 +00:00
Peter Rotich
87ac370efb forms: unset "unchanged" field on to_db
This is necessary so the backends can play blind and only update what changed
unless input is required.
2022-07-19 04:15:56 +00:00
Peter Rotich
2c5d114a3c Restore SCP Ajax Login
This commit reverts part of 7af5cf2c18 to restore
Ajax logins  - including scp/js/scj.js would be an overkill for the login page.
2022-07-14 21:09:34 +00:00
Peter Rotich
dff23a7e0d upgrader: Support Upgrading from v1.6 ST
This commit addresses issues related to upgrading osTicket prior to v1.7
2022-07-14 21:09:34 +00:00
Peter Rotich
95d35fc066 database: Add database patch to move config back to central config 2022-07-14 21:08:48 +00:00
Peter Rotich
88d6cfea48 patch: Remove ON UPDATE CURRENT_TIMESTAMP from datetime field 2022-07-14 21:01:39 +00:00
Peter Rotich
e7b1358e1f lint: Misc. Fixes 2022-07-14 21:01:39 +00:00
Peter Rotich
25d77b13a7 forms: Use AddErrors to inject errors to form object 2022-07-14 21:01:38 +00:00
Peter Rotich
f9c7c56f33 plugin: Mass Actions + destroy config on delete 2022-07-14 21:00:51 +00:00
Peter Rotich
e7d1449a4b email: Save Configuration via update on create 2022-07-12 14:36:34 +00:00
Peter Rotich
8bf4154e62 PasswordField: Add ability to set crypto sub-key 2022-07-12 14:24:49 +00:00
Peter Rotich
eb364ceda0 email: Validate Basic Auth 2022-07-12 13:55:24 +00:00
Peter Rotich
b77bdc1a4d plugin: Move plugin Config store to central config
Save plugin config data in central config by default.
2022-07-12 13:50:24 +00:00
Peter Rotich
2a50be2e27 email: Store username and password in central config
Move Basic Auth Credentials storage from email account to central config
2022-07-12 13:39:08 +00:00
JediKev
a80db8a7f7 issue: Manually Sorted Topics
This addresses issue 6197 where setting Help Topics sort to Manually throws
a fatal error. This is due to not checking if `$_POST['ids']` is an array
before passing it to `array_intersect()`. This adds a check to see if the
ids are an array and if not then `$diff` will be set to an empty array
(which is what `array_intersect()` returns if the arrays have no common
values).
2022-07-11 17:36:23 +00:00
JediKev
7a5dd0ebeb i18n: Default Ticket Queue
This adds the Help Tip for Default Ticket Queue setting in Admin Panel >
Settings > Tickets > Settings.
2022-07-11 16:00:30 +00:00
Peter Rotich
36b6e809ae oauth2: Get OAuth2 Credentials
Request oauth2 credentials specifically when configuring OAuth2 Client. This is
necessary because an account could be getting reconfigured.
2022-07-06 03:19:13 +00:00
Peter Rotich
48a1c022d7 plugin: Init All Installed Plugins on bootstrap
This is necessary so plugins can register interfaces that might be necessary to
add new an instance.
2022-07-06 03:19:13 +00:00
Peter Rotich
de02e8cf3a plugin: Bug fix
is_phar > isphar
2022-07-06 03:19:13 +00:00
Peter Rotich
61383cd788 tips: Add Email Authentication tooltip
This commits adds and adjusts email tooltips related to modern authentication.
2022-07-06 03:19:13 +00:00
Peter Rotich
35b457e9c5 mailer: Make sure SMTP Account are unique
This commit makes sure the SMTP accounts are unique and adds email address to
alert logged on error.
2022-07-06 03:19:13 +00:00
Peter Rotich
7e91724cee mail: Only set Content-Type when multipart
Content-Type only set when message is multi part
2022-07-06 03:19:13 +00:00
Peter Rotich
b7d99f9a31 lint: Add Laminas Mail Stubs 2022-07-06 03:19:13 +00:00
Peter Rotich
195577eba6 Highlight Tabs on Error
This pull request improves tabs highlighting on error to provide vitual
indication of errors on tabs that are not in focus.
2022-07-06 03:19:13 +00:00
Peter Rotich
df104e8c3a smtp: Outgoing Email Addresses
Include emails routing to System Default department - if the agent has access
to said department.
2022-07-06 03:19:13 +00:00
Peter Rotich
0d1d9ce06c Misc. Fixes 2022-07-06 03:19:13 +00:00
Peter Rotich
1af3ad416e Add Widget Field id to simple form field
This is necessary for visibility to work when somple form template use used to
print form fields.
2022-07-06 03:19:13 +00:00
Peter Rotich
f433b2f003 Log Alert before attemping to send out email 2022-07-06 03:19:13 +00:00
Peter Rotich
91a5932dec email: Add osTicket\Mail\Fetcher
This commit changes email fetching to use osTicket\Mail with Laminas Mail backend.
2022-07-06 03:19:13 +00:00
Peter Rotich
e4ec833b47 email: Add Email Account Table (v1.17 upgrade)
This commit adds email_account table and Model
upgrader: migrates settings from email table and drops columns.
2022-07-06 03:19:13 +00:00
Peter Rotich
8919d044b1 email: Add Modern Authentication (OAuth2) Support
Overhaul email Authentication / Configuration by adding plugable OAuth Authorization
2022-07-06 03:19:12 +00:00
Peter Rotich
7f95f4fd8f mailer: Add osTicket\Mail\Mailer
This commit changes outgoing emails to use osTicket\Mail with Laminas Mail backend
2022-07-06 03:19:12 +00:00
Peter Rotich
53cee5a0ab mail: Add osTicket\Mail Package
This commit add core mailbox & smptp classes and utils using Laminas Mail backend.
2022-07-06 03:19:12 +00:00
Peter Rotich
b139104005 Laminas: Add Laminas Mail Package
This increases osTicket core size significantly. Starting in 2.0 such packages will be added via composer
2022-07-06 03:19:12 +00:00
Peter Rotich
a91ee207dd auth: Add break and spacing to external auth buttons 2022-07-06 03:19:12 +00:00
Peter Rotich
7af5cf2c18 js: Make objectifyForm global
This is necessary when stashing form data
2022-07-06 03:19:12 +00:00
Peter Rotich
9ca4082c65 auth: Add OAuth2 Backends and osTicket\OAuth2
This commit adds OAuth2 Authentication and Authorization backends interface as well as AccessToken class.
2022-07-06 03:19:12 +00:00
Peter Rotich
ae80e27f30 Plugin: Add Config Signature
Add routine to get signature of the config store. This is important when detecting changes.
2022-07-06 03:19:12 +00:00
Peter Rotich
251150a5b1 Plugin: Add New Instance Options & Defaults 2022-07-06 03:19:12 +00:00
Peter Rotich
8cb6255338 Plugin: Add ability to pass vars when instantiating PluginConfig form
This is important when possible defaults are generated outside the form fields
context.
2022-07-06 03:18:51 +00:00
Peter Rotich
59d57c010d Plugin: Add Defaults to PluginConfig
Add ability to pass defaults to PluginConfig as well as make config cacheable
2022-07-01 22:30:03 +00:00
Peter Rotich
7ee1f406bc plugins: Add init routine
Used to initialize a plugin as part of bootstrapping process
2022-07-01 22:30:03 +00:00
Peter Rotich
8ceb3e8316 auth: Add Authentication Backends Lookup
This is useful to plugins looking for triggered backend.

This commit also adds 'id' to Auth Strike backends - needed to be successfully registered them.
2022-07-01 22:28:56 +00:00
Peter Rotich
5c2d68d548 Utils: Add routine to get base_url 2022-07-01 22:28:56 +00:00
Peter Rotich
0b93b48ec6 plugins: Support Multi-instance Services
Support ability to register multiple instances of the same backend
2022-07-01 22:28:56 +00:00
Peter Rotich
a2e78bf763 plugins: Register ClassLoader on init
Register namespace fallbacks when initializing plugins
2022-07-01 22:28:56 +00:00
Peter Rotich
9f2cc16e35 plugins: Clear side loaded config
Reset sideloaded config used to bootstrap instances
Fix compatible check
2022-07-01 22:28:56 +00:00
Peter Rotich
64c97ea6fc Plugins: Add Version Compatibility Check
This commit adds osTicket version compatibility check to plugins.
Plugins can now indicate required version of core osTicket by specifying
`ost_version` in plugin.php file.
2022-07-01 22:28:56 +00:00
Peter Rotich
a70bd13ae7 phar: Re-add Plugin Verification
Re-add and move plugin phar file verification to PluginManger since it's
a utility functionality.
2022-07-01 22:28:56 +00:00
Peter Rotich
3e96e5fdd6 plugin: Add Multi-instance Support
This commit adds multi-instance support for plugins
2022-07-01 22:28:56 +00:00
Peter Rotich
5d704ffe66 Backends Registry
This commits converts the backends to use the new unified Service
Registry.
2022-07-01 22:28:56 +00:00
Peter Rotich
7e3d4aaf84 JS: Confirm Action
Add util to prompt users for a confirmation when submitting a form
action. Also checks to make sure at least one checkbox is checked.
2022-07-01 22:28:56 +00:00
Peter Rotich
a0e87a053f Add Service Registry Util
This commit adds service registry abstract class
2022-07-01 22:28:56 +00:00
Peter Rotich
d99ff6e196 Controller: Add access check to Dispatcher
This commit adds a top level Controller to provide ability to check if
the caller has access.
2022-07-01 22:28:56 +00:00
JediKev
822a05fedb oops: jQuery UI Images
This adds the images missed in the jQuery UI upgrade. This addresses an
issue where the date picker doesn't show the arrows to skip months/years.
2022-06-01 17:01:41 +00:00
JediKev
e1487278b7 Add Release Notes for v1.16.3 2022-05-19 16:05:54 +00:00
JediKev
94444ab168 Merge branch '1.15.x' into develop 2022-05-19 16:01:11 +00:00
JediKev
0daca43afc Add Release Notes for v1.15.8 2022-05-19 15:53:55 +00:00
JediKev
1cf0201102 Merge pull request #6172 from JediKev/issue/search-and-lookup-improvements
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-05-19 10:47:16 -05:00
JediKev
1f940580bb issue: User Typeahead Lookup
This improves User Typeahaed lookup by switching from JOINS to UNIONS (for
performance reasons).
2022-05-19 15:39:34 +00:00
JediKev
a594d4b2bb issue: Email Search Improvements
This improves Email searching on full search. This ensures the search query
is emailish and if so searches only user emails. This improves sql query
execution time.
2022-05-19 15:38:51 +00:00
JediKev
3079c0a59e Merge pull request #6171 from JediKev/security/latest-security-patches-05-2022
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-05-19 10:27:57 -05:00
protich
57721def6a mpdf: Unregister PHAR
This unregisters PHAR only when calling WriteHTML instead of globally.
2022-05-19 15:22:46 +00:00
JediKev
45b6cf2e6a issue: Form Elements & Attribute
This addresses an issue discovered by the AppSec Research Team at Checkmarx
where the `action` attribute passes through sanitization successfully which
can be potentially harmful. In addition `<form>`, `<input>`, and `<button>`
elements can be maliciously crafted. This updates the htmLawed configuration
to deny the `action` attribute in all elements as well as denies all
`<form>`, `<input>`, and `<button>` elements.
2022-05-19 15:21:48 +00:00
Peter Rotich
85a76f403a Security: Session Fixation
This commit addresses possible session fixation on both agent and end user
login. Upon login users are now issued new session with the old one
invalidated.
2022-05-19 15:21:48 +00:00
JediKev
01a378f640 security: Unvalidated Password Change
This mitigates a vulnerability discovered by the AppSec Research Team at
Checkmarx where it's possible to update your Agent password without passing
a valid current password. This adds a check to compare the provided current
password with the actual current password to ensure they match. If they do
not match an error will be returned stating `Current password is
incorrect.`.
2022-05-19 15:21:48 +00:00
JediKev
334934ec6b xss: System Logs
This mitigates a vulnerability discovered by the AppSec Research Team at
Checkmarx where it's possible to perform Stored XSS via invalid CSRF tokens
in the System Logs. This is due to not properly sanitizing the CSRF content
before saving to the database as well as not properly escaping the content
before displaying in the UI. This adds `Format::sanitize()` to the content
before saving to the database as well as `Format::htmlchars()` before
displaying.
2022-05-19 15:21:48 +00:00
JediKev
a5c4d931e3 xss: Agent Directory
This mitigates a vulnerability discovered by the AppSec Research Team at
Checkmarx where it's possible to perform Reflected XSS in the Agent
Directory. This was due to the `order` and `sort` URL params not being
properly escaped. This adds `Format::htmlchars()` to both params to ensure
they are properly escaped.
2022-05-19 15:21:48 +00:00
JediKev
0a5f557b50 Merge pull request #6170 from JediKev/jquery/update-jquery-ui-1.13.1
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-05-19 10:20:29 -05:00
JediKev
9e30604fb6 Merge pull request #6164 from esamo/patch-3
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-05-19 10:18:21 -05:00
JediKev
b071fc4444 Merge pull request #6169 from JediKev/issue/check-user-status
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-05-19 10:15:58 -05:00
JediKev
3a2f072d63 issue: Check User Status
This is a rewrite of 6163 where we aren’t checking User/Agent status on
login and on session validation. This adds checks to the
UserAuthenticationBackend to ensure the User is active (ie. confirmed and
not administratively locked). This also adds checks to the
StaffAuthentciationBackend to ensure the Agent is active (ie. not locked).
If a User/Agent is not active they will be redirected to the login screen.
2022-05-19 15:11:56 +00:00
JediKev
542b4f0320 Merge pull request #6154 from socsimrishamn/develop
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-05-19 09:12:04 -05:00
JediKev
0ece428fd8 Merge pull request #6168 from JediKev/install/help-topic-disabled-fields
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-05-19 09:08:14 -05:00
JediKev
fbc05c6ead Merge pull request #6166 from JediKev/issue/redactor-freezing
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-05-19 09:07:11 -05:00
JediKev
c91585d1f3 Merge pull request #6160 from JediKev/issue/mpdf-table-print
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-05-19 09:06:37 -05:00
JediKev
81e99fe491 installer: Help Topic Disabled Fields
This addresses an issue where installing `1.16.x` has the Ticket Details
Form Fields disabled for every Help Topic. This is due to checking if the
Field IDs are in an empty array which obviously will return false. This
updates the declaration of `$fields` from `array()` to `null` if the array
index doesn’t exist. This also updates the `if` statement for the Field ID
checking to ensure the `$fields` variable is an array. This ensures that the
check is skipped if `$fields` is `null` avoiding erroneous disabled fields.
2022-05-17 18:51:13 +00:00
JediKev
42525acaa7 issue: Redactor Freezing
This addresses an issue where removing all text in Redactor in the Post
Reply box freezes the entire page (using 90% or more CPU). As a quick
workaround user jarnott from the Forum found that adding a `br` tag
between the `draft_id` input and the Post Reply `textarea` fixes the
issue. This adds the `br` tag to temporarily address the issue until
Redactor addresses the issue permanently.
2022-05-13 14:09:51 +00:00
Patryk Frey
026336948a Do not autocomplete new access fields of the (another) user
Otherwise these fields get autocompleted by browser and need to be emptied to save the form (for example I want only to block the account and save).
2022-05-09 22:07:09 +02:00
JediKev
38c0979e21 issue: mPDF Table Print
This addresses issue 6159 where tables are not appearing correctly in PDFs.
This is due to mPDF config revert when upgrading mPDF. This updates the
config `ignore_table_widths` to `true` so tables appear correctly.
2022-05-06 15:46:00 +00:00
Peter Rundqvist
612183cee6 Make strings localizable 2022-05-04 08:59:52 +02:00
Peter Rundqvist
4cc509b1f8 Make string localizable 2022-05-04 08:43:45 +02:00
JediKev
ed958d98bc jquery: Update jQueryUI 1.13.1
This is a rewrite of pull 6146 where it updates jQueryUI from `1.12.1` to
`1.13.1`. This also includes the updated CSS for jQueryUI `1.13.1`.
2022-04-26 20:36:12 +00:00
JediKev
39ab0c5b5c Add Release Notes for v1.16.2 2022-04-20 15:18:18 +00:00
JediKev
f4e71a9bf3 Merge branch '1.15.x' into develop 2022-04-20 15:09:53 +00:00
JediKev
26ab7e9791 Add Release Notes for v1.15.7 2022-04-20 14:57:45 +00:00
JediKev
16211325d4 Merge pull request #6141 from JediKev/issue/fixes-test-errors
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-04-20 09:53:14 -05:00
JediKev
34cf2f2024 issue: Fixes Test Errors
This addresses a small issue where there was a missing `(` parenthesis.
2022-04-20 14:50:18 +00:00
JediKev
c6ad36303d Merge pull request #6140 from JediKev/typo/emtpy-to-empty
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-04-20 09:39:46 -05:00
JediKev
f926bdc2db Merge pull request #6139 from JediKev/issue/sweden-capitalization
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-20 09:39:21 -05:00
JediKev
126e545fb7 Merge pull request #6138 from aydreeihn/issue/disabled-dept-access
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-20 09:38:58 -05:00
ntozier
9c858b88b1 typo: Emtpy To Empty
This fixes a typo in the Mail Folder help tip. This updates `emtpy` to
`empty`.
2022-04-20 14:31:33 +00:00
JediKev
3cb05ad14a issue: Sweden Capitalization
This capitalizes the word Svenska.
2022-04-20 14:24:37 +00:00
aydreeihn
0b7c9c2148 Issue: Disabled/Archived Primary Dept
This commit fixes an issue where we were only filtering out Private Departments from the Primary Department options for Agents when we should have been filtering out the Disabled and Archived Departments as well. This allowed trying to save an archived/disabled Department as the Agent's primary Department which threw an error.

Another issue was that if there was an error on dept_id, we didn't display the specific error message under the field, so you wouldn't know what to correct. Additionally, the error message for role_id was under the 'Fall back to primary role' checkbox instead of the Role field.

This problem was discovered through Issue #6135
2022-04-20 09:06:18 -05:00
JediKev
f427b66999 Merge pull request #6136 from JediKev/i18n/translatable-tooltip
Reviewed-By: JediKev <kevin@enhancesoft.com>
2022-04-19 17:43:01 -05:00
JediKev
c88ad0a050 Merge pull request #6137 from JediKev/i18n/no-tasks-string
Reviewed-By: JediKev <kevin@enhancesoft.com>
2022-04-19 17:42:36 -05:00
JediKev
01016dbc97 18n: No Tasks String
This adds translation support for the "no tasks" string.
2022-04-19 22:24:01 +00:00
empty88
b063504ed4 Update ticket-tasks.inc.php 2022-04-19 22:23:27 +00:00
JediKev
e2be9e780f i18n: Translatable Tooltip
This is a rewrite of pull 6123 where it adds translation support for client
side queue column sort tooltips. This breaks apart the tooltip strings into
two parts allowing `Sort By` and the column name to be translated
separately.
2022-04-19 22:06:32 +00:00
JediKev
20e9b3033c Merge pull request #6101 from JediKev/issue/maxlength-attribute
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 16:57:23 -05:00
JediKev
225eb7a143 issue: MaxLength Attribute
This addresses an issue reported on the Forum where Fields are not honoring
the Length value. This is due to the label being set to `length` while the HTML
attribute is named `maxlength`. This adds a case for `length` that sets the
attribute name to `maxlength`.
2022-04-19 21:51:19 +00:00
JediKev
7bb477ce67 Merge pull request #6134 from JediKev/i18n/bosnian-flag-css
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:59:45 -05:00
JediKev
39d05d74ea Merge pull request #6133 from JediKev/oops/banlist-created
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:59:24 -05:00
JediKev
5354293557 Merge pull request #6126 from empty88/patch-1
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:55:32 -05:00
JediKev
a5e11df622 Merge pull request #6124 from empty88/patch-12
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:53:57 -05:00
JediKev
69f73e9a4f Merge pull request #6122 from empty88/patch-9
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:50:13 -05:00
JediKev
1b9fdec655 Merge pull request #6109 from JediKev/issue/last-message-data-source
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:49:47 -05:00
JediKev
97e0d944b1 Merge pull request #6108 from JediKev/issue/filter-events
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:47:27 -05:00
JediKev
f9e4e12725 Merge pull request #6099 from JediKev/issue/task-export
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:44:17 -05:00
JediKev
8f1a34df8d Merge pull request #6096 from JediKev/issue/queue-sort
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:43:22 -05:00
JediKev
5a0bfea883 Merge pull request #6094 from cengizonkal/fix-staff-login-redirect-loop-when-offline
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:40:12 -05:00
JediKev
c727290132 Merge pull request #6087 from JediKev/issue/deprecated-required-parameter
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:38:21 -05:00
JediKev
f33e529818 Merge pull request #6071 from JediKev/issue/php-analyzer-each
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:32:02 -05:00
JediKev
14e4877ff7 Merge pull request #6018 from mlocati/fix-l10n-links
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:28:54 -05:00
JediKev
4f9dd9e7c8 Merge pull request #6008 from rmilecki/fix-thread-html-syntax
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:28:23 -05:00
JediKev
eb8436b89a Merge pull request #5913 from wmertens/patch-1
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:28:04 -05:00
JediKev
ad71b22e3c Merge pull request #5876 from gerundt/getHelpTopics-localize-allData
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-19 14:26:32 -05:00
JediKev
94f5e95701 i18n: Bosnian Flag CSS
This fixes the CSS for the Bosnian Flag for Lanugage Packs.
2022-04-18 14:12:03 +00:00
JediKev
f0ae76f4c1 oops: Banlist Created
This addresses an issue where the created date for banlist items show an
old, incorrect date. This is due to not setting a created date before saving
to the database.
2022-04-14 20:05:29 +00:00
JediKev
a77158b6ec issue: Nullable date() Timestamp
This addresses an issue where starting with PHP 8.0 the `date()` method
changed the `timestamp` parameter to be nullable. If the `timestamp` is
`NULL` then it will return the output from the `time()` method. So instead
of returning a default date of `1970-01-01T00:00:00+00:00` like it used to
it returns the current date. This is obviously a problem when it comes to
datetime based Queue Columns like Last Response with no value. Since there
is no value it gets translated to the current time and displays `just now`
in the columns instead of a blank column. This updates the `date()` call to
use `0` if the `timestamp` is `NULL` so that it returns the default datetime
of `1970-01-01T00:00:00+00:00` essentially restoring previous behavior.
2022-04-11 20:23:20 +00:00
cengiz
38b8f53354 fix staff login redirect loop when system is offline 2022-04-11 23:05:27 +03:00
Michele Locati
da1309a363 Fix markdown of jipt.i18n.osticket.com link 2022-04-11 20:57:14 +02:00
Michele Locati
d52cc40300 Use HTTPS version of Crowdin project 2022-04-11 20:57:04 +02:00
JediKev
0d417d3910 Merge pull request #6046 from davidglezz/patch-1
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-11 13:25:23 -05:00
JediKev
20955014f4 Merge pull request #6007 from rmilecki/email-formatting-space
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-11 13:20:03 -05:00
JediKev
7445c04f96 Merge pull request #5946 from Af0x/patch-1
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <peter@osticket.com>
2022-04-11 13:13:44 -05:00
empty88
84c4eb8503 Update ticket-view.inc.php 2022-04-03 13:20:12 +02:00
empty88
e6f437cdcb Update ticket-preview.tmpl.php
fix translation
2022-04-03 13:03:13 +02:00
empty88
8b5ea64068 Update edit.inc.php 2022-04-03 12:51:31 +02:00
JediKev
d59d695c6a Merge pull request #6115 from JediKev/issue/undefined-constant-glob_brace
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-03-28 14:44:02 -05:00
JediKev
bb9810a7a4 Merge pull request #6107 from JediKev/issue/pear-mail-parseaddresslist
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-03-28 14:33:40 -05:00
JediKev
ea6eeba9b4 Merge pull request #6089 from JediKev/tests/validation-checks
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-03-28 14:15:27 -05:00
JediKev
1a9a8027e7 Merge pull request #6088 from JediKev/tests/uninitialized-vars
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-03-28 14:14:21 -05:00
JediKev
9d249c45aa Merge pull request #6080 from JediKev/issue/preg_match-pass-by-reference
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-03-28 14:12:13 -05:00
JediKev
0499b97b73 issue: Undefined Constant GLOB_BRACE
This addresses issue 6079 where using `1.16.x` and PHP 8.0 on certain GNU
systems (eg. Alpine, Solaris, etc.) throws a fatal error of `Undefined
constant: "GLOB_BRACE"` when loading Plugins. This is due to `GLOB_BRACE`
not being available on said GNU systems. This removes `GLOB_BRACE` from
`include/class.plugin.php` completely as it is not used anyways.
2022-03-23 20:07:49 +00:00
JediKev
d185e509ff issue: Last Message Data Source
This addresses an issue reported on the Forum where the Last Message and
Last Response Data Sources are not showing the correct times. This is due to
an erroneous change made to support PHP 8.0. We added `isset()` to parts
where we are selecting array keys but didn’t add a check for the value. This
adds checks for the values to ensure we are continuing at the appropriate
times.
2022-03-21 21:54:55 +00:00
JediKev
8c9b392009 issue: Filter Events
This addresses issue 6059 where Ticket Filter processing stops accurately
but the Thread Events are blindly added for any Filters that match the
criteria. This is due to not checking the current Filter in the iteration
for `stopOnMatch()`. This adds a check for `stopOnMatch()` and if `true` we
will break the loop.
2022-03-21 20:51:21 +00:00
JediKev
713005612f issue: PEAR Mail parseAddressList()
This addresses an issue reported on the Forum where when
`Mail::parseRecipients()` is called it throws a fatal error of `Uncaught
ValueError: mb_convert_encoding(): Argument #2 ($to_encoding) must be a
valid encoding, "localhost" given`. This is due to an erroneous change when
adding PHP 8.0 support. We changed the called class from `Mail_RFC822` to
`Mail_Parse` but left the same arguments. This is obviously an issue as both
classes' methods take different arguments. This changes the called class
back to `Mail_RFC822` to stick to original functionality and updates it for
PHP 8.0 standards.
2022-03-21 19:55:33 +00:00
JediKev
baa46d35cf issue: Task Export
This addresses an issue reported on the Forum where exporting Tasks gives
you a fatal error. This is due to not checking if `$current` is set before
using it in `method_exists()`. This checks to make sure we have `$current`
set before using it.
2022-03-15 14:41:54 +00:00
JediKev
92e820c2d1 issue: QueueSort
This addresses an issue reported on the Forum where when adding a new Queue
Sort an error of `Uncaught TypeError: count(): Argument #1 ($value) must be
of type Countable|array, string given` is thrown. This is due to passing the
wrong arguments to the `QueueSort::update()` method. This corrects the
arguments to `$vars, $errors` to resolve the error.
2022-03-14 14:24:26 +00:00
JediKev
91e7d305d2 tests: Validation Checks
This addresses an issue where when running cli tests a validation check for
`jared@` failed. This is due to switching the calling class of
`parseAddressList()` from `Mail_RFC822` to `Mail_Parse`. This reverts the
calling class to `Mail_RFC822` to fix the issue.
2022-02-24 21:55:47 +00:00
JediKev
60f6ad718e tests: UninitializedVars
This addresses an issue found when running cli tests where two static
methods are using `$this`. This updates the methods to remove the use of
`$this` and updates remaining non-static calls to static.
2022-02-24 21:29:39 +00:00
JediKev
0d0ab46755 issue: Deprecated Required Parameter
This addresses a few issues reported on the Forum where some methods are
throwing `Deprecated: required parameter follows optional parameter` errors.
This updates the erroneous methods to match the PHP 8 standards using
explicit nullable types with defaults.
2022-02-24 20:50:02 +00:00
JediKev
f627a5ec67 issue: php_analyze each()
This cleans up the changes we did for the `each()` statements in
`class.php_analyze.php` as well as fixes reamining `each()`.
2022-02-17 22:10:12 +00:00
JediKev
148a2e70f7 issue: preg_match Pass By Reference
This addresses an issue where in PHP 8 you can no longer pass variables by
reference to preg_match. This moves the definition of the variable outside
the preg_match so it no longer complains.
2022-02-16 15:09:22 +00:00
JediKev
b42ddc7aeb Add Release Notes for v1.16.1 2022-02-15 21:21:54 +00:00
JediKev
b8e341aef0 Merge branch '1.15.x' into develop 2022-02-15 21:20:03 +00:00
JediKev
1a64b841f2 Add Release Notes for v1.15.6 2022-02-15 21:14:06 +00:00
JediKev
984ce78832 Merge pull request #6075 from JediKev/issue/user-sendUnlockEmail
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-15 15:06:54 -06:00
JediKev
7547fe3f49 Merge pull request #6068 from JediKev/issue/remaining-deprecated-each
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-15 15:06:08 -06:00
JediKev
02a930a6a8 Merge pull request #6066 from JediKev/issue/php-version-requirements-1.16.x
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-15 15:05:07 -06:00
JediKev
18198fd83f Merge pull request #6065 from JediKev/issue/email-templates-static
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-15 15:04:49 -06:00
JediKev
a99abcff9d Merge pull request #6064 from JediKev/issue/status-list-getSortModes
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-15 15:04:32 -06:00
JediKev
50c5f0a308 Merge pull request #6058 from dsoms/patch-1
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-15 15:04:10 -06:00
JediKev
69db3a72b1 issue: Remaining Deprecated each()
This addresses an issue reported on the Forum where a couple of `each()`
methods slipped through the cracks. This updates all the `each()` (minus the
php_analyzer file for now) to the new PHP 8 standards.
2022-02-15 20:46:01 +00:00
JediKev
5a2f8292e3 Merge pull request #4487 from JediKev/issue/required-cfield-user-reg
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <protich@enhancesoft.com>
2022-02-15 13:58:01 -06:00
JediKev
13652db2ad issue: User sendUnlockEmail
This addresses issue 6074 where `sendUnlockEmail()` is static but cannot be
as it uses `$this`. This updates the method to non-static and updates all
calls to non-static calls.
2022-02-15 00:44:01 +00:00
JediKev
4378f773f6 issue: Auth_SASL Non-Static
This addresses an issue where `Auth_SASL::factory()` is being called
statically but is not static. This updates the method to static so it can be
called statically with no issues.
2022-02-11 15:54:28 +00:00
JediKev
96995e1a52 issue: Banlist Non-Static
This addresses an issue where `Banlist::add()` and `Banlist::remove()` are
non-static methods that are being called statically. This updates the
methods to static so that they can be called statically.
2022-02-11 14:34:04 +00:00
JediKev
fdc044519c issue: PHP Version Requirements 1.16.x
This updates the PHP version requirements from `PHP version 8.0 (or
greater)` to `PHP version 8.0` until we can fully confirm PHP 8.1 is
supported.
2022-02-09 17:38:46 +00:00
JediKev
fb0b075f2c issue: Email Templates Static
This addresses an issue reported on the Forum where cloning a Template Set
gives you a fatal error of `Non-static method EmailTemplateGroup::add()
cannot be called statically`. This updates the `add()` method to static for
`EmailTemplateGroup` and `EmailTemplate` classes.
2022-02-09 17:34:50 +00:00
JediKev
6d4650d113 issue: Status List getSortModes()
This addresses issue 6063 where TicketStatusList does not have a
`getSortModes()` method and fatal fails when loading the status list. This
was done by `__call()` via `CustomListHandler` previously but we changed
`getSortModes()` to a static method to match PHP 8 standards. We didn't
account for the fact that `__call()` cannot call a static method as it uses
`$this` context. This renames the `getSortModes()` method for `DynamicList`
to `sortModes()`, creates a new method called `getSortModes()` which returns
the self `sortModes()`, updates `dynamic-list.inc.php` to call the method
non-statically and for `DynamicList` calls `sortModes()` statically, and
removes `static` keyword from `getSortModes()` on `CustomList` interface.
2022-02-09 17:17:56 +00:00
JediKev
27b8f55777 Add Release Notes for v1.16 2022-02-08 17:38:25 +00:00
JediKev
cf23b06767 Merge branch '1.15.x' into 1.16.x 2022-02-08 17:35:58 +00:00
JediKev
2ba1d8e5e0 Add Release Notes for v1.15.5 2022-02-08 17:27:30 +00:00
JediKev
d22cfaccdc Merge pull request #6060 from JediKev/issue/php8
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-08 10:34:37 -06:00
JediKev
2767ad4ff7 prereqs: Update README.md
This updates the `README.md` file to mention that v1.16 requires PHP 8.
2022-02-08 16:13:51 +00:00
JediKev
57347ab4b6 upgrader: v1.16 Release
This adds an upgrade patch, updates the install-mysql.sql script, and
updates the core signature to trigger the v1.16 upgrade.
2022-02-08 15:44:48 +00:00
JediKev
0905e7bef7 release: Prep Release
This preps the installer/upgrader/bootstrap for the v1.16 release.
2022-02-08 15:33:19 +00:00
JediKev
0afe2b27df php8: Temporarily Suppress Warnings
This commit suppresses PHP 8 Warnings until we can go through and address
all warnings in the code.
2022-02-07 21:01:12 +00:00
JediKev
1eafd98063 issue: PEAR each()
This addresses a lingering `each()` error with the PEAR library. This
updates the `while(list() = each())` statement to a simple `foreach()` to
get rid of the error.
2022-02-07 16:19:28 +00:00
JediKev
03d203b9fa issue: Further Fixes
This includes further miscellaneous fixes found while running through a
basic installation. This includes calling non-static statically changes,
parameter must be of type array changes, and class not found changes.
2022-02-07 16:19:28 +00:00
JediKev
c4fc76c02f issue: EmailDataParser
This addresses the `Using $this when not in object context` error for
EmailDataParser and ApiEmailDataParser using PHP 8.
2022-02-07 16:19:28 +00:00
JediKev
998cd7d9fe issue: Even More Fixes
This includes even more miscellaneous fixes found while adding PHP 8
support. This includes incorrect capitalization of a class name and removing
unnecessary include statements.
2022-02-07 16:19:28 +00:00
aydreeihn
958a74813a PHP8: Static Method Lint Test
This commit adds a lint test to check the code for any static calls to a non-static function which throws a fatal error as of PHP 8.0.
2022-02-07 16:19:28 +00:00
aydreeihn
59dc587d46 Update MPDF
Update MPDF from version 7.1 to 8.0 to support PHP 8.
2022-02-07 16:19:27 +00:00
JediKev
ec9c09d027 issue: Misc. Fixes
This includes miscellaneous fixes found while adding PHP 8 support.
2022-02-07 16:19:27 +00:00
JediKev
3bb36ff4f3 issue: Static to Non-Static
This updates the static calls that need to be non-static.
2022-02-07 16:19:27 +00:00
JediKev
7668b718c3 issue: create_function()
This addresses the `Call to undefined function create_function()` errors.
2022-02-07 16:19:26 +00:00
JediKev
64076e2718 issue: Unparenthesized
This addresses the `Unparenthesized "a ? b : c ?: d"` warnings.
2022-02-07 16:19:26 +00:00
JediKev
69747343ee issue: Undefined Key, Var, Prop
This addresses the `Undefined array key`, `Undefined variable`, and
`Undefined property` errors.
2022-02-07 16:19:26 +00:00
JediKev
e261a5fb22 issue: Undefined Function each()
This addresses the `Call to undefined function each()` errors.
2022-02-07 16:19:26 +00:00
JediKev
a4ab19d361 issue: Calling Non-Static Statically
This addresses the `Non-static method XXX cannot be called statically`
errors.
2022-02-07 16:19:26 +00:00
Tim Gerundt
ab77c0afcf Fix deprecated implode() syntax for arrays 2022-02-07 16:19:25 +00:00
Tim Gerundt
29dcbd9000 Switch CryptoAlgo->exists() to real static function 2022-02-07 16:19:25 +00:00
Tim Gerundt
6b3c7f9f53 Use static keyword for some helper functions 2022-02-07 16:19:25 +00:00
Tim Gerundt
4d972b53d8 Use static keyword for JsonDataParser/JsonDataEncoder functions 2022-02-07 16:19:25 +00:00
Tim Gerundt
e63998e730 Array and string offset access syntax with {} is deprecated in PHP 7.4. Use [] instead. 2022-02-07 16:19:25 +00:00
JediKev
fc99cfc213 Merge branch 'develop' into 1.15.x 2022-02-07 16:15:18 +00:00
JediKev
92ba15d98f Merge branch '1.14.x' into 1.15.x 2022-02-07 16:11:40 +00:00
JediKev
a0b4c25d6a Merge pull request #6005 from protich/feature/authbackends_auto-register
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <protich@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-07 09:56:02 -06:00
JediKev
2b9e1a9829 Merge pull request #6057 from JediKev/issue/khmer-lang-flag
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <protich@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-07 09:55:19 -06:00
JediKev
79d51bed0b Merge pull request #6056 from JediKev/issue/assignee-item-property
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <protich@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-07 09:54:11 -06:00
JediKev
adc1e18559 Merge pull request #6054 from JediKev/issue/cdata-rebuild-issue
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <protich@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-07 09:49:15 -06:00
JediKev
fe69de4833 Merge pull request #6026 from JediKev/issue/plus-symbol
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <protich@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-07 09:46:14 -06:00
JediKev
d165ffd2c5 Merge pull request #6017 from JediKev/issue/plain-text-canned-responses
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <protich@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-07 09:43:41 -06:00
JediKev
aaa28ee1ee Merge pull request #6014 from JediKev/issue/imporved-validation-for-variable-names
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <protich@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-07 09:42:04 -06:00
JediKev
dcac452c3b Merge pull request #6013 from JediKev/redactor/upgrade-to-version-3.5.2
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <protich@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-07 09:41:09 -06:00
JediKev
549e243012 Merge pull request #5994 from JediKev/develop
Reviewed-By: JediKev <kevin@enhancesoft.com>, protich <protich@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2022-02-07 09:38:26 -06:00
David Soms
823b5fbba5 i18n: Missing translations for the action buttons 2022-02-03 21:20:39 +01:00
JediKev
f878f14480 issue: Khmer Language Flag
This addresses issue 6031 where the Khmer Language Flag is inaccurate. This
updates the `css/flags.css` file to adjust the pixel frame for
`.flag.flag-km`.
2022-02-03 16:17:38 +00:00
JediKev
3cde88a519 issue: Assignee Item Property
This addresses an issue where you cannot save a value for an Assignee field
that’s in the Item Properties of a List Item. This is due to the method used
to prepare the data for the backend as well as the format of the data when
returned from `to_database()`. This updates `to_php()` to `to_database()` to
get the appropriate data for the backend. This also updates `to_database()`
to return the JSON encoded data itself instead of in an array. Lastly, this
updates the `getChanges()` method to remove the need to account for an
array.
2022-02-02 19:46:46 +00:00
JediKev
9da3b5ea31 issue: CDATA Rebuild Issue
This addresses issues 6043 and 6053 where installing osTicket and doing a
User lookup will return a fatal error of `Unknown column 'A5.phone' in
'where clause'`. This is an indirect result of the changes we did to rebuild
CDATA tables post-installation. The issue is that we are using
`getInstance()` which returns a cached object. Changing this to always
return a new instance via `getNewInstance()` subsequently had issues with
the TicketForm not adding the Priority field. We determined this is due to
object caching in the ORM so we added `ModelInstanceManager::flushCache()`
before we rebuild the CDATA tables to clear the object cache and prevent the
reuse of old objects.
2022-01-27 21:50:34 +00:00
David Gonzalez
f72691c638 Fix slugify regex
a-z is inside A-z. A-z range also match [\]^_` chars
2022-01-11 23:18:37 +01:00
JediKev
b0f143ec38 issue: Plus Symbol
This updates the formula regex to allow `+` at the beginning of digit
characters like phone numbers.
2021-11-17 19:42:11 +00:00
arneschuldt
19c03ca0dd issue: Plain-Text Canned Responses
**Problem:**

In a non-rich-text setting, osTicket includes HTML elements if canned
responses are added to a response. [This problem has been discussed, for
instance, in a thread on the osTicket
forum.](https://forum.osticket.com/d/96411-agent-responses-show-html-markup)

**Background:**

The problem came in with commit a1116036af,
probably during an upgrade of the Redactor library. Since this commit, a
canned response loaded from the server always turns the response into a
rich-text response on the client side. However, the server (rightly) expects
non-rich-text content so that the response is malformatted later in this
process.

**Solution:**

The solution to fix this is quite easy. The response HTML element is
annotated the `.richtext` if it is meant to contain rich text. Hence, the
selector for Redactor can be extended with this class. Consequently, rich
text is only used if that is intended, i.e., no more malformatting with
unwanted HTML elements.
2021-11-02 18:56:54 +00:00
JediKev
35c8ca829c issue: Improved Validation for Variable Names
This addresses an issue where a variable name with `/` for example throws
databases errors when reindexing cdata tables. This improves the regex
validation for variable names to ensure alphanumeric characters only.
2021-11-01 14:06:13 +00:00
JediKev
4e4f82e6bd redactor: Upgrade to version 3.5.2
This upgrades Redactor from 3.5.1 to 3.5.2 so that we are utilizing the
latest code. This provides a few bug fixes and improvements.
2021-10-28 14:40:03 +00:00
Rafał Miłecki
84913f5a9e Fix HTML syntax in thread view
This fixes "span" element being closed twice.

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
2021-10-24 17:27:12 +02:00
Rafał Miłecki
7692637bd3 email: use correct e-mail formatting
Add missing space between name and actual e-mail.
Before: foo<foo@bar.com>
After: foo <foo@bar.com>

Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
2021-10-24 16:51:44 +02:00
Peter Rotich
6836b17ef6 auth: Allow AuthBackends to auto-register Users
This commit allows AuthBackends (e.g via SSO) to auto-register Users
even when the registration is set to private.

The rationale is - Users already in such backends like LDAP or SAML are
already approved/registered internally.
2021-10-20 15:52:57 +00:00
JediKev
5c91f64d87 Revert "issue: List Item Properties On Mouseover"
This reverts commit a6a719239b as putting the
preview in the display messes up exports and multi-selection.
2021-10-08 16:01:50 +00:00
JediKev
6bd7884f06 Add Release Notes for v1.15.4 2021-10-07 17:56:28 +00:00
JediKev
f20d21c519 Merge branch '1.14.x' into develop 2021-10-07 17:50:43 +00:00
JediKev
7398e9006f Add Release Notes for v1.14.8 2021-10-07 17:41:07 +00:00
JediKev
ec430472f9 Merge branch '1.14.x' into develop 2021-10-07 17:32:34 +00:00
JediKev
4bd37597bf Merge pull request #5990 from JediKev/xss/tasks
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2021-10-07 12:31:50 -05:00
JediKev
16a4ab64e0 Merge pull request #5989 from JediKev/xss/advanced-search
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2021-10-07 12:30:57 -05:00
JediKev
4a8d3c8b0a xss: Advanced Search
This mitigates a vulnerability reported by Iwan where XSS is possible via
Advanced Search AJAX. This ensures the `parent_id` from the request
`is_numeric` to avoid possible XSS.
2021-10-07 17:29:44 +00:00
JediKev
52407fb271 Merge pull request #5988 from JediKev/security/recipient-injection
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2021-10-07 12:24:53 -05:00
JediKev
4f2183394e Merge pull request #5987 from JediKev/xss/domain-whitelist-bypass
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2021-10-07 12:23:32 -05:00
JediKev
27a0f83709 Merge pull request #5986 from JediKev/security/ssrf-external-images
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2021-10-07 12:22:46 -05:00
JediKev
0fa7efca2b Merge pull request #5985 from JediKev/security/sql-injection-and-username-discoverability
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2021-10-07 12:21:39 -05:00
JediKev
b01c6a2b97 xss: Tasks
This mitigates a vulnerability reported by Iwan where XSS is possible via
Tasks URL. This ensures the parameters are encoded to avoid possible XSS.
2021-10-07 14:55:32 +00:00
JediKev
7c5c584f95 security: Recipient Injection via User's Name
This mitigates a vulnerability reported by Luca where email recipients can
be injected via the User's Name when creating/updating a User. This adds a
check to ensure the passed value is a string. If the value is not a string
we will refuse the request.
2021-10-07 14:55:06 +00:00
JediKev
4b4da5bee7 xss: Stored XSS/Domain Whitelist Bypass
This mitigates a vulnerability reported by haxatron on
[huntr.dev](https://huntr.dev/) where one can bypass the Domain Whitelist
and potentially store XSS via iFrame tags. This adds a new section to the
iFrame REGEX that checks for `@` and denies the iFrame if exists.
2021-10-07 14:54:44 +00:00
JediKev
1c6f98e62f security: SSRF External Images
This is an extension of `d98c2d0` and addresses an issue reported by
haxatron. This ensures the `Allow External Images` setting is Disabled by
default on new installs.
2021-10-07 14:40:45 +00:00
JediKev
86165c2e6b security: Username Discoverability
This mitigates a vulnerability reported by haxtron on
[huntr.dev](https://huntr.dev/) where usernames can be discovered by the
message returned when a username is invalid. This makes it to where
regardless of if the username is correct or not it will display a message
stating `If the information provided is valid a password reset email will be
sent to the email address you have on file.`. This blocks the chance of
someone finding a valid username by brute force guessing.
2021-10-07 14:39:21 +00:00
Peter Rotich
e28291022e security: SQL Injection
This mitigates a possible SQL injection vulnerability reported by
Bittylicious.
2021-10-07 14:38:44 +00:00
Peter Rotich
e90d3be6c5 Merge pull request #5971 from JediKev/search/child-thread-relation
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-10-07 06:48:43 -05:00
Peter Rotich
f0a58ed772 Merge pull request #5972 from JediKev/issue/def-assn-role
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-10-07 06:45:53 -05:00
Peter Rotich
af663758eb Merge pull request #5977 from JediKev/issue/list-item-properties-on-mouseover
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-10-07 06:41:30 -05:00
Peter Rotich
e57673ba14 Merge pull request #5983 from JediKev/issue/auto-assign-comments-var
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-10-07 06:39:15 -05:00
JediKev
c3171c3998 issue: Auto-Assign Comments Var
This addresses 5978 where when a Filter auto-assigns an Agent, the New
Assignment Alert they receive shows the `%{comments}` variable. This is due
to `$comments` being `false` therefore it skips the variable. This adds a
check for `$comments` and if empty/false uses `''` so the variable is
replaced/removed from the final alert.
2021-10-06 21:29:10 +00:00
JediKev
a6a719239b issue: List Item Properties On Mouseover
This addresses an issue where when Inline Edit was introduced it removed the
functionality for the List Item Properties popup on mouseover. This
restructures the `display()` method for DynamicListItem to display the value
with an info icon that on mouseover will display the associated List Item
Properties.
2021-10-05 20:06:06 +00:00
Peter Rotich
8b4da7e9e1 Merge remote-tracking branch 'upstream/develop' into develop 2021-09-25 23:45:29 +00:00
Peter Rotich
edace31d0b Merge pull request #5973 from aydreeihn/issue/delete-referrals
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-10-07 06:44:51 -05:00
aydreeihn
790c0e6f11 Issue: Delete Referrals
This commit fixes an issue where we were not deleting referrals when a Ticket was deleted. Now we will delete any referrals related to a thread when the thread is deleted.
2021-09-27 14:51:17 -05:00
Peter Rotich
de61b6ecf8 Merge remote-tracking branch 'upstream/1.14.x' into develop 2021-09-25 23:45:19 +00:00
JediKev
6ad568f01f issue: def_assn_role
This addresses an issue reported on the Forum where disabling `Fall back to
primary role on assignments` doesn’t actually save. This is due to the third
parameter passed being `false`. The third parameter is `$commit` that
determines wether or not to save it after changing. Since this was `false`
it was never committed/saved in the database. This updates the parameter to
`true` so that it gets committed/saved.
2021-09-24 16:39:47 +00:00
JediKev
08785f9242 search: Child Thread Relation
This addresses issue 5959 where `TicketThread / Last Message` and
`TicketThread / Last Response` appear twice in the Advanced Search available
Fields. This is due to the joins/relationships automatically being added to
searchable fields. In this case, searching TicketThread will search the
Parent and Child Threads so there is no need for two separate options. This
adds a new property called `searchable` (set to false) to the `child_thread`
relation in the Ticket class. In addition, this adds a check when generating
the searchable fields that skips the relation if the `searchable` property
is `false`.
2021-09-24 16:34:44 +00:00
Peter Rotich
e97ac05763 Merge pull request #5953 from aydreeihn/issue/audit-close-dups
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-09-21 17:13:59 -05:00
Peter Rotich
202cf6e7ee Merge pull request #5947 from aydreeihn/feature/ticket-filter-events
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-09-21 17:13:13 -05:00
Peter Rotich
db82ad225d Merge pull request #5962 from gerundt/due-date-link-v2
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-09-21 17:04:51 -05:00
Tim Gerundt
64712eb616 Show "-Empty-" value for empty due dates in ticket view
When you don't use a "SLA Plan" the "Due Date" can be empty. The staff ticket view use now a "-Empty-" display value that the update popup link works.

It also fix a invalid syntax from the table cell.
2021-09-06 11:47:18 +02:00
aydreeihn
311a600521 Issue: Audit Closed Ticket Events
This commit fixes an issue where we were double auditing the Closed event for Tickets. This should have been removed in PR #5051 in the 'Code Optimization' commit where we started automatically logging some of the audits in class.orm.php
2021-08-24 14:56:56 -05:00
aydreeihn
99ec09a2ea Feature: Filter Thread Event Improvement
This commit improves upon the feature by adding a 'getEventDescription' function to the 'TriggerAction' class so that we don't have to check to see if the method exists for the type of filter action.

It also ensures that an object is found that can be used within the Thread Event, and if we don't find one, we will just generalize the wording.

Ex:
Thread Event where name is found:
Set Department Filter set Department to Parent

Thread Event where Dept name is not found:
Set Department Filter set Department
2021-08-11 15:58:17 -05:00
aydreeihn
1fd2b6b95c Feature: Log Event For Filters
This commit adds further detail to logging thread events for filters by creating a thread event for each filter action stating the filter, what it changed, and the value it was set to.
2021-08-10 15:37:40 -05:00
aydreeihn
7d48735acc Feature: Log Event For Filters
This commit adds a thread event to show which filters were applied to Tickets.

Note: If kept this way we would need a patch to update the event table and add the 'filter' event
2021-08-09 16:40:01 -05:00
Af0x
dee6a13a55 Fixes permission issue when registration mode ist disabled 2021-08-08 21:21:58 +02:00
JediKev
65ca4e6f2b Add Release Notes for v1.15.3.1 2021-07-28 19:09:51 +00:00
JediKev
82d56fa68b Merge pull request #5938 from protich/hotfix/auth-backend
Reviewed-By: JediKev <kevin@enhancesoft.com>, Aydreeihn <adriane@enhancesoft.com>
2021-07-28 14:02:03 -05:00
JediKev
0d2bd18dae Add Release Notes for v1.15.3 2021-07-28 15:44:45 +00:00
JediKev
e70f3266d3 Merge branch '1.14.x' into develop 2021-07-28 15:40:10 +00:00
JediKev
4842f6f03b Add Release Notes for v1.14.7 2021-07-28 15:38:33 +00:00
JediKev
f4b7930735 Merge pull request #5936 from JediKev/session/verify-useragent-string
Reviewed-By: JediKev <kevin@enhancesoft.com>, Aydreeihn <adriane@enhancesoft.com>
2021-07-28 10:15:49 -05:00
JediKev
13627c045a Merge pull request #5935 from JediKev/xss/client-side-i18n
Reviewed-By: JediKev <kevin@enhancesoft.com>, Aydreeihn <adriane@enhancesoft.com>
2021-07-28 10:14:35 -05:00
JediKev
ebc6189d01 Merge pull request #5934 from JediKev/security/open_php-refresh
Reviewed-By: JediKev <kevin@enhancesoft.com>, Aydreeihn <adriane@enhancesoft.com>
2021-07-28 10:13:11 -05:00
JediKev
b8603c74fc security: open.php Refresh
This addresses an issue reported by Vladislav Alyohin where Users can create
a Ticket in the Client Portal and click Refresh over and over again on
success. The result is a duplicate Ticket being created (with a different
Ticket Number) for each refresh. This adds an else statement so if there is
no client or if they are no longer valid we will rotate the CSRF token. This
will create the initial Ticket and on refresh will force the User back to
the Landing Page.
2021-07-28 15:11:40 +00:00
JediKev
bac70361ff Merge pull request #5933 from JediKev/xss/svg-image
Reviewed-By: JediKev <kevin@enhancesoft.com>, Aydreeihn <adriane@enhancesoft.com>
2021-07-28 10:09:37 -05:00
Peter Rotich
0fbbf878a5 Merge pull request #5931 from JediKev/issue/setup-admin-password-heltip-verbiage
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-07-28 08:51:42 -05:00
Peter Rotich
4ea1c67721 Merge pull request #5926 from JediKev/issue/getDBVersion-sql-errors
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-07-28 08:50:43 -05:00
Peter Rotich
8cdbd979d2 Merge pull request #5932 from JediKev/redactor/upgrade-to-version-3.5.1
redactor: Upgrade to version 3.5.1
2021-07-28 08:49:47 -05:00
JediKev
7866a7203e issue: Setup Admin Password Heltip Verbiage
This addresses 5930 where the Helptip for the Admin Password field on
Install is incorrect. The Helptip states the password has to be a minimum of
5 characters where in reality it requires a minimum of 6. This updates the
Helptip as well as the inline string from `Must be five (5) characters or
more.` to `Must be six (6) characters or more.`. In addition, this updates
the phrase `(Five characters min)` to `(Six characters min)` in
`include/class.validator.php` as well as updates the check for less than 5
characters.
2021-07-27 17:52:33 +00:00
JediKev
43210e3f19 issue: getDBVersion() SQL Errors
This addresses an issue where when `OsticketConfig::getDBVersion()` is ran,
a `column not found` SQL Error is generated. This is due to the config table
structure being completely different from 1.7 onwards. This adds a check to
see if the `MAJOR_VERSION` constant is defined, if so, it will skip the
`OsticketConfig::getDBVersion()` call in `include/class.ostsession.php`
(thus skipping the query execution). If the constant is not defined it will
continue on and call `OsticketConfig::getDBVersion()`.
2021-07-27 17:29:41 +00:00
JediKev
2617f53120 redactor: Upgrade to version 3.5.1
This upgrades Redactor from 3.5.0 to 3.5.1 so that we are utilizing the
latest code. This provides a few bug fixes and improvements.
2021-07-27 14:49:27 +00:00
JediKev
68dcaa2e54 xss: SVG Image
This addresses a security vulnerability reported by xxx where uploading a
malicious SVG, getting the direct file link, adding `s=1` to the end, and
visiting the link directly will render the SVG in the browser and execute
the malicious Javascript within the SVG. This adds a CSP (Content Security
Policy) header with `default-src 'self'` to the display code. When this
header is present it prevents all inline Javascript execution thus
mitigating the XSS.
2021-07-26 17:32:38 +00:00
JediKev
fd560df058 xss: Client-Side i18n
This mitigates a vulnerability reported by @tieupham267 where XSS is
possible via the `REQUEST_URI` parameter on the Client Portal. This is due
to the parameter not being converted to HTML entities before attaching to
`<link>` tags. This adds `htmlspecialchars()` around the `REQUEST_URI` to
ensure the content is properly converted.
2021-07-26 17:25:30 +00:00
JediKev
f71c95482c session: Verify UserAgent String
This adds an extra layer of security to Sessions where we will verify the
UserAgent string. We will check to see if the UserAgent string saved in the
database matches the current UserAgent string from the request. If the two
do not match we will destroy the session and force the affected User/Agent
to login again.
2021-07-26 17:23:47 +00:00
Peter Rotich
e7ed32c3d6 Merge pull request #5927 from JediKev/redactor/upgrade-to-version-3.5.0
redactor: Upgrade to version 3.5.0
2021-07-26 10:59:25 -05:00
JediKev
2ba24e7544 redactor: Upgrade to version 3.5.0
This upgrades Redactor from 3.4.12 to 3.5.0 so that we are utilizing the
latest code. This provides a few bug fixes and improvements.
2021-07-22 20:22:02 +00:00
Peter Rotich
e624d1178b Merge pull request #5924 from JediKev/issue/missing-thread-on-referral-check
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-07-22 09:40:15 -05:00
JediKev
1359d9197c issue: Missing Thread On Referral Check
This addresses an issue where attempting to Assign a Child Ticket throws a
fatal error of `Call to a member function getReferral() on null`. This is
due to the `thread` relation not being available for Child Tickets; instead
`child_thread` is available. This updates the code to use `getThread()`
which first checks if `thread` relation exists, if not it returns the
`child_thread` relation.
2021-07-20 20:10:28 +00:00
Peter Rotich
da05573f8c Auth: Service Name
This commit addresses an issue introduced by commit b755b990.
2021-07-19 02:06:53 +00:00
Peter Rotich
5eb9cbb04b Merge remote-tracking branch 'upstream/1.14.x' into develop 2021-07-19 00:43:19 +00:00
Peter Rotich
bc6ec6b19c Merge remote-tracking branch 'upstream/1.14.x' into develop 2021-07-18 19:31:22 +00:00
Peter Rotich
487607828f Merge remote-tracking branch 'upstream/develop' into develop 2021-07-17 16:58:22 +00:00
Peter Rotich
cd96ea3c98 Merge pull request #5925 from protich/issue/auth_service-name
Auth: Service Name on Client Portal
2021-07-22 12:53:27 -05:00
Peter Rotich
f64f911151 Merge remote-tracking branch 'upstream/1.14.x' into develop 2021-07-17 16:57:08 +00:00
Peter Rotich
b755b990ec Auth: Service Name on Client Portal
Use configurable service name when supported by the auth backend.
2021-07-17 16:51:07 +00:00
Wout Mertens
0d0d8a1a0b class.email: allow empty smtp_passwd when existing 2021-06-17 15:14:50 +02:00
Peter Rotich
70256e08d4 Merge remote-tracking branch 'upstream/1.14.x' into develop 2021-06-14 16:12:38 +00:00
Peter Rotich
f4f51d9ab8 Merge pull request #5908 from JediKev/readme/update-php-version-1.14.x
readme: Update PHP Version
2021-06-14 11:01:02 -05:00
Peter Rotich
6000cb1af8 Merge pull request #5911 from protich/issue/cdata+installer
CDATA: Rebuild Cdata tables post Install
2021-06-14 11:00:38 -05:00
Peter Rotich
bb1661c238 Merge pull request #5912 from osTicket/revert-5897-develop
Revert "Prevent session fixation"
2021-06-14 11:00:23 -05:00
Peter Rotich
5b30bdd7ae Revert "Prevent session fixation" 2021-06-14 10:57:22 -05:00
JediKev
a1cf24f3b7 readme: Update PHP Version
This updates the PHP version requirements and recommendations to match the
1.14.x series.
2021-06-09 20:58:09 +00:00
Peter Rotich
a9b4095a8f Merge pull request #5907 from JediKev/redactor/upgrade-to-version-3.4.12
redactor: Upgrade to version 3.4.12
2021-06-08 13:55:49 -05:00
JediKev
89b18790b6 redactor: Upgrade to version 3.4.12
This upgrades Redactor from 3.4.11 to 3.4.12 so that we are utilizing the
latest code. This provides a few bug fixes and improvements.
2021-06-03 18:36:27 +00:00
Peter Rotich
4409dbdfd0 CDATA: Rebuild Cdata tables post Install
This commit addresses an issue where CDATA tables got dynamically
created early in the install process, resulting in missing fields.

The change ensures CDATA tables (views) are rebuilt at the end of
install process.
2021-05-13 13:37:18 +00:00
Peter Rotich
fa17c8f9ba Merge remote-tracking branch 'upstream/develop' into develop 2021-05-13 09:45:47 +00:00
Peter Rotich
ee2a3b4901 Merge pull request #5897 from isaacnia/develop
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-06-12 17:49:10 -05:00
Peter Rotich
0f169fef28 Merge pull request #5900 from aydreeihn/issue/deleted-forms
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-06-03 11:31:11 -05:00
aydreeihn
4494bf48ac Issue: Deleted Forms on Help Topics
This commit fixes an issue we had with forms that have been deleted that were attached to a Help Topic. If a custom form is attached to a help topic and then the form is deleted, we put a flag on the form so that existing tickets still show the fields. However, if you are creating new tickets with those help topics, the deleted form is still showing up even though it should be hidden.

A check has now been added in the getFormsForHelpTopic method to skip deleted forms when creating new Tickets.

The commit also updates the isDeletable to use the hasFlag function that was added.
2021-06-01 16:36:46 -05:00
Rasool Isaacnia
c9b9f168c8 Prevent session fixation 2021-05-22 23:28:37 +04:30
Peter Rotich
525b1669d5 Merge pull request #5896 from protich/feature/cdata
CDATA: Dynamic Forms Views
2021-05-19 15:38:43 -05:00
Peter Rotich
f252179c2c Merge pull request #5895 from protich/feature/cdata
CDATA: Check Cdata Tables on Cron
2021-05-19 09:33:41 -05:00
Peter Rotich
5d993c16c6 Merge pull request #5784 from gerundt/tweak-pagenate
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-18 10:27:28 -05:00
Peter Rotich
723e1031c3 Merge pull request #5894 from protich/feature/cdata
CDATA: DynamicFormField Update
2021-05-18 10:24:34 -05:00
Peter Rotich
536ce741ac Merge pull request #5891 from aydreeihn/issue/priority_save
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-17 13:17:19 -05:00
aydreeihn
56c50b8ee8 Issue: Saving Priority Field
This commit fixes an issue introducted by PR #5880 where we needed to split up the string of if statements checking the value and ids passed into to_php so that if we end up getting the id in one of the ifs above, we still do the priority lookup.
2021-05-13 13:02:10 -05:00
Peter Rotich
0331c0c2bf Merge pull request #5886 from aydreeihn/issue/filter-email-vars
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-13 10:16:15 -05:00
Peter Rotich
5c951aa600 Merge remote-tracking branch 'upstream/1.14.x' into develop 2021-05-13 09:45:37 +00:00
Peter Rotich
4ab3602928 CDATA: Dynamic Forms Views
This addreses an issue in 3397987 where the upgrader attempts to create
cdata tables before Task form is loaded.

This commits moves the task to the end of upgrade process.
2021-05-12 19:41:35 +00:00
Peter Rotich
aba59702a0 CDATA: Don't drop data view on SQL error
Data view drop is solely done on form change now. Rebuilding the view on
an SQL error can cause enless rebuild and causing possible database
crash.
2021-05-12 17:59:17 +00:00
Peter Rotich
33979875fa CDATA: Dynamic Forms Load
Make sure cdata tables are created, on dynamic forms load, when
upgrading from 1.6.x
2021-05-12 17:59:17 +00:00
Peter Rotich
b758c14d1a CDATA: Check Cdata Tables on Cron
This commits adds a check, on cron call, to ensure cdata tables exists.
2021-05-12 17:58:28 +00:00
Peter Rotich
9f01ee1d38 CDATA: Installer
Make sure cdata tables are created post install
2021-05-12 09:29:31 +00:00
Peter Rotich
678decc4cb CDATA: DynamicFormField Update
This commit addresses an issue where dynamic form field update can
trigger multiple cdata rebuld queries, resulting in database DOS or even
a cluster crash/lockup depending on the number of form entry entries.

The change makes it so CDATA tables rebuild is done on dynamic form
field update, instead of relying on users/agents to trigger the rebuild
process.
2021-05-12 09:05:43 +00:00
aydreeihn
3a36727caa Issue: Filter Email Variables
This commit fixes an issue where some template variables could not be used when using a Filter to send an email. The filter should run after the appropriate variables have been created in the ticket, and we need to set the recipient as the ticket owner within the filter action as well.
2021-05-06 10:44:14 -05:00
Peter Rotich
24bb680581 Merge pull request #5885 from protich/issue/localize_status_name
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-05 13:17:10 -05:00
Peter Rotich
19baad8b61 Merge pull request #5882 from protich/issue/images_max-age
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-05 13:16:20 -05:00
Peter Rotich
5fe18d0cf5 Merge pull request #5774 from gerundt/persons-name
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-05 12:17:39 -05:00
Peter Rotich
ef48d6edcf Merge pull request #5883 from protich/staff-updatePerms-error
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-05 10:53:54 -05:00
Peter Rotich
f7e9ad5de4 Merge pull request #5884 from JediKev/typo/default-sorting
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-04 16:53:01 -05:00
Peter Rotich
f22e34f779 Merge pull request #5842 from JediKev/issue/choices-field-sanitization
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-04 15:00:08 -05:00
JediKev
89c322b011 typo: Default Sorting
This uses 5835 and rebases it for `1.14.x`. This updates the typos of
`Defaut Sorting` to the correct spelling of `Default Sorting`.
2021-05-04 19:21:48 +00:00
JediKev
07526af672 issue: Choices Field Sanitization
This addresses an issue where ChoicesField configuration is malformed due to
sanitization. This adds a check for `$config['html']` and if it's `false`
(not set) then we skip heavy sanitization.
2021-05-04 18:43:21 +00:00
Peter Rotich
c597d06a2e Merge pull request #5873 from JediKev/issue/edit-entry-dropped-attachments
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-04 11:51:40 -05:00
Peter Rotich
1892ac4584 Merge pull request #5862 from JediKev/issue/release-notes-links
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-04 11:31:17 -05:00
Peter Rotich
99967e11fe Merge pull request #5839 from JediKev/issue/ticket-dept-sla-var-sla_id
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-04 11:27:12 -05:00
Peter Rotich
4950e75941 Merge pull request #5847 from nicoletta-maia/issue/banlist-sorting-by-updated
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-04 10:39:58 -05:00
Peter Rotich
3e8b7067c5 Merge pull request #5869 from JediKev/issue/emailtest-draft
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-04 10:37:43 -05:00
Peter Rotich
09543ef69c Merge pull request #5875 from nicoletta-maia/issue/typo-task-alert-email-template
Reviewed By: Peter Rotich <peter@osticket.com>
2021-05-04 10:35:38 -05:00
Peter Rotich
1e7cc6d176 Merge pull request #5870 from JediKev/redactor/upgrade-to-version-3.4.11
redactor: Upgrade to version 3.4.11
2021-05-04 10:33:30 -05:00
Tim Gerundt
a078a0fc34 Issue: Topic->getHelpTopics() don't return localized names when $allData = true
The function Topic->getHelpTopics() don't return localized names when the parameter $allData is true.
2021-04-28 05:48:43 +02:00
Nicoletta Maia
8178b4d4cb issue: "New Task Alert" email template typo 2021-04-27 15:38:24 +02:00
JediKev
a9a64ed643 issue: Edit Entry Dropped Attachments
This addresses an issue where editing your own Thread Entry and clicking
Save two separate times drops the attachment(s). This is due to the order of
operations in the backend where if editing your own Thread Entry we delete
the previous entry and set `$old` to the original Thread Entry (parent of
the previous entry). This causes the attachment lookup to search for the
wrong `object_id` which obviously finds no attachments. This moves the
attachment lookup before we delete the previous entry so we can search with
the appropriate ID.
2021-04-26 21:00:13 +00:00
JediKev
8d6c2790ec redactor: Upgrade to version 3.4.11
This upgrades Redactor from 3.4.9 to 3.4.11 so that we are utilizing the
latest code. This provides a few bug fixes and improvements.
2021-04-22 18:37:10 +00:00
JediKev
27259e1f74 issue: EmailTest Draft
This addresses a very minor issue where the draft save on EmailTest throws
an error. This is due to changes made in 5694 where `message` was removed
from `$field_list` (security reasons). This updates the name of the textarea
from `message` to `body`. This allows the `_findDraftBody()` method to find
the body successfully and continue on. This also updates every reference of
`message` to `body` in this instance.
2021-04-22 17:20:50 +00:00
JediKev
e9a2155ce4 issue: Release Notes Links
This addresses a small issue where the links to the Release Notes were
pointing the old location in the Docs. This updates the links to point to
the Github Releases page where it shows all Release Notes for all versions.
2021-04-14 19:08:30 +00:00
Peter Rotich
6173a73043 status: Localize Status Names
Localize status names by default
2021-04-14 04:49:06 +00:00
Peter Rotich
7226677468 Merge remote-tracking branch 'upstream/1.14.x' into develop 2021-04-14 04:36:13 +00:00
Peter Rotich
e012899bfb Merge pull request #5880 from aydreeihn/issue/cust-field-in-queue
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-05 10:54:49 -05:00
aydreeihn
bd4cfb4524 Issue: Queue Columns Custom Fields
This commit fixes an issue where a DepartmentField or PriorityField added to a Custom Form would not show up in a
 Queue Column.

PriorityField:
In to_php, if the $value passed in is actually the priority_id or the $id passed in is actually the priority_id, we should use the id to get the Priority value that should be displayed, however, if the $value passed in is already the Priority value as a string, we should return that value.

DepartmentField:
A display function needed to be added for this field. If the $dept passed in is the Department name, we should return that, otherwise if the $dept isn't a Dept object, we should use the parent display function as it was doing before. Finally, if the $dept is a Dept object, we should get the Department name from that.
2021-05-04 14:49:29 -05:00
Peter Rotich
d180ba69e6 Merge pull request #5871 from protich/feature/zipexport
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-04 11:39:12 -05:00
Peter Rotich
7e45f36442 Merge pull request #5864 from gerundt/translate-open-for-users
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-04 11:32:38 -05:00
Peter Rotich
d5be99cc4b Merge pull request #5854 from aydreeihn/issue/cust-field-exports
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-04 11:30:32 -05:00
Peter Rotich
af4b3bd617 Merge pull request #5845 from aydreeihn/issue/list-item-spaces
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-05-04 10:38:47 -05:00
Peter Rotich
e8807dd929 Merge pull request #5868 from aydreeihn/enhancement/s3-plugin-folders
Enhancement: S3 Plugin Folder Capability
2021-05-04 10:34:28 -05:00
aydreeihn
ae4ed635a5 Enhancement: S3 Plugin Folder Capability
This commit adds functionality that will allow us to use the attrs field in the file table to determine the file location being used for the S3 Pluign.

Credit goes to @protich
2021-04-22 12:10:57 -05:00
aydreeihn
8140d4b769 Issue: Custom Dept/Custom Assignee Exports
This commit fixes an issue with exporting Custom Department or Custom Assignee fields. In the exports, the fields were exporting as IDs instead of the actual field value.

Custom Department Field:
In from_query, if the value is just a dept_id instead of the department name, the field should pass the display function.

Custom Assignee Field:
- In to_php, we were missing logic needed to parse cdata into an array if the value was saved as 'id,value'
Ex: t34,Team1
First, we need to make sure not to accidentally clear out this value if the JsonDataParser doesn't work.
Next, this string needs to be set to an array like this in order to render properly:
['t34'] => 'Team1'

- If there is an Assigntee type, we should use substr to remove the letter from the array key in the event that the id for the field is more than one number
Ex: t34
The type should be 't' and the id should be 34.
Using key($value)[1] would set the id to just 3

- If the value coming into AssigneeField::to_php is the staff_id, meaning the value is just a number and we are not sending a type through, we should look up and return the Staff object.
2021-04-15 17:04:37 -05:00
Tim Gerundt
6065715378 Issue: 'Open' heading don't get translated
In the ticket overview for the users get the 'Open' heading not translated.
2021-04-15 09:30:34 +02:00
Peter Rotich
4211952583 Role: Handle null perms
This commits improves on f9626f8 by defaulting to empty array instead of
suppressing warning on param 2 being null.
2021-04-14 00:05:00 +00:00
Tim Gerundt
f9626f8401 Issue: Missing null check in Staff->updatePerms()
If a agent has no permissions and you will give him/her the first permission, the class Staff->updatePerms() wrote a `array_key_exists() expects parameter 2 to be array, null given` warning.

Problem is, that $permissions->perms is null. With a RolePermission->exists() function is the code easier to read an don't show the warning.
2021-04-14 00:03:05 +00:00
Peter Rotich
292df94078 Make Max-Age consistent across backends
This commits makes max-age (ttl) for logos and backgrounds consistent
regardless of the storage backend.
2021-04-13 19:45:12 +00:00
Peter Rotich
1328bd76c0 Zip Export: Include Custom File Upload Files
Add dynamic file upload field attachments to zip file export.
2021-04-13 10:41:06 +00:00
Nicoletta Maia
15ccc71571 Banlist sorting by Updated 2021-03-26 17:51:41 +01:00
aydreeihn
ef6c949065 Issue: Spaces in List Items
This commit fixes an issue we had with list items that began or ended with a space. If the list was being used in a Typeahead or Input field, the values couldn't be selected if they didn't match with the spaces exactly. This commit strips the leading and trailing spaces before saving the list items.
2021-03-24 10:58:15 -05:00
JediKev
bf15d6f696 issue: ticket.dept.sla Variable sla_id
This addresses an issue where when using the variable `ticket.dept.sla` the
system throws a fatal error. This is due to the SLA's relation to Department
defined in `include/class.dept.php`. It's defined as `array('sla_id' =>
'SLA.sla_id')` which is incorrect as `SLA.sla_id` does not exist. This
updates the relation from `array('sla_id' => 'SLA.sla_id')` to
`array('sla_id' => 'SLA.id')` so that it uses the appropriate column.
2021-03-17 17:17:34 +00:00
JediKev
cb6766e5e4 Add Release Notes for v1.15.2 2021-03-03 19:44:37 +00:00
JediKev
f76a351bff Merge branch '1.14.x' into 1.15.x 2021-03-03 19:41:35 +00:00
JediKev
cc2f481e78 Add Release Notes for v1.14.6 2021-03-03 19:16:23 +00:00
Peter Rotich
4d37494bc5 Merge pull request #5830 from JediKev/xss/onerror-property
Reviewed-By: Peter Rotich <peter@rotich.com>
2021-03-03 12:59:55 -06:00
JediKev
8d956e0f46 xss: FormAction Attribute
This mitigates a vulnerability reported by Hieu Tran (STeam) where someone
can potentially input malicious code via the `formaction` attribute. This
adds `formaction` to HtmLawed's `deny_attribute` option so that any code
within it is stripped out.
2021-03-03 18:48:13 +00:00
JediKev
25e6d123ac xss: onerror Property
This mitigates a vulnerability reported by Yunus AYDIN where some field
types are vulnerable to XSS via the `onerror` property. This adds `on*` to
the HtmLawed config to remove all of the `on*` properties from content. This
also updates `Format::htmlchars()` in some places to force sanitization of
the content.
2021-03-03 18:45:17 +00:00
Peter Rotich
dcf435d22c Merge pull request #5828 from JediKev/redactor/upgrade-to-version-3.4.9
redactor: Upgrade to version 3.4.9
2021-03-03 12:35:41 -06:00
JediKev
ab40f97d87 redactor: Upgrade to version 3.4.9
This upgrades Redactor from 3.4.8 to 3.4.9 so that we are utilizing the
latest code. This provides a few bug fixes and improvements.
2021-03-03 18:22:35 +00:00
Peter Rotich
d62e96f7f4 Merge pull request #5826 from JediKev/issue/mark-as-popup-manager-no-access
issue: markAs Popup Manager (No Access)
2021-03-03 12:10:12 -06:00
JediKev
8d1d623c65 issue: markAs Popup Manager (No Access)
This addresses an issue where if an Agent does not have access to a
Department but is the Manager of the Department and they go to mark a Ticket
as Answered/Unanswered a blank popup appears. This is due to `isManager()`
only checking the Agent’s Primary Department for Manager access. This
updates the method to accept a Department object and if one is passed we
will check this for Manager access, otherwise we will default to the Agent’s
Primary Department.
2021-03-03 15:21:26 +00:00
Peter Rotich
07a5e8dfc6 Merge pull request #5821 from protich/issue/misc-fixes++
Misc. Fixes
2021-02-28 07:41:20 -06:00
Peter Rotich
b91b7f6974 Merge pull request #5760 from JediKev/issue/export-memory-limit
issue: Export Memory Limit
2021-02-28 07:39:29 -06:00
Peter Rotich
d09b0d1f32 Merge pull request #5782 from JediKev/issue/dashboard-export-date-range
issue: Dashboard Export Date Range
2021-02-28 07:39:02 -06:00
Peter Rotich
a775d19e20 Merge pull request #5793 from aydreeihn/issue/task-inline-transfer
Issue: Task Inline Transfer
2021-02-28 07:38:40 -06:00
Peter Rotich
f5435565d5 Merge pull request #5814 from aydreeihn/issue/unlinking
Issue: Unlinking Tickets
2021-02-28 07:38:07 -06:00
Peter Rotich
3e177bb556 Make word count error match the actual limit 2021-02-24 14:43:27 +00:00
Peter Rotich
2a56da7d1f Mute warning when Every Minute is selected. 2021-02-24 14:25:34 +00:00
Peter Rotich
b564ce3af0 Remove extra selection - Choice Field handles prompt. 2021-02-24 14:15:08 +00:00
Peter Rotich
4550b65c8f Fail gracefully when supported matches return null 2021-02-24 14:00:34 +00:00
Peter Rotich
858649c111 Create variable before passing it by reference 2021-02-24 13:57:43 +00:00
Peter Rotich
edd1feb86e FAQ: Check for lookup failures 2021-02-24 13:53:27 +00:00
Peter Rotich
7f68060919 2fa: use isset to check checkbox 2021-02-24 13:42:02 +00:00
Peter Rotich
14e9fb2343 Session: Regenerate session id before closing it.
:wq!
2021-02-24 13:29:56 +00:00
aydreeihn
98efec5dac Issue: Unlinking Tickets
This commit fixes an issue where unlinking all Tickets from a Parent Ticket did not remove the linked flag from the Parent Ticket which caused the Parent Ticket to show up in queues as still being Linked.

This addresses Issue #5811
2021-02-18 12:54:42 -06:00
Peter Rotich
ea01bd0954 Merge pull request #5792 from aydreeihn/issue/visibility
Issue: Visibility Permissions
2021-02-11 14:11:33 -06:00
aydreeihn
8da9da3215 Issue: Visibility Permissions
This commit fixes an issue with checking on choices for the DepartmentChoiceField. We were setting $this->_choices to an empty array in the getQuickFilterChoices function, so when we did the check to see if choices were set or not, they were technically already set which resulted in the quick filters for the department field always showing as none.
2021-02-11 13:40:57 -06:00
aydreeihn
e43d6bf423 Issue: Task Inline Transfer
This commit fixes an issue where we were not checking role permissions for inline edit on Tasks. If an Agent without the role permission to Transfer Tasks tried to click the Deparment to transfer it, it popped up a blank modal and said 'Permission Denied'. Now, the Department will not have the edit link if they don't have the permission.
2021-02-04 16:32:49 -06:00
Peter Rotich
92f797fb6b Merge pull request #5789 from aydreeihn/issue/visibility
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-02-03 22:07:54 -06:00
aydreeihn
d8f6ef6f86 Issue: Agents/Depts in Queue Cols
This commit fixes an issue with how Departments and Agents show up in queue columns. If an Agent's Visibility was set to where they could only see Depts/Agents in a Department they have access to, it became an issue if the Agent was assigned a ticket in a Department they couldn't access (queue column would be blank) or if a Ticket was assigned to an Agent's Department but was assigned to an Agent that is not in any of the Agent's Departments (queue column would be the staff_id).

As long as an Agent has access to a Ticket, they should be able to see the value of the Dept/Agents related to that Ticket.
2021-02-03 13:37:48 -06:00
Peter Rotich
d0f68c3e6b Merge pull request #5787 from protich/issue/deptvisibility
Depts Visibility
2021-02-02 10:59:27 -06:00
Peter Rotich
fe37ae29cb Depts Visibility
Consolidate how departments visibility is applied.
2021-02-02 01:46:57 +00:00
Peter Rotich
a48fe813b4 Merge pull request #5783 from JediKev/issue/getDefaultDeptId-on-null
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-01-30 00:11:25 -06:00
Peter Rotich
9411eab1f4 Merge pull request #5785 from aydreeihn/issue/visibility-permissions
Reviewed-By: Peter Rotich <peter@osticket.com>
2021-01-30 00:09:57 -06:00
aydreeihn
71f4c0cbd5 Issue: Revise getDepartments
This commit cleans up the logic for how we use the getDepartments function. We should specify publiconly vs activeonly so that they can be used individually to specify which departments we want to get: publiconly, activeonly, or both as the criteria.
2021-01-29 12:31:06 -06:00
aydreeihn
3ee5941849 Issue: Visibility Permissions
This commit refactors the way we handle the visibility permissions for the ability to see all Agents and Departments.
2021-01-29 10:31:11 -06:00
Tim Gerundt
573ab3305b Issue: Class PageNate had problems with total value as string
If the total value for the class PageNate is a *valid* string number the class still used a fixed 500 value
2021-01-29 09:37:43 +01:00
JediKev
38a09e6202 issue: getDefaultDeptId() On Null
This addresses an issue where the system throws a fatal error of `Fatal
error: Uncaught Error: Call to a member function getDefaultDeptId() on null`
when doing a fresh installation. This was introduced with 5777 and is due to
trying get the default Department's ID from the system config when it's not
available. This adds a check for `$cfg` before calling it to ensure no fatal
errors are thrown.
2021-01-28 22:18:01 +00:00
JediKev
db791495a4 issue: Dashboard Export Date Range
This addresses an issue where choosing a Report Timeframe in the Dashboard
and clicking Refresh defaults the date to 2020 (yikes, please don't make us
relive it). In addition, the CSVs exported from the selected time periods
are blank. This is due to a date formatting issue in
`OverviewReport::getStartDate()`. This updates the replacement format from
`array('yy', 'yyyy', 'mm')` to `array('y', 'yy', 'mm')`.
2021-01-28 22:13:18 +00:00
Peter Rotich
ea3f0150d8 Merge pull request #5779 from JediKev/issue/task-last-update-var
issue: Task last_update Var
2021-01-27 09:05:28 -06:00
JediKev
08cd76232b issue: Task last_update Var
This addresses a small issue reported on the Forum where when using the
`%{task.last_update}` variable in the Task Email Templates you receive a
fatal error of `Uncaught OrmException: Task: last_update: Field not defined
in`. This is due to the variable pulling data from `last_udpate` whilst not
having a column called `last_update` in the `ost_task` table. This updates
the variable to pull data from `updated` as this is the correct column to
use in the `ost_task` table.
2021-01-26 15:29:54 +00:00
Peter Rotich
c4353efde6 Merge remote-tracking branch 'upstream/develop' into develop 2021-01-21 21:53:28 +00:00
Peter Rotich
8d1a74fe65 Merge pull request #5777 from aydreeihn/issue/default-dept
Issue: Echoing Default Dept Status
2021-01-27 09:04:39 -06:00
aydreeihn
fe315757ec Issue: Echoing Default Dept Status
This commit fixes an issue introduced with PR #5755 where we just echo the status of the Default Department so that you don't have the option to disable/archive it. When we update a Department, if $vars['flags'] isn't present, we clear out the flags to 0 and then set them according to the other vars set. Since we are just echoing the status name for the default department, $vars['status'] is NULL, so when you save the department, it ends up being disabled (we can't put the flag back). So if we're updating the default department, we need to confirm that it is the default and then manually set $vars['status'] to 'active' so that the flag is set correctly.
2021-01-25 09:22:40 -06:00
Peter Rotich
6ee644ac4f Merge remote-tracking branch 'upstream/1.14.x' into develop 2021-01-21 21:53:19 +00:00
Tim Gerundt
fa64ad42e3 Tweak PersonsName->getShort() and getShortFormal()
The functions PersonsName->getShort() and getShortFormal() had also problems with users that don't have first AND last name
2021-01-20 11:17:37 +01:00
Tim Gerundt
ad91e6651f Tweak PersonsName->getMiddleInitial()
The function PersonsName->getMiddleInitial() adds the "." only if necessary. Now it can used internal easier.
2021-01-20 11:04:21 +01:00
Tim Gerundt
8671a68c8e Tweak PersonsName->getLastFirst()
If a user has not first AND last name the function PersonsName->getLastFirst() returned still a ", " seperator
2021-01-20 10:53:29 +01:00
JediKev
3a5e5c9990 issue: Export Memory Limit
This addresses an issue where exporting large datasets (eg. 100,000+ Closed
Tickets) gives you a blank CSV once complete. This is due to PHP running out
of memory which results in no data being written to the CSV at all. This
sets the `QuerySet::OPT_NOCACHE` option to `true` so the result sets are
not stored in memory. Essentially, storing large result sets in memory is no
bueno.
2021-01-19 21:28:15 +00:00
JediKev
fe5702f930 Merge pull request #5768 from JediKev/issue/scp-login-redirect
Reviewed-By: osTicket Team
2021-01-15 09:58:05 -06:00
JediKev
2a2e375a89 Merge pull request #5766 from gerundt/pagenate-showing
Reviewed-By: osTicket Team
2021-01-15 09:56:07 -06:00
JediKev
98b1d3197f Merge pull request #5763 from gerundt/no-queue-capitalize
Reviewed-By: osTicket Team
2021-01-15 09:55:07 -06:00
JediKev
4b3f5a6e13 Merge pull request #5762 from JediKev/issue/client-side-reply-draft-saving
Reviewed-By: osTicket Team
2021-01-15 09:54:17 -06:00
JediKev
70afa8a95a Merge pull request #5761 from JediKev/redactor/upgrade-to-version-3.4.8
Reviewed-By: osTicket Team
2021-01-15 09:53:27 -06:00
JediKev
b7d10e5eb4 Merge pull request #5755 from aydreeihn/issue/disabled-dept-email
Reviewed-By: osTicket Team
2021-01-15 09:50:12 -06:00
JediKev
beea4e17bd Merge pull request #5748 from JediKev/issue/assign-to-sort-alphabetically
Reviewed-By: osTicket Team
2021-01-15 09:48:29 -06:00
JediKev
58684d7b83 Merge pull request #5744 from ntozier/develop
Reviewed-By: osTicket Team
2021-01-15 09:47:32 -06:00
JediKev
9b12a54c89 issue: SCP Login Redirect
This addresses issue 5741 where when logged in as an Agent and visiting
`scp/login.php` directly it does not redirect you to the Ticket Queues,
instead it shows the login modal. This adds a check to `scp/login.php` to
see if there is a valid Agent Session and if so we redirect to the Ticket
Queues.
2021-01-13 19:46:19 +00:00
Tim Gerundt
63f0ae8e4c Use PageNate->showing() for Users and Orgs in SCP 2021-01-11 09:51:11 +01:00
Tim Gerundt
23488508b2 Don't capitalize Queue menu items 2021-01-08 11:51:18 +01:00
JediKev
996cd9ea7a issue: Client-Side Reply Draft Saving
This addresses an issue where Draft saving for the Post a Reply box on the
Client Portal returns the error `Draft body not found in request`. This is
due to using the generic name of `message` instead of the hashed Form name.
This updates the code to set the hashed Form name using
`$messageField->getFormName()`.
2021-01-07 19:53:02 +00:00
JediKev
ecb0193ff3 redactor: Upgrade to version 3.4.8
This upgrades Redactor from 3.4.6 to 3.4.8 so that we are utilizing the
latest code. This provides a few bug fixes and improvements.
2021-01-06 19:10:26 +00:00
aydreeihn
b1397a35ee Issue: Disabled Dept on Email
This commit finishes fixing an issue we had with disabling or archiving a Department that is assigned to an Email. At one time, we were setting the Department in the Email to the default Department if an Email's Department was disabled or archived. Part of this was removed in #4588. If we are going to leave the Department in the Email, we need to make sure that Tickets fetched from that email are not assigned to the Disabled/Archived Department. This commit will check the deptId that comes in and if the Department is not active, the Ticket will be assigned to the default Department.

It also makes it so that you cannot change the status of the Default Department to Archived or Disabled. Rather than showing up as a selection, we will just show the Department's status.
2020-12-22 13:53:46 -06:00
JediKev
77c7a12ea6 issue: Assign To Sort Alphabetically
This addresses a small issue where Agents were not sorted alphabetically
when Assigning/Re-Assigning a Ticket or Task. This is especially frustrating
when you have an enormous list of Agents. This adds `nsort()` to
`getDeptAgents()` so we can sort the Agents by the system's Name Format.
2020-12-14 18:41:11 +00:00
ntozier
4a3451fefe Update class.plugin.php
change **Admin panel -> manage -> Plugins** to display plugins by name (alphabetical) instead of by install id.
2020-12-09 14:52:56 -05:00
JediKev
fe1d1f8224 Add Release Notes for v1.15.1 2020-12-07 19:21:22 +00:00
JediKev
4de4ca8a27 Merge branch '1.14.x' into 1.15.x 2020-12-07 19:19:45 +00:00
JediKev
7234a1f7ad Add Release Notes for v1.14.5 2020-12-07 19:00:42 +00:00
JediKev
bb97d630f6 Merge pull request #5739 from JediKev/security/parent-ticket-access-client
Reviewed-By: JediKev <kevin@enhancesosft.com>, aydreeihn <adriane@enhancesoft.com>
2020-12-07 12:12:46 -06:00
JediKev
6071b70fca Merge pull request #5738 from JediKev/issue/mailfetch-inline-disposition
Reviewed-By: JediKev <kevin@enhancesosft.com>, aydreeihn <adriane@enhancesoft.com>
2020-12-07 12:11:43 -06:00
JediKev
443335ef50 Merge pull request #5737 from JediKev/issue/editor-spacing
Reviewed-By: JediKev <kevin@enhancesosft.com>, aydreeihn <adriane@enhancesoft.com>
2020-12-07 12:09:59 -06:00
JediKev
fbf0c7d889 issue: MailFetch Inline Disposition
This is a rewrite of 5733 that addresses issue 3884 where `imap_fetchbody()`
is not sufficient with some emails. This updates `MailFetcher::getPart()` to
check the MIME part's disposition and part number, if the disposition is
`inline` and the part number is `1` then we will use `imap_body()` instead.
2020-12-07 17:55:20 +00:00
JediKev
5972fe819c security: Parent Ticket Access (Client)
This addresses a vulnerability reported by Daniel Treffenstädt (MuonPi Team)
where any User can get access to any Parent Ticket by ID (not Number) even
if they don't have access to the Parent or any Children. This is due to
checking if the ticket is a parent and is merged (not linked) without
checking for access to the children. This updates the check to grab all
children and check the User's access to each. If the User has access to one
of the children they are allowed access to the Parent, however if they do
not have access to one of the children they are denied access.
2020-12-07 17:37:11 +00:00
JediKev
a6cbc5c08c issue: Editor Spacing
This addresses an issue where the `editor_spacing` was being applied to
emails and web created tickets. This updates the code to check for an Agent
or User session and if exists we will run `editor_spacing`; otherwise we
will not.
2020-12-07 17:35:34 +00:00
Peter Rotich
afebae33be Merge pull request #5731 from protich/issue/5729
placeholder: Quote and encode html chars
2020-12-07 09:14:55 -06:00
Peter Rotich
14045ee23e Merge pull request #5734 from protich/issue/reply-recipients
mail: Reply to Ticket Owner Only
2020-12-07 09:12:34 -06:00
Peter Rotich
2341c7a3b7 Merge pull request #5732 from aydreeihn/issue/add-email-collabs
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-12-04 11:31:41 -06:00
Peter Rotich
737a6e17ec Merge pull request #5728 from protich/issue/deptdel
dept: Dept Deletion Bigly Bad Bug
2020-12-04 11:30:45 -06:00
aydreeihn
a4ab6b615d Issue: Collaborator Adding New Collabs
This commit fixes an issue where if a Collaborator does a reply all to a Ticket and the reply includes the Ticket Owner as well as a new Collaborator, the new Collaborator was not added because of the error 'Ticket Owner cannot be a Collaborator' not being cleared out.
2020-12-04 11:28:43 -06:00
Peter Rotich
a4bb20ae02 mail: Reply to Ticket Owner Only
This commit addresses a bug where ticket reply is not sent to ticket
owner on a ticket with disabled collaborators or when ticket owner is
the only selected recipient.
2020-12-04 03:15:26 +00:00
Peter Rotich
1dccf46621 Merge pull request #5723 from JediKev/typo/change-user-confimation-popup
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-12-03 09:18:13 -06:00
Peter Rotich
0056d1444a placeholder: Quote and encode html chars
Double quote placeholder text and encode html chars.
2020-12-02 23:54:27 +00:00
Peter Rotich
7cba73d4dd dept: Dept Deletion Bug
This commit addresses a bug where deleting a department resulted in
deletion of associated help topics and emails!!
2020-12-02 21:33:52 +00:00
JediKev
79e6513b16 typo: Change User Confirmation Popup
This fixes a small typo in the Change User Confirmation Popup. This updates
`will longer have access to the ticket` to `will no longer have access to
the ticket`.
2020-12-01 15:47:54 +00:00
Peter Rotich
6d6b879837 Merge pull request #5715 from JediKev/readme/update-php-version
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-11-24 23:01:59 -06:00
Peter Rotich
d4a668f716 Merge pull request #5713 from JediKev/redactor/upgrade-to-version-3.4.6
redactor: Upgrade to version 3.4.6
2020-11-24 23:01:09 -06:00
JediKev
a4c85d7305 readme: Update PHP Version
This updates the PHP version requirements and recommendations to match the
1.15.x series.
2020-11-24 17:11:39 +00:00
JediKev
90652cc41d Merge branch '1.15.x' into develop 2020-11-24 17:02:50 +00:00
JediKev
5c77b0d274 redactor: Upgrade to version 3.4.6
This upgrades Redactor from `3.4.5` to `3.4.6` so that we are utilizing the
latest code. This provides a few bug fixes and improvements.
2020-11-23 15:17:16 +00:00
Peter Rotich
2cc22a0253 Merge pull request #5708 from JediKev/issue/task-from-ticket
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-11-20 10:42:35 -06:00
JediKev
4b48456118 issue: Task From Ticket
This addresses an issue where creating a Task from a Ticket does not save
the Task Description. This is due to a field name mismatch. This adds
`$desc->getClean()` to `$vars['description']` so we have the field name and
value ready for `TaskThread::addDescription()`.
2020-11-18 16:44:08 +00:00
JediKev
d5ee0df82c Merge pull request #5706 from JediKev/issue/major-version-boostrap
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2020-11-17 13:07:40 -06:00
JediKev
f525d39557 issue: Major Version Bootstrap
This updates the Major Version for 1.15
2020-11-17 18:23:44 +00:00
JediKev
462f8df8b0 Add Release Notes for v1.15 2020-11-17 18:09:42 +00:00
JediKev
faf0539118 Merge remote-tracking branch 'origin/develop' into 1.15.x 2020-11-17 18:06:30 +00:00
JediKev
5fc29c3c7a Add Release Notes for v1.14.4 2020-11-17 17:19:16 +00:00
JediKev
7acfcccdc7 Merge pull request #5705 from aydreeihn/issue/event-yaml-upgrades
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>
2020-11-17 10:22:54 -06:00
aydreeihn
38232f2edb Issue: Missing Events
This commit adds to the latest database task. We need to see if the event table has the login, logout, message, and note events, and if a database does not, we need to add them to be used with the audit plugin.
2020-11-17 10:04:18 -06:00
Peter Rotich
467cdb695d Merge pull request #5704 from aydreeihn/issue/event-yaml
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-11-16 16:45:58 -06:00
aydreeihn
52c7211ead Issue: Event YAML
This commit adds the login, logout, message, and note events to new helpdesk installations so that they can be used in the audit plugin.
2020-11-16 14:07:52 -06:00
Peter Rotich
7d99164714 Merge pull request #5703 from protich/revert/077d26f6
Partially revert commit 077d26f6d0
2020-11-16 13:18:46 -06:00
Peter Rotich
8e309ed368 Merge pull request #5701 from JediKev/mpdf/logo-overlap
mpdf: Logo Overlap
2020-11-13 11:47:59 -06:00
Peter Rotich
3f163e12d6 Merge pull request #5700 from aydreeihn/issue/template-groups
Issue: Viewing Email Templates
2020-11-13 11:46:50 -06:00
Peter Rotich
6ff24a9fdd Merge pull request #5694 from JediKev/issue/draft-save
issue: Draft Save
2020-11-13 11:46:35 -06:00
JediKev
949acc687a issue: Missing Description On New Task
This addresses an issue where the Task Description is missing when creating
new Tasks. This is due to a field name mismatch when 5694 was applied. This
gets the clean value to ensure the content is saved.
2020-11-13 17:09:54 +00:00
JediKev
f2c5c5a43c issue: Draft Save
This addresses a small issue introduced with 5684 where Drafts do not save
when creating a New Ticket via Staff/Client side. This is due to a field
name mismatch in `include/ajax.draft.php`. We are expecting `message` but we
get the hashed name instead. This addresses another issue where Drafts do
not save when creating a New Task. We are expecting `description` but we get
the hashed name instead. This adds the hashed names to the array of possible
fields which allows the system to find the Draft bodies and save the Drafts
successfully.
2020-11-13 17:09:54 +00:00
JediKev
5012ccc4dd mpdf: Logo Overlap
This addresses a small annoyance where the logo overlaps the date-timestamp
and looks ugly for bigger logos. This adds a blank line between the two so
the formatting looks nice again, no matter what size it is.
2020-11-13 17:02:48 +00:00
aydreeihn
817cdeeda7 Issue: Viewing Email Templates
This commit addresses Issue #5663 where there was a default selection option in the list of Email Templates that would display empty template fields that could not be saved.
2020-11-13 10:03:07 -06:00
Peter Rotich
982cc00bef Merge pull request #5696 from protich/issue/field-names+
forms: Pseudo-random name for Dynamic forms on POST
2020-11-12 19:08:22 -06:00
Peter Rotich
775661950d Merge pull request #5695 from protich/issue/authtoken
authtoken: Add ticket link when recipient is ticket owner
2020-11-12 19:07:26 -06:00
Peter Rotich
0ede727c57 Merge pull request #5699 from aydreeihn/issue/topics
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-11-12 19:06:58 -06:00
aydreeihn
bfaad5beeb Issue: Topics on Install
This commit addresses Issue #5697. We need to make sure that we are not trying to ensure there are Help Topics before installation has completed.
2020-11-12 16:00:01 -06:00
Peter Rotich
e36975f5bb Merge remote-tracking branch 'upstream/develop' into develop-next 2020-11-11 08:54:43 +00:00
Peter Rotich
b23d2b15d8 Merge pull request #5702 from protich/issue/dept_id+email
Change dept_id and priority_id fron tinyint to int
2020-11-16 13:03:18 -06:00
Peter Rotich
d554c2bc57 Partially revert commit 077d26f6d0
This commit partially reverts 077d26f6d0 by disabling forced random
form name for now.
2020-11-11 08:52:16 +00:00
Peter Rotich
97c0e727f8 Merge remote-tracking branch 'upstream/develop' into develop-next 2020-11-11 06:49:35 +00:00
Peter Rotich
e54f6f3e24 Change dept_id and priority_id fron tinyint to int
This commit changes dept_id and priority_id in email table from
tinyint(3) to int(11)
2020-11-11 06:37:01 +00:00
Peter Rotich
2a88796ec6 Merge pull request #5681 from aydreeihn/issue/topics
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-11-10 16:30:57 -06:00
Peter Rotich
10b922056b Merge pull request #5691 from aydreeihn/issue/sub-queues
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-11-10 16:01:00 -06:00
aydreeihn
8d2b8c6c83 Issue: Prevent Deleting All Topics
This commit makes sure that we always have at least 1 Public and Active Help Topic

Mass Process:
- Do not allow deletion of all Topics
- Do not allow archiving/disabling all Topics
- Allow changing Topics from Disabled to Archived and vice versa

Note: If you try to archive, disable, or delete all Topics OR all Active Topics at once, it will throw the error that at least 1 topic must be active.

Topic Update:
- Do not allow changing Topic to Private if it's the only one that's Public
- Do not allow archiving/disabling if it's the only active Topic
- Allow changing Topics from Disabled to Archived and vice versa

It also gets rid of code we had in place in the Client Portal that would put a 'General Inquiry' Topic in the list if all Topics had been deleted. It didn't have an id to get a Topic form, so it still wouldn't allow for Ticket creation.
2020-11-10 14:55:42 -06:00
aydreeihn
8e3a6c66b0 Issue: Sub Queues
This commit fixes an issue where sub queues were not being saved for personal queues or searches because the parent_id was not being stored.
2020-11-10 14:30:43 -06:00
Peter Rotich
635692ec78 Merge pull request #5684 from protich/issue/field-name
forms: Form Field Names
2020-11-10 14:24:08 -06:00
Peter Rotich
88fc702b80 Merge pull request #5689 from protich/issue/accesslink
Authcode: Ticket Access Link
2020-11-10 14:23:46 -06:00
Peter Rotich
077d26f6d0 forms: Pseudo-random name for Dynamicforms on POST
This commit addresses an issue introduced by 133362db where internal
forms failed to load values on POST. The change limits forcing
psudo-ramdom name just on dynamic forms.
2020-11-10 17:05:21 +00:00
Peter Rotich
2be608c02d authtoken: Add ticket link when recipient is ticket owner
This commit adds ticket link (possibly with authtoken) if the ticket
owner is the only recipient selected on a ticket with collabs.
2020-11-10 16:36:32 +00:00
Peter Rotich
c7eccd916c Merge pull request #5685 from JediKev/issue/better-url-parsing-for-external-inline-images
issue: Better URL Parsing For External Inline Images
2020-11-10 10:06:08 -06:00
Peter Rotich
652767086c Merge pull request #5686 from JediKev/redactor/upgrade-to-version-3.4.5
redactor: Upgrade to version 3.4.5
2020-11-10 10:05:27 -06:00
Peter Rotich
d231dafae2 Merge pull request #5687 from JediKev/redactor/improper-formatting-when-double-spacing
redactor: Improper Formatting When Double Spacing
2020-11-10 09:46:26 -06:00
JediKev
fe26123076 redactor: Improper Formatting When Double Spacing
This addresses an issue where if using Double Spacing in Redactor and you
put 2 or more lines in between paragraphs, the final content shows single
spacing formatting. This is due to Redactor using `<p></p>` for the double
spaced new lines and HTMLawed does not like that. This adds a new Format
function called `editor_spacing()` that uses simple regex to find and
replace `<p></p>` with `<p></br></p>` to ensure the formatting stays as
typed.
2020-11-10 15:08:46 +00:00
Peter Rotich
d6ee1a8a49 Merge remote-tracking branch 'upstream/develop' into develop-next 2020-11-10 04:31:00 +00:00
Peter Rotich
5b5c22160f Merge pull request #5690 from aydreeihn/issue/2fa-upgrade
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-11-10 15:45:18 -06:00
aydreeihn
0065c3b154 Issue: 2FA Upgrade
This commit fixes an issue where the task needed in order to add the 2FA Email template to the database for upgrades was omitted from the codebase.

The new template needed to be added to fresh installs as well.
2020-11-10 15:35:14 -06:00
Peter Rotich
3dc3ed97e9 Merge remote-tracking branch 'upstream/develop' into develop-next 2020-11-10 03:11:28 +00:00
Peter Rotich
cf16ca683b Merge remote-tracking branch 'upstream/develop-next' into develop-next 2020-11-10 03:11:15 +00:00
Peter Rotich
0895654cfc Merge pull request #5680 from aydreeihn/issue/user-dept-field
Reviewed-By: <peter@osticket.com>
2020-11-10 14:25:43 -06:00
Peter Rotich
9aabb77563 Merge pull request #5679 from aydreeihn/issue/ticket-from-emails
Ticket From Email
2020-11-10 14:24:57 -06:00
Peter Rotich
043c3fea43 Authcode: Ticket Access Link
osTicket provides ability to add ticket access link that can auto-login
users (if auth codes feature is enable), but the auth code is not added
when a ticket has collaborators. This is on purpose to avoid access
leak, because one email is sent to all recipients. As workaround, a user
can request ticket Access Link, individually, but the system still
assumed that multiple recipients are getting the link based on number of
collaborators on the ticket - meaning auth code is not added.

This commit addresses the issue by making sure Access Link requests
bypass collaborators check.
2020-11-10 01:33:22 +00:00
Peter Rotich
4eeb4b5d3f forms: Add SECRET_SALT to field name hash
This commit adds SECRET_SALT as part of the items to use to generate
pseudo-random id for form field names. This is necessary to make sure
the name is not guessable since the salt is server-side secret.
2020-11-09 23:21:20 +00:00
Peter Rotich
133362dbf0 forms: Form Field Names
osTicket uses pseudo-random names, based on user session, for form
fields when rendering input fields. This was done to ward off bot
attacks via web forms, but the backend failed to enforce strict name
check when sourcing the data.

This commit forces field widgets to source data based on the expected
form field name as opposed to all possible names.
2020-11-09 23:21:20 +00:00
Peter Rotich
143176ae2f Merge remote-tracking branch 'upstream/develop' into develop-next 2020-11-09 22:06:20 +00:00
JediKev
50eed90880 issue: Better URL Parsing For External Inline Images
This improves the parsing for external inline image URLs to better detect
path extensions. This uses `parse_url()` instead of
`preg_match()`/`explode()` to get the true URL path extension.
2020-11-09 17:37:14 +00:00
JediKev
e593c5cd5a redactor: Upgrade to version 3.4.5
This upgrades Redactor from `3.4.4` to `3.4.5` so that we are utilizing the
latest code. This provides a few bug fixes and improvements.
2020-11-09 17:07:28 +00:00
aydreeihn
f02edd94bc Ticket From Email
This commit ensures that Agents only have the option to choose the From Email on a Ticket based on the Department Emails they have access to.
2020-11-05 12:44:33 -06:00
aydreeihn
52825f0fce Issue: User Custom Dept Field
This fixes an issue introduced with the new Visibility Permissions. It did not account for the possibility that Users may be able to view a Custom Department field. In that event, we must make sure we can get active Departments that should show up as choices in custom Dept fields.
2020-11-05 10:48:39 -06:00
Peter Rotich
9e425a3051 Merge pull request #5671 from aydreeihn/issue/default-delimiter
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-11-04 11:49:09 -06:00
aydreeihn
f302503bb2 Issue: Default Delimiter
This commit fixes an issue where we needed to make sure to put a default delimiter for Ticekt exports. If no delimiter is specified, the deault delimiter will default to the delimiter for their locale.
2020-11-03 12:22:21 -06:00
Peter Rotich
656b309f22 Merge pull request #5667 from gerundt/ticket-assign-comment
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-11-03 09:33:42 -06:00
Peter Rotich
4f5cda209d Merge pull request #5676 from JediKev/issue/update-autocomplete
issue: Update Autocomplete
2020-11-03 08:48:14 -06:00
JediKev
d3245b151e issue: Update Autocomplete
This updates how the autocomplete attribute is set so we can allow specific
autocomplete values for individual fields. Before these changes
`autocomplete` would be either `on` or `off` only. This also updates old
`autocomplete=OFF` references to `autocomplete="off"`.
2020-10-28 11:51:24 -05:00
Peter Rotich
b1b970b8ed Merge remote-tracking branch 'upstream/develop' into develop-next 2020-10-28 03:30:54 +00:00
Peter Rotich
cbec8b5c36 Merge pull request #5674 from protich/issue/password-policies
Staff: Password Change
2020-11-03 08:48:51 -06:00
Peter Rotich
059e3283f5 Merge pull request #5675 from protich/feature/csrftoken+rotate
csrf: Add ability to rotate tokens
2020-11-03 08:48:30 -06:00
Peter Rotich
7527ea7ef6 Staff: Password Change
Exclude current password from policies enforcement when changing
password.
2020-10-26 23:58:53 +00:00
Peter Rotich
36e614c397 csrf: Add ability to rotate token
This commit adds ability to rotate csrf token post check. This can be
useful as anti-spam measure for web tickets.
2020-10-26 22:52:51 +00:00
Peter Rotich
40b39e6be9 Merge remote-tracking branch 'upstream/develop' into develop-next 2020-10-26 21:44:08 +00:00
Peter Rotich
5c1b3a1af5 Merge pull request #5669 from protich/issue/csvimport+BOM
CsvImporter: Skip Byte Order Mark (BOM) if present
2020-10-23 10:54:52 -05:00
Peter Rotich
ec6b3eb089 Merge pull request #5670 from xkvnn/patch-1
Reviewed-by: Peter Rotich <peter@osticket.com>
2020-10-23 10:54:17 -05:00
Khanh Nguyen
e8f0c588bb Fix incorrrect compare locked staff at Ticket Preview 2020-10-23 14:48:09 +07:00
Tim Gerundt
433e62dbca Don't use a default comment on ticket assignment 2020-10-22 12:10:50 +02:00
Peter Rotich
791a45eaf5 Merge pull request #5403 from aydreeihn/feature/agent-dept-visibility
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-10-21 09:43:20 -05:00
Peter Rotich
ca9817c9e7 Merge pull request #5659 from aydreeihn/feature/search-slas
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-10-21 09:42:42 -05:00
Peter Rotich
dbdfb8a896 Merge pull request #5661 from aydreeihn/issue/export-delimiter
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-10-21 09:36:06 -05:00
aydreeihn
38dbe738c5 Issue: Ticket Export Delimiters
This commit fixes an issue we had with changing the delimiter when exporting Tickets as a CSV. In order to save the delimiter to the Agent's session, we needed to match the input field name of 'csv-delimiter' rather than just 'delimiter'. This just makes it so that if the Agent has to do another export, they won't have to reset the delimiter again. Also, in order to correctly pass the delimiter to the options of the CsvExporter class, the delimiter needed to be added to the options array before constructing the new exporter.
2020-10-21 08:44:26 -05:00
aydreeihn
4e86313ce1 Code Improvements
- Use array_keys instead of a foreach loop to filter canned responses for staff
- add $options var to AssigneeField getWidget function to match parent
2020-10-20 16:58:47 -05:00
aydreeihn
ca8117610a FAQ Topic Quick Filter
This commit makes sure that we do not show the names of any hidden Help Topics in the Quick Filter for Topics on the FAQs page in the Agent Panel.
2020-10-20 16:37:58 -05:00
aydreeihn
07b2373f2e Clean Topics Array
This commit makes sure that we have a clean array for filtered topics so that disabled/archived help topics are correctly handled in the returned selection.
2020-10-20 16:37:58 -05:00
aydreeihn
9902ac2270 Filter FAQs Based on Topic Access
This commit makes it so that FAQs that are associated with Help Topics that are associated with Departments an Agent does not have access to are hidden. It also ensures that an Agent cannot create an FAQ associated with a Help Topic that they do not have access to based on the Help Topic's Department.
2020-10-20 16:37:58 -05:00
aydreeihn
642514692c Filter Topics Based on Dept Access
This commit makes it so that Help Topics are hidden from the Agent Panel if they are assigned a Department an Agent does not have access to and the Agent does not have the 'Ability to see all Departments' permission checked.

If a Help Topic is Public, it will be shown in the Agent Panel.

If a Parent Help Topic is Private and assigned a Department an Agent does not have access to, we hide both the Parent and Children Help Topics.

If a Help Topic is not assigned a Department at all, it is shown throughout the Agent Panel.

Help Topics are filtered for:
- Inline Ticket Edit
- Ticket Edit
- Ticket Open
- Advanced Search
- Quick Filters
- Dashboard
2020-10-20 16:37:58 -05:00
aydreeihn
3722fc509b Ticket Open Canned Responses
If an Agent is opening a Ticket, they should only see Canned Responses for Departments they have access to.
2020-10-20 16:37:58 -05:00
aydreeihn
484023d099 Update Existing Staff Permissions
This commit updates existing staff members so that they will still be able to see departments and agents within the agent panel the same way they are used to seeing them. This is done during the upgrade within a task.
2020-10-20 16:37:58 -05:00
JediKev
7f0602a3ba db: Latest Indexes
This adds all indexes we've implemented/accumulated over time.
2020-10-20 16:37:58 -05:00
aydreeihn
4489b2fe3c Agent/Dept Visibility Defaults
This commit makes it so that the Agent and Department visibility permission is checked by default on fresh installs and newly created Agents unless otherwise specified.
2020-10-20 16:37:58 -05:00
aydreeihn
6fdc111812 Issue: Assignment Field Quick Filter
This commit fixes an issue where quick filters for the AssigneeField class would not work because we were returning an array of AgentsName + Team name strings which did not sanitize correctly in htmlchars.
2020-10-20 16:37:58 -05:00
aydreeihn
f306ce887e Option to Filter Criteria Choices
This commit gives us a way to determine if we should filter choices for setting field criteria. We need this to be optional because we use the same method for getting criteria choices in the Agent and Admin Panel, and for the Agent panel, we need to filter the choices based on the Agent's permission to view all Agents and Departments.

If Criteria are being set in the Admin Panel, all choices should be shown regardless of an Agents permissions.

filterVisibility needs to be applied for the following:
- AgentSelectionField
- DepartmentManagerSelectionField
- AssigneeChoiceField
- DepartmentField
- DepartmentChoiceField
2020-10-20 16:37:58 -05:00
aydreeihn
6eae7e682d Limit Agent Choices
This commit checks if the Agent has permission to see all Agents, and if they don't, only show Agents that are in Departments they have access to. This covers the following:
- Queue Assign Mass Process
- Ticket open Assign
- Ticket View assign
- Ticket Inline Edit Assign
- Ticket Refer
- Assigned Staff Quick Filter
- Assignee Quick Filter
- Department Manager Quick Filter

It also limits Agents shown in the Agent Directory based on the Agent permission checkbox as well as the Departments shown in the Department filter of the Agent Directory.
2020-10-20 16:37:58 -05:00
aydreeihn
3a8ea4b25b Canned Responses for Dept Roles
This commit fixes a bug where we did not accurately check individual Roles for Departments an Agent could access to determine if they could manage that particular Canned Response.

Now, we check to see if the Agent has a Role that can manage Canned Responses at all to determine if Canned Responses show up in the Knowledge Base.

Additionally, we filter Canned Responses shown based on the Role permissions of the Agent's Departments (Primary and Extended)
2020-10-20 16:37:58 -05:00
aydreeihn
46033d11c0 getDepartmentNames Publiconly Option
This commit allows us to determine if only public Departments should be returned or all Departments regardless of anything else. We need this for Agents that can see all Departments and search all Tickets
2020-10-20 16:37:58 -05:00
aydreeihn
49b2f1b355 Limit Departments in DepartmentField Choices
This commit checks to see if the Agent has permission to see all Departments, and if they don't, show only their Departments in forms that include a DepartmentField. This covers the following:
	- Ticket Transfers
	- Task Transfers
	- Ticket Referrals
	- Task Creation

Standard Forms:
	- Ticket Creation
2020-10-20 16:37:58 -05:00
aydreeihn
4ad7e95a2f Add Agent/Department Visibility Checkboxes
This commit adds the following checkboxes to Admin Panel | Agents | Choose an Agent | Permissions | Miscellaneous:
- Agent — Ability to see Agents in all Departments
- Department — Ability to see all Departments
2020-10-20 16:37:58 -05:00
aydreeihn
e4346d26e0 Filter Canned Response Creation
This commit makes it so that Agents can only create Canned Responses for Departments they can access or Canned Responses that will show up for all Departments.
2020-10-20 16:37:58 -05:00
aydreeihn
5fbd762483 Filter Canned Responses Page
This commit filters Canned Responses so that Agents can only see Canned Responses for Departments they can access (Primary or Extended Access) or Canned Responses assigned to all Departments.
2020-10-20 16:37:58 -05:00
Peter Rotich
a2a09d2754 Merge pull request #5660 from JediKev/oops/indexes-patch-schema
oops: Indexes Patch Schema
2020-10-20 16:36:41 -05:00
JediKev
709b55fee2 oops: Indexes Patch Schema
This addresses an issue where I forgot to recheck the hash after making
changes to installer. This updates the schema signature to the correct hash
so the upgrader can continue.
2020-10-20 16:32:04 -05:00
Peter Rotich
003ac86231 Merge pull request #5362 from JediKev/db/latest-indexes
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-10-20 15:20:14 -05:00
Peter Rotich
5086e5241f Merge pull request #5656 from gerundt/ticket-open
Drop nested table from open new ticket
2020-10-20 15:19:06 -05:00
JediKev
4c9968bd11 upgrader: Add ticket_pid Index
This updates the AddIndexMigration Task to include an index for the newly
added `ticket_pid` column in the Ticket table.
2020-10-20 15:17:03 -05:00
JediKev
ea0937384d upgrade: Add Version Column To Plugin Table
This addresses an issue where we've never added the `version` column to any
of the upgrade patches so if someone were to upgrade from pre-1.8, they will
not have the `version` column and they will not be able to install plugins.
This adds a prepared statement to check if the column already exists, if it
does not exists we will add the column. We have to use a prepared statement
as unfortunately MySQL doesn’t have the concept of `ADD COLUMN IF NOT
EXISTS` like MariaDB does.
2020-10-20 15:17:03 -05:00
JediKev
c359d12e43 forms: Task Title/Description Field Flags
This addresses an issue where the Task Title field allows any Admin to
remove the View and Required perms for Agents even though this field should
be Viewable and Required. This adds SQL so we can see if the
`FLAG_AGENT_REQUIRED`, `FLAG_AGENT_VIEW`, `FLAG_MASK_REQUIRE` and
`FLAG_MASK_VIEW` flags already exists, if not, we will add them to ensure
the field is Viewable and Required for Agents and to ensure Admins cannot
change this behavior for both perms. This also addresses an issue where the
Task Description field allows any Admin to remove the View perms for Agents
even though this field should always be Viewable. This adds SQL so we can
see if the `FLAG_AGENT_VIEW` and `FLAG_MASK_VIEW` flags already exists, if
not, we will add them to ensure the field is Viewable to Agents and to
ensure Admins cannot change this behavior.
2020-10-20 15:17:03 -05:00
JediKev
da2fd378f5 db: Latest Indexes
This adds all indexes we've implemented/accumulated over time.
2020-10-20 15:17:03 -05:00
aydreeihn
2731074729 Issue: Auto Referral
This commit fixes an issue we had with Auto Referrals. If a Ticket had been transfered/responded to by 3 or more departments and a user sent in an email response to one of the transferred departments (not including the original or current department), we created an auto referral for that department which could potentially give agents to access they should not have access to.

A new column, email_id, has been added to the thread_entry_email table so that we can see which system email each thread entry has been fetched from.

This commit also adds the event (EVENT_TABLE) relationship to the ThreadEvents (THREAD_EVENT_TABLE) class.

An index for ticket_pid on the ticket table has been added.
2020-10-20 15:14:14 -05:00
aydreeihn
0fd63b4284 SLA Plan Search Field
This commit allows Agents to do advanced searches and exports on the SLA Plan field. It also allows for adding an SLA Plan column to queues.
2020-10-20 14:56:09 -05:00
Peter Rotich
9e1dfeffee CsvImporter: Skip Byte Order Mark (BOM) if present
This commit adds logic to skip BOM at the beginning of a file (if
        present).
2020-10-17 00:35:46 +00:00
Peter Rotich
bfd5da8e20 CsvImporter: Skip Byte Order Mark (BOM) if present
This commit adds logic to skip BOM at the biggining of a file (if
        present).
2020-10-17 00:30:19 +00:00
Peter Rotich
4aef938556 Merge remote-tracking branch 'upstream/develop-next' into develop-next 2020-10-16 14:22:30 +00:00
Peter Rotich
0ce2499fbd Merge pull request #5662 from aydreeihn/issue/inheritance-compatibility
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-10-21 11:39:06 -05:00
aydreeihn
cb13b82a73 Oops: Method Inheritance Compatibility
This commit fixes an issue with the getChoices method for the new SLAChoiceField class. It needed the $options variable to be added so that it would match the parent class.
2020-10-21 10:21:10 -05:00
Peter Rotich
7f0130bff6 Merge remote-tracking branch 'upstream/develop-next' into develop-next 2020-10-16 12:25:34 +00:00
Peter Rotich
c605c7d934 Merge remote-tracking branch 'upstream/develop-next' into develop-next 2020-10-16 11:24:34 +00:00
Peter Rotich
ff06cc3558 Merge remote-tracking branch 'upstream/develop-next' into develop-next 2020-10-16 11:15:24 +00:00
Peter Rotich
a62288938c Merge remote-tracking branch 'upstream/develop' into develop-next 2020-10-16 11:00:51 +00:00
Tim Gerundt
fb0164b5ae Drop nested table from open new ticket 2020-10-14 14:00:28 +02:00
Peter Rotich
d4c289ee18 Merge pull request #5646 from protich/issue/authbackends
Auth: External authentication service name.
2020-10-13 10:49:51 -05:00
Peter Rotich
4b82e048cc Merge pull request #5628 from JediKev/issue/assignee-field
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-10-13 10:49:21 -05:00
Peter Rotich
1882ee6a32 Merge pull request #5634 from JediKev/redactor/upgrade-to-version-3.4.3
Reviewed-By: Peter Rotich <peter@rotich.com>
2020-10-08 12:37:31 -05:00
Peter Rotich
5a7635277b Merge pull request #5643 from JediKev/issue/new-message-alert-recipients
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-10-08 12:34:44 -05:00
Peter Rotich
c1f6b98949 Merge remote-tracking branch 'upstream/develop' into develop-next 2020-10-08 11:25:18 +00:00
Peter Rotich
eec0f4fb52 Merge pull request #5568 from protich/feature/2fa
Reviewed-By: osTicket team.
2020-10-13 10:50:48 -05:00
JediKev
ea9cd567dc issue: New Message Alert Recipients
This addresses an issue where a User updates a Ticket that is assigned but
no alert is sent to the Assigned Agent/Team. This is due to
`getNumMembersForAlerts()` that returns the number of members that can
receive alerts for the Department. This method returns `0` if there are no
Primary Members and the Department Alert settings are set to "Department
members only" which causes the system to return before we send the New
Message alert. This method is not necessary for New Message Alerts as we
only alert the Last Respondent, Assigned Agent/Team, Department Manager,
and/or Org Account Manager. This removes the method from
`Ticket::postMessage()` so that we continue to check for recipients and send
the alerts.
2020-10-07 17:33:02 -05:00
Peter Rotich
e9b12f3101 Merge pull request #35 from aydreeihn/feature/2fa-rewrite-mods
Reviewed-By: Peter Rotich <peter@osticket.com>
2020-10-07 15:29:08 -05:00
JediKev
9102240775 redactor: Upgrade to version 3.4.4
This upgrades Redactor from `3.4.3` to `3.4.4` so that we are utilizing the
latest code. This provides a few bug fixes and improvements.
2020-10-07 15:23:42 -05:00
JediKev
e47113200d redactor: Upgrade to version 3.4.3
This upgrades Redactor from `3.4.2` to `3.4.3` so that we are utilizing the
latest code. This provides a few bug fixes and improvements.
2020-10-07 15:23:19 -05:00
JediKev
4c8a03a0f6 Merge pull request #5642 from JediKev/issue/custom-regex-failure
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <protich@enhancesoft.com>
2020-10-07 14:43:57 -05:00
JediKev
ecb68e1e2f Merge pull request #5641 from aydreeihn/issue/session-attachments
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <protich@enhancesoft.com>
2020-10-07 14:40:52 -05:00
JediKev
28c11fb2cd Merge pull request #5631 from JediKev/cli/manage-php-errors
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <protich@enhancesoft.com>
2020-10-07 14:28:41 -05:00
JediKev
b808890857 Merge pull request #5620 from JediKev/issue/agent-pwreset-with-no-existing-pw
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <protich@enhancesoft.com>
2020-10-07 14:21:08 -05:00
JediKev
aa03fd3f2b Merge pull request #5619 from Fonata/patch-1
Reviewed-By: JediKev <kevin@enhancesoft.com>, aydreeihn <adriane@enhancesoft.com>, protich <protich@enhancesoft.com>
2020-10-07 14:19:54 -05:00
Peter Rotich
c3c01d3c75 Auth: Client Create Request
Check to make sure client registration is enabled before attempting to
auto register clients on client create request.

This is important to prevent auth plugins from auto registering clients
without checking config settings.
2020-10-07 13:29:40 +00:00
Peter Rotich
43e07c2154 Ext. Auth: Service Name
Allow external authentication backends to make service name
configurable.

This commit also makes 'Sign in with' string translatable.
2020-10-07 13:23:45 +00:00
JediKev
4850b2a453 issue: Custom REGEX Failure
This addresses an issue reported on the Forum where when using a Custom
REGEX Validator like `/^[0]\d{6}$/iu` and someone inserts a value like
`0000000` the REGEX will fail. This is due to a check where we use the
equals operator (`==`) to check if the value is equal to `0` and if so we
change the value to `&#48`. This is a problem for values such as `0000000`
as technically `0000000` is equal to `0`. This updates the equals comparison
operator to the identical comparison operator to ensure that only values
that are identical to `0 (string)` are changed to `&#48`.
2020-10-06 16:53:47 -05:00
aydreeihn
1de3f6a8b7 Issue: Ticket From Thread Attachments
This commit fixes an issue where attachments were dropped if you tried to create a Ticket from a Thread and changed the Help Topic more than one time.
2020-10-06 15:18:11 -05:00
JediKev
239b9ba135 cli: Manage.php Errors
This addresses three issues, the first of which is 5629 where running `$ php
manage.php` throws the error `Cannot declare class Exporter, because the
name is already in use`. The second issue is when addressing the declare
error you receive the error `Uncaught Error: Call to a member function
query() on null`. The last issue is when running `$ php manage.php export`
we receive the warnings `GROUP_TABLE: Cannot export table with no fields`
and `ost_timezone: Cannot export table with no fields`. This addresses the
first issue by renaming the Exporter class used in the CLI from `Exporter`
to `CliExporter` and updating all references to the class. This addresses
the second issue by using `Bootstrap::connect();` to ensure we have a
database connection before calling the Exporter. This addresses the last
issue by removing the references to `GROUP_TABLE` and `TIMEZONE_TABLE` in
the DatabaseExporter class. These tables are not used any longer so it’s
okay to remove the references.
2020-09-03 15:36:18 -05:00
JediKev
3c8911759f issue: Assignee Field
This addresses a list of issues with Custom Assignee Fields:
- The current value is not shown as selected when updating the field
- The Thread Events do not show the changes
- Custom Columns do not show the current values
- Advanced Search with `includes` and `does not include` criteria does not
find proper results
- Exports do not show the current values
- Template Variables do not show the proper values

This overhauls the AssigneeField class to make it like an independent Custom
Field. This adds new methods such as `getChoice()`, `getKeys()`, `asVar()`,
`getChanges`, and `whatChanged()` to work with AssigneeField specific data
instead of relying on the ChoiceField class. This also updates methods like
`getWidget()`, `display()`, `getValue()`, `to_php()`, and `to_database()` to
ensure all methods work with a unified data format (JSON/Array).
2020-09-02 15:12:01 -05:00
aydreeihn
8f4fe1892f Post Review Modifications
- Use get2FAConfig to check if 2FA backend is verified. This eliminates the is2FAConfigured function
- Check to make sure staff and staff is admin before allowing an agent to reset another agent's 2FA
- Only reset the default2fa when resetting 2FA (leave the configuration)
- Make sure there is an id before trying to call enable2fa
- Change login 'Loading' wheel to 'Verifying'
2020-08-20 16:03:59 -05:00
JediKev
101ebea20f issue: Agent Password Reset With No Existing Password
This addresses an issue where if an Agent never finishes registering their
account via the link in the Registration Email and tries to reset their
password, the system says `Unable to reset password. Contact your
administrator`. This is due to no password being set in the first place; we
cannot reset a password that doesn't exist. This adds a check for the
Agent's password when requesting password reset and if none set we will
resend the Registration Email. This will ensure the Agent can set a password
and login successfully.
2020-08-20 14:41:13 -05:00
Fonata
84195ec5ed More modern, cleaner DocBlock
Tells IDEs and static code analyzers which types to expect.
2020-08-20 11:43:34 +02:00
Peter Rotich
41e0c6c041 Merge pull request #5618 from JediKev/issue/ticket-merge-select2
issue: Ticket Merge Select2
2020-08-19 21:51:28 -05:00
JediKev
bffac981a5 issue: Ticket Merge Select2
This addresses an issue where the Select2 upgrade apparently changed the way
you get data from the selection. This updates the call to get data from
`data = $sel.data();` to `data = select.select2('data');`.
2020-08-19 16:04:06 -05:00
JediKev
f4f5bc6ec0 Update WHATSNEW.md and add the new commit (f6cd8c4). 2020-08-19 12:27:50 -05:00
JediKev
29c7b939e2 Merge pull request #5617 from JediKev/oops/local-inline-images
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-08-19 13:16:45 -05:00
JediKev
f6cd8c463e oops: Local Inline Images
This addresses an issue caused by `d98c2d0` where local inline images are
stripped from the thread entries. This adds a check for the `cid` tag and if
exists we know it’s a local image and we will allow it.
2020-08-19 12:18:16 -05:00
JediKev
c5623eceeb Add Release Notes for v1.14.3 2020-08-19 09:50:38 -05:00
JediKev
e95ff6286a Merge pull request #5616 from JediKev/security/reported-vulns-jul-aug-2020
Reviewed-By: JediKev <kevin@enhancesoft.com> & aydreeihn <adriane@enhancesoft.com>
2020-08-19 09:32:49 -05:00
JediKev
518de22393 xss: Draft Uploaded Attachment
This mitigates an XSS vulnerability reported by [The NAVEX
Project](https://sisl.lab.uic.edu/projects/chess/) where if an attachment is
uploaded via Draft AJAX, the filename stored/returned in the response is not
sanitized. This updates `DraftAjaxAPI::_uploadInlineImage()` to sanitize the
filename before it's returned in the JSON encoded response. This also
updates `AttachmentFile::format()` to sanitize the filename before saving to
the backend. In addition this forces the `application/json` Content-Type on
all AJAX responses that return strictly JSON; this adds another layer of
protection.
2020-08-19 09:22:56 -05:00
JediKev
d98c2d096a ssrf: External Inline Images
This mitigates an SSRF security vulnerability reported by [Talat
Mehmood](https://twitter.com/Blackbatsecuri1) where we do not check if the
src URL for external inline images contain a valid image extension when
displaying. This means if someone puts something like `<img
src="mymalicioussite.com/badscript.js">` in the body of their message, when
someone clicks Show Images or when the ticket is printed the server will
call the src URL to get the "image" data for display. This is a problem as
this could load malicious code/scripts in the browser. This adds a new
setting called `Allow External Images` and if Disabled we will not allow any
external images in Threads. If this setting is Enabled (default), we will
only allow `<img>` src URLs with valid image extensions
(`png`,`jpg`,`jpeg`,`gif`).
2020-08-19 09:22:56 -05:00
JediKev
d2491c1f25 banlist: Sanitize Internal Notes When Adding New Rule
This addresses an issue where we are not sanitizing the Internal Notes when
adding a new Banlist item. This adds a check for `$extra['notes']` and if
exists we will sanitize the content before it is saved. This will ensure no
malicious content is saved in the database.
2020-08-19 09:22:56 -05:00
JediKev
fb570820ef xss: Internal Notes
This addresses a vulnerability reported by heinhtetaung where Internal Note
contents are not correctly sanitized if errors are returned. This adds
`true` as the second argument to `Format::htmlchars()` so that all content
is sanitized properly. In some cases however we cannot blanket sanitize all
the content as Inline Images, etc. tend to get obfuscated. So in those cases
this adds `Format::sanitize()` to the Internal Notes directly.
2020-08-19 09:22:56 -05:00
Peter Rotich
ce3562dcf1 Merge pull request #5614 from JediKev/select2/update-to-4.0.13
select2: Update To 4.0.13
2020-08-18 11:35:54 -05:00
Peter Rotich
7677fd269c Merge pull request #5613 from JediKev/jquery/update-to-3.5.1
jquery: Update To 3.5.1
2020-08-18 11:35:35 -05:00
JediKev
b67c75b6fb select2: Update To 4.0.13
This updates Select2 to the latest stable release of v4.0.13.
2020-08-18 10:42:55 -05:00
JediKev
121ab41ad1 jquery: Update To 3.5.1
This updates jQuery to the latest stable release of v3.5.1.
2020-08-18 10:42:45 -05:00
Peter Rotich
fbb47c7735 Merge pull request #5226 from JediKev/issue/attachment-upload-config
issue: Attachment Upload Configuration
2020-08-18 09:13:16 -05:00
Peter Rotich
36ef030d34 Merge pull request #4910 from JediKev/issue/translated-form-instructions
issue: Form Instructions Translation
2020-08-18 09:11:22 -05:00
Peter Rotich
900aadcb4b Merge pull request #5612 from aydreeihn/issue/field-saves
Issue: Ticket Edit Save
2020-08-18 08:49:00 -05:00
aydreeihn
3281e743b0 Issue: Ticket Edit Save
This commit fixes issues we had with the display of Thread Events when updating multiple fields on a Ticket. On getChanges, we need to do to_database before we compare the new and old values for Choice Fields.
2020-08-17 10:52:24 -05:00
Peter Rotich
60a49f3b43 Merge pull request #5610 from aydreeihn/issue/revert-ht-field-saves
Revert Topic Saving Fixes
2020-08-17 09:58:18 -05:00
aydreeihn
0ff87f3a6d Revert Topic Saving Fixes
This commit reverts two changes that were made that dealt with the fields shown when editing Tickets based on the Ticket's Help Topic. Some changes will need to be made to how we save fields before these changes should be redone.
2020-08-12 13:05:51 -05:00
Peter Rotich
d219d6f18d Merge pull request #5609 from JediKev/redactor/upgrade-to-version-3.4.2
redactor: Upgrade to version 3.4.2
2020-08-12 10:49:22 -05:00
Peter Rotich
ce9258ad14 Merge pull request #5603 from JediKev/issue/notls-for-imap-pop-without-ssl
issue: NOTLS For IMAP/POP Without SSL
2020-08-12 10:48:53 -05:00
JediKev
7506937f44 issue: NOTLS For IMAP/POP Without SSL
This is a rewrite of 5519 and addresses issue 5020 where in some cases,
using IMAP/POP without SSL fails because class MailFetcher is not disabling
start-TLS. This adds a new if statement to check if the encryption method is
SSL if not, we will add `/notls` to the server string to disable start-TLS.
2020-08-12 10:19:50 -05:00
Peter Rotich
6f9eae73c1 Merge pull request #5606 from antiuser/patch-1
Update dynamic-field-config.tmpl.php
2020-08-12 10:08:49 -05:00
JediKev
384fe271fb redactor: Upgrade to version 3.4.2
This upgrades Redactor from 3.4.1 to 3.4.2 so that we are utilizing the
latest code. This addresses a few security issues with upstream Redactor as
well as provides a few bug fixes and improvements.
2020-08-11 21:29:31 -05:00
antiuser
e847ddbeb9 Update dynamic-field-config.tmpl.php
So, this add support for translating word 'Editable'
2020-08-11 15:02:56 +05:00
Peter Rotich
eb29cd0483 Merge pull request #5600 from aydreeihn/issue/translation-improvement
Ticket Merge Translation Improvement
2020-08-07 09:36:05 -05:00
Peter Rotich
46d2ea5f3a Merge pull request #5575 from JediKev/issue/track-fields-disabled-by-system-default-help-topic
issue: Track Fields Disabled By System Default Help Topic
2020-08-06 16:42:21 -05:00
aydreeihn
ba389a6d5a Ticket Merge Translation Improvement
This commit is based off of PR #5494 and ensures that all of the text on the Merge/Link modal will be translated.
2020-08-06 16:25:34 -05:00
Peter Rotich
131f4e4534 Merge pull request #5283 from aydreeihn/issue/filter-email-vars
Issue: Template Variables in Ticket Filter
2020-08-06 16:22:32 -05:00
Peter Rotich
6dd94f5587 Merge pull request #5562 from JediKev/inline/richtext-fields-view-first
inline: RichText Fields View First
2020-08-06 16:20:57 -05:00
Peter Rotich
9b7368cc0c Merge pull request #5545 from aydreeihn/issue/topic-fields
Issue: Topic Fields on Ticket Edit
2020-08-06 16:17:37 -05:00
Peter Rotich
3522350259 Merge pull request #5490 from josemonsalve2/develop
Adding translation to the labels in the dashboard plot
2020-08-06 16:10:59 -05:00
Peter Rotich
a176abe33d Merge pull request #5550 from JediKev/i18n/dont-store-files-under-branch-name
i18n: Don't Store Files Under Branch Name
2020-08-06 16:08:44 -05:00
Peter Rotich
ded0ba8e98 Merge pull request #5579 from PeopleInside/patch-2
Create SECURITY.md
2020-08-06 16:08:14 -05:00
JediKev
6a2953fa40 visibility: Fields Disabled By Help Topic Appear In Ticket Header (Client Portal)
This addresses an issue where having a Field that is Disabled by Help Topic
and has a Default Value appears in the Ticket Header in the Client Portal.
This is due to the system not checking for Disabled Fields per Help Topic,
rather just checking for any entries with values. This adds a check to see
if any Fields are Disabled by Help Topic, if so, we will exclude them from
the Ticket Header in the Client Portal. This adds a new method called
`getDisabledFieldsIds()` that retrieves an array of Form ID and disabled
Field IDs (eg. `array(form_id => array(disabled_field_ids))`).
2020-08-06 15:10:19 -05:00
JediKev
ad8cfbfcfe issue: Track Fields Disabled By System Default Help Topic
This addresses an issue where Tickets that get assigned the System Default
Help Topic (mainly emails) have Disabled Fields (disabled by Help Topic)
appear in the Client Portal on Edit. This is due to not running through the
Disabling of Fields for the Default Help Topic. This moves the section to
track Disabled Fields to a new method called `trackDisabledFields()` in
class Topic that can be reused. This also adds a check for the Default Help
Topic and if set, we will run through the new method.
2020-08-06 15:10:19 -05:00
aydreeihn
8a82d1e2a8 Post Create Filters
This commit controls when we run certain types of filters. If we are sending out an email, we want those filter actions to run after the ticket is created in case template variables are used. All other types of filter actions can run before the ticket is created.
2020-08-06 13:57:27 -05:00
aydreeihn
8ef505d920 Issue: Template Variables in Ticket Filter
This commit fixes an issue where you could not use template variables when using the 'Send an Email' filter action. All variables would just display as 'Array'.

We needed to pass the Ticket object to FA_SendEmail::apply however, we were running the filters before the Ticket object was created. To fix this, we can add the Ticket object to vars and run the filterTicketData function again after the Ticket is created and only apply the send email filter action if the Ticket object is found.
2020-08-06 13:57:27 -05:00
Peter Rotich
82dab98179 Merge pull request #5599 from aydreeihn/issue/ht-form-save
Issue: Saving Forms/Help Topic Forms
2020-08-06 12:35:27 -05:00
aydreeihn
bc5ba13560 Issue: Saving Forms/Help Topic Forms
- Fix error: array_reduce() expects parameter 1 to be array, null given
- On Help Topic forms, the only fields that should be unchecked in the 'Enable' column are the fields that the Admin specifically unchecked. We don't need the fields that are disabled from Manage Forms to display as unchecked when viewing the Help Topic form because if you save the Help Topic form with them unchecked and then go enable the fields in Manage Forms, the fields will still be disabled in the Help Topic form which may not be what the Admin would expect to happen. They remain disabled in the Help Topic form because they end up being added to the disabled array in the extra column of the Help Topic form.
2020-08-05 10:18:05 -05:00
Peter Rotich
c7150e00e9 Merge pull request #5598 from JediKev/oops/task-missing-parentheses
oops: Task Missing Parentheses
2020-08-04 13:34:39 -05:00
JediKev
b7684ad3d0 oops: Task Missing Parentheses
This addresses an issue where there is a missing parentheses in an upgrade
task. This is due to me 3heading the commit and forgetting to run the lint
tests so the missing parentheses was not revealed. This adds the missing
parentheses so the lint tests pass and there are no PHP errors/warnings.
2020-08-03 14:02:47 -05:00
Peter Rotich
3fea981f82 Merge pull request #5488 from JediKev/issue/mass-delete-help-topics-warning
issue: Mass Delete Help Topics Warning
2020-08-01 13:51:39 -05:00
Peter Rotich
91b32534d3 Merge pull request #5489 from aydreeihn/issue/lang-verification
Issue: Language Verification
2020-08-01 13:42:22 -05:00
Peter Rotich
3a0fbd8283 Merge pull request #5492 from JediKev/issue/mysql-8-min-max-value-error
issue: MySQL 8.0 {min,max} Value Error
2020-08-01 13:15:22 -05:00
Peter Rotich
65938a6573 Merge pull request #5498 from JediKev/refactor/ht-status-refresh
refactor: Help Topic Status Refresh
2020-08-01 13:08:33 -05:00
Peter Rotich
7be9517451 Merge pull request #5495 from aydreeihn/issue/task-open-files
Issue: Create Task File Upload
2020-08-01 13:07:16 -05:00
Peter Rotich
339a2f7d19 Merge pull request #5500 from JediKev/issue/update-print-options-icons-text-title
issue: Update Print Options Icons/Text/Title
2020-08-01 13:05:44 -05:00
Peter Rotich
717528905f Merge pull request #5505 from JediKev/issue/delete-users-with-tickets
issue: Delete Users With Tickets
2020-08-01 13:03:51 -05:00
Peter Rotich
be41cf6905 Merge pull request #5527 from JediKev/install/add-mark-as-answered-to-all-access
install: Add Mark As Answered To All Access
2020-08-01 13:02:22 -05:00
Peter Rotich
5a0a844de5 Merge pull request #5561 from protich/feature/password-policy-revisited
Password Policy Revisited
2020-07-31 13:59:00 -05:00
Peter Rotich
36fad111e6 Merge pull request #5554 from JediKev/issue/activity-notice-getLastRespondent
issue: Activity Notice getLastRespondent()
2020-07-31 13:54:32 -05:00
Peter Rotich
2cfe1645a2 Merge pull request #5573 from JediKev/issue/get-team-members-for-alerts
issue: Get Team Members For Alerts
2020-07-31 13:48:47 -05:00
Peter Rotich
44cf4fe348 Merge pull request #5577 from JediKev/redactor/upgrade-to-version-3.4.1
redactor: Upgrade to version 3.4.1
2020-07-30 16:04:02 -05:00
aydreeihn
87f5006dc6 Issue: Create Task File Upload
This commit fixes an issue where attachments were not being added if you tried to create a Task and populate a custom File Upload field. getClean() would return an empty array, so there was no information that could be used to create the attachment record.
2020-07-30 10:28:39 -05:00
JediKev
d88e384733 issue: Get Team Members For Alerts
This addresses an issue where when sending Alerts to Team Members, we grab
all Members regardless of if they have the Alerts checkbox Enabled or not.
This adds a new method called `getMembersForAlerts()` that will retrieve a
list of all Team Members that have the Alerts checkbox Enabled. This updates
all of the `getMembers()` calls to `getMembersForAlerts()` when sending
Alerts.
2020-07-29 16:17:23 -05:00
Peter Rotich
4d043d85b2 Merge pull request #5587 from JediKev/issue/form-field-help-text-not-nulll
issue: Form Field Help Text Not Null
2020-07-29 15:40:15 -05:00
Peter Rotich
015b85dd09 Merge pull request #5567 from aydreeihn/issue/task-print
Issue: Ticket Task Print
2020-07-29 15:39:49 -05:00
Peter Rotich
fae1db56ad Merge pull request #5593 from aydreeihn/issue/topic-help-tip
Issue: Topic Help Tip
2020-07-29 15:38:13 -05:00
Peter Rotich
7d10f45df4 Merge pull request #5523 from JediKev/templates/ticket-thread-complete-not-respecting-identity-masking
templates: %{ticket.thread.complete} Not Respecting Identity Masking
2020-07-29 15:34:39 -05:00
Peter Rotich
eddb0f6edb Merge pull request #5520 from JediKev/print/update-icons-and-add-titles
print: Update Icons and Add Titles
2020-07-29 15:33:34 -05:00
JediKev
9d2e1da9b9 issue: Delete Users With Tickets
This addresses an issue where deleting Users with Tickets and checking the
box to delete all tickets throws a warning of `Unable to manage any of the
selected end users`. This is due to commit b1f881b where we didn’t pass
the data to the submit function. All data was present in the POST array
except for the `deletetickets` option which we need to determine wether or
not to delete all tickets. This changes `promise` to `data` and passes it to
`submit()` (if exists).
2020-07-29 15:29:21 -05:00
Peter Rotich
f7936b0a43 Merge pull request #5493 from aydreeihn/issue/merge-php-warning
Issue: PHP Warning
2020-07-29 15:16:07 -05:00
Peter Rotich
10bdbc6f8e Merge pull request #5496 from JediKev/issue/flush-model-cache
issue: Flush Model Cache
2020-07-29 15:15:22 -05:00
Peter Rotich
7450d6511d Merge pull request #5572 from JediKev/i18n/redactor-files-not-included
i18n: Redactor Files Not Included
2020-07-29 15:14:57 -05:00
Peter Rotich
15110a0404 Merge pull request #5518 from JediKev/issue/filter-action-add-button
issue: Filter Action Add Button
2020-07-29 15:07:22 -05:00
Peter Rotich
fe8da4c023 Merge pull request #5497 from JediKev/issue/php74-warnings
issue: PHP 7.4 Warnings
2020-07-29 14:53:25 -05:00
Peter Rotich
da0d4f9c81 Merge pull request #5539 from aydreeihn/issue/dept-topic-cols
Issue: Topic and Department Columns
2020-07-29 14:42:06 -05:00
Peter Rotich
f9180f34c7 Merge pull request #5580 from JediKev/issue/email-template-internal-notes
issue: Email Template Internal Notes
2020-07-29 14:33:11 -05:00
Peter Rotich
433cc5e598 Merge pull request #5574 from JediKev/oops/change-lastupdate-to-updated-for-tasks
oops: Change lastupdate To updated For Tasks
2020-07-29 14:32:06 -05:00
Peter Rotich
5598c52411 Merge pull request #5586 from JediKev/export/duplicate-results
export: Duplicate Results
2020-07-29 14:31:15 -05:00
aydreeihn
66fc808d99 Issue: Topic Help Tip
This commit fixes an issue where we had 2 hrefs in the Help Topic help tips called #status, so the 'New Ticket Options' status tip was incorrect. Now there are 2 separate hrefs and help tips.
2020-07-29 09:00:03 -05:00
Peter Rotich
21fc5919a8 Merge pull request #5508 from aydreeihn/issue/ticket-num-search
Issue: Ticket Number Search
2020-07-28 13:27:58 -05:00
Peter Rotich
6a6cdf9e67 Merge pull request #5509 from JediKev/install/schedule-sla-and-help-tip-updates
install: Schedule, SLA, and Help Tip Updates
2020-07-28 13:25:49 -05:00
Peter Rotich
bc4e79e1c9 Merge pull request #5510 from JediKev/install/embedded-domain-whitelist
install: Embedded Domain Whitelist
2020-07-28 13:22:33 -05:00
Peter Rotich
1aef8906ea Merge pull request #5517 from JediKev/xss/faq-category-on-errors
xss: FAQ Category On Errors
2020-07-28 13:20:58 -05:00
Peter Rotich
00518b4f76 Merge pull request #5543 from JediKev/template/add-ticket-id-to-var-scope
template: Add Ticket ID To Var Scope
2020-07-28 13:20:18 -05:00
Peter Rotich
54c0ad9a17 Merge pull request #5525 from JediKev/print/client-print-not-respecting-identity-masking
print: Client Print Not Respecting Identity Masking
2020-07-27 15:48:37 -05:00
Peter Rotich
c97de51f2d Merge pull request #5535 from JediKev/oops/js-method-typo
oops: JS Method Typo
2020-07-27 15:47:37 -05:00
Peter Rotich
97d78c640f Merge pull request #5549 from aydreeihn/issue/team-members
Issue: Create Team With Members
2020-07-27 15:41:36 -05:00
Peter Rotich
14101247ce Merge pull request #5534 from JediKev/issue/signature-box-no-longer-expands
issue: Signature Box No Longer Expands
2020-07-27 15:39:28 -05:00
Peter Rotich
66f497a83a Merge pull request #5537 from JediKev/sla/force-intval-for-scientific-floats
sla: Force Intval For Scientific Floats
2020-07-27 15:37:46 -05:00
Peter Rotich
0b1dee3cc8 Merge pull request #5588 from protich/issue/ticket-cdata
DynamicField name
2020-07-27 15:27:08 -05:00
aydreeihn
9d46c84bcb Extra 2FA Modifications
- Make sure 2FA backend is saved AND configured
- Give Admins option to reset 2FA for an Agent if they lose ability to log in w/current 2FA config
- The getConfigsByNamespace function is useful for 2FA so that we can use the value of an Agent's default_2fa to check to see if they have their 2FA configured
- Add Help Tip for require_agent_2fa field
- Do not automatically select 2FA option if it's configured, just enable it.
- Add Login loading wheel
2020-07-27 13:20:48 -05:00
Peter Rotich
c21452b8d4 DynamicField Update
This commit addresses an issue where cdata tables are dropped due to sql
error on field update.
2020-07-20 19:01:24 +00:00
JediKev
e295c5261a issue: Form Field Help Text Not Null
This addresses a small issue where removing all content from the Help Text
portion for a Form Field and Saving Changes shows extra padding between the
Field Label and input field on Ticket creation. This is due to when saving
the empty content we save as an empty string which is not NULL. So when we
render the Form Field and grab the Help Text it’s not NULL so we display the
empty content. This adds a ternary operator when saving the `hint` content
that says if there is actual content after sanitizing then save the content
otherwise save `NULL`.
2020-07-20 11:26:03 -05:00
JediKev
b415bafbf8 export: Duplicate Results
This addresses an issue where some complex queue criteria returns duplicate
tickets in export results. This adds `distinct('ticket_id')` to the export
query to ensure there are no duplicate results.
2020-07-17 11:41:00 -05:00
aydreeihn
3f08e626d8 Add 2FA Email Template
This commit adds an email template for sending out the 2FA token.

**Note:** We will need to add an upgrader task to import the template for existing helpdesks. I'll add it below in the comments.
2020-07-15 16:09:21 -05:00
aydreeihn
a1b78264d7 2FA Modifications
This commit adds to the functionality of two factor authentication for osTicket.

- Ensures that we do not clear out external 2fa configurations
- Enables 2fa options in the dropdown box of the profile when they are configured
- Adds help tip to the Default 2FA field
- Forces Agents to configure and save 2FA if 'Require agents to turn on 2FA' is checked upon next login
- Fixes the following error:
	- Call to a member function getTabs() on null in include/staff/templates/navigation.tmpl.php
2020-07-15 14:46:39 -05:00
JediKev
8d6b9aa0d6 issue: Email Template Internal Notes
This addresses issue 3796 where adding Internal Notes when creating or
updating an Email Template do not appear. This is due to the `$info`
variable being overwritten by a `foreach(){}`. This changes the
`foreach(){}` variable from `$info` to `$i` so the original `$info` variable
is not overwritten.
2020-07-13 09:50:49 -05:00
Marco Borla
0ecfcebfd2 Update SECURITY.md 2020-07-10 21:52:46 +02:00
Marco Borla
165cf18e38 Create SECURITY.md 2020-07-10 21:50:58 +02:00
JediKev
8f08a0934c redactor: Upgrade to version 3.4.1
This upgrades Redactor from `3.3.5` to `3.4.1` so that we are utilizing the
latest code. This addresses a few security issues with upstream Redactor as
well as provides a few bug fixes and improvements. This also updates
Redactor's core plugins to ensure everything Redactor is fully up-to-date.
2020-07-09 11:01:55 -05:00
JediKev
03bedc533c oops: Change lastupdate To updated For Tasks
This addresses a small issue where we are using the wrong column name of
`lastupdate` to update the Task’s last updated date. This updates
`lastupdate` to `updated` so the column is updated correctly.
2020-07-08 14:14:48 -05:00
JediKev
f91308af36 i18n: Redactor Files Not Included
This addresses an issue where upon building the language packs, the Redactor
i18n files are not included. This is due to the wrong file paths being used
to check if the file exists and to get the file contents. This updates all
the file paths to point to the correct directory.
2020-07-08 11:16:24 -05:00
Peter Rotich
4b6bc735e8 Textbox & Textarea Attributes
Make attributes processing a little dynamic.
2020-07-03 09:31:46 +00:00
Peter Rotich
ea8610348a Support 2FA on agents login form
This commit adds 2FA as part of login process for agents
2020-07-03 07:57:28 +00:00
Peter Rotich
cff12f7078 Manage 2FA
This commit adds the ability for agents to configure supported 2FA
backends and set backend to use.
2020-07-03 07:57:28 +00:00
Peter Rotich
4ef752c68e Add setting to require 2FA
This commit adds setting to Admin Panel > Settings > Agents to force
agents to setup 2FA.
2020-07-03 07:57:28 +00:00
Peter Rotich
5dd0a34f13 Add the concept of 2FA backends
This adds base functionality for 2FA backend and includes email 2fa
support out the box.
2020-07-03 07:27:36 +00:00
aydreeihn
7b6ba94ab1 Issue: Ticket Task Print
This commit fixes an issue we had with printing Tasks from within a Ticket. The task-action class needed to be removed.
2020-06-29 14:51:00 -05:00
aydreeihn
f79a28a97e Issue: Topic Fields on Ticket Edit
This commit fixes an issue where we did not check the Help Topic to see which fields should be shown for Ticket Edits.
Now, a checkbox has been added to the inline edit for Help Topics that gives an option to show fields based on the Help Topic.

If this box remains unchecked, all visible/editable fields on a Ticket's forms will show up when the edit all button is clicked.
	- This is useful in the event that fields were populated before a Topic was changed to a Topic that does not necessarily include those populated fields.

If the box is checked, fields and forms will be shown/hidden based on the fields and forms for the Help Topic selected.
	- This is useful in the event that a Help Topic is chosen by default for incoming Tickets that may include fields that are not needed for the Help Topic that a Ticket is switched to.

One thing to note is that on Ticket creation, if a Help Topic was chosen that didn't include custom forms and the Topic is changed to one that should have custom forms, those forms will not be added automatically with the Help Topic being changed. The Agent would have to go to Manage Forms to add the other form to the Ticket.
2020-06-24 16:21:51 -05:00
JediKev
a97ddba5a8 events: LongAnswer Fields
This addresses an issue where some LongAnswer fields with really long
content cut off the thread event `data`. This is due to the content being
longer than the max allowed characters for the `data` column. This adds
`Format::striptags()` and `Format::truncate()` to the TextareaField changes
to ensure they have no HTML and to ensure they are below the max allowed
characters. Stripping tags and truncating is done after we save the field
changes as if we do it beforehand, it will save that as the changes instead
of the actual changes.
2020-06-23 14:08:09 -05:00
JediKev
d8ff946c0a inline: RichText Fields View First
This addresses an issue where things such as really long tables in inline
RichText Fields causes the remainder of the page to be malformed. This is
due to the content being truncated causing the broken HTML to interfere with
the page. This adds a check for RichText Fields when displaying inline and
if one, strips all tags. With the content being stripped, this adds a View
Popup so Agents can view the entire, true content. From the View Popup,
Agents can click the Edit button to edit the content. This adds a new Field
View template as well as AJAX regex/methods for returning the View Popup.
2020-06-23 14:07:05 -05:00
JediKev
07024fc3af issue: Activity Notice getLastRespondent()
This addresses issue 3647 where Internal Activity Alerts are never sent out
for both Tasks and Tickets. Upon initial investigation it appeared that we
set the `lastrespondent` property before we call
`onResponse()`/`onActivity()` so when we checked the Last Respondent it was
the same Agent posting the Reply so an email was never sent out. Upon moving
the `lastrespondent` property below the `onResponse()`/`onActivity()` calls,
it still grabbed the current Responding Agent. Looking deeper into
`getLastRespondent()` (for both Ticket and Task classes) I found that the
query we use to get the Last Response from an Agent on the Thread, grabs the
newly added Response. This is because the Thread Entry is added before we
call `getLastRespondent()` so we really need to grab the second record, not
the first. This updates the `limit()` clause from `1` to `1,1` to utilize
MySQL/MariaDB "LIMIT offest" so that we grab the second entry which is the
true Last Response. This also moves the `lastrespondent` property below the
`onResponse()`/`onActivity()` calls to ensure we don't return the current
Responding Agent.
2020-06-17 15:04:21 -05:00
aydreeihn
6f50e91080 Issue: Create Team With Members
This commit fixes an issue we had with creating Teams with members at the same time.

Errors:

1064:
[UPDATE `ost_team_member` SET  WHERE (`ost_team_member`.`team_id` = 4 AND `ost_team_member`.`staff_id` = '2') LIMIT 1]

You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE (`ost_team_member`.`team_id` = 4 AND `ost_team_member`.`staff_id` = '2') L' at line 1

1062:
[INSERT INTO `ost_team` SET `created` = NOW(), `flags` = 1, `name` = 'Team1', `updated` = NOW()]

Duplicate entry 'Team1' for key 'name'
2020-06-15 16:40:15 -05:00
JediKev
31dfc6e30f i18n: Don't Store Files Under Branch Name
This addresses an issue where upon building the language packs we store the
files for a particular branch in an identically named directory within the
PHAR archive. (ie. if branch name is `1.14.x` then the directory name will
be `1.14.x`). For instance, the Russian PHAR archive has the structure of:
```
1.14.x
|_ help/
|_ templates/
…
```

This is problematic as when we attempt to retrieve a template with
`$i18n->getTemplate()` the system can’t find it. A good example is Help
Tips, when we get a help tip like
`$i18n->getTemplate("help/tips/settings.ticket.yaml")`,
`help/tips/settings.ticket.yaml` cannot be found (because the actual path is
`1.14.x/help/tips/settings.ticket.yaml`) so the default English version is
returned. This adds a check for `$branch` and if exists we will remove the
branch name from the name/path.
2020-06-15 15:18:45 -05:00
JediKev
351f8ecead template: Add Ticket ID To Var Scope
This addresses an issue where using the variable `%{ticket.id}` throws an
Unsupported Variable Warning even though it's a valid variable. This adds
`id` to the var scope for class Ticket so that the warning is not thrown.
2020-06-12 10:17:55 -05:00
Peter Rotich
744676bbca Localize Password Policy checks for agents
Make sure we're using correct password policy when changing or resetting
agents passwords.
2020-06-10 08:19:25 +00:00
Peter Rotich
e1aba7c2c7 Password Policy Revisited
This commit improves upon how osTicket enforces password policies
systemwide for Agents and Users. Notable changes include;

* Ability to enforce policies on login
* Ability to specify applicable policy for Agents or Users alike
* Allow Password Policy plugins to expire passwords
2020-06-09 21:41:13 +00:00
aydreeihn
36778ccbac Issue: Topic and Department Columns
This commit adds the Created column to Help Topics and Departments in the Admin Panel.
2020-06-08 15:54:52 -05:00
JediKev
9ea2e4dba3 sla: Force Intval For Scientific Floats
This addresses issue 5532 where some floats are being formatted in
Scientific Format (ie. `2.777E+4`) which causes a fatal error for
`DateInterval::__construct()`. This is most likely due to the `precision`
INI setting in some instances. This adds `intval()` around `round()` to
ensure an INT value is returned to avoid the fatal error on format issues.
2020-06-05 11:15:01 -05:00
JediKev
58e559da1f oops: JS Method Typo
This addresses a small typo where `this.activeAjax` should actually be
`this.ajaxActive`.
2020-06-04 14:51:05 -05:00
JediKev
5d68847185 issue: Signature Box No Longer Expands
This addresses issue 5531 where the Signature Box no longer expands when
hovering over it. This is due to some outdated jQuery that needs to be
updated. This updates `.on('hover'` and breaks it into `.on('mouseenter'`
and `.on('mouseleave'`. This also removes `originalHeight = Math.max` as it
just kept adding more and more pixels causing the collapsed area to grow and
grow (ew). In addition, this adds 25 pixels to the offsetHeight to expand
the box past the content and subtracts 10 pixels from originalHeight so it
collapses back to the same height.
2020-06-04 13:38:22 -05:00
JediKev
0765571a2c install: Add Mark As Answered To All Access
This adds the Mark As Answered permission to the All Access Role for new
installs. This will ensure the "All Access" Role has all access for Tickets.
2020-05-28 10:43:38 -05:00
JediKev
5db5a7288e print: Client Print Not Respecting Identity Masking
This addresses an issue where Client-side Print does not respect Agent
Identity Masking. This adds a check for `hideStaffName()` and if `TRUE` we
will use `Staff` as the Agent's name in the PDF. If
`hideStaffName()` returns `FALSE` then we will use the Agent's actual name.
2020-05-27 10:53:40 -05:00
JediKev
faec1a797c templates: %{ticket.thread.complete} Not Respecting Identity Masking
This addresses an issue where Karen is not respecting the drip…just kidding.
This addresses an issue where `%{ticket.thread.complete}` does not respect
Agent Identity Masking. This adds a check for `hideStaffName()` and if
`TRUE` we will use `Staff` as the Agent's name in the thread export template
for clients. If `hideStaffName()` returns `FALSE` then we will use the
Agent's actual name. This only applies to the `thread-export.tmpl.php` for
clients.
2020-05-27 10:51:22 -05:00
JediKev
be18e46c95 print: Update Icons and Add Titles
This updates the icons for the Print options to be more explanatory of what
you will receive. PDF Files will have File Icons and ZIP Archives will have
Folder Icons. In addition this adds `title` attributes to all Print options
to note if the Agent will receive a PDF File or ZIP Archive.
2020-05-22 09:37:46 -05:00
JediKev
adc46aeb42 issue: Filter Action Add Button
This addresses issue 5513 where clicking the Add button on the Filter
Actions tab without selecting an option will insert an `undefined` Action.
This is due to the placeholder option having an empty `value` attribute.
This updates the JS to check the selected option's `value` attribute and if
empty we will return without appending. This will ensure the placeholder
option does not append an `undefined` Action.
2020-05-21 17:02:56 -05:00
JediKev
292e7ddf77 xss: FAQ Category On Errors
This addresses 1/2 of the vulnerability reported at 5514 where pasting an
XSS Payload in the Category Description/Notes and saving changes without
filling out required info executes the XSS Payload. This is due to the
system not sanitizing the return values on errors. This adds
`Format::sanitize()` to the Description and Notes fields so that any value
displayed is properly sanitized. The Description/Notes are properly
sanitized before saving to the database, the issue only lies when returning
values on errors.
2020-05-21 16:44:25 -05:00
JediKev
e0b5d81b33 install: Embedded Domain Whitelist
This adds `youtube.com, dailymotion.com, vimeo.com, player.vimeo.com,
web.microsoftstream.com` as the default values for the Embedded Domain
Whitelist feature for new installs.
2020-05-20 16:22:36 -05:00
JediKev
1860db4851 tips: Update Grace Period
This updates the SLA Grace Period Help Tip to include more information about
Schedules and how they affect the Grace Period.
2020-05-20 16:19:12 -05:00
JediKev
e589c1b243 install: Update Default SLA
This updates the System Default SLA's Grace Period from 48 Hours to 18
Hours. This ensures the SLA is in tandem with the new System Default
Schedule. With this update, the two 9 Hour days (8am-5pm) will then allow
tickets to become overdue in 2 business days.
2020-05-20 15:51:35 -05:00
JediKev
88dd0aa4a4 install: Set Default Schedule
This sets the System Default Schedule to the `Monday - Friday 8am - 5pm with
U.S. Holidays` Schedule for new installs. This will ensure all SLAs are
counted during normal US business hours (excluding US Holidays).
2020-05-20 15:51:01 -05:00
aydreeihn
61443efec2 Issue: Ticket Number Search
This commit fixes an issue we had where we were doing a union on the adhoc search queries. One should return a lookup by number and the other should return tickets that belong to the user of the number searched.

    When doing the union, we just needed to make sure the columns were lined up correctly.
2020-05-19 15:47:49 -05:00
JediKev
b4cd46a804 issue: Update Print Options Icons/Text/Title
This updates the Print options' icons and text to be more descriptive. This
updates all PDF Print options' icons to `icon-file-text-alt` which
symbolizes PDF file. This updates all ZIP Print options' icons to
`icon-folder-close-alt` which symbolizes ZIP Archive. In addition, this
updates the `Export with …` ZIP options' names to match the PDF options'
names. Lastly, this add a tooltip (title) to each Print option that
indicates what type of download you will receive (ie. `PDF File` or `ZIP
Archive`).
2020-05-13 16:44:23 -05:00
JediKev
2dee16b5fd refactor: Help Topic Status Refresh
This addresses an issue where setting a Help Topic via Inline Edit does not
refresh the statuses in the Reply box, but it does refresh the statuses in
the Internal Note box. This is due to jQuery not being able to append the
same `<option>` object to multiple `<select>` objects. When you use the same
`<option>` object for multiple `<selelct>` objects, it removes the object
from the first `<select>` and appends it to the second `<select>`. Instead
of reusing the same object we must clone it so it does not interfere with
the first `<select>`.
2020-05-11 11:41:42 -05:00
JediKev
90f598505c issue: Countable Warning
This addresses an issue where using PHP 7.4, setting Help Topic Sort to
Manually, rearranging the Help Topics, and Saving Changes throws a warning
of `Parameter must be an array or an object that implements Countable`. This
is because when sorting Help Topics, we send no IDs so the `count()`
obviously fails. This checks to see if `$_POST['ids']` exists first, if so
then we count, otherwise we default to `0`.
2020-05-07 16:30:39 -05:00
JediKev
d93379e5bc issue: Undefined Constant Warning
This addresses an issue where upgrading from pre-`1.10.x` and using PHP 7.4
throws a Warning of `Use of undefined constant TICKET_EMAIL_INFO_TABLE`.
This checks if `TICKET_EMAIL_INFO_TABLE` is defined in the Task and if not,
we define it to avoid warnings/errors.
2020-05-07 16:30:03 -05:00
JediKev
1aafa42552 issue: Compatible Warnings
This addresses some PHP 7.4 Compatibility Warnings.
2020-05-07 16:29:26 -05:00
JediKev
db5eb0777a issue: Flush Model Cache
This addresses an issue where `ModelMeta::flushModelCache()` doesn't work
correctly. In theory, it's supposed to clear all APCu cache. This is
especially helpful for Upgrades by preventing the selection of
data/structures that don't exist anymore. This is due to the fact that when
we updated `apc_clear_cache()` to `apcu_clear_cache()` we forgot to remove
the argument. `apcu_clear_cache()` takes no arguments and you would think
that PHP would be smart enough to void the argument but apparently it's not.
This removes the argument so that it works properly and clears all APCu
cache.
2020-05-07 16:25:24 -05:00
aydreeihn
49977809f3 Issue: PHP Warning
This commit fixes a PHP warning that was found within the code when counting child tickets.
2020-05-05 08:54:57 -05:00
JediKev
bb54deaa57 issue: MySQL 8.0 {min,max} Value Error
This addresses an issue reported on the Forum where registering as a User
with MySQL 8.0 throws an error of `Incorrect description of a {min,max}
interval.`. This is due to MySQL seeing `{` in the regex
`_auth\|.*"user";[a-z]+:[0-9]+:{[a-z]+:[0-9]+:"id";[a-z]+:` as the start of
repetition notation. In order to avoid this, we can simply escape the `{` so
it’s seen as a literal squiggly bracket and not the start of repetition
notation.

Reference:
- https://dev.mysql.com/doc/refman/8.0/en/regexp.html#regexp-syntax
2020-05-04 11:39:19 -05:00
Jose Manuel Monsalve Diaz
ebfd68b57e Adding translation to the dashboard plot labels. 2020-05-01 17:44:06 -05:00
aydreeihn
a1e9342238 Issue: Language Verification
This plugin updates the line of code we have to check the DNS record for language packs to verify them as one of our official language packs.
2020-05-01 13:13:04 -05:00
JediKev
52fd884def issue: Mass Delete Help Topics Warning
This addresses an issue where deleting 2 or more Help Topics shows a warning
of `X of X selected help topics deleted` even though all selected Help
Topics were deleted. This is due to the check that ensures that the number
of Help Topics deleted is the same as the how many Help Topics you selected.
This updates the check to compare against the actual Topic count rather than
the QuerySet itself.
2020-04-30 15:40:25 -05:00
Peter Rotich
741122a614 Merge pull request #5487 from JediKev/issue/org-added-collabs
issue: Org Added Collabs
2020-04-29 15:36:25 -05:00
JediKev
0ee25b877c issue: Org Added Collabs
This addresses an issue where creating a ticket with a Reply and
Collaborators failed to add the Response. This was caused by the Owner ID
check in class Ticket as it returned an error that wouldn’t let the response
be added. This also addresses an issue where Collabs added via Organization
were being Enabled regardless of the Disable Agent Collab setting.
2020-04-29 14:42:55 -05:00
JediKev
cba6035649 Add Release Notes for v1.14.2 2020-04-28 15:07:16 -05:00
JediKev
669fd3fded Merge branch 'develop' into develop-next 2020-04-28 15:04:53 -05:00
JediKev
6b5288987d Merge pull request #5482 from JediKev/upgrade/redactor-3.3.5
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-04-28 14:35:54 -05:00
JediKev
e351ba55a4 Add Release Notes for v1.12.6 2020-04-28 14:30:10 -05:00
JediKev
96c8bc6308 Merge pull request #5481 from JediKev/xss/all-reported-vulns
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-04-28 14:24:18 -05:00
JediKev
4634a86e2d upgrade: Redactor 3.3.5
This upgrades Redactor from `3.2.2` to `3.3.5` so that we are utilizing the
latest code. This addresses a few security issues with upstream Redactor as
well as provides a few bug fixes and improvements. This also updates
Redactor's core plugins as well as the CSS to ensure everything Redactor is
fully up-to-date.
2020-04-28 13:47:03 -05:00
JediKev
601fdcd6ba oops: Wrong Var Name
This addresses a tiny annoyance where updating a queue you get the message
`Successfully updated _` with the Queue Name missing. This is due to the
wrong variable name being used. This updates the variable name from `name`
to `queue-name` so the queue name shows properly on updates.
2020-04-28 13:34:07 -05:00
JediKev
6c724ea3fe xss: Queue Name
This mitigates an issue discovered by Matthew Aberegg where the Name field
for a Queue can be exploited via XSS to execute code. This sanitizes the
`$_POST['queue-name']` variable in a few places via `Format::htmlchars()` so
we are safe from any XSS attempts on creations and updates.
2020-04-28 13:34:07 -05:00
JediKev
d54cca0b26 xss: Saved Search Name
This mitigates an issue discovered by Matthew Aberegg where the Name field
for Saved Searches can be exploited via XSS to execute code. This sanitizes
the `$_POST['queue-name']` variable via `Format::htmlchars()` so we are
safe from any XSS attempts on creations and updates. All other Saved Search
content is parsed/sanitized correctly.
2020-04-28 13:34:06 -05:00
JediKev
fc4c8608fa xss: SLA Name
This mitigates an issue discovered by Gais Cyber Security where the SLA Name
can be exploited via XSS to execute code. This sanitizes the content for
`create()` and `update()` with `Format::htmlchars()` so we are safe from any
XSS attempts.
2020-04-28 13:34:06 -05:00
JediKev
de41aeb14b xss: List Values
This addresses an issue reported by Security Innovation where the "Plural
Name" value is not sanitized which results in XSS possibilities. Upon
further investigation, none of the Create List values are sanitized so any
of them could potentially house XSS. This adds sanitization to `update()`,
`create()`, and `add()` so that all content is safe from XSS before reaching
the database and/or being returned in errors. In addition, this adds a new
argument to `create()` called `$sanitize` that determines wether or not to
sanitize the content. This argument is `TRUE` by default. Lastly, this
sanitizes the `$_POST` vars when updating the List Properties.
2020-04-28 13:34:06 -05:00
JediKev
f705001ae4 xss: Response & Internal Note
This addresses an issue found when investigating a separate vulnerability
where XSS can be executed in the Response and Internal Note Fields when
errors are returned or if they are rendered with data (like drafts). This
adds sanitization to both Response and Internal Note fields for the New
Ticket page and the Ticket View page. This will sanitize both POST data and
Drafts to ensure all content is safe before rendering. This also adds
sanitization to the ThreadEntryWidget so any ThreadEntryField is safe from
XSS upon rendering (like the New Ticket Issue Summary in the Client Portal).
2020-04-28 13:34:06 -05:00
JediKev
0c6c330e9b Merge pull request #5474 from JediKev/issue/show-custom-validation-message
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-04-27 14:34:58 -05:00
JediKev
5e8c7dfcff Merge pull request #5477 from protich/issue/sla-grace-period
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-04-27 14:07:06 -05:00
JediKev
ca6ad5c735 issue: Show Custom Validation Message
This addresses an issue where custom validation messages are not appearing,
instead the system shows the default validation messages. This is due to
9e21dfd where we failed to consider custom validation messages. Basically,
the referenced commit made it to where we could use validation messages from
the source validation method which is great but it overwrites the custom
validation message. The end goal is to have Custom Messages displayed first,
if no custom messages then we display the Source Messages, and if no source
messages we display the Default Messages. This renames the Default
Validation Message variable from `$error` to `$ferror` (for Function Error)
and updates the ternary check to first check `$error` (Custom Message) then
check `$err` (Source Message) then lastly `$ferror` (Default Message).
2020-04-27 13:17:55 -05:00
Peter Rotich
77e53ca41d Merge remote-tracking branch 'upstream/develop' into develop-next 2020-04-23 20:43:02 +00:00
Peter Rotich
7d8bdc76b2 Merge pull request #5480 from aydreeihn/issue/misc-fixes
Issue: Merge Child Status
2020-04-28 13:27:20 -05:00
aydreeihn
34af39016d Issue: Merge Child Status
This commit fixes an issue where we needed to ensure that we were checking ids against an actual user object when trying to avoid adding the ticket owner as a collaborator when merging child tickets.
2020-04-28 13:16:20 -05:00
JediKev
9df07a961d Merge pull request #5454 from jdelhome3578/ui/action-buttons
ui: improve action buttons
2020-04-28 12:51:27 -05:00
aydreeihn
869d11798d 1.14 Misc. Fixes
- addCollaborator on Merge:
	- We need to make sure we're not trying to add the TicketOwner as a Collaborator at any point when we're merging Tickets.
2020-04-28 08:50:07 -05:00
Peter Rotich
c15be584b4 Merge remote-tracking branch 'upstream/develop-next' into develop-next 2020-04-23 18:54:41 +00:00
Peter Rotich
713923ecea Merge pull request #5478 from aydreeihn/issue/misc-fixes
1.14 Misc. Fixes
2020-04-28 11:15:02 -05:00
Peter Rotich
c5106d74bd Merge pull request #5465 from aydreeihn/issue/deleted-obj-filters
Issue: Filter Actions for Deleted Objects
2020-04-28 11:10:43 -05:00
aydreeihn
b918e2d253 Issue: Filter Actions for Deleted Objects
This commit fixes an issue where an object could be deleted that was included in a filter action without properly accounting for the deletion. Now, if something is deleted and there is a Filter Action associated to that object, the Filter will be disabled and the Filter Action configuration will be updated to no longer include the invalid id. This has been done for the following objects:

- Help Topic
- Department
- Agent
- Team
- SLA
- Ticket Status
- Email
- Canned Response
2020-04-28 08:35:37 -05:00
JediKev
c6c1e02377 Merge pull request #5475 from protich/issue/v1.14-fixes
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-04-27 14:03:46 -05:00
JediKev
11aca99373 Merge pull request #5472 from protich/issue/task-forms
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-04-27 13:40:13 -05:00
JediKev
dea61c6765 Merge pull request #5466 from aydreeihn/issue/audit-delete
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-04-27 13:38:15 -05:00
Peter Rotich
bdf05e85f4 Merge remote-tracking branch 'upstream/develop' into develop-next 2020-04-23 18:54:32 +00:00
Peter Rotich
b373b8f269 SLA Grace Period
Limit grace period to 8760 hours (1 year). The limit will be lifted once
Schedule implementation is revisited.
2020-04-23 14:18:12 +00:00
Peter Rotich
51b583917d Mute warning when fetching and email without a body 2020-04-23 08:06:08 +00:00
Peter Rotich
c9cc1e2e38 Ticket: Optimize getting ticket's children
This addresses a warning on doing a count on a null.
2020-04-23 08:05:53 +00:00
Peter Rotich
c2b99ab9c1 Make Email Search Faster, Again!
Limit search to email field when search term is an email
2020-04-23 03:00:01 +00:00
Peter Rotich
5955c3a18a Silence DNS check errors (warnings) on email verify 2020-04-23 02:56:09 +00:00
Peter Rotich
3c0dd3deb5 Return true on session update even when disabled
This is required of session updates in PHP 7.3+ to avoid a warning
2020-04-23 02:48:19 +00:00
Peter Rotich
bfa7b57f4f MailParse: parse filename from content disposition
Parse out filename when not formatted as expected
2020-04-23 02:38:29 +00:00
Peter Rotich
e397f03e69 Use is_array instead of count to check if array 2020-04-23 02:34:28 +00:00
Peter Rotich
77577dff81 Make sure filter action object exists b4 use 2020-04-23 02:32:02 +00:00
Peter Rotich
ac5f93e5a5 Export: Invalid / Unknown Queue
Die gracefully when attempting to export an invalid queue
2020-04-23 02:25:44 +00:00
Peter Rotich
aed5d6f9fc Cleanup Status mishap introduced by PR #5223 2020-04-23 02:20:48 +00:00
Peter Rotich
f5d166493c Uncessary Due date event log
Make sure date format matches MySQL format to avoid uncecessary Due Date
change event log when the date is unchanged.
2020-04-23 02:16:30 +00:00
aydreeihn
8023ba94d2 Issue: Class AuditEntry Not Found
This commit fixes an issue where we were trying to use a Plugin function that some helpdesks may not include. Rather than calling the class from the Plugin, we can use the object.deleted Signal.
2020-04-22 08:49:17 -05:00
Peter Rotich
609b8d88ca Merge pull request #5421 from JediKev/issue/dynamicform-i18n-instructions-decode
issue: DynamicForm i18n Instructions Decode
2020-04-21 12:08:58 -05:00
JediKev
56d3d675fc issue: DynamicForm i18n Instructions Decode
This addresses an issue where saving translated Form Instructions with HTML
formatting renders the Instructions as plaintext on the Client Portal
showing all HTML, etc. This is due to saving the translated Instructions as
encoded thanks to `Format::htmlchars()`. This uses `Format::htmldecode()`
for `instructions` in `DynamicForm::getForm()` so that when the Form is
rendered the Instructions are properly displayed.
2020-04-20 15:15:55 -05:00
Peter Rotich
73d4b6dfb4 Merge pull request #5422 from JediKev/issue/information-field-help-text-decode
issue: Information Field Help Text Decode
2020-04-20 12:12:16 -05:00
Peter Rotich
e8cdedb48a Merge pull request #5447 from aydreeihn/issue/new-agent-dept-team
Issue: New Agent Extended Access and Teams
2020-04-20 12:10:34 -05:00
Peter Rotich
e710c2ab6c Merge pull request #5453 from pitbulk/improve-ext-errors
Allow external UserAuthenticationBackend to provide a way to set an error while running the triggerAuth.
2020-04-20 11:51:31 -05:00
Peter Rotich
8f8b06bd2a Merge pull request #5410 from JediKev/i18n/help-text-formatting
i18n: Help Text Formatting
2020-04-16 11:57:11 -05:00
JediKev
6370484aa1 issue: ThreadEntryField Help Text
This addresses an issue introduced with the previous commit where since we
allow Formatting to be saved for Help Text now, the ThreadEntryFields do not
render the Help Text correctly. Only ThreadEntryFields display the Help Text
within the `placeholder` attribute. Since the content is placed in an
attribute, it cannot be rendered as HTML. This adds `Format::striptags()` to
`ThreadEntryField::getWidget()` so that tags are stripped from the Help Text
before rendering.
2020-04-16 09:29:33 -05:00
Peter Rotich
ac4dc34305 Merge pull request #5429 from JediKev/issue/department-parent
issue: Department Parent
2020-04-15 22:25:45 -05:00
Peter Rotich
cf1db48d04 Merge pull request #5458 from JediKev/issue/edit-user-popup-perm
issue: Edit User Popup Perm
2020-04-15 22:08:35 -05:00
JediKev
c73877d99d issue: Edit User Popup Perm
This is a rewrite of 5256 that addresses an issue where if an Agent does not
have permission to Edit Users the Edit User link on Ticket Create will show
a broken/blank popup. This adds a check for the Agent's User Edit Permission
and if they do not have permission to Edit Users we will remove the
`onclick` event so it does not trigger a popup.
2020-04-13 15:30:05 -05:00
JediKev
3f298455af issue: Department Parent
This addresses issue 5428 where you can set a Department's Parent to itself,
which is not supposed to happen. This adds a check to `Department::update()`
that checks if the current Department is in the Parent's path. If so, we
will refuse to save changes and throw an error message stating `Parent
Department cannot contain the current Department`. This also fixes a small
issue where we were not using `$errors['pid']`, instead we were using
`$warn`. This updates `$warn` to `$errors['pid']` so we can use
`$errors['pid']` if set elsewhere.
2020-04-13 13:42:27 -05:00
Peter Rotich
6a565421bf Merge pull request #5456 from protich/issue/annotated-constraint
Support sub-query as annotated constraint
2020-04-13 12:03:16 -05:00
Peter Rotich
e8acf81f51 Task: Dynamic Form Title on view
Don't show dynamic forms titles when there're no dynamic fields to show.
2020-04-12 08:29:17 +00:00
Peter Rotich
f16cd79b46 oopsie: Revert errant delete by commit 027c8d29 2020-04-12 03:14:36 +00:00
Peter Rotich
4f19924a9f lint: oopsie on undefined variable 2020-04-12 02:33:38 +00:00
Peter Rotich
6ed8c7b926 Merge remote-tracking branch 'upstream/develop-next' into develop-next 2020-04-12 02:30:00 +00:00
Peter Rotich
808fe1566e Merge pull request #5223 from aydreeihn/feature/task-inline-edit
Task Inline Edit
2020-04-21 22:13:15 -05:00
Peter Rotich
36839bf323 Merge pull request #5470 from JediKev/issue/move-owner-check-to-ticket-collabs
issue: Move Owner Check to Ticket Collabs
2020-04-21 21:58:36 -05:00
JediKev
7d44262f49 issue: Move Owner Check to Ticket Collabs
This addresses an issue where adding a Task Collab fails with error `Call to
undefined method Task::getOwnerId()`. This updates
`ThreadAjaxAPI::addCollaborator()` to call `$object->addCollaborator()`
instead of `$thread->addCollaborator()`. This gives us the opportunity to
perform separate actions/checks for Ticket and Task Collabs. This also
updates `Ticket::addCollaborator()` to check if the current Collab is the
Owner, if so we will refuse to add the Owner as a Collab.
2020-04-21 13:07:00 -05:00
aydreeihn
cc8d64ecc1 Redo Task Status Edit
Inline edit for task status doesn't need to have the dropdown option since we can only set the status to Open or Closed.
2020-04-21 12:42:19 -05:00
Peter Rotich
e125bef13c Merge pull request #5469 from JediKev/oops/update-schedule-no-desc
oops: Update Schedule No Description
2020-04-21 12:08:35 -05:00
JediKev
774d5f7979 oops: Update Schedule No Description
This addresses issue 5468 where updating a Schedule clears out the
Description. This is due to the wrong property name being used when updating
the Description. This updates `$this->notes` to `$this->description` so that
the Description is set properly.
2020-04-21 10:00:03 -05:00
aydreeihn
1179d60a59 Clean Up Task Status
This commit cleans up the code used to change the status of a Task.
- Remove unneeded code for inline task status edit
- Fix mass process verbs
- Check to see if a status goes in as a string or object for setStatus
- Make sure we're looking at Task Permissions
- Make sure task status can only be default open or closed
2020-04-20 09:33:19 -05:00
aydreeihn
49aba8759f Issue: updateField
We need to have the updateField function in the Ticket and Task class rather than in VerySimpleModel to avoid having an irrelevant function in the ORM.
2020-04-20 08:33:38 -05:00
aydreeihn
79b69aa8c5 Oops: Lint Fixes
Fix undefined variable error.
2020-04-20 08:33:38 -05:00
aydreeihn
2b8a6dc283 Inline Edit Checkboxes
This commit adds the extra switch statement we needed for BooleanFields so that checkboxes will always display as 'Yes' or 'No' rather than 0 or 1.
2020-04-20 08:33:38 -05:00
aydreeihn
7209b03c16 Inline Edit Long Answer
This commit ensures that if a long answer field is cleared using inline edit, we display the faded '--Empty--' string so that the agent still has the option to edit the value again.
2020-04-20 08:33:38 -05:00
aydreeihn
027c8d2918 Task Inline Edit
- Put updateField in VerySimpleModel so that we don't have to have redundant code in the Ticket and Task classes.
- Change Task filter from 'Due Soon' to 'Due Date'
- Make sure we add any new custom fields on the task view
2020-04-20 08:33:38 -05:00
aydreeihn
ad04c0588c Task Inline Edit
Allow inline edit for the following on tasks:
- custom fields
- Status
- Department
- Due Date
- Assign
2020-04-20 08:33:38 -05:00
Peter Rotich
d285f30bd0 Merge pull request #5459 from JediKev/issue/collab-pass-by-reference
issue: Collab Pass By Reference
2020-04-16 17:36:57 -05:00
JediKev
a3a1d4532a issue: Collab Pass By Reference
This addresses an issue introduced with 5f5403d where passing `$vars` by
reference to `Thread::addCollaborator()` broke a couple of things for
Collaborators. This reverts the pass by reference and adds a new global
variable to class Collaborator called `active`. This allows us to track the
`active` variable whilst not messing with other collab functions.
2020-04-16 15:48:52 -05:00
Peter Rotich
d75b7de08b Merge remote-tracking branch 'upstream/develop' into develop-next 2020-04-12 02:29:45 +00:00
Peter Rotich
d9c7bd4371 Merge remote-tracking branch 'upstream/develop-next' into develop-next 2020-04-11 17:56:40 +00:00
Peter Rotich
a52a039f7d Merge pull request #5460 from JediKev/revert/agent-added-agent-collabs
revert: Agent Added Agent Collabs
2020-04-20 13:16:46 -05:00
Peter Rotich
b674e6e430 Merge pull request #5461 from JediKev/issue/auditentry-not-found
issue: AuditEntry Not Found
2020-04-20 13:16:28 -05:00
JediKev
cc7deda0e4 revert: Agent Added Agent Collabs
This adds a check for `$thisstaff` in `Thread::addCollaborator()`. If we
have a staff object we will enable Agent Collabs, if we do not have a staff
object we will disable Agent Collabs. This will ensure all Agent added Agent
Collabs are Enabled and any User added Agent Collabs are Disabled. This also
updates the Help Tip for the setting to remove the `Web created tickets`
part (as users cannot add collabs via web) and to clarify that this only
affects User created tickets.
2020-04-20 11:26:57 -05:00
JediKev
9e3ca8c94c issue: AuditEntry Not Found
This addresses an issue where not having the Audit Log plugin installed and
attempting to delete a Help Topic, Knowledgebase Category, or Page the
system fails with the error `Class 'AuditEntry' not found`. This adds a
check for the `AuditEntry` class before calling it (for Help Topics,
Knowledgebase Categories, and Pages) to avoid the `Class not found` error.
2020-04-17 19:30:36 -05:00
Peter Rotich
0f3b688d3c Merge remote-tracking branch 'upstream/develop' into develop-next 2020-04-11 17:56:29 +00:00
Peter Rotich
d05d68c9ba Merge remote-tracking branch 'upstream/develop' into develop-next 2020-04-11 08:48:25 +00:00
Peter Rotich
d883a15db6 Merge remote-tracking branch 'upstream/develop-next' into develop-next 2020-04-11 05:32:12 +00:00
Peter Rotich
736c1f7b67 Merge pull request #5431 from aydreeihn/issue/ticket-audit-popup
Audit Plugin Modal Fix
2020-04-15 22:40:20 -05:00
Peter Rotich
d7ccee551f Merge pull request #5451 from JediKev/feature/configurable-agents-as-collabs
feature: Configurable Agents As Collaborators
2020-04-15 22:11:43 -05:00
Peter Rotich
d250e7ef0a Merge pull request #5457 from protich/issue/annotated-constraint++
Add AnnotatedField interface to TicketTasksCountField
2020-04-15 12:21:46 -05:00
JediKev
4ed30c58e2 collab: Consolidate Collaborator Events
This adds a new method called `logCollaboratorEvents()` that logs any type
of collaborator event (del, add, etc.) and sends a signal for Audit Logs.
This helps consolidate all Collab Event logging in class Thread to make the
code cleaner and reduce redundancy.
2020-04-13 13:13:56 -05:00
JediKev
9426e67218 collab: Refuse To Add Owner As Collaborator
This adds a new `if()` statement to `Thread::addCollaborator()` that checks
the current Ticket Owner's ID to the User's ID that is being added as a
Collaborator. If the IDs match then we will refuse to add the Owner as a
Collaborator as Users are not supposed to be a Collaborator on Tickets they
own.
2020-04-13 13:13:52 -05:00
JediKev
bdcaeea8a6 issue: Set Ticket Status For addCollaborator()
This addresses an issue where `Thread::getObject()` is not available for
`Thread::addCollaborator()` as the Ticket object is missing a Status
(incomplete). This sets the default Ticket Status (if none) so that the
Ticket object is complete and can be accessible via
`Thread::addCollaborator()`.
2020-04-13 13:13:47 -05:00
JediKev
5f5403dcfb feature: Configurable Agents As Collaborators
This adds a new setting called "Disable Agent Collaborators" that allows Admins
to globally configure wether or not to allow Agents to be added as
Collaborators via any communication on tickets. In some use cases Agents do
not want to be added as Collaborators on tickets to avoid an overload of
emails/alerts, etc. This adds a new checkbox labeled `Disable Agent
Collaborators` to **Admin Panel > Settings > Agents** that if
Enabled/Checked will automatically Disable Agents that are added as
Collaborators. This disables the participant alerts for the Agents whilst
giving other Agents/Admins the ability to enable them at a later date
instead of having to manually add them back. If an Agent tries adding
another Agent as a Collaborator via the Manage Collaborators modal it will
also Disable the Agent Collaborator.
2020-04-13 13:12:18 -05:00
Peter Rotich
04e40b3132 Merge remote-tracking branch 'upstream/develop' into develop-next 2020-04-11 05:31:58 +00:00
jdelhome3578
a11f882974 ui: improve action buttons
Remove the <span> tag and move the <span> class to the <a> tag to make the whole button clickable.
2020-04-10 17:25:59 -04:00
jdelhome3578
b25c66bbaa ui: improve action buttons
Remove the <span> tag and move the <span> class to the <a> tag to make the whole button clickable.
2020-04-10 17:15:16 -04:00
Peter Rotich
fbc1b11916 Add AnnotatedField interface to TicketTasksCountField 2020-04-10 19:50:12 +00:00
Peter Rotich
113e6f182a Merge remote-tracking branch 'upstream/develop' into develop-next 2020-04-10 19:34:43 +00:00
Peter Rotich
0eeec7edcf Support an annotated Field on criteria
Add annotation to the query set if the criteria has an annotated field.
2020-04-10 18:39:40 +00:00
Peter Rotich
f61748c42b Add AnnotatedField interface
This commit adds AnnotatedField interface to provide annotated fields
with way to annotate a query set ondemand.
2020-04-10 18:39:36 +00:00
Peter Rotich
6579cf4715 NumericField: getSearchQ
Add search constraints mapping for NumericField
2020-04-10 18:37:29 +00:00
Peter Rotich
c069def654 Add support for sub-query based constraints.
Constraint on a subquery goes to HAVING clause using the specified alias.
2020-04-10 18:37:29 +00:00
JediKev
76862b346b Merge pull request #5450 from aydreeihn/issue/ticket-merge
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-04-09 11:32:50 -05:00
jezuk
f42f2bafef Update class.filter.php (#5320)
* Update class.filter.php

Remove X-Auto-Response-Suppress from $auto_headers
Fixes #726

* Update class.filter.php

Edit the 'X-Auto-Response-Suppress' filter to only include 'AutoReply'
2020-04-09 11:01:54 -05:00
JediKev
a91d063dff Merge pull request #5239 from JediKev/emoji/strip-from-subject
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-04-09 10:41:50 -05:00
Sixto Martin
ffb179f7d6 Allow external UserAuthenticationBackend to provide a way to set an error while running the triggerAuth. 2020-04-09 17:16:34 +02:00
aydreeihn
d31a0c71ac Ticket Merge Modal Improvements
- Move 'Select Ticket' box above 'Participants'
- Clear 'Select Ticket' when a Ticket is added
- Select the default 'Closed' status by default for the 'Child Status'
2020-04-08 15:30:05 -05:00
aydreeihn
d4b8b3a7fa Issue: New Agent Extended Access and Teams
This commit fixes an issue we had with trying to create new Agents with Extended Department Access or a Team. We were trying to add them before there was a staff_id which resulted in a DB error as well as the actions not being performed. To fix this, we just need to add the Agent's Department access and Team membership after we save the Agent so that they have an id. We also need to save the Staff object in the setDepartmentId function.
2020-04-07 14:05:33 -05:00
Peter Rotich
5461f80c77 Merge remote branch 'upstream/develop' into develop-next 2020-04-03 17:05:02 +00:00
Peter Rotich
6d5dec5a8f Merge pull request #5420 from JediKev/i18n/textareafield-placeholder
i18n: TextareaField Placeholder
2020-04-02 10:49:50 -05:00
Peter Rotich
0b1e5485ed Merge pull request #5437 from JediKev/issue/mass-process-add-users-to-org
issue: Mass Process Add Users To Organization
2020-04-02 10:48:42 -05:00
Peter Rotich
0c00feab3a Merge pull request #5433 from kler/fixOrmArrayIndexWarning
Remove unnecessary PHP Notice in ORM (Fix #5432)
2020-04-02 10:47:41 -05:00
Peter Rotich
f6edad7c07 Merge pull request #5438 from JediKev/issue/confirm-popup-promise
issue: Confirm Popup Promise
2020-04-02 10:46:21 -05:00
Patrik Lermon
03e25a847b Make more efficient array check (only once instead of twice) 2020-04-02 08:01:24 +02:00
JediKev
6cc7c690f2 issue: Mass Process Add Users To Organization
This addresses an issue where checking the box next to a few User’s names
then selecting the Action to Add To Organization does nothing. This is due
to a pesky jQuery issue where `parseJSON()` will crap out if you pass in
JSON (go figure). You MUST provide a string otherwise it will silently fail.
So, this adds an if statement that checks if the content is a string and if
so we will use `$.parseJSON()` otherwise we will not parse it.
2020-04-01 16:06:14 -05:00
JediKev
fa9df2bb60 i18n: TextareaField Placeholder
This addresses an issue where TextareaFields do not show translated
placeholders. This is due to using the placeholder from the default
configuration instead of using the local placeholder. This updates the
`TextareaWidget::render()` method to get the local placeholder instead of
using the default from config. This also passes `$config['placeholder']` as
a default in case there is no translation available.
2020-04-01 15:45:32 -05:00
JediKev
b1f881be25 issue: Confirm Popup Promise
This addresses an issue where clicking Cancel on some popups (eg.
Organization Deletion popup, User Deletion popup, etc.) will perform the
action instead of cancelling. This is because the `then()` and `done()`
callbacks used on the custom `$.confirm()` method do not respect the
returned promise. This adds a check to each `$.confirm()` usage to see if
the promise is equal to `FALSE`, if so we return false. If the promise is
not equal to `FALSE` then we continue with the callback.
2020-03-30 13:22:32 -05:00
Patrik Lermon
5dac5499c2 Remove unnecessary PHP Notice in ORM (Fix #5432) 2020-03-26 12:23:06 +01:00
aydreeihn
a883f9051a Audit Plugin Modal Fix
This commit removes a line of code that caused the Ticket Audit modal to close any time you tried to go to the next page of audits or sort the audits by timestamp. The code was put in place 6 years ago for file upload fields, but they still work fine everywhere in the codebase without that line now.
2020-03-25 09:42:24 -05:00
Peter Rotich
565a9bfaa1 Merge pull request #5270 from JediKev/feature/force-https
feature: Force HTTPS
2020-03-24 19:11:44 -05:00
Peter Rotich
67fda0272e Merge pull request #5409 from JediKev/i18n/help-text-translate-button
i18n: Help Text Translate Button
2020-03-24 18:59:26 -05:00
Peter Rotich
7665e7f923 Merge pull request #5418 from JediKev/export/user-org-tickets
export: User/Org Tickets
2020-03-24 18:23:06 -05:00
Peter Rotich
4b93cb7da7 Merge pull request #5424 from JediKev/oops/is_numeric-soft-fail
oops: is_numeric Soft Fail
2020-03-24 18:11:01 -05:00
Peter Rotich
06e4b0ae42 Merge pull request #5425 from aydreeihn/issue/dup-entry-merge
Issue: Duplicate Thread Entry Merge Records
2020-03-24 17:43:45 -05:00
Peter Rotich
9b8d404263 Merge pull request #5427 from JediKev/session/destroy-warning-php73
session: Destroy Warning PHP 7.3
2020-03-24 17:40:31 -05:00
JediKev
e6f04831e7 session: Destroy Warning PHP 7.3
This addresses an issue where logging out of the system using PHP 7.3 throws
the infamous `session_destroy(): Session callback expects true/false return
value` warning. This was addressed in previous updates with
`(SessionData::objects()->filter(['session_id' => $id])->delete())` but
apparently PHP 7.3 does not like that anymore so this updates it to a
ternary operator to ensure True/False return values.
2020-03-23 10:13:45 -05:00
aydreeihn
ef6b7dac01 Issue: Duplicate Thread Entry Merge Records
This commit fixes an issue we had with creating duplicate records in the thread_entry_merge table. This would happen if you were to merge tickets, deleting the child tickets, and then try to merge that ticket into another ticket.

This fixes Issue #5379.
2020-03-19 12:49:34 -05:00
JediKev
7c9ed61cb0 oops: is_numeric Soft Fail
This addresses an issue introduced with 9e21df where `is_numeric()`
validation fails even when inserting a legitimate number. In the
aforementioned commit, we added the ability to return error messages from
the source validator method. In doing so, we changed `call_user_func()` to
`call_user_func_array()` which now passes two arguments to the validation
method. This broke `is_numeric()` validation as this method does not accept
more than one argument. This adds a new method to class Validator called
`is_numeric()` that accepts two arguments so it does not fail. In addition,
this updates the remaining validators that do not currently accept two
arguments.
2020-03-19 10:09:00 -05:00
Peter Rotich
4ec42c4219 Merge remote branch 'upstream/develop-next' into develop-next 2020-03-18 00:07:18 +00:00
Peter Rotich
11199eab37 Merge remote branch 'upstream/develop' into develop-next 2020-03-18 00:07:12 +00:00
Peter Rotich
307a015498 Merge pull request #5404 from JediKev/install/task-title-description-field-flags
install: Task Title/Description Field Flags
2020-03-17 19:00:52 -05:00
Peter Rotich
1010d77dea Merge pull request #5412 from JediKev/format/strip-pua-plane-16
format: Strip PUA (Plane 16)
2020-03-17 18:30:43 -05:00
Peter Rotich
400cb8e9b8 Merge pull request #5414 from aydreeihn/issue/user-import
Oops: User Import Fix
2020-03-17 18:30:25 -05:00
JediKev
abb97998f3 issue: Information Field Help Text Decode
This addresses an issue where formatting Help Text for Information fields
displays the content as plain-text instead of rendering the HTML. This is
due to `htmlchars()` which uses `htmlspecialchars()` to encode the content.
This updates `Format::htmlchars()` to `Format::display()` so we can render
the content as HTML rather than plaintext.
2020-03-17 16:07:51 -05:00
JediKev
0cd4168e5d export: User/Org Tickets
This addresses an issue introduced with 5207 where reverting the changes of
a commit left some old code behind. This causes the User Ticket exports and
Org Ticket exports to crash when clicking Export. This changes both
`filter()` methods to setting `$this->_queue->config` directly as `filter()`
no longer exists for AdhocSearches.
2020-03-17 09:46:25 -05:00
aydreeihn
40b40f8535 Oops: User Import Fix
This commit fixes an issue we had with a recent change to User Imports. We want to make sure the agent does not have to specify the 'name, email' headers if they are typing user imports, but if they are using a CSV for imports, we need to leave the headers as they are.
2020-03-16 12:38:43 -05:00
JediKev
caeda93df8 format: Strip PUA (Plane 16)
This addresses an issue where if someone has the `U+1000B6` Unicode
character somewhere inside the body of their email, the remainder of the
email is cut off. The system doesn't know what to do with this character as
[it's not considered a standardized character in Unicode
itself](https://en.wikipedia.org/wiki/Private_Use_Areas) so parsing fails at
the character truncating the rest of the content. This adds a new case to
`strip_emoticons()` that strips this character if present so the rest of the
content is safe. We do not need `U+1000B6` anyways as it's part of a PUA
(Private Use Area), specifically in Plane 16, that's typically controlled by
third parties.
2020-03-16 09:17:04 -05:00
JediKev
6b8cc9b778 i18n: Help Text Formatting
This addresses an issue where Help Text for TextareaFields would not let you
save text with formatting due to `Format::striptags()`. This changes
`Format::striptags()` to `Format::sanitize()` to allow formatting whilst
still preventing XSS Injections.
2020-03-11 14:43:51 -05:00
JediKev
cc2d0ab948 i18n: Help Text Translate Button
This addresses an issue where you cannot translate Help Text for
TextareaFields. This is due to no translate button to switch between
languages. This removes the `no-bar` option from the Help Text textarea
which shows Redactor's toolbar including the Translate button.
2020-03-11 14:33:23 -05:00
Peter Rotich
d8eefa1e2b Merge pull request #5398 from JediKev/issue/passwordfield-validation
issue: PasswordField Validation
2020-03-10 17:45:57 -05:00
Peter Rotich
0db9ca715d Merge pull request #5399 from JediKev/issue/multiple-choice-export
issue: Multiple Choice Export
2020-03-10 17:45:13 -05:00
JediKev
9e21dfd905 validate: Validation Error Messages From Source
This adds the ability to use error messages returned by the source
validation method for more detailed errors via TextboxFields (and it's
children classes). If no error is returned by the source validation method
we will use the default error message set by `validateEntry()`.
2020-03-10 15:37:36 -05:00
JediKev
9cc5cb608f issue: PasswordField Validation
This addresses an issue reported in the Plugins repo where attempting to use
a password that starts with any of these characters (`= - + @`) fails with
`Content cannot start with the following characters: = - + @` validation
error. This is due to Formula Injection prevention for any field that has
potential to be exported. I did not take PasswordFields into account as
these are not exportable fields. This adds a new validator to TextboxField
called `password` that calls `Validation::check_passwd` which uses
`PasswordPolicy::checkPassword()` to check the password against all active
policies. This also adds a constructor to class `PasswordField` so we can
add the `password` validator for all password fields. In addition this adds
another validator to TextboxField called `` that returns true to skip
validation (useful for LDAP password, etc.).
2020-03-10 15:37:30 -05:00
JediKev
6727ebbb6e install: Task Title/Description Field Flags
This addresses an issue where the Task Title field allows any Admin to
remove the View and Required perms for Agents even though this field should
be Viewable and Required. This adds the `FLAG_MASK_REQUIRE` and
`FLAG_MASK_VIEW` flags to the form install file to ensure Admins cannot
change this behavior for both perms. This also addresses an issue where the
Task Description field allows any Admin to remove the View perms for Agents
even though this field should always be Viewable. This adds the
`FLAG_MASK_VIEW` flag to the form install file to ensure Admins cannot
change this behavior.
2020-03-10 15:01:39 -05:00
JediKev
3005d42823 issue: Multiple Choice Export
This addresses an issue where saving multiple choices for a ChoiceField does
not show all values in Queue Columns nor Ticket Exports. This is due to the
`to_php()` method exploding on `,` while the keys are saved like `key1,
key2` (with comma then space). This updates the `to_php()` method to explode
on `, ` (comma and space) so we get the proper keys for the value lookups.
2020-03-10 14:08:47 -05:00
Peter Rotich
621e780c61 Merge remote branch 'upstream/develop' into develop-next 2020-03-10 18:56:32 +00:00
Peter Rotich
5ab1782fd1 Merge pull request #5401 from JediKev/lint/uninitialized-matches
lint: Uninitialized Matches
2020-03-10 13:44:09 -05:00
JediKev
7873c5b25e lint: Uninitialized Matches
This resolves lint test complaints of an uninitialized variable `$matches`
in `include/class.mailparse.php`.
2020-03-10 11:39:12 -05:00
Peter Rotich
e62a20a00a Merge pull request #5402 from JediKev/issue/pdf-global-ost
issue: PDF Global $ost
2020-03-10 11:38:32 -05:00
JediKev
07878f5685 issue: PDF Global $ost
This addresses an issue where `$ost` is not available for the ticket and
task print templates which causes `(string) $ost->company;` to appear as an
empty string. This adds `$ost` to the globals for printing tickets and tasks
so that the company name is properly displayed.
2020-03-10 10:50:45 -05:00
Peter Rotich
1a5ec61a43 Merge remote branch 'upstream/develop-next' into develop-next 2020-03-06 16:01:48 +00:00
Peter Rotich
33c06bef0f Merge remote branch 'upstream/develop' into develop-next
Conflicts:
	include/class.ticket.php
	include/class.topic.php
2020-03-06 16:01:33 +00:00
Peter Rotich
aa60fd8d20 Merge pull request #5395 from JediKev/issue/quotes-in-user-name
issue: Quotes In User Name
2020-03-06 09:35:12 -06:00
Peter Rotich
d8c40d5e34 Merge pull request #5396 from Zythub/patch-2
Spelling correction function name
2020-03-06 09:24:46 -06:00
Peter Rotich
b1008e7731 Merge pull request #5386 from JediKev/issue/duplicate-tickets-in-lookup
issue: Duplicate Tickets in Lookup
2020-03-06 09:23:21 -06:00
Zythub
44cbc3051d Spelling correction function name
Just a small spelling correction:
getDymanicFieldById to getDynamicFieldById
2020-03-05 22:59:36 +01:00
JediKev
ea6fc4481b issue: Quotes In User Name
This addresses issue 5345 where double quotes in a User's Name will make
their email address appear as empty (`@`). This is due to the `getEmail()`
method where we combine the User's Name and Email Address into one string by
putting the User's name inside double quotes and the email after in angular
brackets (eg. `"First Last" <email@domain.tld>`). We do not escape double
quotes within the User's name so when we insert the name between double
quotes, the string is cut off at the first double quote (eg. `"First
"Nickname" Last" <email@domain.tld>` -> `"First "`). Since the string is
incomplete we are unable to find the email address so it appears as `@`.
This adds `addcslashes()` to the `getEmail()` method so we can escape any
double quotes within the User's name and the string does not get cut off.
2020-03-05 10:36:05 -06:00
Peter Rotich
b1a2320b83 Merge pull request #5374 from aydreeihn/issue/referrals-and-children
Issue: Managing Child Ticket Threads
2020-03-03 15:44:03 -06:00
Peter Rotich
5d68c3d180 Merge pull request #5381 from JediKev/issue/new-task-alert
issue: New Task Alert
2020-03-03 15:43:42 -06:00
JediKev
3283050e87 vars: Task Subject/Description
This addresses an issue where the `subject` and `description` vars are
missing from `Task::getVar()` so these variables are never replaced in the
Task templates. This adds two cases for `Task::getVar()`; case `description`
that retrieves the Task Description (if any) and case `subject` that
retrieves the Task Subject. This also addresses an issue where the
`description` var is missing from `Task::getVarScope()` so when an Agent
uses the Variable Typeahead the `%{task.description}` option does not show.
2020-03-03 09:12:10 -06:00
JediKev
5dd123e8f7 issue: New Task Alert
This addresses an issue where the New Task Alert was not functioning as it
should. This adds a new method called `onNewTask()` that runs after a Task
is created and sends out the New Task Alert (if enabled). This will take
into account the Global settings as well as the Department settings for
Alerts and Notices.
2020-03-03 09:10:57 -06:00
Peter Rotich
41c4d245ed Merge pull request #5384 from JediKev/issue/add-remote-collab
issue: Add Remote Collaborator
2020-03-02 13:25:34 -06:00
Peter Rotich
b689e1a7de Merge pull request #5373 from aydreeihn/issue/merge-close-child
Oops: Set Child Ticket Status
2020-03-02 12:57:35 -06:00
Peter Rotich
50fe39eda5 Merge pull request #5380 from JediKev/issue/booleanfield-cannot-be-unchecked
issue: BooleanField Cannot Be Unchecked
2020-03-02 11:21:08 -06:00
JediKev
23a463cff1 issue: BooleanField Inline Edit Value
This addresses an issue where after setting a checkbox value via Inline Edit
it shows the value as `0` or `1` instead of `Yes` or `No`. You have to
refresh the page in order for the value to appear correctly. This is due to
the raw value being returned instead of it's string equivalent. This adds a
case in `TicketsAjaxAPI::editField()` for `BooleanField` that converts the
raw value to the string value with `toString()`.
2020-03-02 10:57:46 -06:00
JediKev
1556242a9f issue: BooleanField Cannot Be Unchecked
This addresses an issue where checkboxes cannot be unchecked once saved as
checked. This was introduced with a fix for another issue where it's
necessary to return the default value for VisibilityConstraints. This is
fine for Holiday Schedule checkboxes but for custom fields this breaks basic
functionality. This updates `getValue()` for CheckboxWidget to only return
the default value if `$data` (source) is not set.
2020-03-02 10:55:40 -06:00
JediKev
d8cb1e86c5 issue: Trailing Whitespaces Number Lookups
This addresses issue 5296 where having whitespaces at the beginning or end
of a ticket number lookup (eg. `    643906` or `643906    `) will not show
expected results. This is due to the search query looking for `ticket.number
LIKE '    643906%'` explicitly which will not find results. This updates the
Number Lookup method to trim all white spaces from number criteria so the
`LIKE` comparison operator works as expected and finds the appropriate
results.
2020-03-02 10:29:36 -06:00
Peter Rotich
1f013824d9 Merge pull request #5387 from JediKev/lint/minified-js-warnings
lint: Minified JS Warnings
2020-03-02 10:20:11 -06:00
Peter Rotich
3ab042e7cc Merge pull request #5388 from JediKev/lint/update-est-duedate
lint: updateEstDueDate
2020-03-02 10:19:47 -06:00
JediKev
a8fe0bdff1 lint: updateEstDueDate
This addresses an issue where lint tests complain about an undefined method
`updateEstDuedate()`. This is correct as the method is actually called
`updateEstDueDate()`. This updates the method name from `updateEstDuedate()`
to `updateEstDueDate()`.
2020-02-28 11:26:56 -06:00
JediKev
0443715040 lint: Minified JS Warnings
This addresses an issue where when running lint tests it throws 150+
warnings about minified JS files. This adds the 3rd party minified files to
`$third_party_paths` so that they are ignored (`js/select2.min.js`,
`js/redactor.min.js`, `js/jquery-ui-1.12.1.custom.min.js`,
`js/fabric.min.js`).
2020-02-28 11:16:20 -06:00
JediKev
95f9b83332 issue: Duplicate Tickets in Lookup
This addresses issue 5313 where duplicate tickets appear in the ticket
lookup results; especially when looking for a ticket to merge. This is due
to a discrepancy between both queries looking for hits on the search
criteria. The first query that looks for hits pushed the `number` column
towards the end of the results and the second query has it as the second
column in the results. When we do a `UNION ALL` these values are mapped
incorrectly and it appears as there are 2 results instead of one. This adds
a new method called `lookupByNumber()` that only finds results for number
searches. This also changes the lookup URL for Ticket Merge from `/lookup`
to `/number-lookup` so that we only search for numbers. This also reformats
`lookup()` so that if the search query is a number we will pass to
`lookupByNumber()` and merge the results with `UNION ALL`.
2020-02-28 11:10:35 -06:00
JediKev
c60e2f3750 issue: Add Remote Collaborator
This addresses an issue where adding a Collaborator that is from a remote
backend such as LDAP fails. This is due to the AJAX URL not being
recognized. The regex is expecting
`^(?P<tid>\d+)/add-collaborator/auth:(?P<bk>\w+):(?P<id>.+)$` but the URL
being called is `XXX/add-collabborator/addcc/auth:XXX` (with the added
`/addcc` part). This updates the regex to account for the `/addcc` part, and
adds `$type` as an argument for `addRemoteCollaborator()`.
2020-02-21 12:53:30 -06:00
JediKev
e24c78ce10 oops: Forgot API Emojis
This addresses an issue where we forgot about Emojis in the Issue Details of
Tickets created via API. This adds `Format::strip_emoticons` to class api so
that Emojis are stripped from the Issue Details for Tickets created via API.
2020-02-20 15:03:06 -06:00
JediKev
e3547eaca2 emoji: Strip From Subject
This addresses an issue reported on the Forum where emojis are not stripped
from the subject line which causes either a blank subject or half-rendered
subject. This adds `Format::strip_emoticons` to TextboxField::parse in class
forms so all Textbox Fields (including Issue Summary) is stripped of Emojis
(since we can't handle them at all). This is also added to
ThreadEntry::create in class thread so that the ThreadEntry Titles have
Emojis stripped as well.
2020-02-20 15:01:47 -06:00
aydreeihn
7f8594636b Issue: Managing Child Ticket Threads
This commit makes sure that we do ticket->getThread() rather than ticket->thread so that if we are dealing with a child ticket that doesn't have a thread, we won't get any errors.

This fixes Issue #5372
2020-02-13 15:22:51 -06:00
aydreeihn
c216a72571 Oops: Set Child Ticket Status
This commit fixes an issue where the child status name was changed from statusId to childStatusId in the template but not in the ticket class.
2020-02-11 16:13:00 -06:00
JediKev
1de9b4c96d feature: Force HTTPS
This feature introduces a checkbox in the System Settings to force HTTPS.
This is for people who either can't or don't know how to configure redirect
rules via the webserver. If the setting is enabled, the system will redirect
all osTicket web traffic to the HTTPS protocol automatically. In addition
this adds an `HTTP_OK` option that disables the HTTPS redirect for local
calls such as cron, pipe, and cli. This also updates the remote piping
scripts (`automail.pl` and `automail.php`) to include support for HTTPS.
2020-02-07 11:02:41 -06:00
JediKev
ae15de4b5c Merge pull request #5228 from JediKev/support/ie-discontinued
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 16:43:56 -06:00
JediKev
2540350ada issue: Attachment Upload Configuration
This addresses an issue where we pull the `first()` Form Field configuration
for attachments instead of determining if we are looking for the Ticket
Attachment Configurations or the Task Attachment Configurations. For
example, if you are creating a Ticket as a User and go to add an attachment
if somehow your Task Details Form comes up first in the configuration lookup
query we will apply the Task Attachment Configs instead of the Ticket
Attachment Configs which is totally incorrect. This updates the lookup for
attachment configurations on web uploads to be specific about what it’s
looking for so it can get the correct configuration. This also adds the
original Form's `type` to SimpleForms so we can access the Form Type when
working with SimpleForms.
2020-02-04 16:01:44 -06:00
JediKev
699728f83e support: IE Discontinued
Well folks, the time has finally come to lay IE in it's final resting place.
Twas a long, hard battle with IE but in the end it was defeated and it's
kingdom taken over by it's successor, Edge. Now there is a new king and IE
must be banished from the lands he once ruled, forever. It's sad to see such
a prolific leader fall to the ashes (not lol). Alright, let’s get serious
for a moment. Microsoft is discontinuing IE at the end of January 2020 so
it’s time to start showing a banner that says "osTicket no longer supports
IE." This message is shown on the Installer, the Upgrader, in the Client
Portal, and in the Staff Panel when using IE. This checks the User-Agent
header for IE’s specific header and if detected will show the banner. This
will not show on Edge, Chrome, Firefox, etc. only when using IE. We came to
this conclusion after seeing sites like Github (a microsoft product) showing
"no longer supported" banners for IE (a microsoft product).
2020-02-04 15:50:23 -06:00
JediKev
09267f4e61 Merge pull request #5203 from aydreeihn/feature/merge-tickets
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 15:19:57 -06:00
aydreeihn
bebc724d64 Ticket Merge Parent Status
This commit gives agents the option to change the status of the Parent ticket when doing a merge. To do this, they must choose the desired status for 'Parent Status'. If no status is chosen, the Parent Ticket will remain in its current status.
2020-02-04 15:17:32 -06:00
JediKev
62223e5c34 Merge pull request #5217 from JediKev/install/forum-and-docs-links
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 14:38:46 -06:00
JediKev
1da31af928 Merge pull request #5238 from JediKev/issue/shared-mailbox-auth
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 14:28:29 -06:00
JediKev
72526c5ccb Merge pull request #5240 from aydreeihn/issue/topic-number-flag
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 14:27:26 -06:00
JediKev
b3780e89f5 Merge pull request #5251 from aydreeihn/issue/inline-long-answer
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 14:25:37 -06:00
JediKev
7eee73e6a8 Merge pull request #5291 from aydreeihn/issue/db-errors
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 14:16:00 -06:00
JediKev
704e8943c2 Merge pull request #5321 from aydreeihn/issue/child-no-ht
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 14:13:35 -06:00
JediKev
9781489ce7 Merge pull request #5330 from JediKev/redactor/double-spacing-optional
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 14:11:36 -06:00
JediKev
b82cdc25bf Merge pull request #5351 from JediKev/issue/require-client-login
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 14:07:09 -06:00
JediKev
9a364bc623 Merge pull request #5354 from JediKev/issue/user-manage-org-name
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 14:05:52 -06:00
JediKev
433ff1da28 Merge pull request #5361 from JediKev/queue/inherit-columns-option-redo
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-02-04 14:04:59 -06:00
aydreeihn
18c93119c6 Issue: DB Error #1054
Error: Unknown column 'Z1.ticket_id' in 'field list'

This commit fixes an issue with how we approach skipping counts. If a search has a keyword or if a saved queue/search has an invalid criteria saved, we will completely ignore trying to do a count. In saved queue/searches, rather than showing a number or 500, we will display '-' in its place. For the count at the bottom (Showing # - # of about #), we will just display Showing # - #.
2020-02-04 10:49:47 -06:00
aydreeihn
2fb81aa936 Issue: Close Child Ticket Without Help Topic
When merging Tickets, we automatically set children Tickets to a closed status, however, we had an issue with child Tickets that did not have a Help Topic. If the helpdesk had the 'Require Help Topic to Close' configuration, the children Tickets would not close as expected.

This fixes Issue #5317
2020-02-03 12:17:20 -06:00
JediKev
dddfede215 install: Forum and Docs Links
This addresses issue 5215 where the Post-Install page references the Forum
and Docs site but the link doesn't work. This is due to the pound symbols
being the `href`. This adds the links to the `href` attribute so the links
actually link to the sites.
2020-02-03 10:32:49 -06:00
JediKev
7bb9fd884d issue: Shared Mailbox Auth
This addresses an issue where using "Servername\user@domain.tld" for mailbox
Login Username fails due to the Shared Mailbox Auth introduced here
(ac9ea5b). We do not check the name to see if the first part of the string
contains an @ symbol, indicating an email address. This updates the Shared
Mailbox Auth check to look for 3 parts, if detected it will use the first
two parts as the `authuser` and the second part as the `username`. This also
checks for 2 parts, if detected it will check the first part for @ symbol
and if one is present will use the first part as the `authuser` and the
second part as the `username`. Otherwise it will use both parts as the
`username`. If there are more than three parts or just one part, the entire
string is used as the `username`.
2020-02-03 10:01:11 -06:00
JediKev
2e146ad702 queue: Inherit Columns Option
This is a rewrite of a commit that was accidentally merged. This, in part,
removes all unnecessary code from the accidental commit. This adds a new
`inheritColumns()` method to SavedQueue to use with all queues. Lastly, this
removes `$this->parent_id` from the `$hidden_cols` check so all queues
behave correctly. Most queues will not have a `parent_id` and will fail this
check.
2020-02-03 09:49:35 -06:00
aydreeihn
608044d8a9 Issue: Inline Edit Long Answer
This commit fixes an issue we had with saving an empty long answer field using inline edit. Before, the field would save as an empty line break which would then technically be set and saved, displaying nothing in the field, which prevented agents from doing another inline edit on the long answer field. This is most likely do to the redactor update that makes all the lines double spaced now.
2020-01-31 10:19:00 -06:00
aydreeihn
52c9c59f79 Issue: Help Topic Number Format
This commit fixes an issue where we did not clear the FLAG_CUSTOM_NUMBERS flag when setting the ticket number format back to System Default for Help Topics.

We will also stop clearing saved number_formats so that agents have the option to reenable them without having the reconfigure the format.
2020-01-31 09:53:42 -06:00
JediKev
7a6b85ccf3 issue: User Manage Org Name
This addresses an issue reported on the Forum where clicking Manage Account
for a User the Organization field is blank even though the User has an
Organization. This is due to the system only using `$info` which is set by
`$_POST`. Since we are not posting anything, just loading the popup
template, there is no `$_POST` so `$info` will not be set. In addition, you
cannot update the Organization using the Manage Account modal so there is no
reason to use `$info` nor is there a reason to have the Organization field
as an Input field. This updates the modal template to make the Organization
field simple table data and to use `$user->getOrganization()->getName()` for
the Organization Name.
2020-01-31 08:57:58 -06:00
JediKev
5136198727 issue: Require Client Login
This addresses an issue reported on the Forum where having your Client
Registration set to Private and attempting to enable the setting Require
Client Login for Knowledgebase results in an error saying `The knowledge
base cannot be restricted unless client registration is enabled`. When
saving the Knowledgebase Settings and we are updating the Restrict
Knowledgebase setting we check if Client Registration is Enabled using
the `isClientRegistrationEnabled()` method. This method only checks if the
Registration method is `auto` or `open` (Public) and does not check if it
is `closed` (Private). This is an issue in the aforementioned case as Users
can still be registered by Agents so technically registration is
not completely disabled. This removes the check altogether as Admins should
be able to configure this setting without Registration being required. This
also adds a new function called `isClientRegistrationMode()` that can be
used to compare the current Registration Mode to either a string or an array
or modes.
2020-01-31 08:55:29 -06:00
JediKev
fa418e6351 redactor: Double Spacing Optional
This addresses an issue where upgraded redactor does double spacing by
default (which matches most modern editors). A lot of people do not like
this change however so the solution is to make double spacing optional via a
setting. This adds a new Profile setting called Editor Spacing that allows
you to configure Double or Single spacing or the editor. If set to Double,
the text editor will double space when pressing Enter. If set to Single, the
text editor will single space when pressing Enter like the old redactor
version. If a staff does not have this setting configured, it defaults to
Double Spacing.
2020-01-30 16:17:57 -06:00
JediKev
e4c673b6f2 Merge pull request #5246 from JediKev/issue/redactor-z-index
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 16:01:20 -06:00
JediKev
1383685f92 Merge pull request #5247 from JediKev/notes/confirm-deletion
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 16:00:31 -06:00
JediKev
1bb2505de3 Merge pull request #5252 from aydreeihn/issue/missing-fields
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:50:23 -06:00
JediKev
512c1b28f6 Merge pull request #5253 from aydreeihn/issue/ticket-open-refresh
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:49:24 -06:00
JediKev
9eb36a4f2c Merge pull request #5257 from aydreeihn/issue/search-group-by
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:47:25 -06:00
JediKev
635ff803a7 Merge pull request #5273 from JediKev/tooltip/email-username
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:38:19 -06:00
JediKev
ba98cac0b3 Merge pull request #5284 from aydreeihn/issue/file-thread-events
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:31:18 -06:00
JediKev
ff44f8469e Merge pull request #5293 from JediKev/mail/mail-parse-get-attachments
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:28:04 -06:00
JediKev
482c746ccd Merge pull request #5294 from aydreeihn/issue/transfer-remove-referrals
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:23:16 -06:00
JediKev
57e8cbebc5 Merge pull request #5295 from aydreeihn/issue/blank-date-time
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:20:44 -06:00
JediKev
c4804248c3 Merge pull request #5307 from JediKev/queue/inherit-columns-option
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:17:29 -06:00
JediKev
95ae2a872d Merge pull request #5308 from JediKev/issue/new-agent-welcome-email
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:08:26 -06:00
JediKev
684e4e9c8f Merge pull request #5311 from JediKev/validate/number-field-edit-zero
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:05:04 -06:00
JediKev
eb1d14f4cc Merge pull request #5312 from JediKev/redactor/cancel-button-114x
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:01:56 -06:00
JediKev
c0fbf6b01e Merge pull request #5319 from JediKev/issue/update-staff-checkPassword
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 15:00:47 -06:00
JediKev
d3d848fca6 Merge pull request #5322 from JediKev/inline/set-ht-refresh-statuses
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 14:52:28 -06:00
JediKev
df427535d8 Merge pull request #5324 from aydreeihn/issue/user-import
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 14:49:53 -06:00
JediKev
681fa0aea4 Merge pull request #5326 from JediKev/dept/disable-auto-claim
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 14:47:46 -06:00
JediKev
41ee9960c6 Merge pull request #5336 from aydreeihn/issue/ticket-merge
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 13:31:34 -06:00
JediKev
b8a984d59e Merge pull request #5353 from ThomasLachaux/patch-1
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 13:23:10 -06:00
JediKev
afcdcdd405 Merge pull request #5357 from JediKev/plugins/add-version-column
Reviewed-By: JediKev <kevin@enhancesoft.com>
2020-01-30 13:15:02 -06:00
JediKev
5b0f1ce1ae issue: Plugin Version Install
This addresses an issue where upon installing a plugin, no version number is
added in the database. This is due to not setting the version in the SQL
query when inserting the plugin table record.
2020-01-30 11:11:57 -06:00
JediKev
f86c93eea7 plugins: Add Version Column
This adds a new column to the Plugins template to show the Version Number
for each plugin. This adds a new method called `getVersion()` that will
return either the version number from the database or the version number
from the `load()` method.
2020-01-30 11:10:39 -06:00
Thomas de Lachaux
4e7d12ca5b Fix confusing sentence 2020-01-29 18:40:24 +01:00
aydreeihn
bb0f9bd67c Issue: Ticket Link/Merge
- Make sure we return an Http response after unlinking rather than true
- Make sure we are performing a merge/link on more than 1 Ticket.
2020-01-14 10:09:06 -06:00
JediKev
be4e01e87c inline: Set Help Topic Refresh Statuses
This addresses issue 5316 where having `Require Help Topic to Close` Enabled
and setting a Help Topic via Inline Edit will not let you Close the ticket
via response box unless you refresh the page. This is due to Inline Edit not
refreshing the statues in the dropdown to select from. This adds a check in
`include/ajax.tickets.php` that checks for if we Require HT On Close, if the
ticket is open, if the staff has permission to close, and if we set a help
topic. If all of this is true we gather all of the Closed statuses and
return them in the response as `statuses`. In addition, this adds a check in
the AJAX success to see if `statuses` were returned. If so, we loop through
each, see if they already exist in the list and if not we append them as new
options. After we add all of the statues we then hide the warning banner. At
this point the agent can close the ticket via response box if they choose to
do so.
2020-01-09 10:16:27 -06:00
JediKev
36848795af dept: Disable Auto Claim
This addresses an issue where unchecking `Disable auto claim` and saving
changes will show the option as Enabled still. This is due to some changes
from Audit Log where we set `disable_auto_claim` to either `1` or `0` to
interact with the Audit Log methods. The flag is typically set to `on` or
`Null`. When we check the `disable_auto_claim` flag with `isset()`, and it
is set to `0` it will return True when it is actually Disabled. This updates
the code to unset the option after the Audit code if it does not equal `1`
so the subsequent methods can remove the flag from the department.
2020-01-08 15:19:43 -06:00
aydreeihn
787417f37d Issue: User Imports Headers
This commit makes it so that when importing users, the agent does not have to specify the 'name, email' headers. They can simply put the users' names and emails into the text area field.
2020-01-08 12:45:27 -06:00
JediKev
0659338513 issue: Update Staff checkPassword()
This addresses an issue where clicking Update in the Set Password modal with
the `Send the agent a password reset email` option checked either shows a
forever spinning Loading screen or instantly kicks back to the modal having
accomplished nothing. This is due to checking `$clean['passwd1']` even when
`welcome_email` (password reset) is set. If `welcome_email` is set/enabled
we should not check the variable as there is no new password being set as we
are sending a Reset Email. This adds a check for `welcome_email` and if
none, then we check the password.
2020-01-07 10:13:00 -06:00
JediKev
3bab103084 redactor: Cancel Button
This addresses an issue reported on the Forum where the New Ticket Cancel
buttons do not work in v1.14.1. This is due to the code using older methods
utilized in v1.12. This updates the code to use the new method of accessing
the plugin objects first before accessing the plugin itself.
2020-01-02 16:34:43 -06:00
JediKev
e6e4e90348 validate: Number Field Edit Zero
This addresses an issue reported on the Forum where having a Short Answer
field with it's Validator set to Number will throw validation error of
`Enter a number` when updating the field with a value of `0`. This is due to
the system converting `0` values to `&#48` in
`TextboxField::validateEntry()` for methods ran before the default textbox
field validation (which is `is_numeric`). This adds a check before the
default textbox field validation to see if the validator is `number` and the
value is `&#48`. If both are True we convert the value back to `0` (int) so
the `is_numeric` validation passes.
2020-01-02 15:33:54 -06:00
JediKev
1949d4f89a issue: New Agent Welcome Email
This addresses the underlying problem with issue 2870 where the Welcome
Email checkbox is no longer present but even then no Welcome Email is ever
sent to the Agent regardless of how they are created. This is due to an
option called `welcome_email` that is not being passed to the `update()`
method for Staff. When an Agent account is created with no Password set and
the Authentication backend is not external we should send the Welcome Email
so the Staff in question can create a Password and access the system. If no
password is set and the authentication backend is external however then we
should not send the email as the Staff will use their AD credentials to
login. This adds an else statement to set `welcome_email = 1` if there is no
password set and if there is no backend set or is local.
2019-12-30 13:14:25 -06:00
JediKev
4434a93d51 queue: AdvancedSearch Use Standard Columns
This addresses an issue where saving a Saved Search with "Use standard
columns" Enabled, shows the Customizable Columns instead of the Standard
Columns and does not show the option Enabled as the INHERIT_COLUMNS flag is
not set.  This adds a check when saving a SavedSearch for the
`inherit-columns` setting and if set, we set the Queue's INHERIT_COLUMNS
Flag.
2019-12-30 09:42:03 -06:00
JediKev
1a32e2a9ab queue: Parent/Child "Inherit Columns" Option
This addresses an issue where saving a Parent Queue with "Use standard
columns" Enabled will show the option Enabled but still show the
customizable Columns instead of the Standard Columns. This addresses an
issue where saving a Child Queue with "Inherit columns from the parent
queue" Enabled shows the Standard Columns but does not show the option
Enabled. This adds a check in `inheritColumns()` for Staff Configurations
for the queue and if exists we use the Staff preferences, else we default to
the Queue Flag check. This adds a new method called `staffSettings()` that
returns staff settings for a queue. It takes an optional argument (a
setting's name) that can return a specific setting's value.
2019-12-30 09:41:36 -06:00
JediKev
38df2c87f5 queue: Inherit Columns Option
This addresses part of issue 5259 where Advanced Searches are showing the
Customizable Columns even though you cannot customize an Advanced Search's
columns. This adds some JS to hide the `.if-not-inherited` div on initial
load if `.inherit-columns` checkbox is Disabled.
2019-12-30 09:40:12 -06:00
aydreeihn
2acf9aa256 Issue: Remove Referrals
This commit fixes an issue where we did not check to see if we needed to remove referrals. For example, if a Ticket is referred to a Department and then the Ticket is transferred to that Department, we should remove the referral.

We will now check/remove referrals as needed for Departments, Agents, and Teams.
2019-12-20 10:13:10 -06:00
JediKev
d310740335 mail: Mail_Parse::getAttachments ()
This addresses an issue where some email attachments are not being added to
the thread. This is due to Pear's `Mail_mimeDecode::_parseHeaderValue`
function not parsing the headers correctly. This updates
`Mail_Parse::getAttachments` to check the `content-disposition` for a
filename if all else fails. This will ensure a filename is returned if the
headers are not parsed correctly.
2019-12-20 09:36:10 -06:00
Peter Rotich
af1c4a6118 Support message/rfc822 as attachments
Support importing attachments of type message/rfc822 even when filename is
missing.
2019-12-20 09:35:51 -06:00
aydreeihn
60ccbb7a53 Issue: Blank Date Time
This commit fixes an issue where an unset Date Time field would display as 0. As a result, if you were on the all edit page and edited some other field, it would appear as though you edited the date time field as well because it had a value in it. Instead, we need to make sure that the field renders as truly being blank if it isn't set yet to ensure nothing is being saved to it.
2019-12-19 16:23:50 -06:00
Peter Rotich
a71de79670 Merge remote branch 'upstream/develop' into develop-next 2019-12-19 18:01:34 +00:00
Peter Rotich
1639a6c7e3 Merge pull request #5290 from aydreeihn/issue/incorrectly-saved-queue
Oops: Variable Overwrite
2019-12-19 12:01:00 -06:00
aydreeihn
c048768255 Oops: Variable Overwrite
This commit fixes and issue where the $key variable was overwritten when creating a foreach loop. Since we didn't actually need the key, it can be removed from the loop.
2019-12-19 08:49:44 -06:00
Peter Rotich
161919eca8 Merge remote branch 'upstream/develop-next' into develop-next 2019-12-19 02:17:33 +00:00
Peter Rotich
f8756b9b84 Merge remote branch 'upstream/develop' into develop-next
Conflicts:
	include/class.search.php
	include/staff/ticket-view.inc.php
2019-12-19 02:17:21 +00:00
Peter Rotich
5d1d1199f2 Merge pull request #5279 from protich/issue/schedule-entry-start-date++
Schedule Entry - Initial Occurrence Scope
2019-12-18 20:07:00 -06:00
Peter Rotich
018447313a Schedule Entry - getOccurrences algo.
Use end date, based on grace period, when getting occurrences as opposed to
count. This helps avoid accidental fast-forwarding of date counter since
only entries in scope are considered.

The commit also addresses infinite loop when counting time.
2019-12-19 02:05:42 +00:00
Peter Rotich
4781bf0dfb Merge pull request #5285 from aydreeihn/issue/incorrectly-saved-queue
Issue: DB Error #1064 Queue Counts
2019-12-18 20:03:47 -06:00
Peter Rotich
a05960bbf5 Merge pull request #5288 from aydreeihn/issue/overwrite-thisstaff
Issue: Overwriting thisstaff on Assign
2019-12-18 20:03:18 -06:00
Peter Rotich
e5ac985882 Merge pull request #5289 from JediKev/session/destroy-warning
session: Destroy Warning
2019-12-18 20:03:03 -06:00
JediKev
8c69891072 session: Destroy Warning
This addresses the `session_destroy()` warning many people are receiving
with PHP 7+. The warning states `PHP Warning:  session_destroy(): Session
callback expects true/false return value`. This is because our session
destroy method does not always return true/false, sometimes it returns
`int(1)`. This adds a check to see if the session was not deleted
successfully, if not it returns false, otherwise it returns true. This will
ensure `session_destroy()` always receives a true/false return value.
2019-12-18 14:22:09 -06:00
aydreeihn
f26ce60467 Issue: DB Error #1064 Queue Counts
This commit fixes an error where queue counts cannot be returned if the config saved for a queue is invalid. We try to build a query that does a count based on the criteria saved in the config, so when we try to build the query for an incorrectly saved config, the query we try to write looks something like this:

COUNT(DISTINCT CASE WHEN  THEN A1.`ticket_id` END) AS `q15`

Rather than trying to do a count for these, we should just skip over them so that no error is thrown since there is no way we would be able to count it anyway.

It is also possible for there to be more than 1 criteria defined, and if one of them is wrong, the same error will be thrown. We can check to see if there are multiple criteria, and if one is empty, we can skip that count as well.
2019-12-18 10:57:51 -06:00
aydreeihn
77065f5bc1 Issue: Overwriting thisstaff on Assign
This commit fixes an issue where we were overwriting the thisstaff variable as a result of trying to log audits for the audit log plugin.
2019-12-18 10:00:26 -06:00
Peter Rotich
3da5bd7a59 Schedule Entry - Initial Occurrence Scope
Commit 3a41b0 partially addressed initial occurrence issue from Starts On
perspective but failed to consider if the occurrence is already in the past
or out of scope.

This commit addresses the issue for realz.
2019-12-18 02:00:58 +00:00
aydreeihn
4d43adfc56 Issue: Thread Events for File Field Changes
This commit fixes an issue where we were displaying array keys instead of array values for the thread events of edited file upload fields. Displaying the array values will show the file's name rather than the file's index in an array.
2019-12-17 11:31:47 -06:00
JediKev
edd1fc3a36 tooltip: Email Username
This adds a tooltip for the Email Login Information Username. This explains
the different formats we accept and includes a link to the documentation
site for a deeper explanation.
2019-12-12 13:17:50 -06:00
aydreeihn
9b9a56f348 Issue: Ticket Search Typeahead
When an agent uses the search bar located in the ticket queue, we include a dropdown that shows if the search has found any tickets based on what the agent has typed so far. We also include the number of tickets found in parentheses.

This commit fixes an issue where the number in parentheses for the tickets found always showed as (1). To fix this, we needed to group tickets found based on the ticket user's email address.
2019-12-09 09:42:21 -06:00
aydreeihn
f2e2403ca8 Issue: Ticket Open URL
This commit fixes an issue where when an Agent opens a Ticket, the URL still had a=open in it. This made it to where if you refreshed the page immediately after creating the ticket, a new identical ticket would be created. It also made it to where if you tried to open a task from within the ticket immediately after opening it, you would be navigated to the open ticket screen.

To fix this, we can just set the redirect to go to the ticket's id once the ticket has been created.
2019-12-05 15:39:08 -06:00
aydreeihn
959141198f Issue: New Custom Fields
This commit fixes an issue where new custom fields added to a form did not show up in the inline edit fields.
2019-12-05 14:39:39 -06:00
JediKev
0d86e7f514 notes: Confirm Deletion
This addresses 1/2 of issue 3573 where deleting Notes does not ask for
confirmation which can be a huge problem if you accidentally click the trash
can. This adds basic javascript confirmation to ensure you truly want to
delete the note.
2019-12-04 12:17:35 -06:00
JediKev
19cc9a07d2 issue: Redactor z-index
This addresses an issue where the Action drop downs, if long enough, will
appear behind the Redactor toolbar. This adds a `z-index` property of `1` to
Redactor toolbar so it appears in the background.
2019-12-04 10:52:25 -06:00
Peter Rotich
920d3f2447 Merge pull request #5222 from aydreeihn/issue/merge-role-default
Ticket Merge/Link Defaults
2019-11-26 16:23:32 -06:00
Peter Rotich
ff1d08a0b5 Merge pull request #5227 from aydreeihn/issue/queue-query
Queue Query Optimization
2019-11-26 16:23:05 -06:00
Peter Rotich
71b3a33db8 Merge pull request #5229 from JediKev/issue/mpdf-print-tables
issue: mPDF Print Tables
2019-11-26 16:22:48 -06:00
aydreeihn
8c07c1750c Queue Query Optimization
This commit improves the query we use to get tickets in queues.
It also makes the relationships for user and dept nullable in Tickets which should help with performance as well.
2019-11-26 15:32:09 -06:00
JediKev
2bd464fb3c issue: mPDF Print Tables
This addresses an issue where printing a Ticket with a Table in one of the
threads will cause the PDF to be malformed. This is due to mPDF config
variable that was changed (most likely by `git checkout` or git conflicts).
This sets the `ignore_table_widths` variable back to true so that tables
will fit the PDF width.
2019-11-26 15:00:20 -06:00
Peter Rotich
a61f2eff3f Merge pull request #5224 from protich/issue/overdue-oopsie+
Clear Overdue Flag 4realz
2019-11-25 15:45:43 -06:00
Peter Rotich
057c8173ae Clear Overdue Flag 4realz 2019-11-25 21:37:52 +00:00
aydreeihn
3f93cd9ddb Ticket Merge/Link Defaults
This commit makes it so that the Ticket Merge and Link roles are enabled by default on fresh installs.
2019-11-25 13:19:08 -06:00
Peter Rotich
7edb183033 Merge pull request #5209 from aydreeihn/issue/audits
User Audit Issue
2019-11-25 10:48:49 -06:00
Peter Rotich
08147d734a Merge pull request #5214 from protich/issue/schedule-entry-start-date
Schedule Entry - Initial Occurrence Scope
2019-11-25 10:47:53 -06:00
Peter Rotich
7578d5cd9b Merge pull request #5204 from aydreeihn/issue/inline-field-integrity
Inline Edit Fields With Data Integrity
2019-11-25 10:47:20 -06:00
Peter Rotich
3a41b0925b Schedule Entry - Initial Occurrence Scope
This commit fixes an issue where Starts On date wasn't considered when
determining entry's initial occurrence. This was an issue for entries with
start date in the future.
2019-11-24 00:04:13 +00:00
aydreeihn
613b4abaf8 Issue: Audit Log Phar File
This commit fixes an issue we had with Windows users trying to use the Audit Plugin
2019-11-22 10:44:28 -06:00
aydreeihn
97a55a4d67 User Audit Issue
This commit fixes an issue where we accidentally audited user ticket edits twice.
2019-11-21 12:56:50 -06:00
JediKev
f1e9e88a1d Add Release Notes for v1.14.1 2019-11-21 09:57:54 -06:00
JediKev
8ddc221d3a Merge branch 'develop' into develop-next
Conflicts:
	WHATSNEW.md
2019-11-21 09:55:11 -06:00
JediKev
933bb1f2d5 Add Release Notes for v1.12.5 2019-11-21 09:42:24 -06:00
aydreeihn
6015d04927 Inline Edit Fields With Data Integrity
This commit adds the 'Required to close tickets' warning to inline edit fields if they are configured with the Data Integrity box checked (Require entry to close a thread)
2019-11-21 09:28:12 -06:00
Peter Rotich
8876338ab3 Merge remote branch 'upstream/develop-next' into develop-next 2019-11-21 15:01:09 +00:00
Peter Rotich
1976cc1d7b Merge remote branch 'upstream/develop' into develop-next 2019-11-21 15:01:04 +00:00
Peter Rotich
8e0c0c0649 Merge pull request #5200 from protich/issue/5198
Allow Repeatable Once Entries
2019-11-21 08:59:41 -06:00
Peter Rotich
9f84331ba0 Merge pull request #5207 from protich/issue/adhoc-queues-describe
queues: Revert commit cedd6121
2019-11-21 08:59:22 -06:00
Peter Rotich
2eb36991dc Merge pull request #5206 from protich/issue/duedates-revisited
Clear Overdue On Reopen
2019-11-21 08:59:08 -06:00
Peter Rotich
1708722679 Merge pull request #5205 from protich/issue/data_cbk
Hotfix: File data callback
2019-11-21 08:58:53 -06:00
Peter Rotich
7dd7bfa078 Revert commit cedd6121
This commit reverts commit cedd6121 because it broke adhoc search queue name
(describe).

The spirit of the initial change was correct but support of complex criteria
wasn't needed after all due to difficulty supporting multiple organizations
- something we will revisit in the future.
2019-11-21 06:58:54 +00:00
Peter Rotich
d3e643d9d2 Hotfix: File data callback
Commit 4dfb77ca failed to fully address the issue referenced.
2019-11-21 05:56:24 +00:00
Peter Rotich
6dc0b749b2 Clear Overdue On Reopen
Commit 8c76d70 changed how SLA due date is updated but failed to clear
existing & expired due dates when a ticket gets reopened.

We also previously removed the SLA on  expired SLA due dates but this commit
simply clears old date and recalculates new one based on reopen date.
2019-11-21 03:53:02 +00:00
Peter Rotich
cb9bb2f97a Allow Repeatable Once Entries
This commit fixes a bug where you could have only one "once" entry in a
schedule by allowing it on different days.
2019-11-20 00:08:36 +00:00
JediKev
9ea8e771c9 Add Release Notes for v1.14 2019-11-19 10:34:36 -06:00
JediKev
20ee37bd7a Merge branch 'develop' into develop-next
Conflicts:
	WHATSNEW.md
2019-11-19 10:32:11 -06:00
JediKev
bd38765245 Add Release Notes for v1.12.4 2019-11-19 10:24:01 -06:00
Peter Rotich
cc4fa3daa9 Merge remote branch 'upstream/develop-next' into develop-next 2019-11-19 16:18:44 +00:00
Peter Rotich
5a977e9fbd Merge remote branch 'upstream/develop' into develop-next 2019-11-19 16:18:40 +00:00
Peter Rotich
2cd7af46f2 Merge pull request #5196 from protich/issue/secvuln-redforce
Security Vulnerabilities
2019-11-19 10:17:45 -06:00
Peter Rotich
9c190b2b12 Merge pull request #5195 from aydreeihn/issue/audits
Issue: Configuration Audits
2019-11-19 10:17:30 -06:00
aydreeihn
8523c01e9a Issue: Configuration Audits
This commit fixes an issue where configuration updates were causing extra/unneeded audits to be captured within ORM saves.
2019-11-19 10:03:45 -06:00
Peter Rotich
4dfb77caf2 Arbitrary Method Invocation
This commit addresses possible Arbitrary Method Invocation via AJAX file upload.

To save some memory osTicket uses callback method to fetch the content of a
file on mail fetch. $file['data'] was overloaded as a callback by simply
checking if the content is callable, resulting in method invocation when
content of the uploaded file is a callable.

The address the issue we're not using locally set callback parameter / method.
2019-11-19 15:27:55 +00:00
Peter Rotich
a9834d88f7 Auth: Authentication Token Bypass
This commit addresses a vulnerability on how osTicket authenticates
auth-tokens used for auto-login to view ticket status.

The validation process failed to handle unexpected type handling issue
making it possible for users to exploit type juggling and authenticate using
only email and ticket number.
2019-11-19 15:27:55 +00:00
Peter Rotich
6e039ab7cd mPDF: Remote Code Execution Vulnerability
This commit mitigates insufficient validation in mPDF library that enables a
malicious intruder to inject arbitrary PHP objects via css @import utility
that may result in Remote Code Execution.
2019-11-19 15:27:55 +00:00
Peter Rotich
05fd2aef39 Merge remote branch 'upstream/develop-next' into develop-next 2019-11-19 15:00:32 +00:00
Peter Rotich
de4b8720ff Merge remote branch 'upstream/develop' into develop-next 2019-11-19 15:00:12 +00:00
Peter Rotich
9951125e2b Merge pull request #5192 from protich/issue/dialog-jserror
Dialog: Highlight tab with error(s)
2019-11-19 08:42:44 -06:00
Peter Rotich
37a7ce4e22 Merge pull request #5191 from protich/issue/datetime-between
Require Between Date Entries
2019-11-19 08:42:30 -06:00
Peter Rotich
1aaee586b4 Require Between Date Entries
This commit adds requirement for between dates. Also overrides default
InlineFormField error - not required for Advanced Search interface.
2019-11-19 14:21:41 +00:00
Peter Rotich
b81b703972 Highlight tab with error(s)
This commit addresses javascript error - on error - on a dialog modal with tab content.
2019-11-19 02:47:00 +00:00
Peter Rotich
f81de55592 Merge remote branch 'upstream/develop-next' into develop-next 2019-11-18 22:19:25 +00:00
Peter Rotich
8b157cbc5e Merge remote branch 'upstream/develop' into develop-next 2019-11-18 22:19:19 +00:00
Peter Rotich
a3ddced558 Merge pull request #5190 from JediKev/format/clickableurls
format: Clickable URLs
2019-11-18 15:22:35 -06:00
Peter Rotich
e3cc92a6f7 Merge pull request #5100 from aydreeihn/feature/task-ticket-ref
Add Ticket Reference to Tasks
2019-11-18 15:22:15 -06:00
aydreeihn
af97900a4e Add Ticket Reference to Tasks
If a Task has a related ticket, put a link to get to the ticket from within the task as well as add a ticket column to the tasks queue.

This fixes Issue #5093
2019-11-18 15:19:51 -06:00
Peter Rotich
f628ccf83c Merge pull request #5099 from protich/feature/auto-refer
Auto-refer tickets to assigned Agent on close
2019-11-18 15:04:40 -06:00
Peter Rotich
c3d9d1d21f Merge pull request #5189 from aydreeihn/issue/org-update
Issue: Organization Update
2019-11-18 14:35:25 -06:00
Peter Rotich
042bfc3616 Merge pull request #5188 from JediKev/issue/redactor-reset-buttons
issue: Redactor Reset Buttons
2019-11-18 14:35:09 -06:00
aydreeihn
7b6bd90237 Issue: Organization Update
This commit fixes discrepencies we had with organization updates for the audit plugin and organization updates from a User.

It also ensures that we log the following Organization edits:
- Update Primary Contacts list
2019-11-18 13:57:44 -06:00
JediKev
4f7569d941 format: Clickable URLs
This addresses issue 5176 where some Plaintext URLs are not completely
clickable. This is due to the regex check for clickable URLs not including a
few characters. This adds `[`, `]`, and `/` as matchable characters so urls
like
`https://test.com/cart/add?route=marketplace/extension/info&product[123]=3`
will be completely clickable.
2019-11-18 13:31:46 -06:00
JediKev
8078d4d1e8 issue: Redactor Reset Buttons
This addresses an issue where since the Redactor upgrade the Reset buttons
do not work anymore. This is due to the code referencing old plugin/module
code that either no longer exists or has changed names. This updates the
reset button code to reference the new Redactor plugin/module methods.
2019-11-18 12:29:36 -06:00
Peter Rotich
ed9f63f905 Merge pull request #5177 from protich/issue/no-teams
Queues:  Agents with no team assignment
2019-11-18 09:10:55 -06:00
Peter Rotich
094b7de79c Merge pull request #5183 from protich/issue/disabled-sla
Disabled SLA
2019-11-18 09:10:00 -06:00
Peter Rotich
2fe5370c07 Disabled SLA
Make sure effective SLA is still active when computing estimated due date
2019-11-17 05:02:16 +00:00
Peter Rotich
a00cee9cd0 Queues: Agents with no team assignment
Commit d8b61e83 correctly addressed an issue with criteria for team assignment
when an agent doesn't belong to a single team, BUT failed to consider cases
that the criteria is part of a set of constraints. e.g Tickets assigned to
Me OR one of my Teams.

This commit adds a check to skip team check when multiple constraints are
included.
2019-11-15 04:22:47 +00:00
Peter Rotich
fe140f414e Merge remote branch 'upstream/develop' into develop-next 2019-11-15 03:34:17 +00:00
aydreeihn
a27a2975ef Merge pull request #5175 from aydreeihn/issue/saved-queue-pages
Queue Pages Default
2019-11-14 15:36:05 -06:00
aydreeihn
dff8bc1d9d Queue Pages Default
Remove page limit parenthesis
2019-11-14 15:34:40 -06:00
aydreeihn
f42f2ba809 Merge pull request #5174 from aydreeihn/issue/saved-queue-pages
Queue Pages Default
2019-11-14 15:33:13 -06:00
aydreeihn
510525023f Queue Pages Default
Default to the page limit when the queue returns 0 results instead of 3 pages.
2019-11-14 15:32:07 -06:00
aydreeihn
b5b311f920 Merge pull request #5173 from aydreeihn/issue/php56
PHP 5.6 Support
2019-11-14 15:16:58 -06:00
aydreeihn
5f3a8f4ca6 PHP 5.6 Support 2019-11-14 15:14:41 -06:00
Peter Rotich
88243e09bd Merge remote branch 'upstream/develop' into develop-next
Conflicts:
	include/class.ticket.php
2019-11-14 18:36:37 +00:00
Peter Rotich
d1e370d034 Merge pull request #5168 from JediKev/php/5.6-support
php: 5.6 Support
2019-11-14 12:25:44 -06:00
Peter Rotich
45d794eeb8 Merge pull request #5167 from aydreeihn/issue/lint-fixes
Oops: Lint Fixes
2019-11-14 12:25:04 -06:00
Peter Rotich
b7522f10af Merge pull request #5166 from protich/issue/5155
Add Time boundaries to Between date range
2019-11-14 12:24:29 -06:00
Peter Rotich
31c97cfd20 Remove user's timezone conversion
The date picker already has the user's timezone factored in to the
selection. Removing user's timezone allows for admin set queues to maintain
the original timezone selection.
2019-11-14 18:22:21 +00:00
Peter Rotich
f3e7bbe5df Merge pull request #5165 from protich/issue/5160
Clear Overdue Flag on Due Date Change
2019-11-14 12:17:23 -06:00
JediKev
5e7497d9a4 php: 5.6 Support
This addresses an issue with v1.14 where `??` (null coalescing operator) in
class Export throws a fatal error when using PHP 5.6. This is an issue
especially for people who cannot upgrade PHP but want to take advantage of
the latest osTicket codebase/features. This updates the null coalescing
operator to an isset ternary operator to keep backwards compatibility with
PHP 5.6.
2019-11-13 17:00:42 -06:00
aydreeihn
c5b15d6088 Oops: Lint Fixes 2019-11-13 15:06:27 -06:00
Peter Rotich
cbc89b3ce2 Add Time boundaries to Between date range
Add time boundaries to between data range dates and convert results to
database timezone.
2019-11-13 18:31:17 +00:00
Peter Rotich
8c76d70424 Clear Overdue Flag on Due Date Change
Clear overdue flag on SLA / Duedate change that results in a duedate in the
future.
2019-11-13 15:47:18 +00:00
Peter Rotich
24f3a0ba36 Merge remote branch 'upstream/develop' into develop-next
Conflicts:
	include/staff/ticket-view.inc.php
2019-11-12 23:21:01 +00:00
Peter Rotich
f3d4b284be Merge pull request #5135 from RikkiMasters/develop
Feature: Mark as Answered permission option
2019-11-12 17:14:28 -06:00
Peter Rotich
a689373719 Merge remote branch 'upstream/develop-next' into develop-next 2019-11-12 23:09:33 +00:00
Peter Rotich
8b029608ec Merge remote branch 'upstream/develop' into develop-next 2019-11-12 23:09:26 +00:00
Peter Rotich
af4ee63514 Merge pull request #5164 from JediKev/db/system-time-zone-2
db: System Time Zone
2019-11-12 17:05:40 -06:00
Peter Rotich
32b339410c Merge pull request #5151 from aydreeihn/feature/merge-tickets
Ticket Merge Upgrade Patch
2019-11-12 17:05:27 -06:00
JediKev
d8adf8508f db: System Time Zone
This updates the change made in d227d54 to use the system time zone rather
than the global time zone.
2019-11-12 15:59:53 -06:00
aydreeihn
38fada0fb8 Ticket Merge Upgrade Patch
This patch modifies the upgrader for ticket merges to add a new table, thread_entry_merge that will store data for thread entries related to ticket merges. This modification improves the upgrade process.
2019-11-12 15:53:56 -06:00
Peter Rotich
96479902b0 Merge remote branch 'upstream/develop-next' into develop-next 2019-11-12 21:29:22 +00:00
Peter Rotich
31f06ea70f Merge remote branch 'upstream/develop' into develop-next 2019-11-12 21:29:14 +00:00
Peter Rotich
b7334807de Merge pull request #5119 from JediKev/feature/separate-smtp-creds
feature: Separate SMTP Credentials
2019-11-12 15:20:29 -06:00
Peter Rotich
87ac6bbbe8 Merge branch 'develop-next' into feature/separate-smtp-creds 2019-11-12 15:20:19 -06:00
Peter Rotich
8dce9d5f00 Merge pull request #5109 from JediKev/feature/fetch-from-mail-folder
feature: Fetch From Mail Folder
2019-11-12 15:14:30 -06:00
Peter Rotich
d227d54e1e Merge pull request #5163 from JediKev/db/system-time-zone
db: System Time Zone
2019-11-12 15:14:07 -06:00
JediKev
76087fcff3 db: System Time Zone
This addresses issue 5156 where using something like AWS RDS shows incorrect
timezone for the database. In systems like AWS RDS you cannot set the
`@@global.system_time_zone` variable to anything other than `UTC` which is a
problem. This updates `db_connect` to set the session timezone to the global
timezone for every connection. This will ensure the appropriate timezone is
used in subsequent methods.
2019-11-12 13:47:01 -06:00
Peter Rotich
c2da773821 Merge pull request #5159 from protich/feature/ticket-pdf-export
ticket-view: Add ZIP export option
2019-11-11 13:30:47 -06:00
Peter Rotich
5e5b6b8495 ticket-view: Add ZIP export option
This adds the ability to dowload a ticket thread PDF in a ZIP file with all of
the attachments included. And, optionally, also include the associated tasks,
again with a PDF of the thread and all attachments included.

Conflicts:

	include/staff/ticket-view.inc.php
	scp/tickets.php
2019-11-11 18:35:39 +00:00
Peter Rotich
7a7304ba51 Merge remote branch 'upstream/develop' into develop-next 2019-11-11 18:04:15 +00:00
Peter Rotich
a0221ef1f0 Merge pull request #5157 from aydreeihn/issue/auto-assignment
Modify Reopen Assignment
2019-11-11 11:56:32 -06:00
Peter Rotich
ed8b9cd798 Merge pull request #5152 from JediKev/issue/format-file-name
issue: Format File Name
2019-11-08 09:46:03 -06:00
aydreeihn
d50ebbb16a Modify Reopen Assignment
This commit modifies the code to ensure that if the 'Disable auto assign on reopen' box is checked for a department, reopened tickets are open as unassigned when a ticket is reopened by a user's message as well as when an agent manually reopens the ticket.
2019-11-08 09:19:50 -06:00
JediKev
b6d13a248c issue: Add Default Embed Whitelist Domains
This adds the default Domains for the Embed Whitelist feature.
2019-11-07 15:04:57 -06:00
Peter Rotich
4c066ac800 Merge remote branch 'upstream/develop-next' into develop-next
Conflicts:
	include/class.organization.php
2019-11-06 22:04:09 +00:00
Peter Rotich
0c3e8d9935 Merge remote branch 'upstream/develop' into develop-next 2019-11-06 22:01:48 +00:00
Peter Rotich
806b479825 Merge pull request #5150 from JediKev/issue/check-cfg-iframe
issue: Check $cfg iFrame
2019-11-06 15:47:54 -06:00
Peter Rotich
cca97edae0 Merge pull request #5149 from JediKev/issue/db-error-1062
issue: DB Error #1062
2019-11-06 15:47:42 -06:00
JediKev
bd427cdfd9 issue: Format File Name
This formats the filename before using it in an error to avoid chance of
XSS.
2019-11-06 15:26:29 -06:00
JediKev
a6b820039b issue: Check $cfg iFrame
This addresses an issue where we don’t check if $cfg exists before using it.
This adds a check for `$cfg` before we use it to avoid fatal errors.
2019-11-06 11:51:39 -06:00
JediKev
27c925cca5 issue: DB Error #1062
This addresses a long-time issue of the famous `DB Error #1062` when
uploading an Inline File to a Draft. The issue is that the system does not
check if an Attachment record exists before creating a new one. We create a
new Attachment record, we go to save it, and the system errors out because
that record already exists. This adds a check to see if the Attachment
record already exists and if so we use that instead of creating a new one.
2019-11-06 10:26:11 -06:00
Peter Rotich
88f97b5506 Merge pull request #5143 from aydreeihn/issue/task-update
Issue: Edit Task Fields
2019-11-05 11:58:13 -06:00
Peter Rotich
9301136aef Merge pull request #5138 from JediKev/issue/inreplyto-header
issue: In-Reply-To Header
2019-11-05 11:57:49 -06:00
Peter Rotich
086135c883 Merge pull request #5117 from stfrbrntyu/develop
small fix for index.php
2019-11-05 11:54:24 -06:00
aydreeihn
05cbb75857 Issue: Edit Task Fields
This commit fixes an issue where you were unable to edit custom fields if they were added to a task form after a task had been created.
2019-11-04 14:34:44 -06:00
Peter Rotich
fdef6848ff Merge pull request #5102 from protich/feature/task_count
Ticket task count decorator
2019-11-01 13:27:30 -05:00
JediKev
093984b6dc css: Checkbox Vertical Alignment
This addresses a small issue where the system shows inline checkboxes
centered at the bottom of the text which makes it look out of place. This
updates the CSS for `input[type=checkbox]` to make the `vertical-align`
property equal to `middle` which renders the checkbox correctly.
2019-11-01 11:43:09 -05:00
JediKev
9d4bcb5ac7 patch: Add Mark Answered Permission
This adds the Mark Answered permission by default to Roles with the Reply
Permission Enabled. Piggy backs on 5135.
2019-11-01 11:43:09 -05:00
JediKev
d2cb614a63 issue: Authentication Autocomplete
This addresses an annoying issue where Chrome autofills the Username and
Password for Email Authentication even though we have the
`autocomplete="off"` attribute set. This changes the attribute from
`autocomplete="off"` to `autocomplete="new-password"` so that Chrome will
not attempt to autofill the credentials. More information on this can be
found [here](https://bugs.chromium.org/p/chromium/issues/detail?id=468153).
2019-11-01 11:43:09 -05:00
JediKev
edb8ac6cbe feature: Separate SMTP Credentials
This feature adds the ability to separate the IMAP/POP and SMTP credentials
for a System Email. This adds a checkbox next to the Authentication Required
setting where, if Enabled, will show two additional inputs for the SMTP
Username and Password. If Authentication Required is set to No the SMTP
Username and Password inputs will disappear as they are not needed. If the
checkbox is Disabled the system will use the IMAP/POP credentials for SMTP.
2019-11-01 11:43:09 -05:00
JediKev
901d30a066 feature: Fetch From Mail Folder
This feature adds a textbox in the Email configurations that allows you to
configure a specific Folder to fetch from. If no folder is provided the
system will fetch from the INBOX as usual. This also adds a check so that if
a Folder is given but doesn't exist and can't be created then the system
will error out with a detailed message.
2019-11-01 11:37:29 -05:00
Peter Rotich
c2a3d1f772 Merge pull request #5129 from JediKev/feature/configurable-iframe-whitelist
feature: Configurable iFrame Whitelist
2019-11-01 11:33:10 -05:00
Peter Rotich
eb9db7fccf Merge pull request #4740 from JediKev/issue/delete-org-session-failure
issue: Delete Org Session Failure
2019-11-01 11:32:25 -05:00
Peter Rotich
108f1c663f Merge pull request #5051 from aydreeihn/feature/audit-logs
Audit Log Plugin
2019-11-01 11:30:08 -05:00
Peter Rotich
ffa68a3d8d Merge pull request #5114 from aydreeihn/feature/merge-tickets
Ticket Merge: Close Children
2019-11-01 11:29:23 -05:00
JediKev
8849c1972d issue: In-Reply-To Header
This addresses an issue raised in 5111 where the `in-reply-to` header is not
sent with outgoing emails. This is due to the `$recipients` variable being
an instance of `MailingList` which is not handled correctly in
`class.mailer.php`. This adds a new case to handle `MailingList` directly.
2019-11-01 11:28:31 -05:00
JediKev
44200e5d46 feature: Configurable iFrame Whitelist
This adds a new feature called iFrame Whitelist that offers the ability to
configure what domains you want to be whitelisted for iFrames used in the
system. Basically, if you want to insert an iFrame in the system you'll have
to whitelist the domain first. If you insert an iFrame with a
non-whitelisted domain the system will remove the iFrame upon saving. This
keeps current functionality where by default the system allows YouTube,
Vimeo, and Daily Motion.
2019-11-01 09:07:59 -05:00
JediKev
d70dfc17b5 feature: Fetch From Mail Folder
This feature adds a textbox in the Email configurations that allows you to
configure a specific Folder to fetch from. If no folder is provided the
system will fetch from the INBOX as usual. This also adds a check so that if
a Folder is given but doesn't exist and can't be created then the system
will error out with a detailed message.
2019-10-31 13:41:53 -05:00
Peter Rotich
77a2eda292 Merge pull request #5133 from JediKev/issue/attachment-filter
issue: Attachment Filter
2019-10-31 11:08:11 -05:00
Peter Rotich
88f605cf55 Merge pull request #5131 from JediKev/issue/umlauts-sender-name
issue: Umlauts In Sender's Name
2019-10-31 11:07:29 -05:00
Peter Rotich
b58251df4f Merge pull request #5132 from JediKev/issue/umlauts-subject-line
issue: Umlauts In Subject
2019-10-31 11:07:06 -05:00
JediKev
eb4bda8459 orm: Refetch Failure
This addresses an ORM failure where upon refetching an object from the
database that no longer exists the system crashes hard. We use the `one()`
method which expects one result, if there is no result it throws a
`DoesNotExist` exception. We are not catching the exception properly which
crashes osTicket and forces you to clear the session via browser or
database.
2019-10-30 15:58:40 -05:00
JediKev
bbd0c25524 issue: Delete Org Session Failure
This addresses an issue on the Forum where deleting an Organization causes
the session to fail. This is due to the Organization QuerySet being stored
in the session and not being cleared out when deleted from the system. This
causes the system to try to refetch the object from the database which it's
not there as it's been deleted and therefore causes the session to crash.
2019-10-30 15:50:46 -05:00
Rikki Masters
52aaa0bb18 Mark as Answered permission correction 2019-10-30 10:11:59 +00:00
JediKev
9f4fbc2708 issue: Attachment Filter
This addresses issue 5123 where fetched Emails do not reject attachments
that are not allowed. This is due to setting a File ID inside of an array
called `$file[]` but not unsetting it when the attachment hits an
FileUploadError. This updates class MailFetch to set the file array back to
empty so that the ID is cleared and the error is added correctly which
rejects the attachment.
2019-10-29 10:04:20 -05:00
Rikki Masters
2fcc664e15 Feature: Mark as Answered permission option
Some roles need the ability to mark a ticket as Answered/Unanswered but must not be able to reply directly to the customer. Both are controlled by the Post Reply permission. This seperates the two functions so they can be managed independently.
2019-10-29 14:44:38 +00:00
aydreeihn
6fef208f02 Ticket Merge: Close Children
When tickets are merged, we should automatically close children Tickets. This commit gives the Agent an option of which closed status they want children tickets to be set to.

This references issue #5049
2019-10-29 09:15:08 -05:00
JediKev
cccdb1525d issue: Umlauts In Subject
This addresses an issue where Piping email to osTicket and having Umlauts in
the Subject line causes the Subject to be malformed. This is due to the
`mimedecode()` method for class Format which is used by the API to transcode
the Subject line in emails. This adds a check to see if the
`mb_detect_encoding()` method exists so we can detect the value's encoding.
If it exists and we can detect the value's encoding the system will
transcode the text from the detected encoding to UTF-8. If we cannot detect
the encoding the text will continue through the other encoding checks.
2019-10-28 14:06:47 -05:00
JediKev
e3f42c33fe issue: Umlauts In Sender's Name
This addresses issue 4884 where sending an email with Umlauts in the From
Name causes the User's Name and Email to be malformed. This is due to
outdated RFC822 from Pear. This replaces the old RFC822 Pear module with the
latest release so that we are up to date.
2019-10-28 14:04:20 -05:00
JediKev
2330f47fb8 issue: Allow iFrame Rename
This renames the `Allow iFrames` setting to `Allow System iFrame` as this
better fits the use-case. This also updates the Help Tip information to
include the new title and expands on what you can input (ie. URLs). Lastly,
this renames the validator for the `Allow System iFrame` setting from
`cs-domain` to `cs-url` as it technically validates a comma separated list
of URLs (not just domains).
2019-10-28 12:41:34 -05:00
Peter Rotich
fe28bc5213 Merge pull request #5125 from kler/feature/fix-use-uninitialised-server-var
Fix use of possibly uninitialised $_SERVER['HTTPS']
2019-10-25 11:06:29 -05:00
Patrik Lermon
8e9b150fd1 Fix use of possibly uninitialised $_SERVER['HTTPS'] 2019-10-25 16:46:04 +02:00
Peter Rotich
eff0bca1c9 Merge pull request #5121 from JediKev/i18n/kb-category-and-js
i18n: KnowledgeBase Category and JS
2019-10-24 16:29:42 -05:00
Peter Rotich
618c2e15ea Merge pull request #5124 from JediKev/issue/spaces-in-username
issue: Spaces In Username
2019-10-24 14:11:50 -05:00
JediKev
7c8f55763b issue: Spaces In Username
This addresses issue 5122 where having a space at the beginning and/or end
of the login Username/Email on the Client Portal the system will return
`Access Denied`. This is due to the system not trimming the rogue spaces.
This adds `trim()` around the Username/Email so that the spaces are removed
and login will be successful.
2019-10-24 11:57:01 -05:00
JediKev
bce8296e05 i18n: KnowledgeBase JS
In 5120, the reporting party also mentioned that they receive an error of
`script '/xxx/osTicket/kb/ajax.php' not found or unable to stat`.  This is
due to the AJAX call being inside the KB directory, and `/kb/ajax.php` truly
does not exist. This adds `ROOT_PATH` to the beginning of the AJAX call so
that no matter where it is, it will point to the correct location.
2019-10-23 09:16:26 -05:00
JediKev
5646e7c787 i18n: KnowledgeBase Category
This addresses 5120 where main (or Parent) FAQ Category Titles are not
translated even though the child Category titles are translated correctly.
This is due to to the system pulling the Full Name instead of the Local
(translated) Name.
2019-10-23 09:15:28 -05:00
Peter Rotich
9ab42de70e Merge pull request #5096 from JediKev/i18n/openssl-error
i18n: OpenSSL Error
2019-10-21 10:48:32 -05:00
Peter Rotich
7620b47b6a Merge pull request #5097 from protich/issue/msg-variable
Make message variable (%{message}) optional
2019-10-21 10:48:03 -05:00
Peter Rotich
a6e22ab223 Merge pull request #5103 from protich/issue/overdue-oopsie
Overdue oopsie
2019-10-21 10:45:11 -05:00
Marcel
e7779e2d0c Update index.php 2019-10-20 21:10:16 +02:00
aydreeihn
419a478583 Code Optimization
We can log some edits in class.orm.php during the save function when this->dirty is generated rather than having to log them all within their classes.
2019-10-16 15:03:23 -05:00
Peter Rotich
de7271d1de Overdue oopsie
Commit 17f958c4 changed overdue query to ORM but failed to take into account
the state of the ticket's status. This resulted in closed tickets being
marked overdue.

This commit fixes the issue by making sure the check is limited to open
tickets only.
2019-10-12 12:53:46 +00:00
Peter Rotich
b4fca250ed Ticket Task count
This commit adds a ticket queue decoration for tasks count as well as option
to export same.
2019-10-11 15:41:22 +00:00
Peter Rotich
b2a470e1e4 Auto-refer tickets to assigned Agent on close
This commit adds a setting to Admin Panel > Settings > Tickets to enable
ability to auto-refer tickets, on close, to assigned or closing agent.

This is necessary when you want to give agents with limited access continued
access to assigned tickets after they're closed.
2019-10-10 16:56:29 +00:00
aydreeihn
5ba9e899ea Code Cleanup
- Send delete signal within delete methods
- Make sure we are not unnecessarily calling PluginManager::auditPlugin()
2019-10-10 09:19:21 -05:00
aydreeihn
54a175a8bd Audit Plugin: Reduce Lookups
Reduce the number of calls we make to the database for users or agents loggin in or out of the helpdesk.
2019-10-10 09:19:21 -05:00
aydreeihn
203c716b7d Audit Plugin HTML Injection
This commit uses a signal to inject HTML for the plugin.
2019-10-10 09:19:21 -05:00
aydreeihn
59e5d71a5f Remove Unnecessary if Statement
We do not need to check for the plugin each time we want to send a signal.
2019-10-10 09:19:21 -05:00
aydreeihn
ac1e99c434 Code Cleanup
- remove unused $thisstaff variables
- pass an array called $extra to the register function so that we can set the interval and file name
- Error Fix: missing curly brace
- Lint Fixes: misspelled method calls
- Add AuditEntry stubs
- Reduce lines of code
2019-10-10 09:19:20 -05:00
aydreeihn
5c91dc1885 Audit Export Update
Make audit exports work with the changes implemented in PR #5015.
2019-10-10 09:19:20 -05:00
aydreeihn
205b3ae509 Audit Dashboard Help Tips
This commit adds the yaml file for audit dashboard help tips
2019-10-10 09:19:20 -05:00
aydreeihn
f26128381a Export Email
This commit allows us to email audit exports to an Agent if we reach the max execution limit.
2019-10-10 09:19:20 -05:00
aydreeihn
2c350f3b7c Audit Export Hide Views
This commit ensures that we check the 'Show View Audits' configuration before exporting Ticket audits so we can determine if we want to see the Ticket view events in the export or not.
2019-10-10 09:19:20 -05:00
aydreeihn
30eeaf9d3e Assigned Audit Wording
Distinguish between claimed and auto assigned Tickets in audits.
2019-10-10 09:19:20 -05:00
aydreeihn
40771eaee2 Remove Redundancy
We can audit most ticket and task actions within the logEvent function rather than having to write individual logs for each one.
2019-10-10 09:19:20 -05:00
aydreeihn
ff9063895e Code Cleanup
- For agent 'locked' field, audit as islocked instead of isactive
- Audit for deleting pages needed tweaking
2019-10-10 09:19:20 -05:00
aydreeihn
2aacbd1abe Audit Agent replies
- Agent response to tickets
- Agent response to tasks
- Agent note to tickets
- Agent note to tasks
2019-10-10 09:19:20 -05:00
aydreeihn
d942b160b3 Code Cleanup
- Reduce lines of code for Organization audits
- Refer to audit files in phar format, not normal file format
- Update Plugin name
- Remove unneeded comments
- Do not write audit record if the object hasn't been initially saved yet (Dept/Team create)
- Add the audits.php file
2019-10-10 09:19:20 -05:00
aydreeihn
e0ca7e2ac7 Add Mass Process Audits
- Users
- Email Templates
2019-10-10 09:19:20 -05:00
aydreeihn
a4bd53b46a Code Cleanup/Optimization
- add a new method called auditPlugin that returns true/false depending on if the plugin exists and is active
- reduce the amound of info in the $type array. we can get the rest of the info needed in auditObjectEvent
- remove unnecessary model info
- etc
- create flagChanged/statusChanged functions to see if flags have changed
2019-10-10 09:19:20 -05:00
aydreeihn
7cfc062e3e Fix Configuration Audits
- Agents (checkboxes, Department Access)
- Teams (flags/checkboxes)
- SLA (flags)
- Email (checkboxes)
- Users (dynamic fields)
- User Account (whole object)
- Organizations (dynamic fields, flags)
- Departments (checkboxes)
2019-10-10 09:19:20 -05:00
aydreeihn
349c9823ff Show Plugin if Installed and Enabled
Function getPluginByName added to class.plugin.php. This function has 2 variables that can be passed in: $name and $active (bool default false). It will return the name of a plugin if it is found in the database. If $active is true, it will also check to see if the plugin is active before returning the name of the plugin.

Using this function, we can be sure that the plugin is invisible and no extra code is run to try to log an audit if the plugin is disabled or not installed at all.
2019-10-10 09:19:19 -05:00
aydreeihn
69da6455f9 Audit Extra Configurations
- Make sure all audits contain the following data
	{"name":"object name","person":"thisstaff name"}
- Audit configurations that do not pertain to specific objects. These configurations are found in the config table
- Audit individual configurations that can be set per object for the following:
	- Help Topics
	- Departments
	- SLAs
	- Pages
	- Agents
	   - Account
	   - Permissions
	   - Profile
	- Teams
	- Roles
	   - Definition
	   - Permissions
	- Ticket Filters
	- Email Templates
	- Emails

Note: In class.auth.php, the extra lookup has to be done because the staff/user that were looked up are using the StaffSession/ClientSession classes
2019-10-10 09:19:19 -05:00
aydreeihn
27cfd653f7 Add Dashboard Logging
Add Create, Edit, or Delete logging for the following:

- Departments
- Organizations
- Staff
- Task
- Ticket
- User
- Canned Response
- FAQ Categories
- Emails
- FAQs
- Ticket Filters
- Help Topics
- Lists
- Pages
- Roles
- SLA
- Teams
- Email Templates
2019-10-10 09:19:19 -05:00
aydreeihn
72974c8f74 Add Agent/Ticket Audit Export
- ability to export Agent audits
- ability to export Ticket audits
- ensures that the export for Agents, Tickets, and Users takes plugin options chosen into account.
2019-10-10 09:19:19 -05:00
aydreeihn
46a764f3dc Remove State Enum, Use Event Table
This commit allows us to use the event table's event_ids instead of using an enum field for states in the audit table.
2019-10-10 09:19:19 -05:00
aydreeihn
bb3d092e5f Audits Feature
This commit adds the functionality for the Audits view to be available within Tickets, User Directory, Admin Dashboard, and Agents section
2019-10-10 09:19:19 -05:00
aydreeihn
8e3fd4d4a9 Audit Plugin Capability
- Add a Ticket Audit Log to show all Ticket activities
- Add a User Audit Log to show all actions a User makes in the system:
	- Login
	- Logout
	- Excessive Login Attempts
	- View Ticket (as User or Collaborator)
	- Edit Ticket Field
	- Edit User Profile
	- Create Ticket (through email or front end)
	- Add Collaborator (through email)
	- Post Message (as User or Collaborator)
2019-10-10 09:19:19 -05:00
aydreeihn
9b80889a10 User Audit Exports:
This commit adds the ability to export the User Audit log as a CSV.
2019-10-10 09:19:19 -05:00
JediKev
af6f0e92d8 i18n: OpenSSL Error
This addresses issue 5095 where installing a Language Pack and visiting the
Dashboard > Information page without OpenSSL installed/configured will throw
a fatal error of `Call to undefined function openssl_pkey_get_public()`.
This is due to no check for the `openssl` extension before the dependant
method is called. This adds a check so that if OpenSSL is not available we
can return a useful error code of `VERIFY_EXT_MISSING` (which is error code
`2`) and continue without disrupting the content.
2019-10-09 15:36:04 -05:00
Peter Rotich
315c4e7c8b Message Variable - %{message}
Make message variable optional for new tickets opened by agents. This is
necessary for help topics with issue details disabled.
2019-10-09 20:14:28 +00:00
Peter Rotich
919e1b70be Merge remote branch 'upstream/develop' into develop-next 2019-10-09 19:53:41 +00:00
Peter Rotich
1c987179b9 Merge pull request #5092 from protich/issue/time-format
Datatimepicker: Time format
2019-10-08 13:34:13 -05:00
Peter Rotich
f0fccbc0e1 Datatimepicker: Time format
This commit addresses an issue where time format in 24 hrs resulted in
double hours.
2019-10-07 15:07:16 +00:00
Peter Rotich
f7335ed428 Merge remote branch 'upstream/develop-next' into develop-next 2019-10-04 14:06:40 +00:00
Peter Rotich
7c12b106a0 Merge remote branch 'upstream/develop' into develop-next 2019-10-04 14:06:34 +00:00
Peter Rotich
759cdbdaab Merge pull request #5085 from JediKev/issue/revert-fefed14
issue: Revert  fefed14
2019-10-04 08:56:38 -05:00
Peter Rotich
08b32416f6 Merge pull request #5087 from protich/issue/dependent-fields_comparator
Visibility: Move getJsComparator to Widget class
2019-10-04 08:56:18 -05:00
Peter Rotich
1a2a5fe09c Merge pull request #5089 from JediKev/issue/acl-oopsie
issue: ACL Oopsie
2019-10-04 08:55:39 -05:00
JediKev
4d774bc47f issue: ACL Oopsie
This addresses an issue where initially saving the ACL will fail. This is
due to the incorrect variable being used to lookup the IP in the ACL. This
updates the variable from `$acl` to the correct variable `$vars['acl']`.
2019-10-04 08:50:39 -05:00
Peter Rotich
d3f46bfd67 Visibility: Move getJsComparator to Widget class 2019-10-03 20:19:34 +00:00
Peter Rotich
36b44f77ed i18n spelling oopsies
osTicket is not running for presidency after all!
2019-10-03 15:45:08 +00:00
JediKev
c9be2e0011 issue: Revert fefed14
This addresses issue 5084 by partially reverting commit `fefed14`. In said
commit, we updated `THIS_VERSION` to utilize `MAJOR_VERSION` which is fine.
However, we also updated the deploy module to copy the same format. This
interferes with the osTicket Version check by not including the entire
subversion and not starting with a `v` (ie. `v1.12.3`). This reverts the
copied format section of the commit so that `THIS_VERSION` will be the full,
non-git version when deployed/packaged.
2019-10-02 14:59:32 -05:00
JediKev
4b9a699c63 Add Release Notes for v1.14-rc2 2019-10-02 10:23:56 -05:00
JediKev
be4ca2cc38 Merge branch 'develop' into develop-next
Conflicts:
	WHATSNEW.md
2019-10-02 10:23:07 -05:00
JediKev
bcf1a6f1de Add Release Notes for v1.12.3 2019-10-02 10:18:52 -05:00
JediKev
a210b98760 Merge branch 'develop' into develop-next 2019-10-02 10:08:55 -05:00
Peter Rotich
2e6d1e55ef Merge pull request #5079 from JediKev/issue/mbstring-ext-requirement
issue: Mbstring Extension Requirement
2019-10-02 08:52:46 -05:00
Peter Rotich
b7cb9dfd74 Merge pull request #5078 from aydreeihn/issue/task-drafts
Issue: Task Drafts
2019-10-02 08:52:13 -05:00
JediKev
5a96884dd1 issue: Mbstring Extension Requirement
This addresses an issue reported on the forum where printing a ticket in
v1.12 and above requires `mbstring`. This updates the print call to check
for the `mbstring` extension and if not loaded will fail with a detailed
error `mbstring extension required to print ticket to PDF`.
2019-10-02 08:30:26 -05:00
aydreeihn
3e8bce47de Issue: Task Drafts
Make sure that we delete task drafts if the reply was posted successfully.
2019-10-01 16:08:10 -05:00
Peter Rotich
3eabaa165e Lint Fixes 2019-10-01 20:17:46 +00:00
Peter Rotich
d31a97e9c0 Merge remote branch 'upstream/develop-next' into develop-next 2019-10-01 20:10:52 +00:00
Peter Rotich
58f3676d9c Merge remote branch 'upstream/develop' into develop-next 2019-10-01 20:10:48 +00:00
Peter Rotich
51bc96ee6a Merge pull request #5077 from protich/issue/4967
Instantiate  StaffDeptAccess
2019-10-01 15:07:35 -05:00
Peter Rotich
2ce7fdff38 Merge pull request #5076 from protich/issue/datetime_formats
Datetime Formats
2019-10-01 15:07:16 -05:00
Peter Rotich
4993abd274 Merge pull request #5066 from JediKev/issue/redactor-quicknotes
issue: Redactor QuickNotes
2019-10-01 15:07:00 -05:00
Peter Rotich
535d97725b Merge pull request #5067 from aydreeihn/feature/merge-tickets
Ticket Link Fixes
2019-10-01 14:43:18 -05:00
Peter Rotich
9b0f644c02 Merge pull request #5075 from aydreeihn/issue/task-collab-count
Issue: Task Collaborator Display
2019-10-01 14:41:10 -05:00
Peter Rotich
390ec3e0e4 Instantiate StaffDeptAccess 2019-10-01 17:45:34 +00:00
Peter Rotich
4709824220 Datetime Formats
This commit addresses two issues related to date / time format.

* 24 hrs format, when selected, is now used system-wide even on thread items
* PHP-to-JS date / time format translation is now down in the backend
2019-10-01 15:57:58 +00:00
aydreeihn
d1790f1b51 Issue: Task Collaborator Display
Part fo the span for collaborators was left out, so it threw off the sprintf as well as the display.
2019-10-01 09:35:24 -05:00
Peter Rotich
46ee7ebfb6 Merge pull request #5065 from aydreeihn/issue/thread-delete
Delete Thread Merge Conflict
2019-09-29 04:27:05 -05:00
aydreeihn
3a41a8aba7 Fix Link Sort
The link form should allow agents to rearrange the tickets to display in the order they want.
2019-09-26 16:33:03 -05:00
aydreeihn
c76cb21a6a Issue: Unlinking From Child Ticket
Make sure we account for unlinking within a ticket using an AJAX call.
2019-09-25 09:33:48 -05:00
JediKev
7251bcf274 issue: Redactor QuickNotes
This addresses issue 5053 where since the Redactor Upgrade, QuickNotes are
not working correctly. This is due to using old redactor methods instead of
the new methods. This updates QuickNotes to use the new methods so they work
properly again.
2019-09-25 09:29:28 -05:00
aydreeihn
d4b6ab675b Delete Thread Merge Conflict
Looks like there was an issue when merging the code that put an extra thread delete in there.
2019-09-25 08:56:37 -05:00
Peter Rotich
aa0bfee0c2 Merge pull request #5063 from JediKev/issue/staff-user-email-length
issue: Staff/User Email Length
2019-09-24 11:02:16 -05:00
Peter Rotich
87bc84a90a Merge remote branch 'upstream/develop-next' into develop-next 2019-09-24 15:50:58 +00:00
Peter Rotich
8f18418d79 Merge remote branch 'upstream/develop' into develop-next 2019-09-24 15:50:53 +00:00
Peter Rotich
2fa491b96d Merge pull request #5056 from protich/issue/queue-default-sort
Queue Sort on Search
2019-09-24 10:39:20 -05:00
Peter Rotich
bbd2e80847 Custom Queue default sort selection
Clear sort_id when `None` or `Inherit from parent` is selected.
2019-09-24 15:35:44 +00:00
Peter Rotich
84ef000032 Merge pull request #5060 from JediKev/issue/revert-453e815
issue: Revert 453e815
2019-09-24 10:10:26 -05:00
Peter Rotich
8b18506271 Merge pull request #5039 from aydreeihn/issue/priority-field
Default for Choice Fields
2019-09-24 10:02:10 -05:00
Peter Rotich
1407def8e9 Merge pull request #5061 from JediKev/issue/complete-thread-var-padding-outlook
issue: Complete Thread Var Padding (Outlook)
2019-09-24 10:00:57 -05:00
JediKev
b96940720e issue: Staff/User Email Length
This implements 5059 to make it valid for upgrades and new installs. This
updates the Staff/User email lengths to match the `ost_email.email` column
length. This makes all email address lengths consistent throughout the
helpdesk.
2019-09-23 14:45:33 -05:00
JediKev
d96285f7f3 issue: Complete Thread Var Padding (Outlook)
This addresses issue 5007 where when using the complete thread variable
there is no padding between thread messages in Outlook desktop app and makes
the thread hard to follow. Outlook does not respect some CSS rules that are
accepted in most (if not all) modern email clients. Since we can’t use
normal CSS the workaround is to add a blank table row (with a single space)
so that it forces "padding" between the end of a message and the start of
another.

Before
(image)

After
(image)
2019-09-23 13:04:56 -05:00
JediKev
ddde34b08f issue: Revert 453e815
This addresses an issue where upgrading from v1.6 to a release on or after
v1.12 will hang on login and eventually timeout. This is due to the system
not being able to fetch the config which logs a db error which calls the
config and continues the loop. For now, we need the config in the
constructor so that the loop doesn't occur and we can continue to upgrade as
normal.

TODO:
- For a permanent fix, we need to figure out why the loop occurs when not in
the constructor and vice versa.
2019-09-20 10:35:31 -05:00
Peter Rotich
d2611b5d3d Queue Sort Options
Allow agent to select sort options on saved queues
2019-09-20 15:33:23 +00:00
aydreeihn
d85ede8c71 Default for Choice Fields
This commit fixes an issue where we sometimes show a default option in selection fields when they cannot be set anyway.

Moving forward, the option to set fields to a default value will only be shown while opening a ticket.
2019-09-20 10:32:31 -05:00
Peter Rotich
f024d2a828 Merge remote branch 'upstream/develop' into develop-next 2019-09-19 18:42:25 +00:00
Peter Rotich
006ea0a660 Merge pull request #5058 from aydreeihn/issue/lint-fixes
Oops: Lint Fixes
2019-09-19 13:34:59 -05:00
Peter Rotich
cbe75db46a Merge pull request #5052 from JediKev/issue/php73-new-agent-set-password
issue: PHP 7.3 New Agent Set Password
2019-09-19 13:34:25 -05:00
Peter Rotich
611d12f53d Merge pull request #5055 from protich/issue/topics-edit
Show list of nested help topics on edit.
2019-09-19 13:33:55 -05:00
Peter Rotich
7a4125aa2e Queue Settings Inheritance
This commit makes inheritance sticky when selected as well as only show
sorting and filtering inheritance option if a queue has a parent.
2019-09-19 18:21:47 +00:00
aydreeihn
e76c64ec42 Oops: Lint Fixes
- Misspelled method calls
- Add fseek to stubs
2019-09-19 12:10:20 -05:00
Peter Rotich
b25b2f28cd Queue Sort on Search
This commit adds a default sort of create date for adhoc and saved searches.
2019-09-19 02:09:59 +00:00
Peter Rotich
f4ec1443dc Merge remote branch 'upstream/develop-next' into develop-next 2019-09-18 20:22:45 +00:00
Peter Rotich
4d4c7ed822 Merge remote branch 'upstream/develop' into develop-next
Conflicts:
	include/class.ticket.php
2019-09-18 20:22:35 +00:00
Peter Rotich
d7120e9737 Merge pull request #5054 from aydreeihn/issue/empty-due-date
Issue: Empty Due Date
2019-09-18 14:49:51 -05:00
Peter Rotich
423c915aa7 Show list of nested help topics on edit. 2019-09-18 17:31:30 +00:00
aydreeihn
30f3b5534c Issue: Empty Due Date
This commit fixes an issue that allowed Agents to clear the Duedate on a ticket using inline edit. We were saving the value 0000-00-00 00:00:00 to the database which the ticket would then display as 12/1/02 06:09 pm.

Instead, if an Agent clears the Duedate field, we should save the duedate as null and the ticket should continue using the est_duedate.
2019-09-18 11:50:55 -05:00
JediKev
1bcd0e2f46 issue: PHP 7.3 New Agent Set Password
This addresses an issue reported on the Forum where creating a new Agent and
setting a password hangs when using PHP 7.3. This is due to too few
arguments passed to `PasswordPolicy::checkPassword()`. This updates the call
to include a second argument of `null` so the method is satisfied and we can
continue with checking the password.
2019-09-17 13:41:07 -05:00
Peter Rotich
16ef60c8f3 Merge pull request #5046 from aydreeihn/issue/drafts
Draft Saving in New Redactor
2019-09-17 10:48:56 -05:00
Peter Rotich
3279805b97 Merge pull request #5042 from JediKev/issue/ticket-filter-assignment-event
issue: Ticket Filter Assignment Event
2019-09-17 10:48:34 -05:00
Peter Rotich
d5b5ae7a42 Merge remote branch 'upstream/develop-next' into develop-next 2019-09-17 15:44:27 +00:00
Peter Rotich
e253917cf1 Merge remote branch 'upstream/develop' into develop-next 2019-09-17 15:44:20 +00:00
Peter Rotich
b9f89ba2fb Merge pull request #5048 from protich/issue/qsort
Revert "issue: Advanced Search Default Sorting"
2019-09-13 15:03:40 -05:00
Peter Rotich
61812965c6 Merge pull request #5045 from aydreeihn/issue/upgrader-ticket-flags
Upgrader Issue: Ticket Flags
2019-09-13 15:01:36 -05:00
Peter Rotich
d4befcd01b Revert "issue: Advanced Search Default Sorting"
This partially reverts commit dda483ebdc.
Forcing created by sort resulted in queue columns based sorting getting
overridden.
2019-09-13 19:31:59 +00:00
aydreeihn
e0298f20e7 Upgrader Issue: Ticket Flags
This commit fixes an issue where the flags field was added to the Ticket table in the installer, but it was never added to the upgrader, so when trying to add a column after the flags field, there would be an error for people whose install was done before the flags field was introduced to the installer.
2019-09-13 10:28:06 -05:00
Peter Rotich
59f649be2f Merge pull request #5044 from aydreeihn/issue/date-format
European Date Format Issue
2019-09-13 09:46:43 -05:00
aydreeihn
df7306f303 European Date Format Issue
This commit fixes an issue where if your date format is dd/MM/y h:mm a, the date picker will show the wrong year because the dates were not translating correctly between PHP and JS.
2019-09-13 09:40:54 -05:00
JediKev
606993e2c9 issue: Ticket Filter Assignment Event
This addresses 5035 where the ticket Assignment Event show the Ticket
Owner's name or "SYSTEM" as the assigner when tickets are created via Client
Portal, API, or Email Fetching. This updates the event to include "Ticket
Filter" as the assigner if the assignment was triggered by a Ticket Filter
Action. This makes for more accurate events and is very useful for
statistics/debugging. This keeps current functionality of Agents creating
tickets shows the creating Agent's name as the assigner. This also adds a
new parameter to `assignToAgent()` and `assignToTeam()` called `$user`
(defaults to null) that allows us to pass different usernames/user objects
for the events. This makes the two methods versatile so if we add new ways
to assign to Staff/Teams in the future we can pass the new name/object with
no issues.
2019-09-12 14:02:58 -05:00
aydreeihn
644da1bdb3 Draft Saving in New Redactor
- Make auto save time every 10 seconds
- Modify saveDraft button for new redactor
- Fix inline edit auto saves
2019-09-12 13:10:48 -05:00
JediKev
c32990df55 Merge branch '1.14.x' into develop-next 2019-09-11 10:42:27 -05:00
JediKev
833262fc6d Add Release Notes for v1.14-rc1 2019-09-11 10:36:50 -05:00
JediKev
f69ab021b5 version: Update MAJOR_VERSION
This updates the MAJOR_VERSION for 1.14.x series.
2019-09-11 10:36:50 -05:00
aydreeihn
48d6da075c Cache Children Tickets
Cache the results when getting children tickets.
2019-09-11 10:36:50 -05:00
aydreeihn
4e5cab9949 Don't Delete Child Threads
If we choose to delete a child ticket during merging, we should still keep the child thread so that we have the merge indicator on the parent ticket to show us which threads belonged to the deleted child and which belong to the parent ticket.
2019-09-11 10:36:50 -05:00
aydreeihn
a63c93478f Make getChildrenTickets Static
This commit makes the getChildrenTickets static and then creates a new function called getChildren for the times we need to get children from an existing Ticket.
2019-09-11 10:36:50 -05:00
aydreeihn
8097cbbdb7 Lint Fixes
- Uninitialzed Variable
2019-09-11 10:36:50 -05:00
JediKev
1bad6de019 Merge remote-tracking branch 'origin/develop-next' into develop-next 2019-09-11 10:21:42 -05:00
JediKev
b81ff83ca8 Merge remote-tracking branch 'origin/develop' into develop-next 2019-09-11 10:16:32 -05:00
Peter Rotich
06faacb475 Merge pull request #5038 from aydreeihn/feature/merge-tickets
Ticket Merge Code Fixes
2019-09-11 10:15:29 -05:00
aydreeihn
a0a58e4bf2 Cache Children Tickets
Cache the results when getting children tickets.
2019-09-10 15:53:35 -05:00
Peter Rotich
8a13545154 Merge pull request #5036 from aydreeihn/issue/inline-edit-refresh
Field Length Truncate
2019-09-10 09:04:45 -05:00
Peter Rotich
957ee3ff41 Merge pull request #5037 from aydreeihn/issue/custom-prio-field
Custom Priority Field Blank
2019-09-10 09:04:33 -05:00
Peter Rotich
2ed22baa5b Merge pull request #4690 from greezybacon/feature/redactor-3.1
Redactor :: Upgrade to 3.1.6
2019-09-10 09:02:39 -05:00
Peter Rotich
be996b8b82 Merge branch 'develop-next' into feature/redactor-3.1 2019-09-10 09:02:06 -05:00
aydreeihn
f7ea1f6594 Custom Priority Field Blank
If no value is saved to a custom Priority field, we need to make sure we don't t
ry to treat a null value as an array. We should instead just return the null priority.
2019-09-09 12:47:36 -05:00
aydreeihn
24b220de06 Don't Delete Child Threads
If we choose to delete a child ticket during merging, we should still keep the child thread so that we have the merge indicator on the parent ticket to show us which threads belonged to the deleted child and which belong to the parent ticket.
2019-09-09 12:14:20 -05:00
aydreeihn
4d6de403e7 Field Length Truncate
We should truncate the length of a field if it is not a FileUploadField and its length is more than 200.
2019-09-09 10:04:17 -05:00
Peter Rotich
71224152bc Merge pull request #5032 from protich/issue/inline-edit-refresh
Issue/inline edit refresh
2019-09-08 11:05:57 -05:00
Peter Rotich
e8fac06a86 Merge pull request #4994 from aydreeihn/issue/inline-edit-refresh
Don't require refresh for inline edit
2019-09-08 11:05:12 -05:00
Peter Rotich
12e975830d Merge pull request #5033 from JediKev/issue/fix-patch-issue
issue: Fix Patch Issue
2019-09-06 14:20:35 -05:00
Peter Rotich
2313dd8af6 Merge pull request #5030 from aydreeihn/issue/annul_events
Issue: Annul Closed Events
2019-09-06 14:08:21 -05:00
Peter Rotich
fd2bd47985 Merge pull request #4992 from JediKev/issue/csv-patch-adv-search-error
issue: CSV Patch Adv. Search Error
2019-09-06 14:08:06 -05:00
Peter Rotich
5ae88de36d Merge pull request #5025 from JediKev/issue/form-field-flags
issue: Form Field Flags
2019-09-06 14:05:02 -05:00
Peter Rotich
da991c6ce1 Merge branch 'develop-next' into issue/form-field-flags 2019-09-06 14:03:57 -05:00
Peter Rotich
3f1585de4c Merge pull request #5008 from aydreeihn/issue/delete-threads
Add thread_type Field
2019-09-06 13:59:24 -05:00
Peter Rotich
d0de2902bd Formatting cleanup 2019-09-06 18:48:41 +00:00
aydreeihn
42339c2cbe Make getChildrenTickets Static
This commit makes the getChildrenTickets static and then creates a new function called getChildren for the times we need to get children from an existing Ticket.
2019-09-06 13:39:35 -05:00
aydreeihn
98f4b37e55 Lint Fixes
- Uninitialzed Variable
2019-09-06 13:10:13 -05:00
JediKev
8a8167e8f6 issue: Fix Patch Issue
This addresses an issue where resolving conflicts on Git instead of rebasing
caused a file to appear that wasn’t supposed to. This also addresses a typo
where there were extra underscores in the table names.
2019-09-06 13:00:25 -05:00
JediKev
6ea7526d52 issue: CSV Patch Adv. Search Error
This addresses an issue where the previous CSV security patch causes an
error when creating an Advanced Search with criteria like `User / Email
Address => contains => @domain.tld`. The system tries to validate the field
and since `is_formula` is the default validation for TextboxFields the
system sees `@domain.tld` criteria as a formula and throws the `Content
cannot start with the following characters: = - + @` error. Advanced
Searches do not need the `is_forumal` validation as the fields are not
exportable. This adds a check to see if the field's form is
`AdvancedSearchForm` and if there is no `validator` set it gets set to `adv`
which bypasses the validation.
2019-09-06 12:47:19 -05:00
aydreeihn
8029b1b020 Issue: Annul Closed Events
This commit fixes an issue where if you were to change a Ticket to the Resolved status and then to Closed, the dashboard statistics would show that you had closed 2 Tickets even though both events were done on the same Ticket.

We should only count one closed event per Ticket.

This was reported in Issue #5018.
2019-09-06 11:14:00 -05:00
aydreeihn
6ff44915ce Code Cleanup
- Remove unnecessary code
- Fix line spacing
2019-09-06 10:25:28 -05:00
aydreeihn
9f9292fe5d Add thread_type Patch
This commit adds the database patch to add the thread_type field to the thread_event table.

**Note: it is rebased on top of the Schedules and Ticket Merge feature in order to be the latest patch. We must merge those two features before merging this!
2019-09-06 10:04:22 -05:00
aydreeihn
e06fb467d0 Modify Draft Saving
This commit adds a button to redactor to save drafts automatically when the admin clicks it, rather than having to wait 30 seconds every time.

Note: This option currently only appears if there is an existing draft already

Also, it will automatically save drafts on tickets if a field that causes the page to refresh is clicked. These drafts save regardless of if there is an existing draft. Those fields are:

- Status
- Department
- User (includes Change Owner in dropdown)
2019-09-06 08:56:00 -05:00
aydreeihn
1071d10a0a Don't require refresh for inline edit
If an Agent uses inline edit to modify a single field, rather than saving the value and refreshing the page, the value will now populate in the form without having to refresh. This is useful in the event that an agent has begun writing a response to the user and does an inline edit before the draft has had a chance to save, causing them to lose their draft.

This fixes issue #4985.
2019-09-06 08:55:54 -05:00
Peter Rotich
07bbd00fa4 Merge pull request #5001 from JediKev/issue/user-org-tickets-export
issue: User/Org Tickets Export
2019-09-05 21:59:48 -05:00
Peter Rotich
055e356a22 Merge pull request #5002 from aydreeihn/issue/field-saving
Fix Saving For Fields:
2019-09-05 21:58:58 -05:00
Peter Rotich
dda51aaa1c Merge pull request #4990 from aydreeihn/feature/merge-tickets
Feature: Merge/Link Tickets
2019-09-05 21:58:31 -05:00
Peter Rotich
d14ba8927a Merge pull request #4984 from protich/feature/schedules
Introducing Schedules / Business Hours for SLAs (upgrade required)
2019-09-05 21:58:01 -05:00
Peter Rotich
8210f1dc77 Merge pull request #4831 from aydreeihn/issue/assigned-team-queue
Issue: Queue with Teams in Criteria
2019-09-05 21:53:56 -05:00
Jared Hancock
710af09267 redactor: Add language translations for pack building 2019-09-05 21:08:56 -05:00
Jared Hancock
c1a2fe9440 redactor: Fix placement of font buttons 2019-09-05 20:13:56 -05:00
Jared Hancock
558b5434e6 redactor: Upgrade to version 3.2.2 2019-09-05 20:13:56 -05:00
Jared Hancock
394f5a6b8a redactor: Drop breakline mode
This changes the way the Redactor editor works to create paragraph tags
(<p>) instead of div tags. Breaks can be added by pressing SHIFT+ENTER
rather than just ENTER, so there's really no significant difference in
usability. This also fixes the block system so that text direction
plugin can work now.
2019-09-05 20:13:56 -05:00
Jared Hancock
243b25d508 redactor: Reimplement image annotation plugin
This allows for editing a picture added to the Redactor to add
annotations such as arrows, boxes, circles, scribbles, and text.
2019-09-05 20:13:56 -05:00
Jared Hancock
e985d9814e redactor: Fix inspection issue in upstream code 2019-09-05 20:13:56 -05:00
Jared Hancock
8202e62acc redactor: Only show images once in the "Choose" tab 2019-09-05 20:13:56 -05:00
Jared Hancock
267668e381 redactor: Maybe initialize trans plugin
Don't initialize the translatable plugin for Redactor for single language
systems. If there is not at least one secondary language installed for the
system, then there is also no need to allow HTML fields to be translated
into--well ultimately no other language.
2019-09-05 20:13:56 -05:00
Jared Hancock
762ad43d92 redactor: Reimplement the translatable plugin
This is used in places like the help text or html fields for custom forms
where the text can be translated based on the languages installed in the
help desk.
2019-09-05 20:13:56 -05:00
Jared Hancock
8ec2cde811 redactor: Don't save empty drafts 2019-09-05 20:13:56 -05:00
Jared Hancock
81efd72805 redactor: Fixup width on page edit
Also, stretch the edit on the ticket and task view pages so that the
size of the HTML editor is roughly the size of the entries in the thread
listing.

And fixup the CSS for the file drop area so it looks connected to the
HTML editor.
2019-09-05 20:13:56 -05:00
Jared Hancock
f7b3ede7eb redactor: Add fullscreen option for undistracted editing 2019-09-05 20:13:56 -05:00
Jared Hancock
96835a721a redactor: Remove features not quite ready
This includes the textdirection plugin which allows for rotating text
direction from left-to-right to right-to-left and the imageannotate
plugin which allows for marking up images added. These features will be
reimplemented and added as separate pull requests.
2019-09-05 20:13:56 -05:00
Jared Hancock
18010e90f2 redactor: Fix signature plugin
Also fix crash on pjax page change and image "choose" insertion
2019-09-05 20:13:56 -05:00
Jared Hancock
a1116036af redactor: Continue updating plugins 2019-09-05 20:13:56 -05:00
Jared Hancock
587bb7ea1b Upgrade to htmLawed 1.2.4.1 2019-09-05 20:13:56 -05:00
Jared Hancock
9abc0548f9 redactor: Fix buttons, sizing, and remote image plugin 2019-09-05 20:13:56 -05:00
Jared Hancock
a11654f9db Fix compatibility issues with newer jQuery 2019-09-05 20:13:56 -05:00
Jared Hancock
c9c2621d3b redactor: Migrate to version 3.1.6 2019-09-05 20:13:56 -05:00
aydreeihn
fff2e29857 ORM Parentheses Patch
This commit fixes how the ORM determines if we need to add parentheses in an ORM query.

All credit goes to @greezybacon
2019-09-05 16:29:57 -05:00
Peter Rotich
9394351310 Merge remote branch 'upstream/develop-next' into develop 2019-09-05 21:01:12 +00:00
Peter Rotich
7d216929ee Merge pull request #4974 from aydreeihn/issue/required-short-answer-zero
Required Short Answer Field = '0'
2019-09-05 15:54:30 -05:00
Peter Rotich
0edfe960b0 Merge pull request #5026 from protich/issue/queue-daterange-timezone
Date Range Period  / User's Timezone
2019-09-05 15:54:00 -05:00
Peter Rotich
4f9f0feace Merge pull request #5027 from JediKev/issue/department-referral-email
issue: Department Referral Email
2019-09-05 15:53:42 -05:00
aydreeihn
a39c1153b8 Delete Threads/Entries of Deleted Tickets
This commit reallows us to delete threads and thread entries when deleting tickets by adding a column called thread_type to the thread event table that contains the same data as the object_type field on the thread table. The reason for doing this was because in the dashboard reports, we were relying on the object type in the thread table to give us accurate report data.
2019-09-05 12:56:18 -05:00
aydreeihn
a8a4dece16 Ticket Print Thread Event Times
This commit ensures that if we print thread events on Ticket PDFs, the time is never relative time, even if the agent has their time set to relative. Relative time should only be an option when viewing a Ticket online.

Additionally, we do not need to put anything related to relative time in the ticket-print template.
2019-09-05 12:48:49 -05:00
JediKev
94e770acb6 issue: Form Field Flags
This addresses an issue where any Agent can change the Type and Variable of
some of the core fields. In most cases, changing the Type and Variable of
core fields will cause issues later on down the line. With this in mind, we
need to set the flags to where Agents cannot change the Type and Variable of
specific core fields to avoid any issues. This updates the installer to
reflect the additional flags and updates the Upgrader to add these flags to
existing fields.
2019-09-05 11:17:41 -05:00
aydreeihn
15ed4b1c3c Add thread_type Patch
This commit adds the database patch to add the thread_type field to the thread_event table.

**Note: it is rebased on top of the Schedules and Ticket Merge feature in order to be the latest patch. We must merge those two features before merging this!
2019-09-05 12:56:19 -05:00
JediKev
26d2990aa8 issue: Department Referral Email
This addresses an issue where a User sending an email message with a
different Department as CC to the system will not refer the CC'ed Department
until the email is fetched a second time. The old thinking was that since
the User CC'ed the other Department the other Department should receive a
copy of the email in their mailbox. When the system fetches the User's
message from the original Department email it gets added to the thread but
doesn't refer just yet. When the system fetches the copy of the message from
the User in the other Department's email it will then refer the other
Department. This is a problem especially when you are not fetching or
forwarding from the other Department's email address. This updates
`Thread::postEmail()` to include the check for `$mailinfo['system_emails']`
and if set we refer the Department immediately.
2019-09-05 10:10:07 -05:00
aydreeihn
8dd26be957 Ticket Print Sort Order
This commit makes sure that the thread entries on printed tickets match the same order as the ticket in the helpdesk. A new function, sortEntries was added to class.thread.php so it can be called for the entries template as well as the ticket print template.

We also make sure that the order of thread entries display correctly for the client side tickets and printed pdfs of tickets.
2019-09-05 09:53:03 -05:00
JediKev
25153edf38 issue: User/Org Ticket Export
This addresses an issue where User/Orgs Ticket Exports showed ORM relation
names instead of the actual data. This is due to the User/Org Tickets Export
using the old export methods instead of the new Queue export method. This
updates the User/Org Tickets Export to utilize the new Download/Email export
method added in previous commits.
2019-09-05 09:35:55 -05:00
JediKev
cedd61210c queue: Add Filtering To Queues
This adds the ability to use Qs instead of Queue Criteria to better filter
Queues. This updates class Queue and adds two new functions `filter()` and
`getFilters()`. `filter()` simply adds the Q(s) to the new `filters`
property for later access. `getFilters()` simply returns all of the queue
filters (if any). In addition, this updates the `AdhocSearch::load()` method
to detect if the Queue's Config is an instanceof Q and if so we filter the
queue by that Q else we will use the Queue Criteria (if any).

Currently we can't search for tickets with the User's email address equal to
`example@domain.com` **OR** Collaborator’s email address equal to
`example@domain.com` as Queue Criteria is only seen as **AND** statements.
The queue criteria for this would look like:
```
array(
    array('user__emails__address', 'equal', $user->getEmail()->email),
    array('thread__collaborators__user__emails__address', 'equal',
$user->getEmail()->email),
)
```

With the new filter methods we could actually find those tickets with a Q
like:
```
Q::any([
    'user__emails__address' => $user->getDefaultEmailAddress(),
    'thread__collaborators__user__emails__address' =>
$user->getDefaultEmailAddress(),
])
```
2019-09-05 09:35:55 -05:00
JediKev
6db9507f3d issue: Default Queue Sorting
This addresses an issue where Queue Exports do not have a default sort and
therefore are sorted incorrectly by ASC (old tickets on top latest tickets
on bottom). This adds a new method to class Queue called `getColumn()` that
takes a Column ID and returns the appropriate column (useful for applying
specific sorts to a specific column). In addition this updates the
`getSortOptions()` method to check for sorts saved in the session. If sorts
for the queue are saved in the SESSION we will apply them to the Queue, if
none however we will use the Default Sort.
2019-09-05 09:35:55 -05:00
Peter Rotich
0f06f85ba2 Date Rnage Period Timezone
This commit fixes an issue where date range boundaries didn't consider
user's timezone resulting in UTC times being used.
2019-09-05 14:30:13 +00:00
Peter Rotich
78ba92c99f Datetime: Use Format::parseDateTime 2019-09-05 09:06:51 -05:00
Peter Rotich
3760579159 Merge pull request #3948 from aydreeihn/issue/ticket-preview-collabs
Issue/ticket preview collabs
2019-09-04 17:51:41 -05:00
aydreeihn
a157e98ea4 Modify Upgrader
This feature has been updated to be the patch after Schedules (#4984). That being said, this feature requires an upgrade as well, so please do not merge this to your production database. You should test the feature on a new branch until it is officially merged to the main codebase.
2019-09-04 14:26:45 -05:00
aydreeihn
69a3c0eadf Ticket Print Sort Order
This commit makes sure that the thread entries on printed tickets match the same order as the ticket in the helpdesk. A new function, sortEntries was added to class.thread.php so it can be called for the entries template as well as the ticket print template.

We also make sure that the order of thread entries display correctly for the client side tickets and printed pdfs of tickets.
2019-09-04 14:26:29 -05:00
aydreeihn
dc52561927 Ticket Preview Info
- Add the merge/link icon to the ticket preview
2019-09-04 14:05:45 -05:00
aydreeihn
efbfcd3aee When to Unlink
- Fix logic for when we should unlink tickets (changing from link to merge or changing link parent)
- Make sure if we're unlinking to change the parent we still log the link event for the new link
2019-09-04 14:05:45 -05:00
aydreeihn
ed5a36460d Minor Fixes
- allow changing merge type on mass process as well
- fix error message for merged chidlren being selected (add ticket_pid back)
- add an error to not allow merged tickets to be added manually to the form. want them to be checked in mass process so they will sort correctly
- show children tickets in the merge form within ticket view
- fix vertical scroll on merge/link modal
- scoot the merge/link icons div to the left so they don't run into the icon-trash button
2019-09-04 14:05:45 -05:00
aydreeihn
cc46a46468 Child Thread on Parent Delete
If a parent ticket is deleted, we need to go to each child thread and set the object type back to 'T' so that those tickets will show up in the ticket queue again.

Note: If a message is emailed to the child tickets (now regular tickets), they thread back to that ticket as normal
2019-09-04 14:05:45 -05:00
aydreeihn
9ae2eb1a01 Move entries of deleted children
If children tickets are deleted and then the parent is merged to another ticket and becomes a child, we have to move all thread entries, even if they were child entries.
2019-09-04 14:05:44 -05:00
aydreeihn
c12a55ea8e Display Trash Icon
Show the trash icon in the merge/link form as long as the tickets selected are not part of a merge
2019-09-04 14:05:44 -05:00
aydreeihn
7d7a3f4c5e Switch Merge Type
This commit allows you to change the merge type between combine and separate for merged tickets within the parent ticket
2019-09-04 14:05:44 -05:00
aydreeihn
db22f21f05 Code Cleanup
- Remove unneeded code
- Reduce lines of code
- Fix line spacing
2019-09-04 14:05:44 -05:00
aydreeihn
48e9ca0875 Code Cleanup
- Reduce lines of code in 'Related Tickets' tab
- Wording tweaks
- Restructure unlinking
- Make thread entry and collaborator count distinct
- Make sure all merged tickets (children included) show up for searches and saved searches
- Make sure the count for saved searches will count children merges
- Clean up redundancy in general
- Fix linking sort order (if set)
- Make sure child thread entries are separated and then sorted for separate merges
2019-09-04 14:05:44 -05:00
aydreeihn
1039b82bef Linked Icon - Searches
Make sure we still show the linked icon if necessary on searches. Merge and Link follow the same criteria but look for different flags, so if the merge flag isn't on a ticket, we should then check for the link flag
2019-09-04 14:05:44 -05:00
aydreeihn
11712fe8ee Automatic Merge Referrals
When merging tickets, if children have a different department from the parent, refer the children departments to the parent ticket. Otherwise, Agents would only be able to access the children ticket they used to have access to with a link or search because we hide merged children from the ticket queue.
2019-09-04 14:05:44 -05:00
aydreeihn
dc24f1d14f Merge/Link Annotation Alignment
Put annotations in line w/one another on the merge/link modal.
2019-09-04 14:05:44 -05:00
aydreeihn
b4d6266ea5 Referrals and Child Relationships
- Create a child_thread relationship on tickets so that children tickets can be searched
- For Ticket::getThread if the ticket does not have a thread but it has a child_thread, return the child_thread
- Add referred children tickets to staff's ticket visibility
- Do not change the object_id in the thread table
- Allow ticket merge if Agent has referral access to a Ticket
- Hide children tickets from queues
- Make sure children tickets can be searched
- Remove getIdByObjectId function (no longer needed)
- Remove children tickets from queue counts
2019-09-04 14:05:44 -05:00
aydreeihn
a2ce67fbf4 Hide Manage Collaborators for Merge/Link
- Pass a new variable, $manage, to the previewCollaborators function (and in turn the showCollaborators function) so that we can specify when we want the 'Manage Collaborators' option to be available
- Set the new variable every time one of those functions are called
2019-09-04 14:05:44 -05:00
aydreeihn
576603f4a5 Code Cleanup
- make user + collabs the default option. make sure they still have option to drop collabs if the users are the same
- Space out the 'Delete Child Ticket' and 'Move Child Tasks to Parent' checkboxes
- We should show the Participants dropdown regardless of users on Tickets because if it was ever hidden, other Tickets could be added to the form that would need to see the options and it's a static form field (doesn't pop up if a Ticket is added w/diff user or collabs)
2019-09-04 14:05:44 -05:00
aydreeihn
0cfa9fb317 Ticket Merge Patch
- Update event.yaml
- Events added to newest patch

Note: new fields were already done previously w/merge version 1
2019-09-04 14:05:44 -05:00
aydreeihn
e8e02c78d3 Thread Entry Annotation + Code Cleanup
- Add annotation for thread entry count (if any)
- Fix ticket links
2019-09-04 14:05:44 -05:00
aydreeihn
9907c08ea5 Participant Options
This commit will give the Agent the option to move participants to the parent ticket based on whether the user on multiple tickets is the same or different as well as if there are any collaborators involved in the tickets.
2019-09-04 14:05:44 -05:00
aydreeihn
2a4bec502f Merge/Link Annotation + Enhance Ticket Listing
This commit adds an icon to the merge tickets form that shows child tickets when hovered over.

Additionally:
- pull annotations to the far right
- Only show annotations if the count is > 0
- Decide whether to show link or merge annotation based on the merge type
- Add a new collaborator annotation for the collaborator preview
- Put the ticket preview on the ticket number rather than collaborator preview
2019-09-04 14:05:44 -05:00
aydreeihn
9f17dcf5b1 Task Handling
- Give an option to move child tasks to parents for merges
- Add a task count to the merge/link field
- Make sure the tickets display the same info on mass process and adding tickets individually
2019-09-04 14:05:44 -05:00
aydreeihn
06d0ece62c Code Fixes/Cleanup
- make sure ticket #, subject, and user name appear when adding new tickets to the form
- use getThread() function instead of ->thread since a ticket could be a child which has no thread (it uses the parent thread)
2019-09-04 14:05:44 -05:00
aydreeihn
6356330bc6 Task Handling
- Move tasks to parent if deleting children
- Make sure thread entries work correctly for tasks and tickets
2019-09-04 14:05:43 -05:00
aydreeihn
d9b62e6758 Restructure Code
- Make sure that for both mass process and ticket-view merge/link, we're getting tickets by filtering,not lookups
- Move getMergeType beside relevant functions
- Create function to get merge types based on flags
- Add Subject and User Name to Merge/Link form
2019-09-04 14:05:43 -05:00
aydreeihn
90cc7598b2 Front End Merge Handling
- Show merged thread events to Users
- Put a warning for the Users logged into the front end to let them know they can’t reply to merged children
        - Put a link to the Parent where they can reply
- Allow a User to view and reply to a parent ticket even if they're not the ticket owner or a collaborator (they can reply via email anyway)
	- This will add them as a collaborator to the parent
- During a merge, if the users are differnt, give the option to move users or users + collaborators to the parent (remove the 'none' option)
2019-09-04 14:05:43 -05:00
aydreeihn
aadf478685 Feature Cleanup/Modifications
- Put checkboxes before label text on Merge/Link form
- Move 'Delete Child Ticket' option to bottom of form
- Add extra info to tickets on Merge/Link list
	- Subject
- Minor fix with Link annotation so it shows up everywhere
- Make the tickets div in the Merge/Link form scrollable
2019-09-04 14:05:43 -05:00
aydreeihn
39e68c4e4e Remove Show Children from Link
This commit removes the option to show child thread entries on visual merges. If an Agent wants to see all thread entries together, they should perform a merge. If they want to see thread entries from child tickets somewhere within the Parent Ticket, they should use Thread Preview on the Related Tickets tab.
2019-09-04 14:05:43 -05:00
aydreeihn
ec1fbecd45 Merging a Linked Parent
If a linked parent is merged into another ticket w/a separate or combine merge, what should happen to the linlked children?
	I want it to just unlink the children and handle the parent as usual
2019-09-04 14:05:43 -05:00
aydreeihn
b7b25d261a Code Fixes/Cleanup
- Set the linked flag in the setMergeType function
- Make sure the parent and children tickets' merge types are set each time merge is called
- Make sure we always log a thread event for merges/links on all related tickets
- Make sure no flags are set if child tickets are deleted upon merge
- Make sure we save the parent ticket when choosing whether to show child tickets in link
- Fix the reload page function
2019-09-04 14:05:43 -05:00
aydreeihn
01396e179e Option to Move User/Collaborators
When merging tickets, give the option to move the user and/or collaborators if they differ from the current parent user.
2019-09-04 14:05:43 -05:00
aydreeihn
e8195b8604 Change 'Visual Merge' to Link
- Create Role permission for linking tickets
- Logic to show/hide merge or link option depending on what is chosen
- Change 'split' event to 'unlink'
- Write thread events for link and unlink
- Add link annotation
- Add link column
- Make merge and link available in advanced searches
- Make merge and link exportable
- Make sure merged Tickets cannot be linked
2019-09-04 14:05:43 -05:00
aydreeihn
821e5618e9 Disable Children From Merge Part 2
This commit disables children from being allowed to be a part of new merges when merging from an individual ticket. It also makes sure that the merge type cannot be changed.
2019-09-04 14:05:43 -05:00
aydreeihn
42d375c98b Object Ensurance
Check to see if we have Threads/Collaborators before trying to call a function from them.
2019-09-04 14:05:43 -05:00
aydreeihn
0218d4cabb Disable Children From Merge
This commit disables children from being allowed to be a part of new merges on mass process merge
2019-09-04 14:05:43 -05:00
aydreeihn
a1273b5d53 Merge Indicators
This commit makes sure that we show merge indicators, whether it is an annotation or the Merged column, for both parent and child tickets.
2019-09-04 14:05:43 -05:00
aydreeihn
1f8f9e6b53 Delete Child Ticket Issue
This commit ensures that if you choose to delete child tickets when doing a merge, we set the parent ticket's merge type to visual. Since the child ticket merged into it no longer exists, the parent ticket should act as a normal ticket that can continue to be merged as needed with any other ticket.
2019-09-04 14:05:43 -05:00
aydreeihn
0c25dd7673 Merged Thread Fixes
- Do not show collaborator information for merged tickets because their thread is now the parent ticket's
- only do the thread lookup one time to eliminate unnecessary calls
- Adjust getThread and getThreadId methods to account for the merge feature
	- getThread adjustments allow us to still see the thread events for child tickets
2019-09-04 14:05:43 -05:00
aydreeihn
3ba74361c1 Allow Further Merging
- make it to where you can merge other tickets to a parent, but the options are locked down for already merged tickets.
	Ex: if already separate option, that should be the only option moving forward
- prevents admins from trying to merge tickets together if more than one parent ticket is selected for merging.
- make sure only visual merges allow you to change who is the parent
2019-09-04 14:05:43 -05:00
aydreeihn
e1f1bea8d1 Delete Child Ticket Option
This commit adds an option for the Agent to delete the child ticket when doing a Separarate or Combined merge. A warning pops up so the Agent knows which Ticket will be deleted.
2019-09-04 14:05:42 -05:00
aydreeihn
3a6aa2d934 Merge Availability
Make sure we do not show the rest of the form to add more tickets if merge is already in place
2019-09-04 14:05:42 -05:00
aydreeihn
414e0820e6 Issue: Ticket View Permissions for Merged Tickets
This commit changes merged Ticket permissions to the following:

If the Agent does not have access to the Child ticket and the threads are merged, they should not be allowed to view the Parent. If the threads are not merged, the Agent should still be able to access the Parent Ticket.
2019-09-04 14:05:42 -05:00
aydreeihn
8c54f4612c For merged threads, when hovering over the merge icon, put the Ticket # if possible, otherwise, put 'Merged' 2019-09-04 14:05:42 -05:00
aydreeihn
dcc6c1fd05 Make sure we add thread events for merge/split in both the parent and child ticket. 2019-09-04 14:05:42 -05:00
aydreeihn
4a18749cf8 Ticket Merge Feature Additions
- Change visual flag to separate thread flag. Visual should be the default since messages will route to them the same way they route to unmerged tickets
- Modify code as needed to account for possibly not having a thread when getThread() is called
- UI change to merge ticket template to include Merge Types
- Allow visually merged tickets to be split
- Make thread entries display according to the merge types for Combined and Separate merges
- Make responses to child tickets for combined or separate merges thread to the parent ticket
    - When posting a message, we need to check to see if the ticket is a parent or a child, and if it is for a child, which type of merge it is for. From there, we must decide which ticket the message should go to and route it accordingly with the new $ticket variable (instead of using $this).
    - Block replies on child tickets
    - Create an object type 'C' for child tickets that will allow us to correctly set the extra field for incoming thread entries that were made to children tickets
2019-09-04 14:05:42 -05:00
JediKev
f0a72c7d24 issue: getObjectType Typo
This addresses a typo of `getObJectType()`, this should be
`getObjectType()`.
2019-09-04 14:05:42 -05:00
aydreeihn
20992509aa Option to hide Children Thread Entries
This commit gives Agents the option to hide children thread entries on parent Tickets using a checkbox on the Merge Tickets modal. If hidden, the Agent is still able to see the related children Tickets in the 'Related Tickets' tab of the Parent Ticket. The thread entries will be hidden by default.
2019-09-04 14:05:42 -05:00
aydreeihn
64296fae64 Merge Thread Entries Fix
This commit fixes an issue on the order of merged thread entries. We needed to do a UNION instead of a UNION ALL in order for them to show up in the correct order.
2019-09-04 14:05:42 -05:00
JediKev
bb7f8f6c4e merge: Set Children Statuses
This pull adds the option to set the status of all Child Tickets if setting
status of a Parent Ticket. This is helpful for situations like closing a
Parent Ticket and needing to close all Children as well. This option is only
visible when setting the status of a Ticket with Children.
2019-09-04 14:05:42 -05:00
Peter Rotich
7d2bad1fe3 Implement Thread Preview 2019-09-04 14:05:42 -05:00
Nathan Febuary
9218a426a8 Jquery double click issue fix
Fixes the funky double click after a message is expanded now there are
only single clicks.
2019-09-04 14:05:42 -05:00
Nathan Febuary
46e9d15496 Thread preview design and function modification
Changes to the new ticket thread preview design. Removes avatars and
makes color changes to the header ticket when collapsed. Thread preview
expands when clicked and collapses when header is clicked.
2019-09-04 14:05:42 -05:00
Nathan Febuary
9ca465ff61 Add preview option of threads in a ticket. 2019-09-04 14:05:42 -05:00
root
7e157c4751 PHP 7.1 Errors
This commit fixes PHP 7.1 warning messages.
2019-09-04 14:05:42 -05:00
aydreeihn
f90627b95f Code Fixes
- Do not check merge type for Tasks
2019-09-04 14:05:42 -05:00
aydreeihn
7638584312 Additional PHP 7.1 fixes for class.filter.php 2019-09-04 14:05:42 -05:00
aydreeihn
d2be8b8ae5 Completely Hide Disabled Fields
If a Field is disabled, it will not be shown anywhere in the system (ticket view, search, export).
2019-09-04 14:05:42 -05:00
aydreeihn
4915c5582d Code Fixes:
- Ensure that we do not put the merged icon on task threads
- Make sure we remove the parent_id on child tickets if we delete the parent ticket
2019-09-04 14:05:42 -05:00
aydreeihn
3d77c4329e Issue: Ticket # Containing Letters
This commit fixes an issue where we could not merge Tickets if the Ticket# included letters.
2019-09-04 14:05:42 -05:00
aydreeihn
c870df0f52 Ticket Merge Version 1
This feature implements a basic, visual Ticket Merge where thread entries from other Tickets can be made visible on a Parent Ticket.
2019-09-04 14:05:41 -05:00
Peter Rotich
8cd995b338 Datetime: Use Format::parseDateTime 2019-09-04 14:05:32 -05:00
aydreeihn
c3eaec1f68 Fix Saving For Fields:
This commit fixes/cleans up how we do the getChanges function in the FormField class. It also fixes saving/displaying the following field types:

- Multiselect Choices (clearing all options)
- Assignee Field
- Department Field
- Priority Field
2019-09-04 13:54:01 -05:00
Peter Rotich
54e06e9bae oopsie: Revert mistaken change on field__op split
Commit af322a41d introduces a new field operator and in an attempt to
simplify how a field and it's operator is split a bug was introduced when a
field with a nested complex name is being split.

This commit reverts to the original "complex" splitter.
2019-09-04 18:46:05 +00:00
Peter Rotich
d15757eda2 Make sure Schedule Entries are unique per Schedule
The system assumes one entry per day - meaning no individual day chunking is
allowed within the same schedule unless it's an exclusion via a Holiday
schedule on a Business Hours schedule.
2019-09-04 18:46:05 +00:00
Peter Rotich
6b19b423d4 Fixes: Address PHP 7.3 warnings
Also makes sure schedule is truly saved in sla plan page

All Credit goes to @aydreeihn
2019-09-04 18:46:05 +00:00
Peter Rotich
28daf367a3 Onetime Entries: Stop on end date & time 2019-09-04 18:46:05 +00:00
Peter Rotich
17f958c411 CheckOverdue: ORM implementation
This commit implements checking for overdue tickets in ORM.
2019-09-04 18:46:04 +00:00
Peter Rotich
aa4b51df9e Introducing the concept of Schedules
Schedules can be used to specify when SLA are active by defining Business
Hours and Holidays.
2019-09-04 18:46:04 +00:00
Peter Rotich
0146ee6769 VisibilityConstraint: Add support for neq
Support 'not equal' on visibility constraints
2019-09-04 18:46:04 +00:00
Peter Rotich
932276a3b1 FormRenderer: Show empty Label
This is necessary to make sure fields still line-up even when label is not
provided.
2019-09-04 18:46:04 +00:00
Peter Rotich
342e724712 Add setting to hide/show timezone hint
This is necessary for timezone agnostic date/time inputs.
2019-09-04 18:46:04 +00:00
Peter Rotich
a3c0cbac26 Add ORDINAL suffix to a number
e.g 1st, 2nd, 3rd etc.
2019-09-04 18:46:04 +00:00
Peter Rotich
9e3692931d VisibilityConstraint: Change watcher
Make JS checker function unique for each field/widget.
2019-09-04 18:46:03 +00:00
Peter Rotich
fad2ed8803 TimeField: Add initial stump of TimeField
This commits introduces TimeField and it's picker widget. The field uses
jQuery ui & datetimepicker addon for time input.
2019-09-04 18:46:03 +00:00
Peter Rotich
5f02941caf Datetime: Use Format::parseDateTime 2019-09-04 18:46:00 +00:00
Peter Rotich
9e3a0a7c93 ChoicesWidget: Allow numeric zero option
Use strict type check comparison when checking if a choice value equals the
default value. This is necessary to allow for choices with numeric zero (0)
    as the value.
2019-09-04 18:45:08 +00:00
Peter Rotich
d5c5848cd7 CheckboxWidget: getValue
Return default value when data source is not set - this is necessary for
Visibility Constraint that's dependent on the value of a checkbox field.
2019-09-04 18:45:07 +00:00
Peter Rotich
66dba5d524 Form::process
Adds a routine similar to getClean but forms downstream can use it to return
database ready data. This is especially necessary when UI elements don't
match database fields.
2019-09-04 18:45:07 +00:00
Peter Rotich
5476c536c1 CheckboxWidget: Support setting value by field Id.
This commit adds ability to set initial checkbox value via source data
2019-09-04 18:45:07 +00:00
Peter Rotich
39771f8b6a Field Visibility: Add multi-option constraint
This commit adds ability to add visibility constraint that is dependent on
multiple options. It also addresses cases where constrain is on an existing
or misspelled field.
2019-09-04 18:45:07 +00:00
Peter Rotich
06816206e3 Merge pull request #5024 from JediKev/i18n/register-inc
i18n: Register Include
2019-09-04 13:17:54 -05:00
JediKev
9b18dd65d4 i18n: Register Include
This addresses issue 4965 where the register.inc.php file for clients was
missing translations for the action buttons.
2019-09-04 11:25:00 -05:00
Peter Rotich
68f11e1f0e Lint Fix 2019-09-04 15:17:48 +00:00
Peter Rotich
d991f2bd0d Merge remote branch 'upstream/develop-next' into develop-next 2019-09-04 15:10:48 +00:00
Peter Rotich
44f986f181 Merge remote branch 'upstream/develop' into develop-next 2019-09-04 15:10:41 +00:00
Peter Rotich
cee3222daf Merge pull request #4968 from JediKev/issue/set-staff-password-on-creation
issue: Set Staff Password On Creation
2019-09-04 09:43:00 -05:00
Peter Rotich
e295422ffe Merge pull request #5022 from aydreeihn/issue/php73
Update osTicket Requirements
2019-09-03 16:07:06 -05:00
aydreeihn
a6a18eea53 Update osTicket Requirements
- PHP 7.0-7.3
- MySQL 5.5
2019-09-03 15:36:58 -05:00
Peter Rotich
19ac222c4d Use hidden <a> link to download export file
This commit addresses "Failed to load resource: Frame load interrupted"
thrown by Safari when a  url results in a file download by adding a hidden
HTML compliant anchor element to trigger the file download without the
error.

Thanks to @JediKev for the tip.
2019-08-31 02:26:16 +00:00
Peter Rotich
d5505a3d13 Move Ack and Finalize to Exporter class 2019-08-31 00:59:13 +00:00
Peter Rotich
6c5ef9f0f6 Make export Id unique and url safe
The commit also makes sure the prefix used on temp file is file name safe.
2019-08-30 20:35:51 +00:00
Peter Rotich
7c93f4acaf Retire the old export route 2019-08-30 14:40:05 +00:00
Peter Rotich
5d31bf8a21 Merge pull request #4980 from JediKev/feature/expanded-print-view
feature: Expanded Print View
2019-08-30 09:26:29 -05:00
Peter Rotich
7b8f2ed775 Merge pull request #4993 from JediKev/issue/dashboard-no-help-topics
issue: Dashboard No Help Topics Error
2019-08-30 09:23:26 -05:00
Peter Rotich
e59f3688de Merge pull request #5010 from aydreeihn/issue/php73
Update osTicket Requirements
2019-08-30 09:21:53 -05:00
Peter Rotich
5c6582611a Merge pull request #5012 from aydreeihn/issue/devnext-php73
Issue: Undefined Constant Warning
2019-08-30 09:21:37 -05:00
Peter Rotich
02a5a0a957 CsvExporter: Utilize Exporter on queue export
This commit changes how queues are exported by utilizing the new exporter.
It also provide a framework on how exports will be done going forward.
2019-08-29 16:25:09 +00:00
Peter Rotich
fa3262ba3b Add Exporter
This commits revisits how export is done by introducing the concept of
exporter with the goal of replacing SQL based exports which are prone to
memory and timeout issues.

Adds ability to create temporary files for the export data which can be
downloaded or emailed to the requester.
2019-08-29 16:25:00 +00:00
Peter Rotich
f9b7c2279b Mailer: Suppprt FileObject attachments
This commit adds support for FileObject attachments. It also changes the
routine called to get mime type. This is necessary to avoid conflict in
SplFileObject class extended by FileObject.
2019-08-29 16:21:50 +00:00
Peter Rotich
aac4096257 Add FileObject class which extends SplFileObject
This will give us OO interface to files making it easy to pass it around.
2019-08-29 16:21:50 +00:00
Peter Rotich
045f6a6aae HTTP Flush
Add http routine to flush the content to requester.
2019-08-29 16:21:50 +00:00
aydreeihn
c2ca730384 Issue: Undefined Constant Warning
For the is_a function, the class name should be in quotation marks to avoid the warning in PHP 7.3
2019-08-28 09:17:04 -05:00
aydreeihn
27f157892f Update osTicket Requirements
Recommend PHP 7.3
2019-08-27 16:03:30 -05:00
Peter Rotich
cc879b72f6 Merge remote branch 'upstream/develop-next' into develop-next 2019-08-26 17:17:53 +00:00
Peter Rotich
6ff70cab66 Merge remote branch 'upstream/develop' into develop-next
Conflicts:
	bootstrap.php
	include/ajax.orgs.php
	include/class.dept.php
	include/class.file.php
	include/class.organization.php
	include/class.staff.php
	include/staff/profile.inc.php
2019-08-26 17:17:39 +00:00
Peter Rotich
e8b9ac1e5a Merge pull request #4999 from aydreeihn/issue/inline-ticket-assign
Issue: Inline Ticket Assignment
2019-08-26 11:57:30 -05:00
Peter Rotich
0fd3bd4e96 Merge pull request #4982 from JediKev/issue/error-on-queuesort-config
issue: Error On QueueSort Config
2019-08-26 11:42:58 -05:00
Peter Rotich
48e10195ec Merge pull request #4879 from aydreeihn/issue/auto-assignment
Issue: Reopen Assignment
2019-08-26 11:34:07 -05:00
Peter Rotich
a2017cfa88 Merge pull request #4970 from JediKev/issue/image-attachment-view
issue: Image Attachment View
2019-08-26 11:31:31 -05:00
Peter Rotich
a06ccc1cb1 Merge pull request #4988 from JediKev/issue/update-installer-php-reqs
issue: Update Installer PHP Requirements
2019-08-26 11:29:20 -05:00
Peter Rotich
e7624b5d40 Merge pull request #4996 from JediKev/issue/support-exchange-shared-mailbox-auth
issue: Support Exchange Shared Mailbox Auth
2019-08-26 11:27:54 -05:00
Peter Rotich
8042eb0864 Merge pull request #4954 from JediKev/issue/adv-search-default-sort
issue: Advanced Search Default Sorting
2019-08-26 11:24:57 -05:00
Peter Rotich
4bf16ff647 Merge pull request #4971 from aydreeihn/issue/admin-alert
Fix Admin Alert
2019-08-26 11:23:44 -05:00
Peter Rotich
bd668c0931 Merge pull request #4989 from JediKev/issue/update-outdated-links
issue: Update Outdated Links
2019-08-26 11:23:03 -05:00
Peter Rotich
d0b47a0263 Merge pull request #4991 from protich/issue/org-update
Organization Update
2019-08-26 11:22:45 -05:00
JediKev
ac9ea5b9b9 issue: Support Exchange Shared Mailbox Auth
This addresses an issue where the system cannot successfully authenticate to
an Exchange server using shared mailbox auth credentials (eg. Username:
`main-user@domain.com\shared-mailbox@domain.com`). The system passes the
entire Username value as the `username` parameter for `imap_open()` and
Exchange fails to authenticate. This adds two new variables called
`authuser` and `username` to class MailFetcher. This also updates the
`MailFetcher::__construct()` method to explode the Username value at the
backslash giving us two parts: the Authentication Username and the Mailbox
Username. If there are in fact two parts we will assign the first part to
the new `authuser` variable and assign the second part to the new `username`
variable. If we detect an `authuser` we will add it to the `imap_open()`
flag called `authuser` and append it to the `srvstr`. In addition this
updates the `MailFetcher::getUsername()` method to return the new `username`
variable instead of the hash table data.
2019-08-21 12:03:43 -05:00
aydreeihn
b757ec49d1 Issue: Inline Ticket Assignment
Within a Ticket, if you click the Assign dropdown and choose Agent or Team, the possible assignees are filtered based on who can be assigned to the Department, however, the inline Assigned To option did not filter the possible assignees. This commit ensures that we do filter possible assignees when assigning via inline edit.
2019-08-21 10:12:41 -05:00
JediKev
ab0cdc63ea issue: Dashboard No Help Error
This addresses an issue reported on the Forum where visiting the Agent
Dashboard with no Help Topics in the system completely breaks the Dashboard
view and throws a database error `You have an error in your SQL syntax;
check the manual that corresponds to your MySQL server version for the right
syntax to use near ') GROUP BY A1.topic_id' at line 1`. This is due to the
statistics code assuming we will always have `$topics` but this is not
always the case, as some people rock their helpdesk without a single Help
Topic. This adds a check to see if `$topics` is empty and if so, we return
the appropriate headers with an empty array as the plot data. This will
avoid the database error and show the appropriate Dashboard view with no
statistics listed under "Topics" tab.
2019-08-19 12:34:47 -05:00
Peter Rotich
15883448d1 Organization Update
This commit addresses an issue where updating (editing) organization from
User's page resulted in ALL settings getting cleared. The change makes sure
the update is routed to the proper routine.
2019-08-15 18:33:19 +00:00
Kevin Thorne
dda483ebdc issue: Advanced Search Default Sorting
This addresses an issue where conducting an Advanced Search will show the
results in ASC order (from oldest to most recent) by default. If there are
no keywords the search is supposed to show the results in DESC order (from
most recent to oldest) by default. If there are keywords the search is
supposed to show the results sorted by `relevance`. This adds additional
`select` options to the search criteria for keyword searches so that we can
use `relevance` in the outer query. This also adds an `order_by` to the
tickets to order them by the `relevance` in `DESC` order. In addition this
adds a new `order_by` to sort the results by `created` in DESC if there are
no keywords.
2019-08-15 11:04:13 -05:00
JediKev
15d678beb2 issue: Update Installer PHP Requirements
This updates the Installer PHP Requirements from `5.4` to `5.6`. This
updates the `$prereq` variable to be protected and updates depending methods
so they can use the static variable.
2019-08-15 10:22:26 -05:00
Peter Rotich
a2145bdc74 Merge pull request #4973 from JediKev/issue/reset-role-perms
issue: Reset Role Permissions
2019-08-14 19:15:22 -05:00
Peter Rotich
fefed14725 Merge pull request #4964 from JediKev/issue/this-version-utilize-major-version
issue: THIS_VERSION Utilize MAJOR_VERSION
2019-08-14 19:14:23 -05:00
JediKev
25bf88f429 issue: Update Outdated Links
This updates all the old, outdated osTicket links in the software. This
includes things like the forum URL, the support URL, the Installation Guide
URL, etc.
2019-08-14 14:18:39 -05:00
JediKev
eb1a4eafb9 issue: Image Attachment View
This enhances security patch (33ed10) to allow image attachments to be
opened in a new tab if the setting is enabled. This adds a new setting to
the Agent Profile labeled "Image Attachment View" that determines how image
attachments are handled. The two options are "Download" and "Inline" with
"Download" being the default. If the option is set to "Download" all image
attachments will be forced to download. If the option is set to "Inline" all
image attachments will open in a new tab when you right click + open in new
tab.
2019-08-13 09:53:00 -05:00
JediKev
0c2cecb6d5 issue: Reset Role Permissions
This addresses an issue reported on the Forum where clicking the "Reset
Permissions" action in the Agent Directory shows a blank popup. Inspecting
the console shows 500 error and checking the error logs shows `Too few
arguments to function` error. This is due to the
`RolePermission::__construct()` method expecting 1 parameter but in
`ajax.staff.php` we are not passing anything to it. This updates
`resetPermissions()` to pass `null` to `RolePermission::__construct()` so
that it doesn't complain and error out.
2019-08-13 09:25:41 -05:00
JediKev
1b1e742894 issue: Error On QueueSort Config
This addresses an issue where clicking on Config next to a Queue Sort will
show a blank popup. Upon viewing the error logs you receive the error `Call
to a member function asTable() on null`. This is due to defining
`$data_form` inside of the `if ($_POST)` block instead of defining it
outside the block. This updates `SearchAjaxAPI::editSort()` to define
`$data_form` outside of the `if ($_POST)` block so that `$data_form` is
always set.
2019-08-07 15:46:58 -05:00
aydreeihn
c58916b059 Required Short Answer Field = '0'
This commit fixes an issue where trying to save the value '0' to a required short answer field would not save because it did not register that the field contained a value.
2019-07-31 16:20:24 -05:00
aydreeihn
5f6bd42f76 Fix Admin Alert
This commit fixes an issue where alerts are not sent out to the Admin Email if a Department does not have any primary or extended members.

Now, if the Admin Email is checked for the New Ticket Alert and a Department does not have any members at all, an Alert will still go out to the Admin unless the Department recipients field is set to 'No one (diable Alerts and Notices)'

To make things more clear, an option has been added to have the 'Admin Only' as the recipient, so the Alert will go out ONLY to the Admin if  selected and the New Ticket Alert is enabled for the Admin Email.

If 'No one (diable Alerts and Notices)' is selected, no alert will go out at all, regardless of what is checked in Settings | Tickets | Alerts and Notices
2019-07-31 08:50:11 -05:00
JediKev
d9108b1102 issue: Set Staff Password On Creation
This addresses an issue reported on the Forum where setting a password for
an Agent upon creation doesn't save the password in the backend. This means
if you set a password, click Create, and then try to login as the agent you
will be denied access (as there is no password saved). We store the
PasswordResetForm data in the session for later use but we do not actually
use the form data anywhere in the `Staff::update()` method. This updates the
`Staff::update()` method to include a check for the form data and if exists
sets the password and saves it in the backend. This maintains current
functionality where if `Send the agent a password reset email` is enabled
then we do not set the password, instead we send the Agent a registration
email.

In addition, this updates the `StaffAjaxAPI::setPassword()` to include
password validation so if a password is not valid we do not save it.
Instead, we will keep the modal open and throw validation errors until a
valid password is given. This means the form data will not be stored in the
session until we have a valid password.
2019-07-29 15:07:43 -05:00
JediKev
5b4c512478 issue: THIS_VERSION Utilize MAJOR_VERSION
This addresses an issue where using osTicket from git would show the
incorrect git version in `Admin Panel > Dashboard > Information`. This is
due to a hardcoded git version of `1.8-git`. This updates `THIS_VERSION` to
utilize `MAJOR_VERSION` so that it sets the correct git version. This also
updates the `deploy` CLI module to match the same format (example:
`1.12-git`).
2019-07-26 11:55:56 -05:00
JediKev
a5d898b266 Add Release Notes for v1.12.2 2019-07-26 10:42:33 -05:00
JediKev
505bcbb1bd Merge remote-tracking branch 'origin/develop' into develop-next 2019-07-26 10:25:56 -05:00
JediKev
25d775e4e4 Merge pull request #4962 from JediKev/issue/readme-image-size
Reviewed-by: JediKev <kevin@enhancesoft.com>
2019-07-26 10:23:28 -05:00
Peter Rotich
f8fd20f6a0 Merge pull request #4024 from nicoletta-maia/develop-issue_migrate_empty_file
Issue: manage.php file migrate fails when files have size=0
2019-07-26 10:17:23 -05:00
Peter Rotich
7869644b70 Merge pull request #4963 from JediKev/issue/datetime-field-remove-unused-vars-use-parse-date-time
issue: DatetimeField Remove Unused Vars / Use parseDateTime()
2019-07-26 10:12:33 -05:00
JediKev
d9aa91b149 issue: DatetimeField Remove Unused Vars / Use parseDateTime()
This addresses an issue where creating a ticket with a Due Date set fails
with an error of `Select a time from the list`. This is due to unused
variables in the `Ticket::create()` function. This also improves the
datetime conversion to GMT by using `Format::parseDateTime()` instead of
trying to create a DateTime object directly which also provides a fallback
if an incorrect time. This can correctly determine the timezone (if present)
and return a proper DateTime object.
2019-07-26 10:10:13 -05:00
JediKev
8b90010c7c issue: README.md Image Size
Last one I promise ;) This addresses the sizing issue of the logo in the
`README.md` file.
2019-07-26 09:59:41 -05:00
Peter Rotich
889684bcda Merge pull request #4960 from JediKev/issue/readme-osT-logo
issue: README.md osTicket Logo
2019-07-26 09:46:08 -05:00
Peter Rotich
dbfaa60681 Merge pull request #4961 from JediKev/issue/v1-12-git-major-version
issue: v1.12 Git MAJOR_VERSION
2019-07-26 09:44:33 -05:00
JediKev
3f80266462 issue: v1.12 Git MAJOR_VERSION
This addresses an issue where if you’re running an outdated version of the
1.12 series, the latest version it shows available is the latest release of
the 1.10 series. This updates the `MAJOR_VERSION` variable used to check for
the latest release for the series you’re currently on so that it shows the
appropriate release.
2019-07-26 09:37:15 -05:00
JediKev
71210433ed issue: README.md osTicket Logo
This adds the osTicket logo to the `images/` folder so that we don't have to
reference a URL that might change in the future. In addition this updates
the osTicket logo reference in the `README.md` file to point to the new
location.
2019-07-25 14:29:21 -05:00
JediKev
a8c4f57b19 Add Release Notes for v1.12.1 2019-07-25 10:06:44 -05:00
JediKev
281d4faef7 Merge branch '1.10.x' into 1.12.x
Conflicts:
	WHATSNEW.md
2019-07-25 10:05:10 -05:00
JediKev
dca01e13d1 Add Release Notes for v1.10.7 2019-07-25 09:14:03 -05:00
Peter Rotich
24c664c2b4 Merge remote branch 'upstream/develop-next' into 1.12.x 2019-07-25 13:55:22 +00:00
Peter Rotich
082aeec103 Merge remote branch 'upstream/develop' into develop-next
Conflicts:
	include/class.file.php
2019-07-25 13:54:09 +00:00
Peter Rotich
306b7ef843 Merge pull request #4959 from JediKev/security/html-file-browser-execution-windows-ie-firefox
security: HTML File Browser Execution (Windows: Firefox/IE)
2019-07-25 08:42:04 -05:00
JediKev
33ed106b16 security: HTML File Browser Execution (Windows: Firefox/IE)
This addresses an issue reported by Aishwarya Iyer where attached HTML files
are executed in the browser instead of forcing download in Firefox and IE
for Windows specifically. This is caused by an incorrect
`Content-Disposition` set in the `AttachmentFile::download` function.
Instead of attachments having a disposition of `attachment` (which forces
download) they have a disposition of `inline` (which displays the file
contents in the browser). This updates the download function to use whatever
disposition is passed (for S3 plugin), if none it defaults to `attachment`.
In addition, this overwrites the disposition and sets it to `attachment`
after the `$bk->sendRedirectURL()` so that S3 attachments still work and the
issue of an attacker passing their own disposition is mitigated.
2019-07-24 16:37:43 -05:00
Peter Rotich
94d24a5194 Merge pull request #4957 from JediKev/issue/is-formula-dotall-mode
issue: is_formula Dotall Mode
2019-07-24 13:26:20 -05:00
Peter Rotich
db0cf05c51 Merge pull request #4955 from aydreeihn/issue/add-collab-refresh
Add/Remove Collabs Without Refresh
2019-07-24 13:24:41 -05:00
aydreeihn
ec82131e8c Merge pull request #4951 from protich/feature/datetime-picker
Datetime picker
2019-07-24 13:23:17 -05:00
aydreeihn
5a5044abed Add/Remove Collabs Without Refresh
This code allows users to Manage Collaborators without the page refreshing so that they will not lose any drafts that might not have been saved yet. Instead, adding/removing collaborators will show up instantly in the active collaborators section.

This code also removes the http response from the updateCollaborators function. This triggers collaborators.tmpl.php to correctly update the active collaborators section without needing to refresh the page.
2019-07-24 13:19:22 -05:00
Peter Rotich
c38f59e726 Merge pull request #4958 from JediKev/issue/class-format-disposition-misspelling
issue: Class Format Disposition Misspelling
2019-07-24 10:41:32 -05:00
JediKev
1d3f1a30e8 issue: Class Format Disposition Misspelling
This corrects the spelling of `deposition` to `disposition` so that it's
correctly utilized.
2019-07-23 15:16:12 -05:00
JediKev
992e904418 issue: is_formula Dotall Mode
This addresses an issue where having a new line in a standard, non-richtext
textarea field fails on `is_formula` validation. This is due to the regex
not running in Dotall mode, which does not match new line characters. Dotall
mode makes the dot (`.`) character match anything _including_ new line
characters. This adds the `s` flag to the regex so that new lines are
properly matched.
2019-07-23 09:53:08 -05:00
Peter Rotich
f2c3505bc0 Use DateTime Parser to parse DatetimeField value 2019-07-22 14:32:17 +00:00
JediKev
b2bd45fcc2 feature: Expanded Print View
This feature adds a new Print option labeled "Thread + Internal Notes +
Events" that, when clicked, will print the entire Ticket Thread with
Internal Notes AND all of the Thread Events. This also adds a new option in
the Ticket Print Options labeled "Print Events". Previous print options only
included the Thread only or the Thread + Internal Notes, but people want
more! This inserts the events in the correct order just like it is in the
Ticket View. The only difference between the PDF Thread Events and the
Ticket View Thread Events is the styling. In the Ticket View each event has
it's own icon to separate/differentiate them between the others. In the PDF
the events will not have their own icons rather their own background to
separate/differentiate them.
2019-07-22 09:14:06 -05:00
Peter Rotich
3aae5cf19f Account for ISO Date timezone indicator 2019-07-21 17:46:22 +00:00
Peter Rotich
49900b17a8 Pjax: If <a> tags without href attr.
This helps mute an error when navigating datetime picker
2019-07-16 14:35:59 +00:00
Peter Rotich
58a2c1cfed Datetime Picker Init
No need to set setDate - the plugin uses whatever is set on input field
2019-07-16 14:30:44 +00:00
Peter Rotich
f22d681bc6 Use DateTimeField for Due Date
Use DateTimeField for Due Date to be consistent with in-line edit and standardized use of datetime picker.
2019-07-15 21:16:58 +00:00
Peter Rotich
1c6d64dbf4 DatetimeField: Use in-line time picker
- Use datetimepicker (jquery-ui-timepicker-addon) for Datetime Field with time
selection
- Makes sure the front-end returns ISO formatted date to standardize how dates
are handled
- Fix javascript date format translation from php formats
2019-07-15 20:47:15 +00:00
Peter Rotich
dbff3b2803 Add jquery-ui-timepicker-addon 2019-07-15 20:37:01 +00:00
Peter Rotich
72e66bb96e Merge remote branch 'upstream/develop' into develop-next
Conflicts:
	include/class.forms.php
2019-07-12 14:45:18 +00:00
Peter Rotich
9e5a476909 Merge pull request #4948 from JediKev/security/csv-formula-injection
security: CSV Formula Injection
2019-07-11 21:32:53 -05:00
JediKev
99818486c5 security: CSV Formula Injection
This addresses a security issue discovered by Aishwarya Iyer where a User
can change their Full Name to a windows formula and when an Agent exports a
list of Users containing said User and opens the export file, the formula
will be executed on their computer (if it's windows of course). This adds a
new validator called `is_formula()` to all text fields disallowing the use
of the following characters `= + - @` at the beginning of text. This should
mitigate CSV Formula injections for any text field that allows user-input in
the system. To further prevent CSV Formula injections this adds an escape
mechanism to the Exporter that will escape any content matching the formula
regex with a single quote (as mentioned in many posts about this subject).
2019-07-11 10:56:27 -05:00
Peter Rotich
875fcf6e9d Merge pull request #4945 from JediKev/issue/pdf-squares-instead-of-text
issue: PDF Squares Instead Of Text
2019-07-11 10:24:37 -05:00
Peter Rotich
e65aeb1148 Merge pull request #4946 from JediKev/xss/install-form
xss: Install Form
2019-07-11 10:23:50 -05:00
Peter Rotich
505433f6d4 Merge pull request #4947 from JediKev/issue/rogue-closing-div-breaks-html-thread-tree
issue: Rogue Closing div Breaks HTML Thread Tree
2019-07-11 10:23:26 -05:00
JediKev
c3ba5b7826 xss: Install Form
This addresses an issue reported by Aishwarya Iyer where inserting `<img src
=x onerror = prompt(1)` into any text field on the install form will execute
in the browser after the system is installed and you log in. This is due to
us not sanitizing the content before it’s saved in the database. This adds
`Format::htmlchars()` to the installer to ensure the text field data is
sanitized properly.
2019-07-10 13:31:43 -05:00
JediKev
3bb4c0a155 issue: Rogue Closing div Breaks HTML Thread Tree
This addresses an issue reported by Vincent Monier (Xenos) where posting a
single `</div>` tag as a message or response via the UI will break the HTML
Thread Tree view. This is due to the `html_balance()` method not cleaning
empty div tags. This adds `'div'=>1` to the empty tag array so that any
rogue div tag + any empty div tags are properly removed.
2019-07-10 13:29:00 -05:00
JediKev
69c5095890 issue: PDF Squares Instead Of Text
This addresses an issue with Thai fonts (and a few others like Hebrew,
Arabic, etc.) where printing a PDF will show square characters instead of
the actual content. This is due to `autoScriptToLang` and `autoLangToFont`
not being set to `TRUE`. This updates the mPDF config to set the value of
`autoScriptToLang` to `TRUE` as this formats the HTML using the lang
attribute for the specific language of the content. In addition, this
updates the mPDF config to set `autoLangToFont` to `TRUE` as this selects
the correct font to use for the specific language of the content.

https://mpdf.github.io/fonts-languages/automatic-font-selection.html
2019-07-10 12:15:31 -05:00
Peter Rotich
b0b2dbf3e9 Merge remote branch 'upstream/develop-next' into develop-next 2019-07-09 19:52:46 +00:00
Peter Rotich
81771ded91 Merge remote branch 'upstream/develop' into develop-next
Conflicts:
	include/class.file.php
2019-07-09 19:52:36 +00:00
Peter Rotich
f16830d1db Merge pull request #4894 from aydreeihn/issue/incorrect-reply-to
Reformat Incorrect Reply-To Headers
2019-07-08 22:55:27 -05:00
Peter Rotich
bbfff1a2f8 Merge pull request #4919 from protich/issue/file-type-override
Issue/file type override
2019-07-08 22:54:14 -05:00
Peter Rotich
eba6fb9138 Validate integrity of uploads
This commit adds ability to make sure images are indeed images by checking
image type.
2019-07-09 03:53:11 +00:00
Peter Rotich
8ddfc4fbad Merge pull request #4938 from JediKev/issue/search-reindexing-thread-entries
issue: Search Reindexing Thread Entries
2019-07-08 22:50:03 -05:00
Peter Rotich
372a9a632c Merge pull request #4932 from JediKev/issue/iso-8859-8-i-charset-issues
issue: ISO-8859-8-i Charset Issues
2019-07-08 22:49:39 -05:00
JediKev
bbf1010ccf issue: Search Reindexing Thread Entries
This addresses an issue where `IndexOldStuff()` doesn't reindex everything
it's supposed to. The reindex leaves out all of the Thread Entries with
empty titles or bodies. This is due to the SQL statement that retrieves
thread entries. In the SQL statement, we check if the sum of the Thread
Entry Title length and the Thread Entry Body length is greater than 0. If so
we reindex the entry, otherwise we exclude it. The problem is both
```LENGTH(A1.`title`)``` and ```LENGTH(A1.`body`)``` can return `NULL` and
you cannot add `NULL` (a string) to an integer. This updates the SQL to add
`IFNULL()` statements around the possible `NULL` values so that if `NULL` we
typecast to integer of 0 which can be added to integers successfully.
2019-07-03 15:11:33 -05:00
aydreeihn
e9dda94a1e Reformat Incorrect Reply-To Headers
In the event that we receive an email where the reply-to header is formatted with the name being an unquoted email, we should correct the name by inserting the quotes.

Incorrect Format:
adriane@enhancesoft.com <adriane@enhancesoft.com>

Correct Format:
"adriane@enhancesoft.com" <adriane@enhancesoft.com>
2019-07-01 10:13:36 -05:00
JediKev
4da0324b40 issue: ISO-8859-8-i Charset Issues
This addresses an issue where emails with `ISO-8859-8-i` character-sets
appear as "(empty)" in the system. This is due to `ISO-8859-8-i` not being a
valid character-set for `iconv()`. When you pass `ISO-8859-8-i` to `iconv()`
you will receive an error similar to `iconv(): Wrong charset, conversion
from 'ISO-8859-8-i' to 'UTF-8//IGNORE' is not allowed`. I don’t know why
it's not a valid character-set for `iconv()` but the trailing `-i` is used
to say "keep the text in logical order instead of visual order". Logical
order just means to keep the text in true right-to-left format instead of
transcoding the characters to left-to-right format.

This adds a new case to the `Charset::normalize()` switch statement to match
against `ISO-XXXX-X-i`. If a character set matches the criteria we will
remove the trailing `-i` and set the charset to `ISO-XXXX-X`. This charset
format is valid in `iconv()` which will return the correctly formatted email
instead of "(empty)".
2019-06-28 10:36:34 -05:00
Peter Rotich
40ad7c2a97 Merge pull request #4907 from aydreeihn/issue/empty-list-item-extra
Empty extra in list_items
2019-06-28 09:13:02 -05:00
Peter Rotich
e4cb4e989e Merge pull request #4902 from JediKev/issue/account-registration-throws-errors
issue: Account Registration Throws Errors
2019-06-28 09:12:40 -05:00
Peter Rotich
14bfc4cbf9 Merge pull request #4901 from JediKev/issue/retained-deleted-listitem-errors
issue: Retained Deleted ListItem Errors
2019-06-28 09:11:24 -05:00
Peter Rotich
98860344fb Merge pull request #4931 from JediKev/issue/iframe-single-quotes-devnext
issue: iFrame Single Quotes
2019-06-28 09:09:15 -05:00
JediKev
4b59b4f06b issue: iFrame Single Quotes
It's all about the single quotes baby! Apparently I can't read; the single
quotes are only meant for word options such as `'self'` and `'none'`. When
adding single quotes to the `<host-source>` options it takes them
literally…too literally. For example, if your options are `'localhost:80
localhost:8080 localhost:8000'` then `'localhost:80` and `localhost:8000'` will
be seen as "invalid" due to the single quotes. This removes the single
quotes from every line that sets the CSP so all options are valid. This also
adds single quotes around the `self` option so it stays valid as well.
2019-06-28 08:55:57 -05:00
Peter Rotich
9db5268622 Merge remote branch 'upstream/develop' into develop-next 2019-06-28 13:50:13 +00:00
Peter Rotich
539d343d73 Remove File Type Override
Remove file type overwrite previously used to force downloads. This
addresses potential XSS where an attacker could pass "image" resulting in
the file being displayed in line.
2019-06-13 17:15:57 +00:00
Peter Rotich
9734f9502c Merge pull request #4892 from matzneda/patch-1
Double semicolon removed
2019-06-13 10:09:11 -05:00
Peter Rotich
0e21023a7e Merge pull request #4895 from aydreeihn/issue/dept-disable-alerts
Issue: Ticket Alerts vs Dept Recipients
2019-06-13 10:08:39 -05:00
Peter Rotich
09c195fbf1 Merge pull request #4914 from greezybacon/issue/task-thread-edit
task: Implement edit of task thread
2019-06-13 10:06:54 -05:00
aydreeihn
581f1f9cb6 Issue: Ticket Alerts vs Dept Recipients
If an alert is enabled for only the Department Manager and the Department Recipients field is set to No one, the Department Manager still receives a notification.

If the recipients field is set to no one, nobody should receive an alert regardless of what is checked on the New Ticket Alert selections.

To fix this, we can do a count of what the getMembersForAlerts function returns. This function compares what is set for a Department's group_membership in the database to the ALERTS_DISABLED constant to return a query set of members that should receive an alert. If the count is 0, we know that alerts should be disabled.
2019-06-11 10:48:08 -05:00
Jared Hancock
394ddee8d7 task: Implement edit of task thread
This fixes an issue where, for task threads, if an agent has the thread edit
permission, the agent was neither able to edit his or her own entries, nor the
entries of other agents.
2019-06-03 12:24:37 -05:00
JediKev
4f7d23c855 issue: Form Instructions Translation
This addresses issue 4909 where setting a translated Form Instruction fails
to render properly on the client side. This is due to us formatting the
instructions but not decoding before we render. This adds the decode method
to the translated Form Instructions so they are rendered properly on the
client side.
2019-06-03 09:51:31 -05:00
aydreeihn
1309a6c7f3 Empty extra in list_items
If you have a custom field that's based on a list and the default value is set to a list item where the extra field is empty ('') instead of NULL, you cannot set the default value back to 'Select a Default'. You CAN set it to other default values

Extra is set to empty if you erase the abbreviation and save it. Should save as NULL instead of empty

Note: for some reason this didn't work

if ($k == 'abbrev' && empty($vars[$k]))
                $this->set($v, NULL);
2019-05-29 15:28:50 -05:00
JediKev
a720507371 issue: Account Registration Throws Errors
This addresses issue 4898 where a User that clicks the ticket link in an
email alert to view the ticket, in that ticket view clicks the link to
register for an account, fills out the registration form, and clicks Create
will throw a an "Unable to register account. See messages below." error.
When the Users get this error there are no messages below so they can't see
anything to fix which prevents them from creating an account. This is due to
the email field being disabled which means the value is not sent in POST so
the system thinks the User sent no email address which throws a hidden
"Email field required." error. We disabled the email field to prevent an
attacker from accessing the user’s guest login and registering the user with
a different email (possibly his own). This sets a POST value called 'email'
to the client's email so that the registration process acknowledges and
validates the email allowing registration to continue.
2019-05-23 11:09:45 -05:00
JediKev
a3297a256e issue: Retained Deleted ListItem Errors
This addresses an issue where New Tickets will fail for Users with a deleted
ListItem retained in their Contact Information form. This is due to the
system deleting the `list_id` for the ListItem so when we run
`getFilterData()` for the User we can't find the list which causes a fatal
error later down the line. This adds an OR statement to the
`SelectionField::getFilterData()` method to skip said ListItems if no
`list_id` is present.
2019-05-22 10:30:57 -05:00
matzneda
bacd836171 Double semicolon removed 2019-05-15 10:57:27 +02:00
Peter Rotich
088bd1c368 Merge remote branch 'upstream/develop-next' into 1.12.x 2019-05-10 14:21:02 +00:00
Peter Rotich
35b260f9dd Merge remote branch 'upstream/develop-next' into develop-next 2019-05-10 14:20:21 +00:00
Peter Rotich
44006c7be1 Merge remote branch 'upstream/develop' into develop-next
Conflicts:
	include/class.dynamic_forms.php
	include/class.mailparse.php
	include/client/open.inc.php
	include/staff/templates/user-lookup.tmpl.php
	setup/test/tests/stubs.php
2019-05-10 14:19:47 +00:00
Peter Rotich
f4d5adde1e Merge remote branch 'upstream/develop' into develop 2019-05-10 14:14:30 +00:00
Peter Rotich
fac1c2db96 Merge pull request #4887 from JediKev/cli/package-better-wording
cli: Package Better Wording
2019-05-10 09:06:59 -05:00
aydreeihn
e73e8819fc Issue: Reopen Assignment
This commit fixes an issue where Tickets were not being assigned to the last respondent if ‘Claim on Response’ was disabled and a Ticket was reopened.

Now, a new option has been added on the Department level to Disable auto assign on reopen if desired.
2019-05-09 15:59:18 -05:00
Peter Rotich
ba1fb38314 Merge pull request #4780 from aydreeihn/issue/faqs
FAQ Issues
2019-05-09 14:39:24 -05:00
Peter Rotich
4bf11e6592 Merge pull request #4871 from JediKev/cli/package-no-file-permissions
cli: Package No File Permissions
2019-05-09 14:33:06 -05:00
Peter Rotich
27b2b080d1 Merge pull request #4867 from aydreeihn/issue/limit-visibility
Issue: Tickets Visibility
2019-05-09 14:32:45 -05:00
aydreeihn
60aa7b876f Issue: Tickets Visibility
This commit ensures that an Agent with the 'See all tickets in search results, regardless of access' permission checked can see all Tickets in a search or a saved search, but does NOT see all Tickets within queues.
2019-05-09 14:27:08 -05:00
Peter Rotich
f04f547bfb Merge pull request #4876 from JediKev/oops/eml-msg-missing-not-operator
oops: .eml/.msg Missing Not Operator
2019-05-09 14:12:06 -05:00
Peter Rotich
406c84e13f Merge pull request #4870 from aydreeihn/issue/lint-fixes
Lint Fixes
2019-05-09 14:00:53 -05:00
Peter Rotich
46c9eef189 Merge pull request #4861 from JediKev/issue/api-unexpected-data-warnings
issue: API Unexpected Data Warnings
2019-05-09 13:51:34 -05:00
Peter Rotich
a51b2efb51 Merge pull request #4877 from JediKev/issue/queue-sort-title-no-validation-error
issue: Queue Sort Title No Validation Error
2019-05-09 13:50:21 -05:00
JediKev
bf20bdd5e6 cli: Package Better Wording
This updates the variable name that determines if the current PHP version is
5.6+ from `$php56` to `$php56plus`. This will help other understand better
what the variable is/does.
2019-05-09 13:10:12 -05:00
Peter Rotich
6095d0b373 Merge remote branch 'upstream/develop' into develop 2019-04-30 16:58:48 +00:00
JediKev
029b0f2815 issue: Queue Sort Title No Validation Error
This addresses an issue reported on the Forum where adding a new Sort Option
for Queues without a title fails without error. This is due to the
queue-sorting template that uses a new instance of the
`QueueSortDataConfigForm` form from a new instance of `QueueSort` rather
than the existing form with existing POST data/errors when a POST is
submitted. This updates the queue-sorting template to use the already
available `$data_form` form instance. This also adds an if statement to set
the `$data_form` if one doesn’t exist (this only applies to new modals
without a POST).
2019-04-29 16:03:23 -05:00
JediKev
ce8aadf8d4 oops: .eml/.msg Missing Not Operator
This addresses a typo where we are missing a not operator in class
MailFetcher when checking for no `$body` in the fetched attachments. This
adds the not operator so that the `if()` statement is properly executed and
we correctly set a fake body when there is none.
2019-04-29 10:38:41 -05:00
JediKev
25e6c6e992 cli: Package No File Permissions
This addresses an issue where the `package` cli module is leaving out the
permissions on files. This causes the final ZIP archive to contain files
without permissions meaning the files are un-usable until you restore
permissions. This can make life difficult on people trying to install
osTicket with minimal knowledge as they wouldn’t know what is wrong.

This is due to the `setExternalAttributesName` method not shifting 16 bits
on the file "mode" which will not translate to binary. The file "mode" is
the inode protection mode for a file returned by the `stat()` method. It is
essentially a decimal representation of a file's permissions. Since "mode"
is in decimal format we need to shift by 16 bits to translate it to binary
so the archiver understands. Once the mode is translated to binary the
permissions are preserved.
2019-04-25 15:10:51 -05:00
aydreeihn
8c878db6e2 Lint Fixes
This commit gets rid of PHP warnings. Additionally, it updates the lint tests to be more accurate.
2019-04-25 13:19:06 -05:00
Peter Rotich
a076918121 Add Release Notes for v1.12 2019-04-24 19:04:24 +00:00
Peter Rotich
e58bc50d61 Merge remote branch 'origin/develop' into develop-next
Conflicts:
	WHATSNEW.md
	include/client/header.inc.php
2019-04-24 19:00:42 +00:00
Peter Rotich
91602a7e52 Release notes for v1.10.6 2019-04-24 18:39:20 +00:00
JediKev
f8d085ea03 jquery: Update Again
This updates jQuery to the latest stable release of v3.4.0.
2019-04-24 18:36:42 +00:00
Peter Rotich
dbc39b4fa7 Merge remote branch 'upstream/develop' into develop-next 2019-04-24 17:51:05 +00:00
Peter Rotich
8a52067f6c Merge remote branch 'upstream/develop' into develop 2019-04-24 17:50:36 +00:00
Peter Rotich
9effd2b699 Merge pull request #4869 from JediKev/xss/xss-to-lfi-vulnerability
xss: XSS To LFI Vulnerability
2019-04-24 12:48:47 -05:00
JediKev
eab6747e95 xss: XSS To LFI Vulnerability
This addresses a vulnerability found by [AkkuS CW](https://pentest.com.tr)
where a simple XSS attempt can lead to an LFI (Local File Inclusion) attack.
The issue stems from the system returning the unformatted file contents in
an error message when uploading a CSV to the User Importer. This formats the
contents before uploading so that if the contents are returned in an error
message they will not be executed by the browser which therefore prevents
XSS attempts and the possibility of an LFI attack. This also formats all the
user-created data sent to ImportError to prevent the same issue.
2019-04-24 11:29:09 -05:00
Peter Rotich
e6283739c6 Minor Fixes 2019-04-23 19:40:11 +00:00
aydreeihn
d8b61e83f0 Issue: Queue with Teams in Criteria
This commit fixes an issue with queues or searches that have a criteria for team assignment when the Agent is not assigned to any teams. In this case, the queue should not return any tickets. Previously, it would create an invalid query which would cause system errors.
2019-04-23 12:42:48 -05:00
JediKev
4f68eb9dbe issue: API Unexpected Data Warnings
This addresses an issue reported on the Forum where `API Unexpected Data`
warnings are appearing in the system logs for the `thread_entry_recipients`
and `system_emails` keys for piped emails. This is due to the API request
validator that checks the keys of the API data; if a key's data is an array
itself it loops through the validator again to check the key(s) inside the
data array. This is fine for most keys but for the `thread_entry_recipients`
and `system_emails` keys the request structure does not contain the
necessary sub-keys to validate the data keys. This adds the necessary
sub-keys to the request structure so that `thread_entry_recipients` and
`system_emails` data keys can be validated.
2019-04-23 12:18:26 -05:00
Peter Rotich
ed1381e16a Merge remote branch 'upstream/develop-next' into develop-next 2019-04-23 14:45:15 +00:00
Peter Rotich
fb8a4bf64d Merge remote branch 'upstream/develop' into develop-next 2019-04-23 14:45:11 +00:00
Peter Rotich
3299278d92 Merge pull request #4857 from JediKev/issue/eml-msg-attachments
issue: .eml/.msg Attachments
2019-04-23 09:43:00 -05:00
Peter Rotich
9cdbe45cdc Merge pull request #4865 from protich/issue/ticket-link-var
Ticket Link: Always return a link
2019-04-23 09:42:31 -05:00
Peter Rotich
208bf95d32 Merge pull request #4864 from protich/issue/mailer
Mailer: Allow for ability to pass -f option as from_address
2019-04-23 09:42:18 -05:00
Peter Rotich
6f35a87562 Ticket Link: Always return a link 2019-04-22 23:22:35 +00:00
Peter Rotich
ca00db7dec Mailer: Allow for ability to pass -f option as from_address 2019-04-22 22:53:37 +00:00
Peter Rotich
d3b0a94404 Merge pull request #4863 from aydreeihn/issue/v1.11
Bug fixes and enhancements for v1.11
2019-04-22 17:20:31 -05:00
Peter Rotich
f2f4107e25 Merge pull request #4862 from JediKev/issue/task-est-due-date
issue: Task EstDueDate
2019-04-22 17:13:21 -05:00
aydreeihn
9c076fc518 Bug fixes and enhancements for v1.11 2019-04-22 15:00:01 -05:00
JediKev
deb01f0985 issue: Task EstDueDate
This addresses an issue where having the `%{task.due_date}` variable in a
Task alert template whilst creating a Task with an Assignee causes a fatal
error in the backend leaving the Create Task modal spinning forever. This is
due to the `getVar()` method for Tasks where the `due_date` case references
a non-existing method. This updates the referenced method to an existing
method so it gets the correct value and does not cause a fatal error.
2019-04-22 13:25:44 -05:00
Peter Rotich
f6823c80a9 Merge pull request #4858 from JediKev/jquery/update-again
jquery: Update Again
2019-04-18 18:33:24 -05:00
Peter Rotich
eaafe74215 Merge pull request #4850 from protich/issue/v1.11
Issues since v1.11 release
2019-04-18 18:32:54 -05:00
Peter Rotich
6283425086 Merge pull request #4851 from protich/issue/pear-mimedecode
Mime Decode - Encoded chars
2019-04-18 18:32:26 -05:00
Peter Rotich
8657218b69 Merge pull request #4855 from protich/issue/pjax-timeout
PJAX: Increase default timeout
2019-04-18 18:32:04 -05:00
Peter Rotich
f405bff30c Merge pull request #4856 from aydreeihn/issue/mpdf-export
MPDF Tasks
2019-04-18 18:31:50 -05:00
JediKev
bf54ca4494 jquery: Update Again
This updates jQuery to the latest stable release of v3.4.0.
2019-04-17 16:11:50 -05:00
JediKev
4098a2bfe4 issue: .eml/.msg Attachments
This addresses an issue where `.eml` and `.msg` files on incoming mails are
being dropped. This is due the the mail fetcher that tries to process
`.eml`/`.msg` files and adds them as thread entries rather than adding them
as attachments. This adds a new section that utilizes a new method to fetch
the body of `.eml`/`.msg` files, fetches the subjects of the `.eml`/`.msg`
files as the attachment names, and creates attachments. This preserves the
`.eml` and `.msg` files and adds them to the pertinent thread entries as
attachments.
2019-04-17 15:47:24 -05:00
aydreeihn
4b724fa96e Merge remote-tracking branch 'upstream/develop-next' into issue/mpdf-export
Conflicts:
	include/class.pdf.php
2019-04-17 12:46:25 -05:00
aydreeihn
9ec7debe56 MPDF Tasks
Use the psize that is set in the options array since $psize is not in the Task2PDF contructor.
2019-04-17 12:34:17 -05:00
Peter Rotich
1f2551f2d6 Oppsy: Continue inside a switch 2019-04-17 17:31:04 +00:00
Peter Rotich
15e4787559 PJAX: Increase default timeout
Increase default pjax timeout to 30 seconds to avoid double requests  &
reloads.
2019-04-17 17:26:36 +00:00
Peter Rotich
40c887e7d6 Queue: Don't lookup adhoc search queues. 2019-04-17 17:07:13 +00:00
Peter Rotich
5ac2873a0a Set Column's Queue to avoid unnecessary lookup 2019-04-17 17:04:12 +00:00
Peter Rotich
58206ba945 Misc. fixes 2019-04-17 15:28:36 +00:00
Peter Rotich
683812e3e6 Mime Decode - Encoded chars
This commit addresses an issue where pre_replace fails in php 7.x resulting
in a ticket with an empty body.
2019-04-16 22:57:42 +00:00
Peter Rotich
aa67e992ef Dept: Eliminate unnecessary lookup
Use dept_id provided with the assumption that the caller validated it- this
helps to avoid unnecessary database lookup.
2019-04-16 18:30:13 +00:00
Peter Rotich
2a8b0bd8de Check primary properties first to avoid uncessesary config loading 2019-04-16 18:26:53 +00:00
Peter Rotich
b42ce54d92 Limit search results to 500 records 2019-04-16 18:22:06 +00:00
Peter Rotich
9fea801637 PriorityField: Preload & cache priorities
This is necessary to avoid expensive db lookup when displaying tickets
queues.
2019-04-16 18:12:49 +00:00
Peter Rotich
453e815224 Lazy load $ost Config 2019-04-16 18:04:17 +00:00
Peter Rotich
7a503b7fbe Continue inside a switch block 2019-04-16 17:59:16 +00:00
Peter Rotich
03586517a1 Fix Memcached backed session backed on php 7.x 2019-04-16 17:57:55 +00:00
Peter Rotich
001274a9aa Merge remote branch 'upstream/develop' into develop-next 2019-04-16 15:18:38 +00:00
Peter Rotich
10da3fcc12 Merge remote branch 'upstream/develop' into develop 2019-04-16 15:11:41 +00:00
Peter Rotich
7a01916bb1 Merge pull request #4839 from ntozier/patch-1
Update README.md
2019-04-16 10:01:43 -05:00
Peter Rotich
0436b79e93 Merge pull request #4848 from JediKev/issue/acl-move-to-inc-files
issue: ACL Move To Inc Files
2019-04-15 15:16:30 -05:00
Peter Rotich
4d8de208cb Merge pull request #4829 from JediKev/issue/sendAccessLink-on-null-v111
issue: sendAccessLink On NULL v1.11
2019-04-15 14:54:36 -05:00
Peter Rotich
9d990e38f9 Merge remote branch 'upstream/develop-next' into develop-next
Conflicts:
	include/client/header.inc.php
2019-04-15 19:53:29 +00:00
Peter Rotich
4365bae65b Merge remote branch 'upstream/develop' into develop-next 2019-04-15 19:46:36 +00:00
Peter Rotich
b8b001a996 Merge pull request #4841 from JediKev/feature/access-control-list
feature: ACL (Access Control List)
2019-04-15 14:28:52 -05:00
JediKev
f3fd106c2b issue: ACL Move To Inc Files
This moves ACL enforcement from the header files to the `client.inc.php` &
`staff.inc.php` files so that AJAX/PJAX may bypass ACL.
2019-04-15 14:14:55 -05:00
JediKev
1018b637a1 feature: ACL (Access Control List)
This adds a new feature called ACL that offers the ability to control what
IP addresses are allowed to access the system. This adds a new textfield to
the System Settings to add a comma separated list of IPs. This also adds a
dropdown labeled "Apply To:" that gives you the option to choose which
panel(s) the ACL will apply to. Lastly, this adds a validator for a simple
comma-separated list of IP addresses. (eg. `192.168.1.1, 192.168.2.2,
192.168.3.3`)

If the requester's IP is not in the ACL the system will show an "Access
Denied" page. If the requester's IP is in the ACL they will be able to
access the system as usual. If the ACL field is set to Disabled, anyone will
be able to access the system.

This adds an initial failsafe where if the Admin's current IP address is not
in the ACL upon saving the system will refuse to save the setting to prevent
the Admin from being locked out. This also adds another failsafe where if
there is an "Apply To:" option set but there are no IPs provided the system
will return an error letting the Admin know they have to insert an IP
address to continue.
2019-04-15 12:18:11 -05:00
ntozier
e5f41803aa Update README.md 2019-04-15 13:12:26 -04:00
Peter Rotich
431fefed66 Merge pull request #4828 from JediKev/issue/sendAccessLink-on-null
issue: sendAccessLink On NULL
2019-04-15 11:03:01 -05:00
Peter Rotich
020aa115c3 Merge pull request #4844 from JediKev/issue/iframe-single-quotes
issue: iFrame Single Quotes
2019-04-15 11:01:32 -05:00
Peter Rotich
b89937efe8 Merge pull request #4847 from JediKev/issue/choice-validation-accept-punctuation
issue: Choice Validation Accept Punctuation
2019-04-15 10:55:47 -05:00
JediKev
a01ed2aa43 issue: Choice Validation Accept Punctuation
This addresses issue mentioned in 4071 where the choice field validation is
not accepting punctuations. This updates the regex to accept anything the
user inputs. This introduces another issue that if the choice contains `:`
in the value then it will truncate everything after. This is due to the
explode method that explodes on any `:` character. This updates the explode
method to return only 2 values which only explodes on one `:` character
which returns the full value.
2019-04-12 11:43:17 -05:00
JediKev
ae5ced392c issue: iFrame Single Quotes
It's all about the single quotes baby! Apparently I can't read; the single
quotes are only meant for word options such as `'self'` and `'none'`. When
adding single quotes to the `<host-source>` options it takes them
literally…too literally. For example, if your options are `'localhost:80
localhost:8080 localhost:8000'` then `'localhost:80` and `localhost:8000'`
will be seen as "invalid" due to the single quotes. This removes the single
quotes from every line that sets the CSP so all options are valid. This also
adds single quotes around the `self` option so it stays valid as well.
2019-04-11 12:13:22 -05:00
ntozier
eccc57adce Update README.md 2019-04-09 20:18:46 -04:00
aydreeihn
ce3d69ae10 FAQ Issues
This commit fixes several issues with how we manage FAQs and related objects.

1. When trying to add a Help Topic to an FAQ, we should add the record to the faq_topic table after saving the faq so that we can accurately retrieve the faq_id

2. When deleting a Help Topic, we need to make sure we're using the topic->delete function rather than deleting based on a QuerySet so that the related FAQ Topics will also be deleted.

3. When deleting a FAQ Category, we need to ensure that we delete all related FAQs and FAQ Topics. To do this, we should use the delete function from the FAQ class first to delete all related FAQs and FAQ Topics and then we should use the Category delete function to delete the remaining Category (remove faqs->expunge from the category->delete function since it we now pass through faq->delete as well)
2019-04-05 10:37:27 -05:00
JediKev
035eabd5e1 issue: sendAccessLink On NULL v1.11
This addresses an issue in v1.11 where sending an Access Link via email to a
Collaborator fails with fatal error. This is due to the type of User class
that is sent to the `Mailer::send()` function. The ClientSession User class
is not appropriate for this method, rather, TicketOwner or Collaborator User
classes are appropriate. This adds a function called `getSessionUser()` to
the ClientSession class so we can retrieve the TicketOwner/Collaborator User
class from the session.
2019-04-04 10:08:51 -05:00
Peter Rotich
dcd94b227f Merge pull request #4825 from JediKev/issue/org-ticket-export-no-filename
issue: Organization Ticket Export No Filename
2019-04-04 10:06:40 -05:00
JediKev
6f9f2e17b9 issue: sendAccessLink On NULL
This addresses an issue where entering a collaborator's email to send ticket
email access link throws a fatal error. This is due to the method that
checks for tickets with the User's email equal to the email provided. This
only checks for User's emails not Collaborator emails. This adds a check for
Collaborator emails as well so this will not crash out.
2019-04-04 09:55:25 -05:00
Peter Rotich
6e7e9b4574 Merge pull request #4827 from aydreeihn/issue/mpdf
MPDF Issues
2019-04-03 14:06:35 -05:00
aydreeihn
064e0020ee MPDF Issues
1. Task Exports: This commit fixes the contructor for printing Tasks using MPDF

2. PDF Formatting: This commit fixes an issue where the header of each thread entry did not stretch across the page correctly. This was an unintentional side effect of trying to fix the way HTML tables printed in PDFs.

3. FAQ PDFs: This commit passes the correct values to mPDFWithLocalImages when printing FAQs
2019-04-02 15:12:22 -05:00
aydreeihn
c38f0456ad MPDF Issues:
1. Task Exports: This commit fixes the contructor for printing Tasks using MPDF

2. PDF Formatting: This commit fixes an issue where the header of each thread entry did not stretch across the page correctly. This was an unintentional side effect of trying to fix the way HTML tables printed in PDFs.
2019-04-02 14:38:01 -05:00
JediKev
18089165bd issue: Organization Ticket Export No Filename
This addresses an issue where clicking Export on an Organization's Tickets
will export a file with the filename of 'csv' and no extension. This is due
to the variables we are passing to the `saveTickets` function. We are
missing a variable called '$fields' that contains a list of fields.
2019-04-02 09:47:16 -05:00
Peter Rotich
ea77250de0 Merge remote branch 'upstream/develop' into develop-next 2019-04-01 17:24:48 +00:00
Peter Rotich
a49dbd7bc4 Merge pull request #4824 from JediKev/issue/iframe-on-install
issue: iFrame On Install
2019-04-01 12:15:43 -05:00
Peter Rotich
5f511d86f5 Merge pull request #4796 from aydreeihn/issue/export-headers
Issue: Ticket Export Headers
2019-04-01 12:11:51 -05:00
aydreeihn
e26f62ffa1 Issue: Ticket Export Headers
This commit fixes an issue where custom export headings were being set to numeric values rather than field labels.

For exports that are already saved, we can get the heading directly using getHeading. To get the heading for fields that are not already saved as exports, we can use getExportableFields, which will return path => heading.
2019-04-01 12:05:24 -05:00
Peter Rotich
b76e8f05bf Merge pull request #4797 from aydreeihn/issue/choose-export-fields
Issue: Choosing Fields to Export
2019-04-01 12:00:55 -05:00
JediKev
e7a7e3b00d issue: iFrame On Install
This addresses the "Call to getAllowIframes() on NULL" error on installation
pages. This is due to 4781 that introduced the concept of allowing multiple
iFrames, where we are not checking for `$cfg` before calling the method.
This adds a check for `$cfg` so the errors do not occur.
2019-03-29 10:40:11 -05:00
Peter Rotich
6c24befffb Merge remote branch 'upstream/develop-next' into develop-next 2019-03-29 15:24:27 +00:00
Peter Rotich
93dd672354 Merge pull request #4820 from JediKev/oops/thread-variable-fatal-error
oops: Thread Variable Fatal Error
2019-03-29 10:24:04 -05:00
Peter Rotich
235328a684 Merge remote branch 'upstream/develop' into develop-next 2019-03-29 15:23:11 +00:00
Peter Rotich
4a0e1bc376 Merge pull request #4823 from JediKev/oops/emoji-strips-korean
oops: Emojis Strip Korean
2019-03-29 10:17:56 -05:00
JediKev
6387d820bb oops: Emojis Strip Korean
This addresses an issue where Korean text is stripped from the body. This is
due to the strip_emoticons function, as Korean text is in the same unicode
range as some of the emojis.
2019-03-29 10:01:57 -05:00
JediKev
97a9aa8dcc oops: Thread Variable Fatal Error
This addresses an issue introduced with 4737 where using `%{ticket.thread}`
causes a fatal error. This is because `ObjectThread->asVar()` returns an
object which cannot be converted to a string. This adds a `__tostring()`
function to class ThreadEntries so it can be converted to a string properly.
2019-03-28 13:46:09 -05:00
Peter Rotich
e44ab402fa Merge pull request #4781 from JediKev/iframe/allow-multiple-iframe-domains
iframe: Allow Multiple iFrame Domains
2019-03-27 16:16:02 -05:00
Peter Rotich
efad55a215 Merge remote branch 'upstream/develop-next' into develop-next 2019-03-27 20:53:11 +00:00
Peter Rotich
fa7d1a801e Merge remote branch 'upstream/develop' into develop-next 2019-03-27 20:53:02 +00:00
aydreeihn
668b2c1468 Issue: Choosing Fields to Export
This commit fixes an issue where only the saved export fields would export, whether you checked more fields to export or unchecked some of the saved fields.

For any fields not saved that need to be exported, we need to find their label and then put it in the fields array. For any saved export fields that are unchecked, we need to compare what was checked vs what is saved and then unset the fields that were unchecked.
2019-03-27 15:07:03 -05:00
Peter Rotich
18f5188074 Merge pull request #4340 from JediKev/issue/maxfilesize-comma-crash
issue: Maxfilesize Comma Crash
2019-03-27 15:06:17 -05:00
Peter Rotich
e95f0e2bb8 Merge pull request #4737 from JediKev/variable/complete-thread-asc-or-desc
variable: Complete Thread ASC or DESC
2019-03-27 14:57:48 -05:00
Peter Rotich
89838c0841 Merge pull request #4798 from aydreeihn/issue/checkboxes
Issue: Saving Checkbox Values
2019-03-27 14:42:36 -05:00
aydreeihn
54c6e6a71d Merge pull request #4736 from aydreeihn/issue/closed-queue-dups
Issue: Duplicate Tickets in Closed Queue
2019-03-27 14:42:09 -05:00
JediKev
84d05c6191 variable: Complete Thread ASC or DESC
This pull adds the ability to choose between ASC or DESC order for the
complete thread variable. If `complete_asc` is chosen the system will order
the thread in ASC order, if `complete_desc` is chosen the system will order
the thread in DESC order. This keeps backwards compatibility with just
`complete` as some people might forget to update this for a while.
2019-03-27 14:28:00 -05:00
aydreeihn
03a6e0a445 Issue: Saving Checkbox Values
This commit fixes an issue where checkboxes could not be edited for inline edit or all field edits.

When a BooleanField is directly passed to the to_database method, you are not able to accurately check to see if old != new. To fix this, I added a new getChanges method to the BooleanField class that will first do a comparison on the raw boolean value (true, false) and then get the value needed for the database. I then made sure that we use that new function when editing all fields together.

Additionally, I added a getClean method to the BooleanField class so that $this->_clean for the field would be set to either true or NULL depending on if the box is checked or not and would accurately save to the database when calling $form->saveAnswers()
2019-03-27 09:40:08 -05:00
Peter Rotich
cebdcdd33f Merge pull request #4744 from aydreeihn/issue/show-assigned-only
Assignment Restriction Issue
2019-03-26 16:12:04 -05:00
aydreeihn
2ba9231e67 Assignment Restriction Issue
This commit fixes an issue where we were not checking the restrictions on Ticket assignment correctly. isAccessLimited returns true if showAssignedOnly is true, so we wouldn't want to negate the isAccessLimited check (that would return true if access is not limited).

Also, if an Agent's access is limited to assigned tickets only, we can return the assigned tickets once we have them without needing to go through any further processing.

Finally, we should still allow an agent to view an assigned ticket even if the ticket is closed.

Note: queue counts update themselves a little after you toggle the 'Limit ticket access to ONLY assigned tickets' check box. The 'See all tickets in search results, regardless of access' still works correctly as well.
2019-03-26 15:56:41 -05:00
Peter Rotich
bf741a614c Merge pull request #4523 from JediKev/issue/strip-emoticons
issue: Strip Emoticons
2019-03-26 15:23:12 -05:00
Peter Rotich
1dee111d1d Merge pull request #4728 from aydreeihn/issue/quick-filters
Quick Filter Fixes:
2019-03-26 15:19:45 -05:00
aydreeihn
838b70f0d7 Quick Filter Fixes:
Make the following work:
- Assigned
- Assignee
- Department Manager
- Assigned Team

Also, make sure we account for if there are no choices available for a quick filter Ex: The helpdesk does not have any teams
2019-03-26 15:18:06 -05:00
Peter Rotich
43794f9943 Merge pull request #4731 from JediKev/issue/apc-cli
issue: APC CLI
2019-03-26 15:07:49 -05:00
Peter Rotich
be51f77d3c Merge pull request #4815 from aydreeihn/issue/mpdf-phpversion
Issue: MPDF Export PHP < 7.0
2019-03-26 15:01:29 -05:00
Peter Rotich
da92430775 Merge pull request #4804 from hans-chen/patch-1
Fix bug: send new ticket alert to account manager
2019-03-26 15:01:08 -05:00
aydreeihn
340472b299 Issue: MPDF Export PHP < 7.0
This commit fixes an issue where using MPDF to print Tickets did not work if the PHP version was < 7.0 because MPDF called the random_int function which is only available for PHP 7.0+. Now, we check the PHP version before printing, and if it is less than 7.0, we use the rand function. If it is >= 7.0, we continue to use the random_int function.
2019-03-26 14:56:18 -05:00
Peter Rotich
81ff7321a8 Merge pull request #4812 from JediKev/issue/multilingual-faq-parent
issue: Multilingual FAQ Category w/ Parent
2019-03-26 14:55:35 -05:00
Peter Rotich
ffc35323b8 Merge pull request #4814 from JediKev/issue/task-print-pdf
issue: Task Print PDF
2019-03-26 14:53:12 -05:00
JediKev
f584a26ae3 issue: Strip Emoticons
This addresses an issue where emoticons/emojis cut off the remainder of the
email when being added to a ticket thread.
2019-03-26 14:34:12 -05:00
JediKev
8d8afbc02d issue: Task Print PDF
This addresses an issue where clicking print on a Task throws a fatal error.
This is due to the Task2PDF function passing a string instead of an array to
`Mpdf::__construct()`. The `__construct()` of class Mpdf requires an array
of configurations so we are now passing an array instead of a string.
2019-03-22 09:36:43 -05:00
JediKev
103eed6bd9 issue: Multilingual FAQ Category w/ Parent
This addresses issue 4810 where having more than one language installed and
trying to add a new FAQ Category with a Parent Category relation fails to
add the Parent Category relation. This is due to multiple Select2 fields;
the POST data includes only the last Select2 field's value instead of the
one in the tab you're currently on. This adds a script to set all Select2
fields in all the available languages to the same value so the POST will
always contain the appropriate Parent ID no matter what language tab you’re
on.
2019-03-21 12:59:28 -05:00
Peter Rotich
645a4aff58 Merge pull request #4806 from JediKev/issue/orgs-sort-users
issue: Organizations Users Sort
2019-03-21 10:53:51 -05:00
JediKev
1214c75345 issue: Organizations Users Sort
This addresses issue 4803 where sorting by Users on Organizations does not
sort properly. It sorts by name instead of the User count. This corrects the
value in the `$sortOptions` array from `users` to `user_count`.
2019-03-18 12:26:22 -05:00
Hans Chen
17c7e1d1cd fix bug
not sending new ticket alert to account manager.
2019-03-18 11:57:36 +01:00
Peter Rotich
78a673fbcd Merge remote branch 'upstream/develop-next' into develop-next 2019-03-12 22:11:57 +00:00
Peter Rotich
a37eaa753e Merge remote branch 'upstream/develop' into develop-next 2019-03-12 22:11:43 +00:00
Peter Rotich
f292da9298 Merge remote branch 'upstream/develop' into develop 2019-03-12 22:11:23 +00:00
Peter Rotich
9f97399e18 Merge pull request #4785 from protich/issue/queue-columns
Queue Columns
2019-03-12 17:04:46 -05:00
Peter Rotich
e3f6c6ace6 Merge pull request #4788 from JediKev/issue/duplicate-form-titles
issue: Duplicate Form Titles
2019-03-12 17:04:17 -05:00
Peter Rotich
693a09abaf Merge pull request #4790 from aydreeihn/issue/mpdf-export
Issue: PDF printout
2019-03-12 17:02:36 -05:00
aydreeihn
0cadc04ccd Issue: Exporting Tickets
This commit fixes 2 issues we had with using MPDF to export Tickets:

1. Tickets with inline images
	To refer to images as var:varname, imageVars needs to be set for the MPDF object.
2. Tickets with tables
	When exporting a Ticket where a Thread Entry contains a table, we must ignore table percents and table widths, otherwise, it will always throw the error "Word is too long to fit in table"
2019-03-12 14:03:09 -05:00
JediKev
5bae51593d issue: Duplicate Form Titles
This addresses an issue mentioned in the forum where having more than one
custom field on a ticket shows the same title for all forms on the
client-side ticket view (after creation). This adds an array of the form
names indexed by sort order and displays them in the correct order with the
correct names.
2019-03-11 11:28:29 -05:00
JediKev
4f7c4dcba6 iframe: Allow Multiple iFrame Domains
Previously, we added a security header to prevent click-jacking called
"X-Frame-Options". This introduced an issue with people using osTicket in
iFrames on their websites. To mitigate the issue, this updates the security
header to allow the site to be framed from specified domains, if none
provided we default to 'self'. This adds a new field to General System
Settings called "Allow iFrames" where you may enter a comma separated list
of domains that the site can be framed on. This also adds a validator for
the field to validate the domains and ensure they fit the <host-source>
syntax from [Mozilla Developer
Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/frame-ancestors#Sources).
2019-03-11 09:47:14 -05:00
Peter Rotich
7ce8349833 Queue Columns
Allow admin to setup columns when creating a new parent queue and address an
issue where Assignee standard columns used a wrong Id.
2019-03-09 00:58:09 +00:00
Peter Rotich
33d69252ed Merge remote branch 'upstream/develop-next' into develop-next 2019-03-08 18:49:06 +00:00
Peter Rotich
df65034aa5 Merge remote branch 'upstream/develop' into develop-next 2019-03-08 18:48:55 +00:00
Peter Rotich
4842a3ccf4 Merge remote branch 'upstream/develop' into develop 2019-03-08 18:48:39 +00:00
Peter Rotich
43a5900e45 Merge pull request #4772 from JediKev/issue/faq-return-errors
issue: FAQ Return Errors
2019-03-06 13:15:12 -06:00
Peter Rotich
e60b5c0ad9 Merge pull request #4774 from TechCare-Aus/develop-next
Update settings.email.yaml
2019-03-06 13:14:05 -06:00
Steve
4e1841258f Update settings.email.yaml
Pop up message hyperlink incorrect with changes made by implementing osTicket docs
2019-03-05 15:34:43 +08:00
JediKev
f591cafe95 issue: FAQ Return Errors
This addresses an issue reported on the Forum where creating a new FAQ and
not filling out required information returns the correct error but returns
the incorrect template (FAQ View Template). This is due to the check for an
FAQ when determining the template to return. This adds a check for the FAQ
ID to determine if it’s an actual FAQ or just a model instance.
2019-03-04 13:23:24 -06:00
Peter Rotich
e31420bd44 Merge pull request #4771 from JediKev/issue/faq-search-results
issue: FAQ Search Results
2019-03-04 11:45:38 -06:00
Peter Rotich
50558663d8 Merge pull request #4759 from JediKev/issue/canned-resp-vars
issue: Canned Response Variables
2019-03-04 11:43:35 -06:00
JediKev
cd4ba22678 issue: FAQ Search Results
This addresses an issue reported on the forum where searching for a keyword
in FAQ search brings back more results than it should. This is due to the
format of the query selecting the results, essentially, the `WHERE NOT`
statement is not properly formatted so the `OR` statements take precedence
over the `WHERE NOT` causing non-public results to be shown to the client.
The `WHERE NOT` statement contains the bit to select from only public faqs
and since the `OR` takes precedence it will return the non-public results
too.
2019-03-04 10:46:50 -06:00
Peter Rotich
e56b4cb2c1 Merge pull request #4758 from JediKev/issue/php72-ticket-status
issue: PHP 7.2 Ticket Status
2019-02-27 07:33:45 -06:00
JediKev
1c8e97c84a issue: Canned Response Variables
This addresses issue 4756 where the `%{recipient.ticket_link}` variable is
not being replaced when the canned response is loaded in the reply box; all
other link variables work. This is due to the recipient object not being
passed to the variableReplacer which means the ticket_link is not available.
This adds the recipient object to the variableReplacer so the ticket_link
variable is properly replaced like the others on load.
2019-02-26 12:56:46 -06:00
JediKev
cb710243d8 issue: PHP 7.2 Ticket Status
This addresses issue 4716 where updating a Ticket Status throws a fatal
error of "Too few arguments" when using PHP 7.2. This is due to `$errors`
not being passed to the `update()` function causing PHP 7.2 to freak out.
This creates an `$errors` array and passes it to `update()` so PHP 7.2 is
happy and we are all happy. :)
2019-02-26 12:11:22 -06:00
Peter Rotich
d5f5825dfb Merge pull request #4745 from JediKev/issue/internal-note-ignored
issue: Internal Note Ignored
2019-02-26 04:26:24 -06:00
JediKev
449611ae60 issue: Internal Note Ignored
This addresses issue 4743 where the system ignores Internal Notes on Ticket
Creation. This is due to the ticket being assigned and not having the
Internal Note passed along.
2019-02-25 13:17:02 -06:00
Peter Rotich
2cbcff6957 Merge pull request #4749 from TheHADILP/patch-1
Minor typo fix
2019-02-25 08:53:14 -06:00
Peter Rotich
443c7275c0 Merge pull request #4755 from JediKev/issue/custom-column-org-link
issue: Custom Column Org Link
2019-02-25 08:23:13 -06:00
JediKev
aad4c93b78 issue: Custom Column Org Link
This addresses issue 4579 where setting a Custom Column to User Organization
and choosing the User Org Link filter the system shows the wrong link to the
Org. This is due to "scp/" not being added to the URL therefore showing an
invalid link.
2019-02-22 09:15:20 -06:00
Sebastian Haderecker
ff2e8af56d Minor typo fix 2019-02-21 11:22:33 +01:00
Peter Rotich
a2aa8aec67 Merge pull request #4730 from aydreeihn/issue/info-field-attachments
Issue: Attachments on Information Fields
2019-02-16 22:02:16 -06:00
Peter Rotich
2f62764147 Merge pull request #4732 from JediKev/issue/no-save-button-on-quicknotes
issue: No Save Button On Quicknotes
2019-02-16 21:51:03 -06:00
Peter Rotich
124bb9bd61 Merge pull request #4741 from greezybacon/issue/user-ldap-search
users: Fix searching of users
2019-02-16 21:48:38 -06:00
Jared Hancock
20c993236f users: Fix seaching of users
The CDATA table may be dropped on upgrade and is not created on new installs.
So it should be created on demand when searching for users.
2019-02-15 16:35:53 -06:00
Peter Rotich
fe8c585827 Merge pull request #4739 from JediKev/issue/upgrader-wrong-guide-link
issue: Upgrader Wrong Guide Link
2019-02-15 13:19:54 -06:00
JediKev
b210e4f842 issue: APC CLI
This addresses issue 4720 where creating tickets via CLI fails to set a
status and crashes with an "APC must be enabled" error. This adds a check to
see if the APC module is loaded before continuing.
2019-02-15 11:51:46 -06:00
JediKev
61e240c38e issue: Upgrader Wrong Guide Link
This addresses issue 4738 where the Upgrade and Migration Guide link is
incorrect. This updates the link to the new Documentation site.
2019-02-14 15:44:12 -06:00
aydreeihn
216453f382 Issue: Duplicate Tickets in Closed Queue
When going to my closed queue, I had the same ticket showing multiple times. This commit moves the call to the distinct method outside of any if statements so that the tickets will always be grouped by their id.
2019-02-14 14:51:10 -06:00
JediKev
bff0647f4b issue: No Save Button On Quicknotes
This addresses issue 4725 where there is no save button when editing a quick
note. This is due to the jQuery update which changed how a few things work
with redactor.
2019-02-14 08:47:13 -06:00
aydreeihn
89fb49618d Issue: Attachments on Information Fields
This commit fixes an issue where we failed to upload attachments on Information Fields. In the to_config function, we were only taking the array_values of attachments which would return an array with only the file name ([0] => 'filename') instead of an array with the file id and file name ([123] => 'filename').

Now, when we pass the keepers to keepOnlyFileIds, we have a file id that can be passed to the upload function.
2019-02-13 13:08:39 -06:00
Peter Rotich
eafb34d3a9 Merge pull request #4721 from JediKev/issue/local-avatar-annotation
issue: Local Avatar Annotation
2019-02-12 16:40:37 -06:00
Peter Rotich
4e5de6dc82 Merge pull request #4724 from protich/issue/active-subnav
Selected Navigation Item
2019-02-12 16:38:42 -06:00
Peter Rotich
771e5569aa Selected Navigation Item
This addresses an issue where main queues were not marked as active
resulting in "New Ticket" link getting auto-set as active (bold).
2019-02-12 22:30:47 +00:00
Peter Rotich
55fc20b27c Merge pull request #4722 from JediKev/issue/php72-plugin-delete
issue: PHP 7.2 Plugin Delete
2019-02-12 14:57:07 -06:00
JediKev
6f2fd38490 issue: Local Avatar Annotation
This addresses issue 4700 where local avatars where breaking queues with
Avatar Annotation. This is due to the local avatars not having a `setSize()`
function. This updates local avatars so that they can be resized.
2019-02-12 14:53:07 -06:00
Peter Rotich
8d01b1f6d4 Merge pull request #4719 from greezybacon/issue/jq-3-file-drop
filedrop: Fix file drag and drop
2019-02-12 14:48:58 -06:00
JediKev
5407f907b8 issue: PHP 7.2 Plugin Delete
This addresses issue 4718 where deleting a plugin using PHP 7.2 throws an
error. This is due to errors not being passed to uninstall which causes the
"Too Few Arguments" error.
2019-02-12 11:31:31 -06:00
Jared Hancock
c2fdc0a8f9 jQuery: Fix default slow appearance of .show()
With the patch introduced to fix the `afterShow` event for jQuery three,
this appear sort of slowly be default. This addresses the issue by providing
a default of 0ms to show things, so they show immediately.
2019-02-11 21:06:46 -06:00
Jared Hancock
0ef7cc1aac filedrop: Fix file drag and drop
This fixes an issue introduced in the upgrade to jQuery three. The filedrop
field was not updated correctly and drag and drop files was broken.
Additionally, this handles cases where files are dragged over the box but
not dropped. The style of the box is correctly reset after the drag leaves
the box.
2019-02-11 20:52:17 -06:00
Peter Rotich
eebef63904 Merge branch 'develop' into develop-next 2019-02-11 19:31:27 +00:00
Jared Hancock
c54372fabf queues: Fix compatibility issues with newer jQuery 2019-02-11 19:30:53 +00:00
Peter Rotich
a23aca0fbd Merge pull request #4706 from JediKev/issue/ban-list
issue: System Ban List
2019-02-11 11:03:53 -06:00
Peter Rotich
ce3546182e Merge pull request #4711 from greezybacon/issue/4698
queues: Fix compatibility issues with newer jQuery
2019-02-11 11:03:08 -06:00
Jared Hancock
7496a1cd49 queues: Fix compatibility issues with newer jQuery 2019-02-10 20:29:39 -06:00
JediKev
43f11d1368 issue: System Ban List
This addresses an issue where the system banlist throws the error "SYSTEM
BAN LIST filter is DISABLED". This is due to the Filters moving to ORM but
not updating everywhere they are used.
2019-02-08 12:17:18 -06:00
JediKev
f4e693ef3e issue: Required Custom Field User Registration
This addresses an issue where failing to input data for a Required Custom
Field on the User Registration form will not return validation errors.
2018-08-28 17:34:28 -05:00
JediKev
d729810a96 oops: Fix System Timezone Variable
This addresses an issue where people are getting the incorrect time on
tickets even though they have all the timezones set correctly. The
current MySQL variable the system uses to determine the timezone is
`system_time_zone`. This variable is set by the server and sometimes
cannot be updated properly (or cannot be updated at all). This changes
the variable from `system_time_zone` to `time_zone` so if in the event
the system returns the incorrect time and they can’t update the server
timezone properly, they can just change the `@@global.time_zone` and
`@@session.time_zone` MySQL variables and should get the correct time.
2018-07-17 10:16:34 -05:00
JediKev
c354bb9310 issue: Maxfilesize Comma Crash
This addresses an issue on the forums where having a comma in your number
format (instead of periods) would crash the system if using a language pack
other than English. (Fix suggested by @rspma on the forums.)
2018-07-17 09:32:44 -05:00
Nicoletta Maia
758a9826f2 Issue: manage.php file migrate fails when files have size=0 2017-10-26 11:40:33 +02:00
1486 changed files with 165107 additions and 47921 deletions

2
.gitignore vendored
View File

@@ -7,6 +7,8 @@ setup/cli/modules/importer
.vagrant
._.DS_Store
Vagrantfile
# VS Code workspace files
*.code-workspace
# Staging directory used for packaging script
stage

View File

@@ -2,7 +2,7 @@
* [ ] Can you reproduce the problem in a fresh installation of the "develop" branch?
* [ ] Do you have any errors in the PHP error log, or javascript console?
* [ ] Did you check the [osTicket forums](http://osticket.com/forum/categories)?
* [ ] Did you check the [osTicket forums](https://forum.osticket.com/)?
* [ ] Did you [perform a cursory search](https://github.com/osTicket/osTicket/issues) to see if your bug or enhancement is already reported?
For more information on how to write a good [bug report](https://github.com/osTicket/osTicket/wiki/Github-Issues-Guidelines)
@@ -23,6 +23,6 @@ For more information on how to write a good [bug report](https://github.com/osTi
### Versions
Admin panel -> Dashboard -> Information which also additionally gives you information about you server.
Admin panel -> Dashboard -> Information which also additionally gives you information about your server.
Also, please include the OS and what version of the OS you're running. As well as your browser and browser version.

View File

@@ -1,6 +1,6 @@
osTicket
========
<a href="http://osticket.com"><img src="http://osticket.com/sites/default/files/osTicket.jpg"
<a href="https://osticket.com"><img height="80px" width="80px" src="images/favicon.png"
align="left" hspace="10" vspace="6"></a>
**osTicket** is a widely-used open source support ticket system. It seamlessly
@@ -22,13 +22,14 @@ easy to setup and use. The best part is, it's completely free.
Requirements
------------
* HTTP server running Microsoft® IIS or Apache
* PHP version 5.4 or greater, 5.6 is recommended
* PHP version 8.2 - 8.4 (8.4 recommended)
* mysqli extension for PHP
* MySQL database version 5.0 or greater
* MySQL database version 5.5 (or greater)
### Recommendations
* gd, gettext, imap, json, mbstring, and xml extensions for PHP
* APC module enabled and configured for PHP
* ctype, fileinfo, gd, gettext, iconv, imap, intl, json, mbstring,
Zend OPcache, phar, xml, xml-dom, and zip extensions for PHP
* APCu module enabled and configured for PHP
Deployment
----------
@@ -58,40 +59,16 @@ Upgrading
---------
osTicket supports upgrading from 1.6-rc1 and later versions. As with any
upgrade, strongly consider a backup of your attachment files, database, and
osTicket codebase before embarking on an upgrade.
To trigger the update process, fetch the osTicket tarball from either
the osTicket [github](http://github.com/osTicket/osTicket/releases) page
or from the [osTicket website](http://osticket.com). Extract the tarball
into the folder of your osTicket codebase. This can also be accomplished
with the zip file, and a FTP client can of course be used to upload the new
source code to your server.
Any way you choose your adventure, when you have your codebase upgraded to
osTicket-1.7, visit the /scp page of you ticketing system. The upgrader will
be presented and will walk you through the rest of the process. (The couple
clicks needed to go through the process are pretty boring to describe).
### Upgrading from v1.6
**WARNING**: If you are upgrading from osTicket 1.6, please ensure that all
your files in your upload folder are both readable and writable to your
http server software. Unreadable files will not be migrated to the
database during the upgrade and will be effectively lost.
After upgrading, we recommend migrating your attachments to the database or
to the new filesystem plugin. Use the `file` command-line applet to perform
the migration.
php manage.php file migrate --backend=6 --to=D
View the UPGRADING.txt file for other todo items to complete your upgrade.
osTicket codebase before embarking on an upgrade. Please review our [Upgrade
Guide](https://docs.osticket.com/en/latest/Getting%20Started/Upgrade%20and%20Migration.html)
or the [UPGRADING.txt file](UPGRADING.txt) for upgrade instructions.
Help
----
Visit the [wiki](http://osticket.com/wiki/Home) or the
[forum](http://osticket.com/forums/). And if you'd like professional help
Visit the [Documentation](https://docs.osticket.com/) or the
[forum](https://forum.osticket.com/). And if you'd like professional help
managing your osTicket installation,
[commercial support](http://osticket.com/support/) is available.
[commercial support](https://osticket.com/support/) is available.
Contributing
------------
@@ -101,18 +78,17 @@ the feature is published in your fork, send a pull request to begin the
conversation of integrating your new feature into osTicket.
### Localization
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/osticket-official/localized.png)](http://i18n.osticket.com/project/osticket-official)
[![Crowdin](https://badges.crowdin.net/osticket-official/localized.svg)](https://crowdin.com/project/osticket-official)
The interface for osTicket is now completely translatable. Language packs
are available on the [download page](http://osticket.com/download). If you
do not see your language there, join the [Crowdin](http://i18n.osticket.com)
are available on the [download page](https://osticket.com/download). If you
do not see your language there, join the [Crowdin](https://crowdin.com/project/osticket-official)
project and request to have your language added. Languages which reach 100%
translated are are significantly reviewed will be made available on the
osTicket download page.
The software can also be translated in place in our [JIPT site]
(http://jipt.i18n.osticket.com). Once you have a Crowdin account, login and
translate the software in your browser!
The software can also be translated in place in our [JIPT site](http://jipt.i18n.osticket.com).
Once you have a Crowdin account, login and translate the software in your browser!
Localizing strings in new code requires usage of a [few rules](setup/doc/i18n.md).
@@ -123,18 +99,19 @@ file for the gory details of the General Public License.
osTicket is supported by several magical open source projects including:
* [Font-Awesome](http://fortawesome.github.com/Font-Awesome/)
* [HTMLawed](http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed)
* [jQuery dropdown](http://labs.abeautifulsite.net/jquery-dropdown/)
* [jsTimezoneDetect](http://pellepim.bitbucket.org/jstz/)
* [mPDF](http://www.mpdf1.com/)
* [PasswordHash](http://www.openwall.com/phpass/)
* [PEAR](http://pear.php.net/package/PEAR)
* [PEAR/Auth_SASL](http://pear.php.net/package/Auth_SASL)
* [PEAR/Mail](http://pear.php.net/package/mail)
* [PEAR/Net_SMTP](http://pear.php.net/package/Net_SMTP)
* [PEAR/Net_Socket](http://pear.php.net/package/Net_Socket)
* [PEAR/Serivces_JSON](http://pear.php.net/package/Services_JSON)
* [Font-Awesome](https://fontawesome.com/)
* [HTMLawed](https://www.bioinformatics.org/phplabware/internal_utilities/htmLawed)
* [jQuery dropdown](https://labs.abeautifulsite.net/jquery-dropdown/) (Project Deleted)
* [jsTimezoneDetect](https://pellepim.bitbucket.org/jstz/)
* [laminas-mail](https://github.com/laminas/laminas-mail)
* [mPDF](https://github.com/mpdf/mpdf)
* [PasswordHash](https://www.openwall.com/phpass/)
* [PEAR](https://pear.php.net/package/PEAR)
* [PEAR/Auth_SASL](https://pear.php.net/package/Auth_SASL)
* [PEAR/Mail](https://pear.php.net/package/mail)
* [PEAR/Net_SMTP](https://pear.php.net/package/Net_SMTP)
* [PEAR/Net_Socket](https://pear.php.net/package/Net_Socket)
* [PEAR/Serivces_JSON](https://pear.php.net/package/Services_JSON)
* [php-gettext](https://launchpad.net/php-gettext/)
* [phpseclib](http://phpseclib.sourceforge.net/)
* [Spyc](http://github.com/mustangostang/spyc)
* [phpseclib](https://phpseclib.sourceforge.net/)
* [Spyc](https://github.com/mustangostang/spyc)

5
SECURITY.md Normal file
View File

@@ -0,0 +1,5 @@
# Security Policy
## Reporting a Vulnerability
Please send all POCs to security[at]osticket[dot]com.

View File

@@ -1,5 +1,33 @@
Welcome to osTicket 1.7
=======================
Upgrading osTicket
==================
osTicket supports upgrading from 1.6-rc1 and later versions. As with any
upgrade, strongly consider a backup of your attachment files, database, and
osTicket codebase before embarking on an upgrade.
To trigger the update process, fetch the osTicket tarball from either
the osTicket [GitHub](https://github.com/osTicket/osTicket/releases) page
or from the [osTicket website](https://osticket.com/download). Extract the tarball
into the folder of your osTicket codebase. This can also be accomplished
with the zip file, and a FTP client can of course be used to upload the new
source code to your server.
Any way you choose your adventure, when you have your codebase upgraded,
visit the /scp page of you ticketing system. The upgrader will
be presented and will walk you through the rest of the process. (The couple
clicks needed to go through the process are pretty boring to describe).
### Upgrading from v1.6
**WARNING**: If you are upgrading from osTicket 1.6, please ensure that all
your files in your upload folder are both readable and writable to your
http server software. Unreadable files will not be migrated to the
database during the upgrade and will be effectively lost.
After upgrading, we recommend migrating your attachments to the database or
to the new filesystem plugin. Use the `file` command-line applet to perform
the migration.
php manage.php file migrate --backend=6 --to=D
Some tasks are better left to a system administrator rather than a mindless
upgrade script. These are those remaining things that we'd rather you take
care of:

File diff suppressed because it is too large Load Diff

View File

@@ -34,7 +34,7 @@ elseif ($thisclient) {
$user_form = $f;
$user_form->getField('email')->configure('disabled', true);
}
}
}
}
// Existing client (with an account) updating profile
else {
@@ -57,15 +57,25 @@ elseif ($_POST) {
if ($thisclient) {
$user_form->getField('email')->configure('disabled', true);
$user_form->getField('email')->value = $thisclient->getEmail();
$_POST['email'] = $thisclient->getEmail();
}
if (!$user_form->isValid(function($f) { return !$f->isVisibleToUsers(); }))
if (!$user_form->isValid(function($f) { return $f->isVisibleToUsers(); }))
$errors['err'] = __('Incomplete client information');
elseif (!$_POST['backend'] && !$_POST['passwd1'])
$errors['passwd1'] = __('New password is required');
elseif (!$_POST['backend'] && $_POST['passwd2'] != $_POST['passwd1'])
$errors['passwd1'] = __('Passwords do not match');
else {
try {
UserAccount::checkPassword($_POST['passwd1']);
} catch (BadPassword $ex) {
$errors['passwd1'] = $ex->getMessage();
}
}
if ($errors)
$errors['err'] = $errors['err'] ?: __('Unable to register account. See messages below');
// XXX: The email will always be in use already if a guest is logged in
// and is registering for an account. Instead,
elseif (($addr = $user_form->getField('email')->getClean())
@@ -115,6 +125,8 @@ elseif ($_POST) {
}
break;
}
// Rotate CSRF on successful POST
$ost->getCSRF()->rotate();
}
if ($errors && $user && $user != $thisclient)
@@ -124,4 +136,3 @@ elseif ($_POST) {
include(CLIENTINC_DIR.'header.inc.php');
include(CLIENTINC_DIR.$inc);
include(CLIENTINC_DIR.'footer.inc.php');

View File

@@ -40,12 +40,13 @@ $dispatcher = patterns('',
url('^/form/', patterns('ajax.forms.php:DynamicFormsAjaxAPI',
url_get('^help-topic/(?P<id>\d+)$', 'getClientFormsForHelpTopic'),
url_post('^upload/(\d+)?$', 'upload'),
url_post('^upload/(\w+)?$', 'attach')
url_post('^upload/(\w+)?$', 'attach'),
url_post('^upload/(?P<object>ticket|task)/(\w+)$', 'attach')
)),
url('^/i18n/(?P<lang>[\w_]+)/', patterns('ajax.i18n.php:i18nAjaxAPI',
url_get('(?P<tag>\w+)$', 'getLanguageFile')
))
);
Signal::send('ajax.client', $dispatcher);
print $dispatcher->resolve($ost->get_path_info());
print $dispatcher->resolve(Osticket::get_path_info());
?>

View File

@@ -15,10 +15,19 @@
**********************************************************************/
file_exists('../main.inc.php') or die('System Error');
// Disable sessions for the API. API should be considered stateless and
// shouldn't chew up database records to store sessions
if (!defined('DISABLE_SESSION'))
define('DISABLE_SESSION', true);
/*
* Why API_SESSION ??
* It indicates that the session is API - which session handler should handle as
* stateless for new sessions.
* Existing session continue to work as expected - this it's important for
* SSO authentication, which uses /api/auth/* endpoints. Such calls are not
* stateless.
*
*/
define('API_SESSION', true);
// APICALL const.
define('APICALL', true);
require_once('../main.inc.php');
require_once(INCLUDE_DIR.'class.http.php');

View File

@@ -13,15 +13,9 @@
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
// Use sessions — it's important for SSO authentication, which uses
// /api/auth/ext
define('DISABLE_SESSION', false);
require 'api.inc.php';
# Include the main api urls
require_once INCLUDE_DIR."class.dispatcher.php";
$dispatcher = patterns('',
url_post("^/tickets\.(?P<format>xml|json|email)$", array('api.tickets.php:TicketApiController','create')),
url('^/tasks/', patterns('',
@@ -29,8 +23,8 @@ $dispatcher = patterns('',
))
);
// Send api signal so backend can register endpoints
Signal::send('api', $dispatcher);
# Call the respective function
print $dispatcher->resolve($ost->get_path_info());
print $dispatcher->resolve(Osticket::get_path_info());
?>

View File

@@ -18,10 +18,10 @@ ini_set('memory_limit', '256M'); //The concern here is having enough mem for ema
@chdir(dirname(__FILE__).'/'); //Change dir.
require('api.inc.php');
//Only local piping supported via pipe.php
// Only local piping supported via pipe.php
if (!osTicket::is_cli())
die(__('pipe.php only supports local piping - use http -> api/tickets.email'));
require_once(INCLUDE_DIR.'api.tickets.php');
PipeApiController::process();
PipeApiController::process('cli');
?>

View File

@@ -28,4 +28,4 @@ require_once INCLUDE_DIR.'/class.dispatcher.php';
$dispatcher = new Dispatcher();
Signal::send('ajax.client', $dispatcher);
print $dispatcher->resolve($ost->get_path_info());
print $dispatcher->resolve(Osticket::get_path_info());

View File

@@ -23,7 +23,7 @@ require_once INCLUDE_DIR . 'class.avatar.php';
try {
$ra = new RandomAvatar($_GET['mode']);
$avatar = $ra->makeAvatar($_GET['uid']);
$avatar = $ra->makeAvatar($_GET['uid'], $_GET['size']);
Http::response(200, false, 'image/png', false);
Http::cacheable($_GET['uid'], false, 86400);

View File

@@ -21,9 +21,7 @@ class Bootstrap {
session_cache_limiter('nocache');
#Error reporting...Good idea to ENABLE error reporting to a file. i.e display_errors should be set to false
$error_reporting = E_ALL & ~E_NOTICE;
if (defined('E_STRICT')) # 5.4.0
$error_reporting &= ~E_STRICT;
$error_reporting = E_ALL & ~E_NOTICE & ~E_WARNING;
if (defined('E_DEPRECATED')) # 5.3.0
$error_reporting &= ~(E_DEPRECATED | E_USER_DEPRECATED);
error_reporting($error_reporting); //Respect whatever is set in php.ini (sysadmin knows better??)
@@ -45,11 +43,29 @@ class Bootstrap {
}
date_default_timezone_set('UTC');
if (!function_exists('exif_imagetype')) {
function exif_imagetype ($filename) {
if ((list($width,$height,$type,) = getimagesize($filename)) !== false)
return $type;
return false;
}
}
if (!function_exists('exif_imagetype')) {
function exif_imagetype ($filename) {
if ((list($width,$height,$type,) = getimagesize($filename)) !== false)
return $type;
return false;
}
}
if (!isset($_SERVER['REMOTE_ADDR']))
$_SERVER['REMOTE_ADDR'] = '';
}
function https() {
static function https() {
return osTicket::is_https();
}
@@ -92,6 +108,7 @@ class Bootstrap {
define('THREAD_TABLE', $prefix.'thread');
define('THREAD_ENTRY_TABLE', $prefix.'thread_entry');
define('THREAD_ENTRY_EMAIL_TABLE', $prefix.'thread_entry_email');
define('THREAD_ENTRY_MERGE_TABLE', $prefix.'thread_entry_merge');
define('LOCK_TABLE',$prefix.'lock');
@@ -124,6 +141,7 @@ class Bootstrap {
define('SLA_TABLE', $prefix.'sla');
define('EMAIL_TABLE',$prefix.'email');
define('EMAIL_ACCOUNT_TABLE', $prefix.'email_account');
define('EMAIL_TEMPLATE_GRP_TABLE',$prefix.'email_template_group');
define('EMAIL_TEMPLATE_TABLE',$prefix.'email_template');
@@ -132,6 +150,7 @@ class Bootstrap {
define('FILTER_ACTION_TABLE', $prefix.'filter_action');
define('PLUGIN_TABLE', $prefix.'plugin');
define('PLUGIN_INSTANCE_TABLE', $prefix.'plugin_instance');
define('SEQUENCE_TABLE', $prefix.'sequence');
define('TRANSLATION_TABLE', $prefix.'translation');
define('QUEUE_TABLE', $prefix.'queue');
@@ -142,11 +161,14 @@ class Bootstrap {
define('QUEUE_EXPORT_TABLE', $prefix.'queue_export');
define('QUEUE_CONFIG_TABLE', $prefix.'queue_config');
define('SCHEDULE_TABLE', $prefix.'schedule');
define('SCHEDULE_ENTRY_TABLE', $prefix.'schedule_entry');
define('API_KEY_TABLE',$prefix.'api_key');
define('TIMEZONE_TABLE',$prefix.'timezone');
}
function loadConfig() {
static function loadConfig() {
#load config info
$configfile='';
if(file_exists(INCLUDE_DIR.'ost-config.php')) //NEW config file v 1.6 stable ++
@@ -176,7 +198,7 @@ class Bootstrap {
define('SESSION_TTL', 86400); // Default 24 hours
}
function connect() {
static function connect() {
#Connect to the DB && get configuration from database
$ferror=null;
$options = array();
@@ -187,19 +209,29 @@ class Bootstrap {
'key' => DBSSLKEY
);
if (!db_connect(DBHOST, DBUSER, DBPASS, $options)) {
$ferror=sprintf('Unable to connect to the database — %s',db_connect_error());
}elseif(!db_select_database(DBNAME)) {
$ferror=sprintf('Unknown or invalid database: %s',DBNAME);
$hosts = explode(',', DBHOST);
foreach ($hosts as $host) {
$ferror = null;
try {
if (!db_connect($host, DBUSER, DBPASS, $options))
$ferror = sprintf('Unable to connect to the database — %s', db_connect_error());
elseif (!db_select_database(DBNAME))
$ferror = sprintf('Unknown or invalid database: %s', DBNAME);
} catch (mysqli_sql_exception $e) {
$ferror = sprintf('Database error — %s', $e->getMessage());
}
// break if no error
if (!$ferror) break;
}
if($ferror) //Fatal error
if ($ferror) //Fatal error
self::croak($ferror);
}
function loadCode() {
static function loadCode() {
#include required files
require_once INCLUDE_DIR.'class.util.php';
include_once INCLUDE_DIR.'class.controller.php';
require_once INCLUDE_DIR.'class.translation.php';
require_once(INCLUDE_DIR.'class.signal.php');
require(INCLUDE_DIR.'class.model.php');
@@ -210,14 +242,13 @@ class Bootstrap {
require(INCLUDE_DIR.'class.crypto.php');
require(INCLUDE_DIR.'class.page.php');
require_once(INCLUDE_DIR.'class.format.php'); //format helpers
require_once(INCLUDE_DIR.'class.validator.php'); //Class to help with basic form input validation...please help improve it.
require(INCLUDE_DIR.'class.mailer.php');
require_once(INCLUDE_DIR.'class.validator.php');
require_once INCLUDE_DIR.'mysqli.php';
require_once INCLUDE_DIR.'class.i18n.php';
require_once INCLUDE_DIR.'class.queue.php';
}
function i18n_prep() {
static function i18n_prep() {
ini_set('default_charset', 'utf-8');
ini_set('output_encoding', 'utf-8');
@@ -295,15 +326,21 @@ class Bootstrap {
if (extension_loaded('iconv'))
iconv_set_encoding('internal_encoding', 'UTF-8');
if (intval(phpversion()) < 7) {
function random_int($a, $b) {
return rand($a, $b);
}
}
function mb_str_wc($str) {
return count(preg_split('~[^\p{L}\p{N}\'].+~u', trim($str)));
}
}
function croak($message) {
static function croak($message) {
$msg = $message."\n\n".THISPAGE;
Mailer::sendmail(ADMIN_EMAIL, 'osTicket Fatal Error', $msg,
sprintf('"osTicket Alerts"<%s>', ADMIN_EMAIL));
osTicket\Mail\Mailer::sendmail(ADMIN_EMAIL, 'osTicket Fatal Error', $msg,
sprintf('"osTicket Alerts" <%s>', ADMIN_EMAIL));
//Display generic error to the user
Http::response(500, "<b>Fatal Error:</b> Contact system administrator.");
}
@@ -329,9 +366,9 @@ define('CLI_DIR', INCLUDE_DIR.'cli/');
/*############## Do NOT monkey with anything else beyond this point UNLESS you really know what you are doing ##############*/
#Current version && schema signature (Changes from version to version)
define('THIS_VERSION','1.8-git'); //Shown on admin panel
define('GIT_VERSION','$git');
define('MAJOR_VERSION', '1.10');
define('MAJOR_VERSION', '1.18');
define('THIS_VERSION', MAJOR_VERSION.'-git'); //Shown on admin panel
//Path separator
if(!defined('PATH_SEPARATOR')){
if(strpos($_ENV['OS'],'Win')!==false || !strcasecmp(substr(PHP_OS, 0, 3),'WIN'))
@@ -356,7 +393,7 @@ if (!defined('ROOT_PATH') && ($rp = osTicket::get_root_path(dirname(__file__))))
Bootstrap::init();
#CURRENT EXECUTING SCRIPT.
define('THISPAGE', Misc::currentURL());
define('THISPAGE', Http::url());
define('DEFAULT_MAX_FILE_UPLOADS', ini_get('max_file_uploads') ?: 5);
define('DEFAULT_PRIORITY_ID', 1);

View File

@@ -22,6 +22,10 @@ require_once($thisdir.'main.inc.php');
if(!defined('INCLUDE_DIR')) die('Fatal error');
// Enforce ACL (if applicable)
if (!Validator::check_acl('client'))
die(__('Access Denied'));
/*Some more include defines specific to client only */
define('CLIENTINC_DIR',INCLUDE_DIR.'client/');
define('OSTCLIENTINC',TRUE);
@@ -63,8 +67,9 @@ if($thisclient && $thisclient->getId() && $thisclient->isValid()){
}
/******* CSRF Protectin *************/
// Enforce CSRF protection for POSTS
if ($_POST && !$ost->checkCSRFToken()) {
// Enforce CSRF protection for state-changing methods
if (in_array($_SERVER['REQUEST_METHOD'], ['POST', 'PUT', 'PATCH', 'DELETE'])
&& !$ost->checkCSRFToken()) {
Http::redirect('index.php');
//just incase redirect fails
die('Action denied (400)!');
@@ -75,6 +80,8 @@ $ost->addExtraHeader('<meta name="csrf_token" content="'.$ost->getCSRFToken().'"
/* Client specific defaults */
define('PAGE_LIMIT', DEFAULT_PAGE_LIMIT);
define('SESSION_MAXLIFE', $thisclient ? $thisclient->getMaxIdleTime() :
SESSION_TTL);
require(INCLUDE_DIR.'class.nav.php');
$nav = new UserNav($thisclient, 'home');

View File

@@ -69,9 +69,9 @@
padding-left: 10px;
float: right;
}
.redactor-box + .filedrop .dropzone,
.redactor-box + div > .filedrop .dropzone,
.redactor-box + div > .filedrop .files {
.-redactor-container + .filedrop .dropzone,
.-redactor-container .filedrop .dropzone,
.-redactor-container .filedrop .files {
border-top-width: 1px;
border-top-left-radius: 0;
border-top-right-radius: 0;

View File

@@ -30,10 +30,10 @@
.flag.flag-bi {background-position: -112px -11px}
.flag.flag-bj {background-position: -128px -11px}
.flag.flag-bm {background-position: -144px -11px}
.flag.flag-bn {background-position: -160px -11px}
.flag.flag-bn {background-position: -32px -11px}
.flag.flag-bo {background-position: -176px -11px}
.flag.flag-br {background-position: -192px -11px}
.flag.flag-bs {background-position: -208px -11px}
.flag.flag-bs {background-position: 0px -11px}
.flag.flag-bt {background-position: -224px -11px}
.flag.flag-bv {background-position: -240px -11px}
.flag.flag-bw {background-position: 0 -22px}
@@ -122,8 +122,9 @@
.flag.flag-kg {background-position: -48px -77px}
.flag.flag-kh {background-position: -64px -77px}
.flag.flag-ki {background-position: -80px -77px}
.flag.flag-km {background-position: -96px -77px}
.flag.flag-km {background-position: -64px -77px}
.flag.flag-kn {background-position: -112px -77px}
.flag.flag-ko {background-position: -144px -77px}
.flag.flag-kp {background-position: -128px -77px}
.flag.flag-kr {background-position: -144px -77px}
.flag.flag-kurdistan {background-position: -160px -77px}
@@ -186,7 +187,7 @@
.flag.flag-pm {background-position: -48px -121px}
.flag.flag-pn {background-position: -64px -121px}
.flag.flag-pr {background-position: -80px -121px}
.flag.flag-ps {background-position: -96px -121px}
.flag.flag-ps {background-position: -48px 0px}
.flag.flag-pt {background-position: -112px -121px}
.flag.flag-pw {background-position: -128px -121px}
.flag.flag-py {background-position: -144px -121px}
@@ -211,6 +212,7 @@
.flag.flag-sn {background-position: -192px -132px}
.flag.flag-so {background-position: -208px -132px}
.flag.flag-somaliland {background-position: -224px -132px}
.flag.flag-sq {background-position: -96px 0px}
.flag.flag-sr {background-position: -240px -132px}
.flag.flag-ss {background-position: 0 -143px}
.flag.flag-st {background-position: -16px -143px}
@@ -244,7 +246,7 @@
.flag.flag-vc {background-position: -208px -154px}
.flag.flag-ve {background-position: -224px -154px}
.flag.flag-vg {background-position: -240px -154px}
.flag.flag-vi {background-position: 0 -165px}
.flag.flag-vi {background-position: -16px -165px}
.flag.flag-vn {background-position: -16px -165px}
.flag.flag-vu {background-position: -32px -165px}
.flag.flag-wales {background-position: -48px -165px}
@@ -256,3 +258,5 @@
.flag.flag-zanzibar {background-position: -144px -165px}
.flag.flag-zm {background-position: -160px -165px}
.flag.flag-zw {background-position: -176px -165px}
.flag.flag-fil {background-position: 0px -121px}
.flag.flag-kk {background-position: -208px -77px}

View File

@@ -0,0 +1,30 @@
.ui-timepicker-div .ui-widget-header { margin-bottom: 8px; }
.ui-timepicker-div dl { text-align: left; }
.ui-timepicker-div dl dt { float: left; clear:left; padding: 0 0 0 5px; }
.ui-timepicker-div dl dd { margin: 0 10px 10px 40%; }
.ui-timepicker-div td { font-size: 90%; }
.ui-tpicker-grid-label { background: none; border: none; margin: 0; padding: 0; }
.ui-timepicker-div .ui_tpicker_unit_hide{ display: none; }
.ui-timepicker-div .ui_tpicker_time .ui_tpicker_time_input { background: none; color: inherit; border: none; outline: none; border-bottom: solid 1px #555; width: 95%; }
.ui-timepicker-div .ui_tpicker_time .ui_tpicker_time_input:focus { border-bottom-color: #aaa; }
.ui-timepicker-rtl{ direction: rtl; }
.ui-timepicker-rtl dl { text-align: right; padding: 0 5px 0 0; }
.ui-timepicker-rtl dl dt{ float: right; clear: right; }
.ui-timepicker-rtl dl dd { margin: 0 40% 10px 10px; }
/* Shortened version style */
.ui-timepicker-div.ui-timepicker-oneLine { padding-right: 2px; }
.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time,
.ui-timepicker-div.ui-timepicker-oneLine dt { display: none; }
.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_time_label { display: block; padding-top: 2px; }
.ui-timepicker-div.ui-timepicker-oneLine dl { text-align: right; }
.ui-timepicker-div.ui-timepicker-oneLine dl dd,
.ui-timepicker-div.ui-timepicker-oneLine dl dd > div { display:inline-block; margin:0; }
.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_minute:before,
.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_second:before { content:':'; display:inline-block; }
.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_millisec:before,
.ui-timepicker-div.ui-timepicker-oneLine dl dd.ui_tpicker_microsec:before { content:'.'; display:inline-block; }
.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide,
.ui-timepicker-div.ui-timepicker-oneLine .ui_tpicker_unit_hide:before{ display: none; }

View File

@@ -85,3 +85,9 @@ input.dp {
.delete-draft:hover {
background-color: #fc9f41 !important;
}
.notice_bar { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; border: 1px solid #0a0; background: url('../assets/default/images/icons/ok.png') 10px 50% no-repeat #e0ffe0; }
.warning_bar { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; border: 1px solid #f26522; background: url('../assets/default/images/icons/alert.png') 10px 50% no-repeat #ffffdd; }
.error_bar { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; border: 1px solid #a00; background: url('../assets/default/images/icons/error.png') 10px 50% no-repeat #fff0f0; }

Binary file not shown.

File diff suppressed because one or more lines are too long

2
css/select2.min.css vendored

File diff suppressed because one or more lines are too long

View File

@@ -22,6 +22,8 @@
.thread-body section,
.thread-body summary {
display: block;
margin: 0;
margin-bottom: 1em;
}
.thread-body {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 418 B

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 436 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 262 B

After

Width:  |  Height:  |  Size: 376 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 348 B

After

Width:  |  Height:  |  Size: 458 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 B

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 278 B

After

Width:  |  Height:  |  Size: 394 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 B

After

Width:  |  Height:  |  Size: 438 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

After

Width:  |  Height:  |  Size: 6.4 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -45,9 +45,8 @@ if ($cfg->isAuthRequiredForFiles()
) {
// Try and determine if an agent is viewing the page / file
if (strpos($_SERVER['HTTP_REFERRER'], ROOT_PATH . 'scp/') !== false) {
$_SESSION['_staff']['auth']['dest'] =
'/' . ltrim($_SERVER['REQUEST_URI'], '/');
if (strpos($_SERVER['HTTP_REFERER'], ROOT_PATH . 'scp/') !== false) {
$_SESSION['_staff']['auth']['dest'] = Http::refresh_url();
Http::redirect(ROOT_PATH.'scp/login.php');
} else {
require 'secure.inc.php';
@@ -59,7 +58,7 @@ if ($cfg->isAuthRequiredForFiles()
// and the user has access to the parent ticket!!
if ($file->verifySignature($_GET['signature'], $_GET['expires'])) {
try {
if (($s = @$_GET['s']) && strpos($file->getType(), 'image/') === 0)
if (($s = @$_GET['s']) && $file->isInlineSafeImage())
return $file->display($s);
// Download the file..
@@ -68,7 +67,8 @@ if ($file->verifySignature($_GET['signature'], $_GET['expires'])) {
$file->download($filename, $disposition, @$_GET['expires']);
}
catch (Exception $ex) {
Http::response(500, 'Unable to find that file: '.$ex->getMessage());
$ost->logError(__('File download error'), $ex->getMessage());
Http::response(500, __('Unable to retrieve the requested file'));
}
}
// else

BIN
images/favicon.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@@ -152,7 +152,7 @@ class Services_JSON
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
}
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
$bytes = (ord($utf16[0]) << 8) | ord($utf16[1]);
switch(true) {
case ((0x7F & $bytes) == $bytes):
@@ -205,17 +205,17 @@ class Services_JSON
case 2:
// return a UTF-16 character from a 2-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr(0x07 & (ord($utf8{0}) >> 2))
. chr((0xC0 & (ord($utf8{0}) << 6))
| (0x3F & ord($utf8{1})));
return chr(0x07 & (ord($utf8[0]) >> 2))
. chr((0xC0 & (ord($utf8[0]) << 6))
| (0x3F & ord($utf8[1])));
case 3:
// return a UTF-16 character from a 3-byte UTF-8 char
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
return chr((0xF0 & (ord($utf8{0}) << 4))
| (0x0F & (ord($utf8{1}) >> 2)))
. chr((0xC0 & (ord($utf8{1}) << 6))
| (0x7F & ord($utf8{2})));
return chr((0xF0 & (ord($utf8[0]) << 4))
| (0x0F & (ord($utf8[1]) >> 2)))
. chr((0xC0 & (ord($utf8[1]) << 6))
| (0x7F & ord($utf8[2])));
}
// ignoring UTF-32 for now, sorry
@@ -260,7 +260,7 @@ class Services_JSON
*/
for ($c = 0; $c < $strlen_var; ++$c) {
$ord_var_c = ord($var{$c});
$ord_var_c = ord($var[$c]);
switch (true) {
case $ord_var_c == 0x08:
@@ -283,18 +283,18 @@ class Services_JSON
case $ord_var_c == 0x2F:
case $ord_var_c == 0x5C:
// double quote, slash, slosh
$ascii .= '\\'.$var{$c};
$ascii .= '\\'.$var[$c];
break;
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
// characters U-00000000 - U-0000007F (same as ASCII)
$ascii .= $var{$c};
$ascii .= $var[$c];
break;
case (($ord_var_c & 0xE0) == 0xC0):
// characters U-00000080 - U-000007FF, mask 110XXXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c, ord($var{$c + 1}));
$char = pack('C*', $ord_var_c, ord($var[$c + 1]));
$c += 1;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
@@ -304,8 +304,8 @@ class Services_JSON
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}));
ord($var[$c + 1]),
ord($var[$c + 2]));
$c += 2;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
@@ -315,9 +315,9 @@ class Services_JSON
// characters U-00010000 - U-001FFFFF, mask 11110XXX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}));
ord($var[$c + 1]),
ord($var[$c + 2]),
ord($var[$c + 3]));
$c += 3;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
@@ -327,10 +327,10 @@ class Services_JSON
// characters U-00200000 - U-03FFFFFF, mask 111110XX
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}),
ord($var{$c + 4}));
ord($var[$c + 1]),
ord($var[$c + 2]),
ord($var[$c + 3]),
ord($var[$c + 4]));
$c += 4;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
@@ -340,11 +340,11 @@ class Services_JSON
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
$char = pack('C*', $ord_var_c,
ord($var{$c + 1}),
ord($var{$c + 2}),
ord($var{$c + 3}),
ord($var{$c + 4}),
ord($var{$c + 5}));
ord($var[$c + 1]),
ord($var[$c + 2]),
ord($var[$c + 3]),
ord($var[$c + 4]),
ord($var[$c + 5]));
$c += 5;
$utf16 = $this->utf82utf16($char);
$ascii .= sprintf('\u%04s', bin2hex($utf16));
@@ -519,7 +519,7 @@ class Services_JSON
for ($c = 0; $c < $strlen_chrs; ++$c) {
$substr_chrs_c_2 = substr($chrs, $c, 2);
$ord_chrs_c = ord($chrs{$c});
$ord_chrs_c = ord($chrs[$c]);
switch (true) {
case $substr_chrs_c_2 == '\b':
@@ -549,7 +549,7 @@ class Services_JSON
case $substr_chrs_c_2 == '\\/':
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
$utf8 .= $chrs{++$c};
$utf8 .= $chrs[++$c];
}
break;
@@ -562,7 +562,7 @@ class Services_JSON
break;
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
$utf8 .= $chrs{$c};
$utf8 .= $chrs[$c];
break;
case ($ord_chrs_c & 0xE0) == 0xC0:
@@ -609,7 +609,7 @@ class Services_JSON
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
// array, or object notation
if ($str{0} == '[') {
if ($str[0] == '[') {
$stk = array(SERVICES_JSON_IN_ARR);
$arr = array();
} else {
@@ -648,12 +648,12 @@ class Services_JSON
$top = end($stk);
$substr_chrs_c_2 = substr($chrs, $c, 2);
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
if (($c == $strlen_chrs) || (($chrs[$c] == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
// found a comma that is not inside a string, array, etc.,
// OR we've reached the end of the character list
$slice = substr($chrs, $top['where'], ($c - $top['where']));
array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
//print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
//print("Found split at [$c]: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
if (reset($stk) == SERVICES_JSON_IN_ARR) {
// we are in an array, so just push an element onto the stack
@@ -690,48 +690,48 @@ class Services_JSON
}
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
} elseif ((($chrs[$c] == '"') || ($chrs[$c] == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
// found a quote, and we are not inside a string
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
//print("Found start of string at {$c}\n");
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs[$c]));
//print("Found start of string at [$c]\n");
} elseif (($chrs{$c} == $top['delim']) &&
} elseif (($chrs[$c] == $top['delim']) &&
($top['what'] == SERVICES_JSON_IN_STR) &&
((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
// found a quote, we're in a string, and it's not escaped
// we know that it's not escaped becase there is _not_ an
// odd number of backslashes at the end of the string so far
array_pop($stk);
//print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
//print("Found end of string at [$c]: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
} elseif (($chrs{$c} == '[') &&
} elseif (($chrs[$c] == '[') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-bracket, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
//print("Found start of array at {$c}\n");
//print("Found start of array at [$c]\n");
} elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
} elseif (($chrs[$c] == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
// found a right-bracket, and we're in an array
array_pop($stk);
//print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
//print("Found end of array at [$c]: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($chrs{$c} == '{') &&
} elseif (($chrs[$c] == '{') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a left-brace, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
//print("Found start of object at {$c}\n");
//print("Found start of object at [$c]\n");
} elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
} elseif (($chrs[$c] == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
// found a right-brace, and we're in an object
array_pop($stk);
//print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
//print("Found end of object at [$c]: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
} elseif (($substr_chrs_c_2 == '/*') &&
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
// found a comment start, and we are in an array, object, or slice
array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
$c++;
//print("Found start of comment at {$c}\n");
//print("Found start of comment at [$c]\n");
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
// found a comment end, and we're in one now
@@ -741,7 +741,7 @@ class Services_JSON
for ($i = $top['where']; $i <= $c; ++$i)
$chrs = substr_replace($chrs, ' ', $i, 1);
//print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
//print("Found end of comment at [$c]: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
}
@@ -762,7 +762,7 @@ class Services_JSON
/**
* @todo Ultimately, this should just call PEAR::isError()
*/
function isError($data, $code = null)
static function isError($data, $code = null)
{
if (class_exists('pear')) {
return PEAR::isError($data, $code);

View File

@@ -146,7 +146,7 @@ class Spyc {
* @return array
* @param string $input Path of YAML file or string containing YAML
*/
function YAMLLoad($input) {
static function YAMLLoad($input) {
$Spyc = new Spyc;
return $Spyc->__load($input);
}

View File

@@ -48,7 +48,7 @@ class AdminAjaxAPI extends AjaxController {
}
$title = __("Add New Department");
$path = ltrim($ost->get_path_info(), '/');
$path = ltrim(Osticket::get_path_info(), '/');
include STAFFINC_DIR . 'templates/quick-add.tmpl.php';
}
@@ -95,7 +95,7 @@ class AdminAjaxAPI extends AjaxController {
}
$title = __("Add New Team");
$path = ltrim($ost->get_path_info(), '/');
$path = ltrim(Osticket::get_path_info(), '/');
include STAFFINC_DIR . 'templates/quick-add.tmpl.php';
}
@@ -139,7 +139,7 @@ class AdminAjaxAPI extends AjaxController {
}
$title = __("Add New Role");
$path = ltrim($ost->get_path_info(), '/');
$path = ltrim(Osticket::get_path_info(), '/');
include STAFFINC_DIR . 'templates/quick-add-role.tmpl.php';
}
@@ -186,7 +186,7 @@ class AdminAjaxAPI extends AjaxController {
}
$title = __("Add New Agent");
$path = ltrim($ost->get_path_info(), '/');
$path = ltrim(Osticket::get_path_info(), '/');
include STAFFINC_DIR . 'templates/quick-add.tmpl.php';
}
@@ -225,10 +225,12 @@ class AdminAjaxAPI extends AjaxController {
Http::response(403, 'Access denied');
$sort = new QueueSort();
$errors = array();
if ($_POST) {
$_POST['root'] = $root;
$data_form = $sort->getDataConfigForm($_POST);
if ($data_form->isValid()) {
$sort->update($data_form->getClean() + $_POST, $root);
$sort->update($data_form->getClean() + $_POST, $errors);
if ($sort->save())
Http::response(201, $this->encode(array(
'id' => $sort->getId(),
@@ -237,6 +239,9 @@ class AdminAjaxAPI extends AjaxController {
}
}
if (!$data_form)
$data_form = $sort->getDataConfigForm();
include STAFFINC_DIR . 'templates/queue-sorting-add.tmpl.php';
}

View File

@@ -28,7 +28,7 @@ class ConfigAjaxAPI extends AjaxController {
list($sl, $locale) = explode('_', $lang);
$rtl = false;
foreach (Internationalization::availableLanguages() as $info) {
foreach (Internationalization::getConfiguredSystemLanguages() as $info) {
if (isset($info['direction']))
$rtl = true;
}
@@ -40,7 +40,7 @@ class ConfigAjaxAPI extends AjaxController {
$config=array(
'lock_time' => $cfg->getTicketLockMode() == Lock::MODE_DISABLED ? 0 : ($cfg->getLockTime()*60),
'html_thread' => (bool) $cfg->isRichTextEnabled(),
'date_format' => $cfg->getDateFormat(true),
'date_format' => Format::dtfmt_php2js($cfg->getDateFormat(true)),
'lang' => $lang,
'short_lang' => $sl,
'has_rtl' => $rtl,
@@ -49,6 +49,8 @@ class ConfigAjaxAPI extends AjaxController {
'primary_language' => Internationalization::rfc1766($primary),
'secondary_languages' => $cfg->getSecondaryLanguages(),
'page_size' => $thisstaff->getPageLimit() ?: PAGE_LIMIT,
'path' => ROOT_PATH,
'editor_spacing' => $thisstaff->editorSpacing(),
);
return $this->json_encode($config);
}
@@ -72,6 +74,7 @@ class ConfigAjaxAPI extends AjaxController {
'has_rtl' => $rtl,
'primary_language' => Internationalization::rfc1766($cfg->getPrimaryLanguage()),
'secondary_languages' => $cfg->getSecondaryLanguages(),
'path' => ROOT_PATH,
);
$config = $this->json_encode($config);

View File

@@ -19,7 +19,12 @@ require_once INCLUDE_DIR.'class.ajax.php';
class ContentAjaxAPI extends AjaxController {
function log($id) {
function syslog($id) {
global $thisstaff;
// Ensure there is a Staff and that they are an Administrator
if (!$thisstaff || !$thisstaff->isAdmin())
Http::response(403, 'Access Denied');
if($id && ($log=Log::lookup($id))) {
$content=sprintf('<div
@@ -27,7 +32,7 @@ class ContentAjaxAPI extends AjaxController {
style="white-space:pre-line;">%s</p>
<hr><strong>%s:</strong> <em>%s</em> <strong>%s:</strong> <em>%s</em></div>',
$log->getTitle(),
Format::display(str_replace(',',', ',$log->getText())),
Format::display(str_replace(',',', ',Format::htmlchars($log->getText()))),
__('Log Date'),
Format::daydatetime($log->getCreateDate()),
__('IP Address'),
@@ -142,8 +147,8 @@ class ContentAjaxAPI extends AjaxController {
function manageContent($id, $lang=false) {
global $thisstaff, $cfg;
if (!$thisstaff)
Http::response(403, 'Login Required');
if (!$thisstaff || !$thisstaff->isAdmin())
Http::response(403, 'Access Denied');
$content = Page::lookup($id, $lang);
@@ -168,8 +173,8 @@ class ContentAjaxAPI extends AjaxController {
function manageNamedContent($type, $lang=false) {
global $thisstaff, $cfg;
if (!$thisstaff)
Http::response(403, 'Login Required');
if (!$thisstaff || !$thisstaff->isAdmin())
Http::response(403, 'Access Denied');
$langs = $cfg->getSecondaryLanguages();
@@ -180,10 +185,10 @@ class ContentAjaxAPI extends AjaxController {
}
function updateContent($id) {
global $thisstaff;
global $thisstaff, $cfg;
if (!$thisstaff)
Http::response(403, 'Login Required');
if (!$thisstaff || !$thisstaff->isAdmin())
Http::response(403, 'Access Denied');
elseif (!($content = Page::lookup($id)))
Http::response(404, 'No such content');
@@ -201,6 +206,7 @@ class ContentAjaxAPI extends AjaxController {
}
if (!$errors['err'])
$errors['err'] = __('Correct any errors below and try again.');
$langs = Internationalization::getConfiguredSystemLanguages();
$info = $_POST;
$errors = Format::htmlchars($errors);
include STAFFINC_DIR . 'templates/content-manage.tmpl.php';

View File

@@ -3,10 +3,11 @@
if(!defined('INCLUDE_DIR')) die('!');
require_once(INCLUDE_DIR.'class.draft.php');
require_once(INCLUDE_DIR.'class.file.php');
class DraftAjaxAPI extends AjaxController {
function _createDraft($vars) {
static function _createDraft($vars) {
if (false === ($vars['body'] = self::_findDraftBody($_POST)))
return JsonDataEncoder::encode(array(
'error' => __("Draft body not found in request"),
@@ -16,24 +17,26 @@ class DraftAjaxAPI extends AjaxController {
if (!($draft = Draft::create($vars)) || !$draft->save())
Http::response(500, 'Unable to create draft');
header('Content-Type: application/json; charset=UTF-8');
echo JsonDataEncoder::encode(array(
'draft_id' => $draft->getId(),
));
}
function _getDraft($draft) {
static function _getDraft($draft) {
if (!$draft || !$draft instanceof Draft)
Http::response(205, "Draft not found. Create one first");
$body = Format::viewableImages($draft->getBody());
header('Content-Type: application/json; charset=UTF-8');
echo JsonDataEncoder::encode(array(
'body' => $body,
'draft_id' => $draft->getId(),
));
}
function _updateDraft($draft) {
static function _updateDraft($draft) {
if (false === ($body = self::_findDraftBody($_POST)))
return JsonDataEncoder::encode(array(
'error' => array(
@@ -48,94 +51,96 @@ class DraftAjaxAPI extends AjaxController {
echo "{}";
}
function _uploadInlineImage($draft) {
static function _uploadInlineImage($draft) {
global $cfg;
if (!isset($_POST['data']) && !isset($_FILES['file']))
if (!isset($_FILES['file']))
Http::response(422, "File not included properly");
# Fixup for expected multiple attachments
if (isset($_FILES['file'])) {
foreach ($_FILES['file'] as $k=>$v)
$_FILES['image'][$k] = array($v);
unset($_FILES['file']);
$file = AttachmentFile::format($_FILES['file']);
$file = AttachmentFile::format($_FILES['image']);
# Allow for data-uri uploaded files
$fp = fopen($file[0]['tmp_name'], 'rb');
if (fread($fp, 5) == 'data:') {
$data = 'data:';
while ($block = fread($fp, 8192))
$data .= $block;
$file[0] = Format::parseRfc2397($data);
list(,$ext) = explode('/', $file[0]['type'], 2);
$file[0] += array(
'name' => Misc::randCode(8).'.'.$ext,
'size' => strlen($file[0]['data']),
);
}
fclose($fp);
# TODO: Detect unacceptable attachment extension
# TODO: Verify content-type and check file-content to ensure image
$type = $file[0]['type'];
if (strpos($file[0]['type'], 'image/') !== 0)
return Http::response(403,
JsonDataEncoder::encode(array(
'error' => 'File type is not allowed',
))
);
# TODO: Verify file size is acceptable
if ($file[0]['size'] > $cfg->getMaxFileSize())
return Http::response(403,
JsonDataEncoder::encode(array(
'error' => 'File is too large',
))
);
// Paste uploads in Chrome will have a name of 'blob'
if ($file[0]['name'] == 'blob')
$file[0]['name'] = 'screenshot-'.Misc::randCode(4);
$ids = $draft->attachments->upload($file);
if (!$ids) {
if ($file[0]['error']) {
return Http::response(403,
JsonDataEncoder::encode(array(
'error' => $file[0]['error'],
))
);
}
else
return Http::response(500, 'Unable to attach image');
}
$id = (is_array($ids)) ? $ids[0] : $ids;
}
else {
$type = explode('/', $_POST['contentType']);
$info = array(
'data' => base64_decode($_POST['data']),
'name' => Misc::randCode(10).'.'.$type[1],
// TODO: Ensure _POST['contentType']
'type' => $_POST['contentType'],
// Allow one file at a time.
if (count($file) > 1)
return Http::response(403,
JsonDataEncoder::encode(array(
'error' => 'Send one file at a time',
))
);
# Allow for data-uri uploaded files
$fp = fopen($file[0]['tmp_name'], 'rb');
if (fread($fp, 5) == 'data:') {
$data = 'data:';
while ($block = fread($fp, 8192))
$data .= $block;
$file[0] = Format::parseRfc2397($data);
list(,$ext) = explode('/', $file[0]['type'], 2);
$file[0] += array(
'name' => Misc::randCode(8).'.'.$ext,
'size' => strlen($file[0]['data']),
);
// TODO: Detect unacceptable filetype
// TODO: Verify content-type and check file-content to ensure image
$id = $draft->attachments->save($info);
}
fclose($fp);
// Check file type to ensure image
$type = $file[0]['type'];
if (!AttachmentFile::isInlineSafeImageType($file[0]['type']))
return Http::response(403,
JsonDataEncoder::encode(array(
'error' => 'File type is not allowed',
))
);
// Check if file is truly an image
if (!FileUploadField::isValidFile($file[0]))
return Http::response(403,
JsonDataEncoder::encode(array(
'error' => 'File is not valid',
))
);
// Verify file size is acceptable
if ($file[0]['size'] > $cfg->getMaxFileSize())
return Http::response(403,
JsonDataEncoder::encode(array(
'error' => 'File is too large',
))
);
// Paste uploads in Chrome will have a name of 'blob'
if ($file[0]['name'] == 'blob')
$file[0]['name'] = 'screenshot-'.Misc::randCode(4);
$ids = $draft->attachments->upload($file);
if (!$ids) {
if ($file[0]['error']) {
return Http::response(403,
JsonDataEncoder::encode(array(
'error' => $file[0]['error'],
))
);
}
else
return Http::response(500, 'Unable to attach image');
}
$id = (is_array($ids)) ? $ids[0] : $ids;
if (!($f = AttachmentFile::lookup($id)))
return Http::response(500, 'Unable to attach image');
header('Content-Type: application/json; charset=UTF-8');
echo JsonDataEncoder::encode(array(
Format::sanitize($f->getName()) => array(
'content_id' => 'cid:'.$f->getKey(),
'id' => $f->getKey(),
// Return draft_id to connect the auto draft creation
'draft_id' => $draft->getId(),
'filelink' => $f->getDownloadUrl(
'url' => $f->getDownloadUrl(
['type' => 'D', 'deposition' => 'inline']),
));
)));
}
// Client interface for drafts =======================================
@@ -238,6 +243,7 @@ class DraftAjaxAPI extends AjaxController {
$draft = Draft::create(array(
'namespace' => $namespace,
'body' => ''
));
if (!$draft->save())
Http::response(500, 'Unable to create draft');
@@ -308,7 +314,8 @@ class DraftAjaxAPI extends AjaxController {
Http::response(403, "Login required for image upload");
$draft = Draft::create(array(
'namespace' => $namespace
'namespace' => $namespace,
'body' => ''
));
if (!$draft->save())
Http::response(500, 'Unable to create draft');
@@ -335,43 +342,49 @@ class DraftAjaxAPI extends AjaxController {
if (!$thisstaff)
Http::response(403, "Login required for file queries");
$search = Q::any([
Q::all([
'attachments__type__in' => array('C', 'F', 'T', 'P'),
'attachments__inline' => 1,
]),
'ft' => 'L',
]);
if (isset($_GET['threadId']) && is_numeric($_GET['threadId'])
&& ($thread = Thread::lookup($_GET['threadId']))
&& ($object = $thread->getObject())
&& ($thisstaff->canAccess($object))
) {
$union = ' UNION SELECT f.id, a.id as aid, a.`type`, a.`name` FROM '.THREAD_TABLE.' t
JOIN '.THREAD_ENTRY_TABLE.' th ON (th.thread_id = t.id)
JOIN '.ATTACHMENT_TABLE.' a ON (a.object_id = th.id AND a.`type` = \'H\')
JOIN '.FILE_TABLE.' f ON (a.file_id = f.id)
WHERE a.`inline` = 1 AND t.id='.db_input($_GET['threadId']);
$search->add(Q::all([
'attachments__thread_entry__thread_id' => $_GET['threadId'],
'attachments__inline' => 1,
]));
}
$sql = 'SELECT distinct f.id, a.id as aid, COALESCE(a.type, f.ft), a.`name` FROM '.FILE_TABLE
.' f LEFT JOIN '.ATTACHMENT_TABLE.' a ON (a.file_id = f.id)
WHERE ((a.`type` IN (\'C\', \'F\', \'T\', \'P\') AND a.`inline` = 1) OR f.ft = \'L\')'
.' AND f.`type` LIKE \'image/%\'';
if (!($res = db_query($sql.$union)))
Http::response(500, 'Unable to lookup files');
$images = AttachmentFile::objects()->filter([
$search,
'type__startswith' => 'image/',
])->distinct('id');
$files = array();
while (list($id, $aid, $type, $name) = db_fetch_row($res)) {
if (!($f = AttachmentFile::lookup((int) $id)))
foreach ($images as $f) {
if (!$f->isInlineSafeImage())
continue;
$url = $f->getDownloadUrl(['id' => $aid]);
$url = $f->getDownloadUrl();
$files[] = array(
// Don't send special sizing for thread items 'cause they
// should be cached already by the client
'thumb'=>$url.($type != 'H' ? '&s=128' : ''),
'image'=>$url,
'title'=>$name ?: $f->getName(),
'thumb' => $url.($f->type != 'H' ? '&s=128' : ''),
'url' => $url,
'title' => $f->getName(),
);
}
header('Content-Type: application/json; charset=UTF-8');
echo JsonDataEncoder::encode($files);
}
function _findDraftBody($vars) {
static function _findDraftBody($vars) {
if (isset($vars['name'])) {
$parts = array();
// Support nested `name`, like trans[lang]
@@ -383,8 +396,15 @@ class DraftAjaxAPI extends AjaxController {
return $focus;
}
}
// Get ThreadEntry field name.
$tform = TicketForm::objects()->one()->getForm();
$tfield = $tform->getField('message')->getFormName();
// Get Task Description field name.
$aform = TaskForm::objects()->one()->getForm();
$afield = $aform->getField('description')->getFormName();
$field_list = array('response', 'note', 'answer', 'body',
'message', 'issue', 'description');
$tfield, 'issue', $afield);
foreach ($field_list as $field) {
if (isset($vars[$field])) {
return $vars[$field];

59
include/ajax.email.php Normal file
View File

@@ -0,0 +1,59 @@
<?php
require_once INCLUDE_DIR . 'class.email.php';
class EmailAjaxAPI extends AjaxController {
function access() {
global $thisstaff;
if (!$thisstaff || !$thisstaff->isAdmin())
Http::response(403, 'Access Denied');
return true;
}
function stashFormData($id) {
if (!($email=Email::lookup($id)))
Http::response(404, 'Unknown Email');
$email->stashFormData($_POST ?: []);
Http::response(201, 'Form Stashed Maybe!');
}
function configureAuth($id, $type, $auth) {
if (!($email=Email::lookup($id)))
Http::response(404, 'Unknown Email');
if (!($account=$email->getAuthAccount($type)))
Http::response(404, 'Unknown Authentication Type');
if (!($form=$account->getAuthConfigForm($auth, $_POST ?: null)))
Http::response(404, 'Unknown Authentication Provider');
$info = $errors = [];
if ($_POST && $account->saveAuth($auth, $form, $errors)) {
if ($account->isOAuthAuth()
&& $account->shouldAuthorize()) {
Http::response(201, JsonDataEncoder::encode([
'redirect' => sprintf('emails.php?id=%d&do=autho&bk=%s',
$email->getId(), $account->getBkId())]),
'application/json');
} else {
Http::response(201, __('Successfully Updated Credentials.'));
}
}
// Passible types are basic or oauth2
list($authtype, $provider) = explode(':', $auth);
$template = sprintf('email-%sauth.tmpl.php', $authtype);
include INCLUDE_DIR . "staff/templates/$template";
}
/*
* Delete the OAuth2 token
*/
function deleteToken($id, $type) {
// Check to make sure the email exists
if (!($email=Email::lookup($id)))
Http::response(404, 'Unknown Email');
// Get the authentication account
if (!($account=$email->getAuthAccount($type)))
Http::response(404, 'Unknown Authentication Type');
// Destory the account config which will delete the token
if ($account->destroyConfig())
Http::response(201, __('Token Deleted Successfully.'));
// Couldn't delete the Token
Http::response(404, 'Unable to delete token.');
}
}

28
include/ajax.export.php Normal file
View File

@@ -0,0 +1,28 @@
<?php
require_once INCLUDE_DIR . 'class.export.php';
class ExportAjaxAPI extends AjaxController {
function check($id) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Agent login is required');
elseif (!($exporter=Exporter::load($id)) || !$exporter->isAvailable())
Http::response(404, 'No such export');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if ($exporter->isReady())
Http::response(201, $this->json_encode([
'status' => 'ready',
'href' => sprintf('export.php?id=%s',
$exporter->getId()),
'filename' => $exporter->getFilename()]));
else // Export is not ready... checkback in a few
Http::response(200, $this->json_encode([
'status' => 'notready']));
}
include STAFFINC_DIR . 'templates/export.tmpl.php';
}
}

View File

@@ -29,8 +29,9 @@ class DynamicFormsAjaxAPI extends AjaxController {
}
foreach ($topic->getForms() as $form) {
if (!$form->hasAnyVisibleFields())
if ($form->isDeleted() || !$form->hasAnyVisibleFields())
continue;
ob_start();
$form->getForm($_SESSION[':form-data'])->render(array(
'staff' => !$client,
@@ -78,7 +79,7 @@ class DynamicFormsAjaxAPI extends AjaxController {
$preserve = $field->flags & $p_mask;
// Set admin-configured flag states
$flags = array_reduce($_POST['flags'],
$flags = array_reduce($_POST['flags'] ?: array(),
function($a, $b) { return $a | $b; }, 0);
$field->flags = $flags | $preserve;
@@ -151,6 +152,8 @@ class DynamicFormsAjaxAPI extends AjaxController {
function saveListItem($list_id, $item_id) {
global $thisstaff;
$errors = array();
if (!$thisstaff)
Http::response(403, 'Login required');
@@ -179,7 +182,7 @@ class DynamicFormsAjaxAPI extends AjaxController {
'name' => $basic['name'],
'value' => $basic['value'],
'abbrev' => $basic['extra'],
]);
], $errors);
}
}
@@ -380,19 +383,30 @@ class DynamicFormsAjaxAPI extends AjaxController {
if (!$impl instanceof FileUploadField)
Http::response(400, 'Upload to a non file-field');
header('Content-Type: application/json; charset=UTF-8');
return JsonDataEncoder::encode(
array('id'=>$impl->ajaxUpload())
);
}
function attach() {
function attach($object=null) {
global $thisstaff;
$filter = array('type__contains'=>'thread');
// Determine if for Ticket/Task/Custom
if ($object && is_string($object)) {
if ($object == 'ticket')
$filter['form_id'] = TicketForm::objects()->one()->id;
elseif ($object == 'task')
$filter['form_id'] = TaskForm::objects()->one()->id;
}
$config = DynamicFormField::objects()
->filter(array('type__contains'=>'thread'))
->filter($filter)
->order_by('id')
->first()->getConfiguration();
$field = new FileUploadField();
$field->_config = $config;
header('Content-Type: application/json; charset=UTF-8');
return JsonDataEncoder::encode(
array('id'=>$field->ajaxUpload($thisstaff ? true : false))
);

View File

@@ -49,6 +49,7 @@ class i18nAjaxAPI extends AjaxController {
$json = JsonDataEncoder::encode($phrases) ?: '{}';
//Http::cacheable(md5($json), $lm);
header('Content-Type: application/json; charset=UTF-8');
return $json;
}
@@ -73,7 +74,7 @@ class i18nAjaxAPI extends AjaxController {
}
else {
// Avoid XSS injection
$p->text = trim(Format::striptags($phrase));
$p->text = trim(Format::sanitize($phrase));
$p->agent_id = $thisstaff->getId();
}
}
@@ -124,6 +125,7 @@ class i18nAjaxAPI extends AjaxController {
$json = JsonDataEncoder::encode($langs);
Http::cacheable(md5($json), $cfg->lastModified());
header('Content-Type: application/json; charset=UTF-8');
return $json;
}
@@ -142,6 +144,7 @@ class i18nAjaxAPI extends AjaxController {
$json = JsonDataEncoder::encode($langs);
Http::cacheable(md5($json), $cfg->lastModified());
header('Content-Type: application/json; charset=UTF-8');
return $json;
}
}

View File

@@ -85,7 +85,7 @@ class KbaseAjaxAPI extends AjaxController {
$title = __("Manage FAQ Access");
$verb = __('Update');
$path = ltrim($ost->get_path_info(), '/');
$path = ltrim(Osticket::get_path_info(), '/');
include STAFFINC_DIR . 'templates/quick-add.tmpl.php';
}

View File

@@ -13,6 +13,9 @@ class NoteAjaxAPI extends AjaxController {
Http::response(403, "Login required");
elseif (!($note = QuickNote::lookup($id)))
Http::response(205, "Note not found");
elseif (($note->staff_id !== $thisstaff->getId())
&& !$thisstaff->isAdmin())
Http::response(403, "Access Denied");
Http::response(200, $note->display());
}
@@ -24,6 +27,9 @@ class NoteAjaxAPI extends AjaxController {
Http::response(403, "Login required");
elseif (!($note = QuickNote::lookup($id)))
Http::response(205, "Note not found");
elseif (($note->staff_id !== $thisstaff->getId())
&& !$thisstaff->isAdmin())
Http::response(403, "Access Denied");
elseif (!isset($_POST['note']) || !$_POST['note'])
Http::response(422, "Send `note` parameter");
@@ -41,6 +47,9 @@ class NoteAjaxAPI extends AjaxController {
Http::response(403, "Login required");
elseif (!($note = QuickNote::lookup($id)))
Http::response(205, "Note not found");
elseif (($note->staff_id !== $thisstaff->getId())
&& !$thisstaff->isAdmin())
Http::response(403, "Access Denied");
elseif (!$note->delete())
Http::response(500, "Unable to remove note");
@@ -52,6 +61,9 @@ class NoteAjaxAPI extends AjaxController {
if (!$thisstaff)
Http::response(403, "Login required");
elseif (!in_array(substr($ext_id, 0, 1), ['O', 'U'])
&& !$thisstaff->isAdmin())
Http::response(403, "Access Denied");
elseif (!isset($_POST['note']) || !$_POST['note'])
Http::response(422, "Send `note` parameter");

View File

@@ -17,6 +17,7 @@ if(!defined('INCLUDE_DIR')) die('403');
require_once INCLUDE_DIR . 'class.organization.php';
include_once(INCLUDE_DIR.'class.ticket.php');
require_once INCLUDE_DIR.'ajax.tickets.php';
class OrgsAjaxAPI extends AjaxController {
@@ -24,12 +25,12 @@ class OrgsAjaxAPI extends AjaxController {
if(!isset($_REQUEST['q'])) {
Http::response(400, 'Query argument is required');
}
}
if (!$_REQUEST['q'])
return $this->json_encode(array());
$q = $_REQUEST['q'];
$q = Format::sanitize($_REQUEST['q']);
$limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
if (strlen(Format::searchable($q)) < 3)
@@ -54,7 +55,7 @@ class OrgsAjaxAPI extends AjaxController {
foreach ($orgs as $O) {
list($id, $name) = $O;
$matched[] = array('name' => Format::htmlchars($name), 'info' => $name,
'id' => $id, '/bin/true' => $_REQUEST['q']);
'id' => $id, '/bin/true' => Format::htmlchars($q));
}
return $this->json_encode(array_values($matched));
@@ -92,7 +93,10 @@ class OrgsAjaxAPI extends AjaxController {
Http::response(404, 'Unknown organization');
$errors = array();
if($org->update($_POST, $errors))
if ($profile) {
if ($org->updateProfile($_POST, $errors))
Http::response(201, $org->to_json(), 'application/json');
} elseif ($org->update($_POST, $errors))
Http::response(201, $org->to_json(), 'application/json');
$forms = $org->getForms();
@@ -329,5 +333,29 @@ class OrgsAjaxAPI extends AjaxController {
Http::response(201, 'Successfully managed');
}
function exportTickets($id) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Agent login is required');
elseif (!$id)
Http::response(403, __('Organization ID Required'));
$org = Organization::lookup($id);
if (!$org)
Http::response(403, __('Organization Not Found'));
$queue = $org->getTicketsQueue();
if ($_POST) {
$api = new TicketsAjaxAPI();
return $api->queueExport($queue);
}
$info = array('action' => "#orgs/$id/tickets/export");
include STAFFINC_DIR . 'templates/queue-export.tmpl.php';
}
}
?>

62
include/ajax.plugins.php Normal file
View File

@@ -0,0 +1,62 @@
<?php
require_once(INCLUDE_DIR . 'class.plugin.php');
class PluginsAjaxAPI extends AjaxController {
/*
* Protect all routines in this controller
*/
function access() {
global $thisstaff;
if (!$thisstaff || !$thisstaff->isAdmin())
Http::response(403, 'Access Denied');
return true;
}
// helper func to look up plugin & instance
private function lookup($plugin_id, $instance_id=0) {
if (!($plugin = PluginManager::lookup( (int) $plugin_id)))
Http::response(404, 'No such plugin');
if ($instance_id && !($instance = $plugin->getInstance( (int) $instance_id)))
Http::response(404, 'No such plugin instance');
return [$plugin, $instance];
}
function getInstances($plugin_id) {
list($plugin,)= $this->lookup($plugin_id);
$pjax_container = '#items';
include(STAFFINC_DIR . 'templates/plugin-instances.tmpl.php');
}
function updateInstance($plugin_id, $instance_id) {
list($plugin, $instance) = $this->lookup($plugin_id, $instance_id);
$errors = array();
if ($_POST && $instance->update($_POST, $errors))
Http::response(201, $this->encode([
'redirect' => sprintf('plugins.php?id=%d#instances',
$plugin->getId())
]));
$form = $instance->getForm();
$action = "#plugins/{$plugin->getId()}/instances/{$instance->getId()}/update";
include STAFFINC_DIR . 'templates/plugin-instance-modal.tmpl.php';
}
function addInstance($plugin_id) {
list($plugin,) = $this->lookup($plugin_id);
$errors = array();
if ($_POST && ($instance=$plugin->addInstance($_POST, $errors)))
Http::response(201, $this->encode([
'redirect' => sprintf('plugins.php?id=%d#instances',
$plugin->getId())
]));
// This should return cached form with errors (if any)
$form = $plugin->getConfigForm();
// Set action
$action = "#plugins/{$plugin->getId()}/instances/add";
include(STAFFINC_DIR . 'templates/plugin-instance-modal.tmpl.php');
}
}
?>

130
include/ajax.schedule.php Normal file
View File

@@ -0,0 +1,130 @@
<?php
require_once(INCLUDE_DIR . 'class.schedule.php');
class ScheduleAjaxAPI extends AjaxController {
function add($sid=0) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Login required');
if ($sid && !($schedule = Schedule::lookup($sid)))
Http::response(404, 'No such schedule');
elseif ($_POST['sid'])
$schedule = Schedule::lookup($_POST['sid']);
$action = '#schedule/add';
$errors = array();
$form = Schedule::basicForm($_POST ?: ($schedule ? array(
'type' => $schedule->getType(),
'timezone' => $schedule->timezone,
'description' => 'Copy of '.$schedule->getName()
) : null));
if ($_POST && $form->isValid()) {
$data = $form->getClean();
if (Schedule::getIdByName($data['name'])) {
$form->getField('name')->addError(
__('Name already in use'));
} elseif ($schedule && strcasecmp($schedule->getType(),
$data['type'])) {
$errors['sid'] = sprintf(
__('Type must be of %s to clone this Schedule'),
$schedule->getTypeDesc());
} else {
$vars = array_intersect_key($data, array_flip(['name',
'timezone', 'description']));
$s = Schedule::create($vars);
$s->setFlag(Schedule::FLAG_BIZHRS, ($data['type'] ==
'bizhrs'));
if ($s->save()) {
if ($schedule) $s->cloneEntries($schedule);
Http::response(201, $s->getId());
}
}
}
include STAFFINC_DIR.'templates/schedule-add.tmpl.php';
}
function cloneSchedule($id) {
return $this->add($id);
}
function addEntry($id) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Login required');
elseif (!($schedule = Schedule::lookup($id)))
Http::response(404, 'No such schedule');
$form = $schedule->getEntryForm($_POST ?: null);
$errors = array();
if ($_POST && $form->isValid()) {
if (($entry = $schedule->addEntry($form, $errors)))
Http::response(201, $entry->getId());
foreach ($errors as $k => $error) {
if (($f=$form->getField($k)))
$f->addError($error);
}
}
include STAFFINC_DIR . 'templates/schedule-entry.tmpl.php';
}
function updateEntry($sid, $id) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Login required');
if (!($entry = ScheduleEntry::lookup($id))
|| !($schedule=$entry->getSchedule())
|| $schedule->getId() != $sid)
Http::response(404, 'Unknown Entry');
$form = $entry->getForm($_POST ?: null);
$errors = array();
if ($_POST && $entry->update($form, $errors))
Http::response(201, $entry->getId());
foreach ($errors as $k => $error) {
if (($f=$form->getField($k)))
$f->addError($error);
}
include STAFFINC_DIR . 'templates/schedule-entry.tmpl.php';
}
function diagnostic($id) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Login required');
elseif (!($schedule = BusinessHoursSchedule::lookup($id)))
Http::response(404, 'No such schedule');
$form = $schedule->getDiagnosticForm($_POST ?: null);
if ($_POST) $form->isValid();
include STAFFINC_DIR . 'templates/schedule-diagnostic.tmpl.php';
}
function deleteEntries($id) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Login required');
if (!($schedule = Schedule::lookup($id)))
Http::response(404, 'Unknown Schedule');
$count = 0;
if (isset($_POST['ids']) && is_array($_POST['ids']))
$count = $schedule->entries
->filter(array('id__in' => array_values($_POST['ids'])))
->delete();
Http::response(200, $this->encode(array('success' => $count)));
}
}
?>

View File

@@ -31,7 +31,7 @@ class SearchAjaxAPI extends AjaxController {
$search = new AdhocSearch(array(
'root' => 'T',
'staff_id' => $thisstaff->getId(),
'parent_id' => @$_GET['parent_id'] ?: 0,
'parent_id' => (int) @$_GET['parent_id'] ?: 0,
));
if ($search->parent_id) {
$search->flags |= SavedSearch::FLAG_INHERIT_COLUMNS;
@@ -125,8 +125,9 @@ class SearchAjaxAPI extends AjaxController {
// the recent search list
if (isset($_SESSION[$key])) {
reset($_SESSION[$key]);
while (count($keep) < 5) {
list($k, $v) = each($_SESSION[$key]);
for ($i = 0; $i < 5; $i++) {
$k = key($_SESSION[$key]);
$v = current($_SESSION[$key]);
if (!$k)
break;
$keep[$k] = $v;
@@ -167,7 +168,7 @@ class SearchAjaxAPI extends AjaxController {
'title' => __('Add Queue'),
'root' => 'T',
'staff_id' => $thisstaff->getId(),
'parent_id' => $_GET['pid'],
'parent_id' => (int) $_GET['pid'],
));
$this->_tryAgain($search);
}
@@ -187,11 +188,16 @@ class SearchAjaxAPI extends AjaxController {
'root' => 'T',
'staff_id' => $thisstaff->getId()
));
$new = true;
}
if (false === $this->_saveSearch($search))
return;
//store saved search count when it is created
if ($new)
$search->counts($thisstaff, false);
$info = array(
'msg' => sprintf('%s %s %s',
__('Search'),
@@ -202,6 +208,7 @@ class SearchAjaxAPI extends AjaxController {
}
function _saveSearch(SavedSearch $search) {
$_POST['queue-name'] = Format::htmlchars($_POST['queue-name']);
// Validate the form.
$form = $search->getForm($_POST);
@@ -259,8 +266,8 @@ class SearchAjaxAPI extends AjaxController {
Http::response(404, 'No such queue sort');
}
$data_form = $sort->getDataConfigForm($_POST ?: false);
if ($_POST) {
$data_form = $sort->getDataConfigForm($_POST);
if ($data_form->isValid()) {
$sort->update($data_form->getClean() + $_POST);
if ($sort->save())
@@ -344,17 +351,16 @@ class SearchAjaxAPI extends AjaxController {
function addCondition() {
global $thisstaff;
if (!$thisstaff) {
if (!$thisstaff)
Http::response(403, 'Agent login is required');
}
elseif (!isset($_GET['field']) || !isset($_GET['id'])
|| !isset($_GET['object_id'])
) {
|| !isset($_GET['object_id']))
Http::response(400, '`field`, `id`, and `object_id` parameters required');
}
elseif (!is_numeric($_GET['object_id'])) {
elseif (!is_numeric($_GET['object_id']))
Http::response(400, '`object_id` should be an integer');
}
elseif (!is_numeric($_GET['id']))
Http::response(400, '`id` should be an integer');
$fields = SavedSearch::getSearchableFields('Ticket');
if (!isset($fields[$_GET['field']])) {
Http::response(400, sprintf('%s: No such searchable field'),
@@ -380,8 +386,8 @@ class SearchAjaxAPI extends AjaxController {
Http::response(400, '`prop` and `condition` parameters required');
}
$prop = $_GET['prop'];
$id = $_GET['condition'];
$prop = Format::htmlchars($_GET['prop']);
$id = Format::htmlchars($_GET['condition']);
include STAFFINC_DIR . 'templates/queue-column-condition-prop.tmpl.php';
}

View File

@@ -35,12 +35,15 @@ class StaffAjaxAPI extends AjaxController {
if ($_POST && $form->isValid()) {
$clean = $form->getClean();
if ($id == 0) {
// Stash in the session later when creating the user
$_SESSION['new-agent-passwd'] = $clean;
Http::response(201, 'Carry on');
}
try {
// Validate password
if (!$clean['welcome_email'])
Staff::checkPassword($clean['passwd1'], null);
if ($id == 0) {
// Stash in the session later when creating the user
$_SESSION['new-agent-passwd'] = $clean;
Http::response(201, 'Carry on');
}
if ($clean['welcome_email']) {
$staff->sendResetEmail();
}
@@ -53,8 +56,8 @@ class StaffAjaxAPI extends AjaxController {
Http::response(201, 'Successfully updated');
}
catch (BadPassword $ex) {
$passwd1 = $form->getField('passwd1');
$passwd1->addError($ex->getMessage());
if ($passwd1 = $form->getField('passwd1'))
$passwd1->addError($ex->getMessage());
}
catch (PasswordUpdateFailed $ex) {
$errors['err'] = __('Password update failed:').' '.$ex->getMessage();
@@ -63,7 +66,7 @@ class StaffAjaxAPI extends AjaxController {
$title = __("Set Agent Password");
$verb = $id == 0 ? __('Set') : __('Update');
$path = ltrim($ost->get_path_info(), '/');
$path = ltrim(Osticket::get_path_info(), '/');
include STAFFINC_DIR . 'templates/quick-add.tmpl.php';
}
@@ -105,8 +108,8 @@ class StaffAjaxAPI extends AjaxController {
}
}
catch (BadPassword $ex) {
$passwd1 = $form->getField('passwd1');
$passwd1->addError($ex->getMessage());
if ($passwd1 = $form->getField('passwd1'))
$passwd1->addError($ex->getMessage());
}
catch (PasswordUpdateFailed $ex) {
$errors['err'] = __('Password update failed:').' '.$ex->getMessage();
@@ -116,7 +119,7 @@ class StaffAjaxAPI extends AjaxController {
$title = __("Change Password");
$verb = __('Update');
$path = ltrim($ost->get_path_info(), '/');
$path = ltrim(Osticket::get_path_info(), '/');
include STAFFINC_DIR . 'templates/quick-add.tmpl.php';
}
@@ -145,7 +148,7 @@ class StaffAjaxAPI extends AjaxController {
$form = new ResetAgentPermissionsForm($_POST);
if (@is_array($_GET['ids'])) {
$perms = new RolePermission();
$perms = new RolePermission(null);
$selected = Staff::objects()->filter(array('staff_id__in' => $_GET['ids']));
foreach ($selected as $staff)
// XXX: This maybe should be intersection rather than union
@@ -160,7 +163,7 @@ class StaffAjaxAPI extends AjaxController {
$title = __("Reset Agent Permissions");
$verb = __("Continue");
$path = ltrim($ost->get_path_info(), '/');
$path = ltrim(Osticket::get_path_info(), '/');
include STAFFINC_DIR . 'templates/reset-agent-permissions.tmpl.php';
}
@@ -202,7 +205,7 @@ class StaffAjaxAPI extends AjaxController {
$title = __("Change Primary Department");
$verb = __("Continue");
$path = ltrim($ost->get_path_info(), '/');
$path = ltrim(Osticket::get_path_info(), '/');
include STAFFINC_DIR . 'templates/quick-add.tmpl.php';
}
@@ -229,4 +232,91 @@ class StaffAjaxAPI extends AjaxController {
'code' => $code,
));
}
function configure2FA($staffId, $id=0) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Agent login required');
if ($staffId != $thisstaff->getId())
Http::response(403, 'Access denied');
if ($id && !($auth= Staff2FABackend::lookup($id)))
Http::response(404, 'Unknown 2FA');
$staff = $thisstaff;
$info = array();
if ($auth) {
// Simple state machine to manage settings and verification
$state = @$_POST['state'] ?: 'validate';
switch ($state) {
case 'verify':
try {
$form = $auth->getInputForm($_POST);
if ($_POST && $form
&& $form->isValid()
&& $auth->validate($form, $staff)) {
// Mark the settings as verified
if (($config = $staff->get2FAConfig($auth->getId()))) {
$config['verified'] = time();
$staff->updateConfig(array(
$auth->getId() => JsonDataEncoder::encode($config)));
}
// We're done here
$auth = null;
$info['notice'] = __('Setup completed successfully');
} else {
$info['error'] = __('Unable to verify the token - try again!');
}
} catch (ExpiredOTP $ex) {
// giving up cleanly
$info['error'] = $ex->getMessage();
$auth = null;
}
break;
case 'validate':
default:
$config = $staff->get2FAConfig($auth->getId());
$vars = $_POST ?: $config['config'] ?: array('email' => $staff->getEmail());
$form = $auth->getSetupForm($vars);
if ($_POST && $form && $form->isValid()) {
if ($config['config'] && $config['config']['external2fa'])
$external2fa = true;
// Save the setting based on setup form
$clean = $form->getClean();
if (!$external2fa) {
$config = ['config' => $clean, 'verified' => 0];
$staff->updateConfig(array(
$auth->getId() => JsonDataEncoder::encode($config)));
}
// Send verification token to the user
if ($token=$auth->send($staff)) {
// Transition to verify state
$form = $auth->getInputForm($vars);
$state = 'verify';
$info['notice'] = __('Token sent to you!');
} else {
// Generic error TODO: better wording
$info['error'] = __('Error sending Token - double check entry');
}
}
}
}
include STAFFINC_DIR . 'templates/2fas.tmpl.php';
}
function reset2fA($staffId) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Agent login required');
if (!$thisstaff->isAdmin())
Http::response(403, 'Access denied');
$default_2fa = ConfigItem::getConfigsByNamespace('staff.'.$staffId, 'default_2fa');
if ($default_2fa)
$default_2fa->delete();
}
}

View File

@@ -59,10 +59,17 @@ class TasksAjaxAPI extends AjaxController {
}
function triggerThreadAction($task_id, $thread_id, $action) {
global $thisstaff;
if (!($task = Task::lookup($task_id))
|| !$task->checkStaffPerm($thisstaff))
Http::response(404, 'No such task thread entry');
$thread = ThreadEntry::lookup($thread_id);
if (!$thread)
Http::response(404, 'No such task thread entry');
if ($thread->getThread()->getObjectId() != $task_id)
if ($thread->getThread()->getObjectType() != 'A'
|| $thread->getThread()->getObjectId() != $task_id)
Http::response(404, 'No such task thread entry');
$valid = false;
@@ -110,10 +117,11 @@ class TasksAjaxAPI extends AjaxController {
$vars['default_formdata'] = $form->getClean();
$vars['internal_formdata'] = $iform->getClean();
$desc = $form->getField('description');
$vars['description'] = $desc->getClean();
if ($desc
&& $desc->isAttachmentsEnabled()
&& ($attachments=$desc->getWidget()->getAttachments()))
$vars['files'] = $attachments->getFiles();
$vars['files'] = $attachments->getFiles();
$vars['staffId'] = $thisstaff->getId();
$vars['poster'] = $thisstaff;
$vars['ip_address'] = $_SERVER['REMOTE_ADDR'];
@@ -211,6 +219,82 @@ class TasksAjaxAPI extends AjaxController {
include STAFFINC_DIR . 'templates/task-edit.tmpl.php';
}
function editField($tid, $fid) {
global $thisstaff;
if (!($task=Task::lookup($tid)))
Http::response(404, __('No such task'));
elseif (!$task->checkStaffPerm($thisstaff, Task::PERM_EDIT))
Http::response(403, __('Permission denied'));
elseif (!($field=$task->getField($fid)))
Http::response(404, __('No such field'));
$errors = array();
$info = array(
':title' => sprintf(__('Task #%s: %s %s'),
$task->getNumber(),
__('Update'),
$field->getLabel()
),
':action' => sprintf('#tasks/%d/field/%s/edit',
$task->getId(), $field->getId())
);
$form = $field->getEditForm($_POST);
if ($_POST && $form->isValid()) {
if ($task->updateField($form, $errors)) {
$msg = sprintf(
__('%s successfully'),
sprintf(
__('%s updated'),
__($field->getLabel())
)
);
switch (true) {
case $field instanceof DateTime:
case $field instanceof DatetimeField:
$clean = Format::datetime((string) $field->getClean());
break;
case $field instanceof FileUploadField:
$field->save();
$answer = $field->getAnswer();
$clean = $answer->display() ?: '&mdash;' . __('Empty') . '&mdash;';
break;
case $field instanceof DepartmentField:
$clean = (string) Dept::lookup($field->getClean());
break;
case $field instanceof TextareaField:
$clean = (string) $field->getClean();
$clean = Format::striptags($clean) ? $clean : '&mdash;' . __('Empty') . '&mdash;';
if (strlen($clean) > 200)
$clean = Format::truncate($clean, 200);
break;
case $field instanceof BooleanField:
$clean = $field->getClean();
$clean = $field->toString($clean);
break;
default:
$clean = $field->getClean();
$clean = is_array($clean) ? implode(',', $clean) :
(string) $clean;
if (strlen($clean) > 200)
$clean = Format::truncate($clean, 200);
}
$clean = is_array($clean) ? $clean[0] : $clean;
Http::response(201, $this->json_encode(['value' =>
$clean ?: '&mdash;' . __('Empty') . '&mdash;',
'id' => $fid, 'msg' => $msg]));
}
$form->addErrors($errors);
$info['error'] = $errors['err'] ?: __('Unable to update field');
}
include STAFFINC_DIR . 'templates/field-edit.tmpl.php';
}
function massProcess($action, $w=null) {
global $thisstaff, $cfg;
@@ -228,7 +312,7 @@ class TasksAjaxAPI extends AjaxController {
'verbed' => __('deleted'),
),
'reopen' => array(
'verbed' => __('reopen'),
'verbed' => __('reopened'),
),
'close' => array(
'verbed' => __('closed'),
@@ -374,9 +458,10 @@ class TasksAjaxAPI extends AjaxController {
case 'transfer':
$inc = 'transfer.tmpl.php';
$info[':action'] = '#tasks/mass/transfer';
$info[':title'] = sprintf('Transfer %s',
$info[':title'] = sprintf(__('Transfer %s'),
_N('selected task', 'selected tasks', $count));
$form = TransferForm::instantiate($_POST);
$form->hideDisabled();
if ($_POST && $form->isValid()) {
foreach ($_POST['tids'] as $tid) {
if (($t=Task::lookup($tid))
@@ -402,7 +487,7 @@ class TasksAjaxAPI extends AjaxController {
$inc = 'task-status.tmpl.php';
$info[':action'] = "#tasks/mass/$action";
$info['status'] = $info['status'] ?: 'closed';
$perm = $action = '';
$perm = '';
switch ($info['status']) {
case 'open':
// If an agent can create a task then they're allowed to
@@ -561,6 +646,8 @@ class TasksAjaxAPI extends AjaxController {
);
$form = $task->getTransferForm($_POST);
$form->hideDisabled();
if ($_POST && $form->isValid()) {
if ($task->transfer($form, $errors)) {
$_SESSION['::sysmsgs']['msg'] = sprintf(
@@ -618,7 +705,11 @@ class TasksAjaxAPI extends AjaxController {
__('Task'),
$form->getAssignee())
);
Http::response(201, $task->getId());
$assignee = $task->isAssigned() ? Format::htmlchars(implode('/', $task->getAssignees())) :
'<span class="faded">&mdash; '.__('Unassigned').' &mdash;';
Http::response(201, $this->json_encode(['value' =>
$assignee, 'id' => 'assign', 'msg' => $_SESSION['::sysmsgs']['msg']]));
}
$form->addErrors($errors);

View File

@@ -56,7 +56,7 @@ class ThreadAjaxAPI extends AjaxController {
}
function addRemoteCollaborator($tid, $bk, $id) {
function addRemoteCollaborator($tid, $type, $bk, $id) {
global $thisstaff;
if (!($thread=Thread::lookup($tid))
@@ -74,7 +74,7 @@ class ThreadAjaxAPI extends AjaxController {
if (!$user_info)
$info['error'] = __('Unable to find user in directory');
return self::_addcollaborator($thread, null, $form, 'addcc', $info);
return self::_addcollaborator($thread, null, $form, $type, $info);
}
//Collaborators utils
@@ -83,6 +83,7 @@ class ThreadAjaxAPI extends AjaxController {
if (!($thread=Thread::lookup($tid))
|| !($object=$thread->getObject())
|| !is_subclass_of($object, 'Threadable')
|| !$object->checkStaffPerm($thisstaff))
Http::response(404, __('No such thread'));
@@ -100,20 +101,14 @@ class ThreadAjaxAPI extends AjaxController {
$user = User::fromForm($form);
}
$errors = $info = array();
if ($user) {
// FIXME: Refuse to add ticket owner??
if (($c=$thread->addCollaborator($user,
array(), $errors))) {
$info = array('msg' => sprintf(__('%s added as a collaborator'),
Format::htmlchars($c->getName())));
$c->setCc();
$c->save();
return self::_collaborators($thread, $info);
}
$errors = $info = $vars = array();
if ($user && ($c=$object->addCollaborator($user, $vars, $errors))) {
$info = array('msg' => sprintf(__('%s added as a collaborator'),
Format::htmlchars($c->getName())));
return self::_collaborators($thread, $info);
}
if($errors && $errors['err']) {
if ($errors && $errors['err']) {
$info +=array('error' => $errors['err']);
} else {
$info +=array('error' =>__('Unable to add collaborator.').' '.__('Internal error occurred'));
@@ -178,7 +173,7 @@ class ThreadAjaxAPI extends AjaxController {
return self::_addcollaborator($thread);
}
function previewCollaborators($tid) {
function previewCollaborators($tid, $manage=true) {
global $thisstaff;
if (!($thread=Thread::lookup($tid))
@@ -194,7 +189,7 @@ class ThreadAjaxAPI extends AjaxController {
return $resp;
}
function _addcollaborator($thread, $user=null, $form=null, $type=null, $info=array()) {
static function _addcollaborator($thread, $user=null, $form=null, $type=null, $info=array()) {
global $thisstaff;
$info += array(
@@ -222,20 +217,7 @@ class ThreadAjaxAPI extends AjaxController {
Http::response(404, 'No such thread');
$errors = $info = array();
if ($thread->updateCollaborators($_POST, $errors))
$users = array();
foreach ($thread->getCollaborators() as $c)
$users[] = array('id' => $c->getUserId(),
'name' => $c->getName(),
'email' => $c->getEmail());
Http::response(201, $this->json_encode(array(
'id' => $thread->getId(),
'users' => $users,
'text' => sprintf('(%d)',
$thread->getNumCollaborators())
)
));
$thread->updateCollaborators($_POST, $errors);
if($errors && $errors['err'])
$info +=array('error' => $errors['err']);
@@ -245,7 +227,7 @@ class ThreadAjaxAPI extends AjaxController {
function _collaborator($collaborator, $form=null, $info=array()) {
static function _collaborator($collaborator, $form=null, $info=array()) {
global $thisstaff;
$info += array('action' => sprintf('#thread/%d/collaborators/%d',
@@ -261,7 +243,7 @@ class ThreadAjaxAPI extends AjaxController {
return $resp;
}
function _collaborators($thread, $info=array()) {
static function _collaborators($thread, $info=array()) {
ob_start();
include(STAFFINC_DIR . 'templates/collaborators.tmpl.php');

View File

@@ -23,7 +23,7 @@ include_once INCLUDE_DIR . 'class.thread_actions.php';
class TicketsAjaxAPI extends AjaxController {
function lookup() {
function lookup($wildcard=false) {
global $thisstaff;
$limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
@@ -35,12 +35,16 @@ class TicketsAjaxAPI extends AjaxController {
$visibility = $thisstaff->getTicketsVisibility();
$hits = Ticket::objects()
->filter($visibility)
->values('user__default_email__address')
->values('user__default_email__address', 'cdata__subject', 'user__name', 'ticket_id', 'thread__id', 'flags')
->annotate(array(
'number' => new SqlCode('null'),
'tickets' => SqlAggregate::COUNT('ticket_id', true),
'tasks' => SqlAggregate::COUNT('tasks__id', true),
'collaborators' => SqlAggregate::COUNT('thread__collaborators__id', true),
'entries' => SqlAggregate::COUNT('thread__entries__id', true),
))
->order_by(SqlAggregate::SUM(new SqlCode('Z1.relevance')), QuerySet::DESC)
->distinct('user__default_email__address')
->limit($limit);
$q = $_REQUEST['q'];
@@ -49,32 +53,37 @@ class TicketsAjaxAPI extends AjaxController {
return $this->encode(array());
global $ost;
$hits = $ost->searcher->find($q, $hits, false);
$hits = $ost->searcher->find($q, $hits, false, ['boolean' => $wildcard]);
if (preg_match('/\d{2,}[^*]/', $q, $T = array())) {
$hits = Ticket::objects()
->values('user__default_email__address', 'number')
->annotate(array(
'tickets' => new SqlCode('1'),
))
->filter($visibility)
->filter(array('number__startswith' => $q))
->order_by('number')
->limit($limit)
->union($hits);
$T = array();
if (preg_match('/\d{2,}[^*]/', $q, $T)) {
$hits = $this->lookupByNumber($limit, $visibility, $hits);
}
elseif (!count($hits) && preg_match('`\w$`u', $q)) {
elseif (preg_match('/(.*@.{2,})|(.{2,}@.*)/', $q, $T)) {
$hits = $this->lookupByEmail($limit, $visibility, $hits);
}
elseif (!$wildcard && !count($hits) && preg_match('`^[a-zA-Z0-9]+$`u', $q)) {
// Do wild-card fulltext search
$_REQUEST['q'] = $q.'*';
return $this->lookup();
return $this->lookup(true);
}
// TODO: Why not aggregate based on relationship?
foreach ($hits as $T) {
$email = $T['user__default_email__address'];
$count = $T['tickets'];
if ($T['number']) {
$tickets[$T['number']] = array('id'=>$T['number'], 'value'=>$T['number'],
'ticket_id'=>$T['ticket_id'],
'info'=>"{$T['number']} — {$email}",
'subject'=>$T['cdata__subject'],
'user'=>$T['user__name'],
'tasks'=>$T['tasks'],
'thread_id'=>$T['thread__id'],
'collaborators'=>$T['collaborators'],
'entries'=>$T['entries'],
'mergeType'=>Ticket::getMergeTypeByFlag($T['flags']),
'children'=>count(Ticket::getChildTickets($T['ticket_id'])) > 0 ? true : false,
'matches'=>$_REQUEST['q']);
}
else {
@@ -87,6 +96,102 @@ class TicketsAjaxAPI extends AjaxController {
return $this->json_encode($tickets);
}
function lookupByNumber($limit=false, $visibility=false, $matches=false) {
global $thisstaff;
if (!$limit)
$limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
$tickets=array();
// Bail out of query is empty
if (!$_REQUEST['q'])
return $this->json_encode($tickets);
$q = trim($_REQUEST['q']);
if (!$visibility)
$visibility = $thisstaff->getTicketsVisibility();
$hits = Ticket::objects()
->values('user__default_email__address', 'cdata__subject', 'user__name', 'ticket_id', 'thread__id', 'flags', 'number')
->annotate(array(
'tickets' => new SqlCode('1'),
'tasks' => SqlAggregate::COUNT('tasks__id', true),
'collaborators' => SqlAggregate::COUNT('thread__collaborators__id', true),
'entries' => SqlAggregate::COUNT('thread__entries__id', true),
))
->filter($visibility)
->filter(array('number__startswith' => $q))
->order_by('number')
->limit($limit);
if ($matches && is_a($matches, 'QuerySet'))
return $hits->union($matches);
foreach ($hits as $T) {
$email = $T['user__default_email__address'];
$tickets[$T['number']] = array('id'=>$T['number'], 'value'=>$T['number'],
'ticket_id'=>$T['ticket_id'],
'info'=>"{$T['number']} — {$email}",
'subject'=>$T['cdata__subject'],
'user'=>$T['user__name'],
'tasks'=>$T['tasks'],
'thread_id'=>$T['thread__id'],
'collaborators'=>$T['collaborators'],
'entries'=>$T['entries'],
'mergeType'=>Ticket::getMergeTypeByFlag($T['flags']),
'children'=>count(Ticket::getChildTickets($T['ticket_id'])) > 0 ? true : false,
'matches'=>$_REQUEST['q']);
}
$tickets = array_values($tickets);
return $this->json_encode($tickets);
}
function lookupByEmail($limit=false, $visibility=false, $matches=false) {
global $thisstaff;
if (!$limit)
$limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
$tickets=array();
// Bail out of query is empty
if (!$_REQUEST['q'])
return $this->json_encode($tickets);
$q = trim($_REQUEST['q']);
if (!$visibility)
$visibility = $thisstaff->getTicketsVisibility();
$hits = Ticket::objects()
->values('user__default_email__address', 'cdata__subject', 'user__name', 'ticket_id', 'thread__id', 'flags')
->annotate(array(
'number' => new SqlCode('null'),
'tickets' => SqlAggregate::COUNT('ticket_id', true),
'tasks' => SqlAggregate::COUNT('tasks__id', true),
'collaborators' => SqlAggregate::COUNT('thread__collaborators__id', true),
'entries' => SqlAggregate::COUNT('thread__entries__id', true),
))
->filter($visibility)
->filter(array('user__default_email__address__contains' => $q))
->order_by('user__default_email__address')
->limit($limit);
if ($matches && is_a($matches, 'QuerySet'))
return $hits->union($matches);
foreach ($hits as $T) {
$count = $T['tickets'];
$email = $T['user__default_email__address'];
$tickets[$email] = array('email'=>$email, 'value'=>$email,
'info'=>"$email ($count)", 'matches'=>$_REQUEST['q']);
}
$tickets = array_values($tickets);
return $this->json_encode($tickets);
}
function acquireLock($tid) {
global $cfg, $thisstaff;
@@ -261,7 +366,7 @@ class TicketsAjaxAPI extends AjaxController {
return self::_userlookup($user, null, $info);
}
function _userlookup($user, $form, $info) {
static function _userlookup($user, $form, $info) {
global $thisstaff;
ob_start();
@@ -329,6 +434,89 @@ class TicketsAjaxAPI extends AjaxController {
Http::response(201, 'Successfully managed');
}
function mergeTickets($ticket_id) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, "Login required");
elseif (!($ticket = Ticket::lookup($ticket_id)))
Http::response(404, "No such ticket");
elseif (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_EDIT))
Http::response(403, "Access Denied");
//retrieve the parent and child tickets
$parent = Ticket::objects()
->filter(array('ticket_id'=>$ticket_id))
->values_flat('ticket_id', 'number', 'ticket_pid', 'sort', 'thread__id', 'user_id', 'cdata__subject', 'user__name', 'flags')
->annotate(array('tasks' => SqlAggregate::COUNT('tasks__id', true),
'collaborators' => SqlAggregate::COUNT('thread__collaborators__id', true),
'entries' => SqlAggregate::COUNT('thread__entries__id', true),));
$tickets = Ticket::getChildTickets($ticket_id);
$tickets = $parent->union($tickets);
//fix sort of tickets
$sql = sprintf('SELECT * FROM (%s) a ORDER BY sort', $tickets->getQuery());
$res = db_query($sql);
$tickets = db_assoc_array($res);
$info = array('action' => '#tickets/'.$ticket->getId().'/merge');
return self::_updateMerge($ticket, $tickets, $info);
}
function updateMerge($ticket_id) {
global $thisstaff;
$info = array();
$errors = array();
if ($_POST['dtids']) {
foreach($_POST['dtids'] as $key => $value) {
if (is_numeric($key) && $ticket = Ticket::lookup($value))
$ticket->unlink();
}
Http::response(201, 'Successfully managed');
} elseif ($_POST['tids']) {
if ($parent = Ticket::merge($_POST))
Http::response(201, 'Successfully managed');
else
Http::response(404, 'Unable to manage ticket');
}
$parentModel = Ticket::objects()
->filter(array('ticket_id'=>$ticket_id))
->values_flat('ticket_id', 'number', 'ticket_pid', 'sort', 'thread__id', 'user_id', 'cdata__subject', 'user__name', 'flags')
->annotate(array('tasks' => SqlAggregate::COUNT('tasks__id', true),
'collaborators' => SqlAggregate::COUNT('thread__collaborators__id', true),
'entries' => SqlAggregate::COUNT('thread__entries__id', true),));
if ($parent->getMergeType() == 'visual') {
$tickets = Ticket::getChildTickets($ticket_id);
$tickets = $parentModel->union($tickets);
} else
$tickets = $parentModel;
return self::_updateMerge($parent, $tickets, $info);
}
static private function _updateMerge($ticket, $tickets, $info) {
include(STAFFINC_DIR . 'templates/merge-tickets.tmpl.php');
}
function previewMerge($tid) {
global $thisstaff;
if (!($ticket=Ticket::lookup($tid))
|| !$ticket->checkStaffPerm($thisstaff))
Http::response(404, 'No such ticket');
ob_start();
include STAFFINC_DIR . 'templates/merge-preview.tmpl.php';
$resp = ob_get_contents();
ob_end_clean();
return $resp;
}
function cannedResponse($tid, $cid, $format='text') {
global $thisstaff, $cfg;
@@ -358,7 +546,7 @@ class TicketsAjaxAPI extends AjaxController {
$format.='.plain';
$varReplacer = function (&$var) use($ticket) {
return $ticket->replaceVars($var);
return $ticket->replaceVars($var, array('recipient' => $ticket->getOwner()));
};
include_once(INCLUDE_DIR.'class.canned.php');
@@ -400,7 +588,6 @@ class TicketsAjaxAPI extends AjaxController {
);
Http::response(201, $ticket->getId());
}
$form->addErrors($errors);
$info['error'] = $errors['err'] ?: __('Unable to transfer ticket');
}
@@ -410,105 +597,101 @@ class TicketsAjaxAPI extends AjaxController {
include STAFFINC_DIR . 'templates/transfer.tmpl.php';
}
function referrals($tid) {
function referrals($tid) {
return $this->refer($tid);
}
function refer($tid, $target=null) {
global $thisstaff;
if (!($ticket=Ticket::lookup($tid)))
Http::response(404, __('No such ticket'));
if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_ASSIGN)
|| !($form = $ticket->getReferralForm($_POST,
array('target' => $target))))
Http::response(403, __('Permission denied'));
$errors = array();
$info = array(
':title' => sprintf(__('Ticket #%s: %s'),
$ticket->getNumber(),
__('Refer')
),
':action' => sprintf('#tickets/%d/refer%s',
$ticket->getId(),
($target ? "/$target": '')),
);
if ($_POST) {
switch ($_POST['do']) {
case 'refer':
if ($form->isValid() && $ticket->refer($form, $errors)) {
$clean = $form->getClean();
if ($clean['comments'])
$ticket->logNote('Referral', $clean['comments'], $thisstaff);
$_SESSION['::sysmsgs']['msg'] = sprintf(
__('%s successfully'),
sprintf(
__('%s referred to %s'),
sprintf(__('Ticket #%s'),
sprintf('<a href="tickets.php?id=%d"><b>%s</b></a>',
$ticket->getId(),
$ticket->getNumber()))
,
$form->getReferee())
);
Http::response(201, $ticket->getId());
}
$form->addErrors($errors);
$info['error'] = $errors['err'] ?: __('Unable to refer ticket');
break;
case 'manage':
$remove = array();
if (is_array($_POST['referrals'])) {
$remove = array();
foreach ($_POST['referrals'] as $k => $v)
if ($v[0] == '-')
$remove[] = substr($v, 1);
if (count($remove)) {
$num = $ticket->thread->referrals
->filter(array('id__in' => $remove))
->delete();
if ($num) {
$info['msg'] = sprintf(
__('%s successfully'),
sprintf(__('Removed %d referrals'),
$num
)
);
}
//TODO: log removal
}
}
break;
default:
$errors['err'] = __('Unknown Action');
}
}
$thread = $ticket->getThread();
include STAFFINC_DIR . 'templates/refer.tmpl.php';
}
function editField($tid, $fid) {
global $thisstaff;
function refer($tid, $target=null) {
global $thisstaff;
if (!($ticket=Ticket::lookup($tid)))
Http::response(404, __('No such ticket'));
if (!($ticket=Ticket::lookup($tid)))
Http::response(404, __('No such ticket'));
if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_EDIT))
Http::response(403, __('Permission denied'));
elseif (!($field=$ticket->getField($fid)))
Http::response(404, __('No such field'));
if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_ASSIGN)
|| !($form = $ticket->getReferralForm($_POST,
array('target' => $target))))
Http::response(403, __('Permission denied'));
$errors = array();
$info = array(
':title' => sprintf(__('Ticket #%s: %s %s'),
$errors = array();
$info = array(
':title' => sprintf(__('Ticket #%s: %s'),
$ticket->getNumber(),
__('Refer')
),
':action' => sprintf('#tickets/%d/refer%s',
$ticket->getId(),
($target ? "/$target": '')),
);
if ($_POST) {
switch ($_POST['do']) {
case 'refer':
if ($form->isValid() && $ticket->refer($form, $errors)) {
$clean = $form->getClean();
if ($clean['comments'])
$ticket->logNote('Referral', $clean['comments'], $thisstaff);
$_SESSION['::sysmsgs']['msg'] = sprintf(
__('%s successfully'),
sprintf(
__('%s referred to %s'),
sprintf(__('Ticket #%s'),
sprintf('<a href="tickets.php?id=%d"><b>%s</b></a>',
$ticket->getId(),
$ticket->getNumber()))
,
$form->getReferee())
);
Http::response(201, $ticket->getId());
}
$form->addErrors($errors);
$info['error'] = $errors['err'] ?: __('Unable to refer ticket');
break;
case 'manage':
$remove = array();
if (is_array($_POST['referrals'])) {
$remove = array();
foreach ($_POST['referrals'] as $k => $v)
if ($v[0] == '-')
$remove[] = substr($v, 1);
if (count($remove)) {
$num = $ticket->getThread()->referrals
->filter(array('id__in' => $remove))
->delete();
if ($num) {
$info['msg'] = sprintf(
__('%s successfully'),
sprintf(__('Removed %d referrals'),
$num
)
);
}
//TODO: log removal
}
}
break;
default:
$errors['err'] = __('Unknown Action');
}
}
$thread = $ticket->getThread();
include STAFFINC_DIR . 'templates/refer.tmpl.php';
}
function editField($tid, $fid) {
global $cfg, $thisstaff;
if (!($ticket=Ticket::lookup($tid)))
Http::response(404, __('No such ticket'));
elseif (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_EDIT))
Http::response(403, __('Permission denied'));
elseif (!($field=$ticket->getField($fid)))
Http::response(404, __('No such field'));
$errors = array();
$info = array(
':title' => sprintf(__('Ticket #%s: %s %s'),
$ticket->getNumber(),
__('Update'),
$field->getLabel()
@@ -517,10 +700,11 @@ function refer($tid, $target=null) {
$ticket->getId(), $field->getId())
);
$form = $field->getEditForm($_POST);
if ($_POST && $form->isValid()) {
$form = $field->getEditForm($_POST);
if ($_POST && $form->isValid()) {
if ($ticket->updateField($form, $errors)) {
$_SESSION['::sysmsgs']['msg'] = sprintf(
$msg = sprintf(
__('%s successfully'),
sprintf(
__('%s updated'),
@@ -528,16 +712,91 @@ function refer($tid, $target=null) {
)
);
if ($field instanceof FileUploadField)
$field->save();
Http::response(201, $field->getClean());
}
$form->addErrors($errors);
$info['error'] = $errors['err'] ?: __('Unable to update field');
}
switch (true) {
case $field instanceof DateTime:
case $field instanceof DatetimeField:
$clean = Format::datetime((string) $field->getClean());
break;
case $field instanceof FileUploadField:
$field->save();
$answer = $field->getAnswer();
$clean = $answer->display() ?: '&mdash;' . __('Empty') . '&mdash;';
break;
case $field instanceof DepartmentField:
$clean = (string) Dept::lookup($field->getClean());
break;
case $field instanceof TextareaField:
$clean = (string) $field->getClean();
$clean = Format::striptags($clean) ?: '&mdash;' . __('Empty') . '&mdash;';
if (strlen($clean) > 200)
$clean = Format::truncate(Format::striptags($clean), 200);
break;
case $field instanceof BooleanField:
$clean = $field->toString($field->getClean());
break;
default:
$clean = $field->getClean();
$clean = is_array($clean) ? implode(',', $clean) :
(string) $clean;
}
include STAFFINC_DIR . 'templates/field-edit.tmpl.php';
}
// Set basic response data
$response = array(
'value' => $clean ?: '&mdash;' . __('Empty') . '&mdash;',
'id' => $fid, 'msg' => $msg
);
// If we require HT to close, the ticket is open, the staff has permission
// to close, and we set a HT - ensure we provide all available statuses
if ($cfg->requireTopicToClose() && $ticket->isOpen()
&& $ticket->checkStaffPerm($thisstaff, Ticket::PERM_CLOSE)
&& ($field instanceof TopicField) && $clean) {
$statuses = array();
foreach (TicketStatusList::getStatuses(
array('states' => array('closed'))) as $s) {
if (!$s->isEnabled()) continue;
$statuses[$s->getId()] = $s->getName();
}
if (!is_null($statuses))
$response['statuses'] = $statuses;
}
$clean = is_array($clean) ? $clean[0] : $clean;
Http::response(201, $this->json_encode($response));
}
$form->addErrors($errors);
$info['error'] = $errors['err'] ?: __('Unable to update field');
}
include STAFFINC_DIR . 'templates/field-edit.tmpl.php';
}
function viewField($tid, $fid) {
global $cfg, $thisstaff;
if (!($ticket=Ticket::lookup($tid)))
Http::response(404, __('No such ticket'));
elseif (!$ticket->checkStaffPerm($thisstaff))
Http::response(403, __('Permission denied'));
elseif (!($field=$ticket->getField($fid)))
Http::response(404, __('No such field'));
$errors = array();
$info = array(
':title' => sprintf(__('Ticket #%s: %s %s'),
$ticket->getNumber(),
__('View'),
$field->getLabel()
),
':action' => sprintf('#tickets/%d/field/%s/edit',
$ticket->getId(), $field->getId())
);
$form = $field->getEditForm();
include STAFFINC_DIR . 'templates/field-view.tmpl.php';
}
function assign($tid, $target=null) {
global $thisstaff;
@@ -579,14 +838,18 @@ function refer($tid, $target=null) {
if ($_POST && $form->isValid()) {
if ($ticket->assign($form, $errors)) {
$_SESSION['::sysmsgs']['msg'] = sprintf(
$msg = sprintf(
__('%s successfully'),
sprintf(
__('%s assigned to %s'),
__('Ticket'),
$form->getAssignee())
);
Http::response(201, $ticket->getId());
$assignee = $ticket->isAssigned() ? Format::htmlchars(implode('/', $ticket->getAssignees())) :
'<span class="faded">&mdash; '.__('Unassigned').' &mdash;';
Http::response(201, $this->json_encode(['value' =>
$assignee, 'id' => 'assign', 'msg' => $msg]));
}
$form->addErrors($errors);
@@ -728,6 +991,12 @@ function refer($tid, $target=null) {
'refer' => array(
'verbed' => __('referred'),
),
'merge' => array(
'verbed' => __('merged'),
),
'link' => array(
'verbed' => __('linked'),
),
'claim' => array(
'verbed' => __('assigned'),
),
@@ -758,6 +1027,89 @@ function refer($tid, $target=null) {
$count = $_REQUEST['count'];
}
switch ($action) {
case 'merge':
case 'link':
$inc = 'merge-tickets.tmpl.php';
$ticketIds = $_GET ? explode(',', $_GET['tids']) : explode(',', $_POST['tids']);
$tickets = array();
$title = strpos($_SERVER['PATH_INFO'], 'link') !== false ? 'link' : 'merge';
$eventName = ($title && $title == 'link') ? 'linked' : 'merged';
$permission = ($title && $title == 'link') ? (Ticket::PERM_LINK) : (Ticket::PERM_MERGE);
$hasPermission = array();
$parent = false;
$tickets = Ticket::objects()
->filter(array('ticket_id__in'=>$ticketIds))
->values_flat('ticket_id', 'flags', 'dept_id', 'ticket_pid');
foreach ($tickets as $ticket) {
list($ticket_id, $flags, $dept_id, $ticket_pid) = $ticket;
$mergeType = Ticket::getMergeTypeByFlag($flags);
$isParent = Ticket::isParentStatic($flags);
$role = $thisstaff->getRole($dept_id);
$hasPermission[] = $role->hasPerm($permission);
if (!$ticket)
continue;
elseif (!$parent && $isParent && $mergeType != 'visual') {
$parent = $ticket;
$parentMergeType = $mergeType;
}
if ($mergeType != 'visual' && $title == 'link')
$info['error'] = sprintf(
__('One or more Tickets selected is part of a merge. Merged Tickets cannot be %s.'),
__($eventName)
);
if ($parent && ($isParent && $mergeType != 'visual') && $parent[0] != $ticket_id)
$info['error'] = sprintf(
__('More than one Parent Ticket selected. %1$s cannot be %2$s.'),
_N('The selected Ticket', 'The selected Tickets', $count),
__($eventName)
);
if ($ticket_pid && $mergeType != 'visual' && $title == 'merge')
$info['error'] = sprintf(
__('One or more Tickets selected is a merged child. %1$s cannot be %2$s.'),
_N('The selected Ticket', 'The selected Tickets', $count),
__($eventName)
);
}
//move parent ticket to top of list
if (count($ticketIds) > 1) {
$ticketIdsSorted = $ticketIds;
if ($parent && $parentMergeType != 'visual') {
foreach ($ticketIdsSorted as $key => $value) {
if ($value == $parent[0]) {
unset($ticketIdsSorted[$key]);
array_unshift($ticketIdsSorted, $value);
array_unshift($ticketIdsSorted, new SqlField('ticket_id'));
}
}
}
$expr = call_user_func_array(array('SqlFunction', 'FIELD'), $ticketIdsSorted);
}
$tickets = Ticket::objects()
->filter(array('ticket_id__in'=>$ticketIds))
->values_flat('ticket_id', 'number', 'ticket_pid', 'sort', 'thread__id',
'user_id', 'cdata__subject', 'user__name', 'flags')
->annotate(array('tasks' => SqlAggregate::COUNT('tasks__id', true),
'collaborators' => SqlAggregate::COUNT('thread__collaborators__id'),
'entries' => SqlAggregate::COUNT('thread__entries__id'),))
->order_by($expr ?: 'sort');
$ticket = Ticket::lookup($parent[0] ?: $ticket[0]);
// Generic permission check.
if (in_array(false, $hasPermission) && !$ticket->getThread()->isReferred()) {
$info['error'] = sprintf(
__('You do not have permission to %1$s %2$s'),
__($title),
_N('the selected Ticket', 'the selected Tickets', $count));
$info = array_merge($info, Format::htmlchars($_POST));
} else
$info['action'] = sprintf('#tickets/%s/merge', $ticket->getId());
break;
case 'claim':
$w = 'me';
case 'assign':
@@ -784,13 +1136,8 @@ function refer($tid, $target=null) {
$depts = $tickets->values_flat('dept_id');
}
$members = Staff::objects()
->distinct('staff_id')
->filter(array(
'onvacation' => 0,
'isactive' => 1,
)
);
//agents in depts $thisstaff can access
$members = $thisstaff->getDeptAgents(array('available' => true));
if ($depts) {
$all_agent_depts = Dept::objects()->filter(
@@ -867,6 +1214,9 @@ function refer($tid, $target=null) {
$f->configure('prompt', $prompt);
if ($_POST && $form->isValid()) {
// we need to clear this relation so we can create a fresh
// query that will get roles for all depts this agent can access
unset($thisstaff->ht['dept_access']);
foreach ($_POST['tids'] as $tid) {
if (($t=Ticket::lookup($tid))
// Make sure the agent is allowed to
@@ -889,9 +1239,10 @@ function refer($tid, $target=null) {
case 'transfer':
$inc = 'transfer.tmpl.php';
$info[':action'] = '#tickets/mass/transfer';
$info[':title'] = sprintf('Transfer %s',
$info[':title'] = sprintf(__('Transfer %s'),
_N('selected ticket', 'selected tickets', $count));
$form = TransferForm::instantiate($_POST);
$form->hideDisabled();
if ($_POST && $form->isValid()) {
foreach ($_POST['tids'] as $tid) {
if (($t=Ticket::lookup($tid))
@@ -1098,23 +1449,45 @@ function refer($tid, $target=null) {
$state = strtolower($status->getState());
if (!$errors && $ticket->setStatus($status, $_REQUEST['comments'], $errors)) {
$failures = array();
// Set children statuses (if applicable)
if ($_REQUEST['children']) {
$children = $ticket->getChildren();
if ($state == 'deleted') {
$msg = sprintf('%s %s',
sprintf(__('Ticket #%s'), $ticket->getNumber()),
__('deleted sucessfully')
);
} elseif ($state != 'open') {
$msg = sprintf(__('%s status changed to %s'),
sprintf(__('Ticket #%s'), $ticket->getNumber()),
$status->getName());
} else {
$msg = sprintf(
__('%s status changed to %s'),
__('Ticket'),
$status->getName());
foreach ($children as $cid) {
$child = Ticket::lookup($cid[0]);
if (!$child->setStatus($status, '', $errors))
$failures[$cid[0]] = $child->getNumber();
}
}
if (!$failures) {
if ($state == 'deleted') {
$msg = sprintf('%s %s',
sprintf(__('Ticket #%s'), $ticket->getNumber()),
__('deleted sucessfully')
);
} elseif ($state != 'open') {
$msg = sprintf(__('%s status changed to %s'),
sprintf(__('Ticket #%s'), $ticket->getNumber()),
$status->getName());
} else {
$msg = sprintf(
__('%s status changed to %s'),
__('Ticket'),
$status->getName());
}
} else {
$tickets = array();
foreach ($failures as $id=>$num) {
$tickets[] = sprintf('<a href="tickets.php?id=%d"><b>#%s</b></a>',
$id,
$num);
}
$info['warn'] = sprintf(__('Error updating ticket status for %s'),
($tickets) ? implode(', ', $tickets) : __('child tickets')
);
}
$_SESSION['::sysmsgs']['msg'] = $msg;
Http::response(201, 'Successfully processed');
@@ -1273,7 +1646,7 @@ function refer($tid, $target=null) {
if (!($ticket=Ticket::lookup($tid)))
Http::response(404, __('No such ticket'));
if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_REPLY) && !$thisstaff->isManager())
if (!$ticket->checkStaffPerm($thisstaff, Ticket::PERM_MARKANSWERED) && !$thisstaff->isManager($ticket->getDept()))
Http::response(403, __('Permission denied'));
$errors = array();
@@ -1331,10 +1704,17 @@ function refer($tid, $target=null) {
}
function triggerThreadAction($ticket_id, $thread_id, $action) {
global $thisstaff;
if (!($ticket = Ticket::lookup($ticket_id))
|| !$ticket->checkStaffPerm($thisstaff))
Http::response(404, 'No such ticket thread entry');
$thread = ThreadEntry::lookup($thread_id);
if (!$thread)
Http::response(404, 'No such ticket thread entry');
if ($thread->getThread()->getObjectId() != $ticket_id)
if ($thread->getThread()->getObjectType() != 'T'
|| $thread->getThread()->getObjectId() != $ticket_id)
Http::response(404, 'No such ticket thread entry');
$valid = false;
@@ -1351,7 +1731,7 @@ function refer($tid, $target=null) {
$thread->triggerAction($action);
}
private function _changeSelectedTicketsStatus($state, $info=array(), $errors=array()) {
private static function _changeSelectedTicketsStatus($state, $info=array(), $errors=array()) {
$count = $_REQUEST['count'] ?:
($_REQUEST['tids'] ? count($_REQUEST['tids']) : 0);
@@ -1383,7 +1763,7 @@ function refer($tid, $target=null) {
return self::_changeStatus($state, $info, $errors);
}
private function _changeTicketStatus($ticket, $state, $info=array(), $errors=array()) {
private static function _changeTicketStatus($ticket, $state, $info=array(), $errors=array()) {
$verb = TicketStateField::getVerb($state);
@@ -1413,10 +1793,13 @@ function refer($tid, $target=null) {
$info['status_id'] = $info['status_id'] ?: $ticket->getStatusId();
$info['comments'] = Format::htmlchars($_REQUEST['comments']);
// Has Children?
$info['children'] = count($ticket->getChildren());
return self::_changeStatus($state, $info, $errors);
}
private function _changeStatus($state, $info=array(), $errors=array()) {
private static function _changeStatus($state, $info=array(), $errors=array()) {
if ($info && isset($info['errors']))
$errors = array_merge($errors, $info['errors']);
@@ -1437,6 +1820,16 @@ function refer($tid, $target=null) {
include STAFFINC_DIR . 'ticket-tasks.inc.php';
}
function relations($tid) {
global $thisstaff;
if (!($ticket=Ticket::lookup($tid))
|| !$ticket->checkStaffPerm($thisstaff))
Http::response(404, 'Unknown ticket');
include STAFFINC_DIR . 'ticket-relations.inc.php';
}
function addTask($tid, $vars=array()) {
global $thisstaff;
@@ -1456,7 +1849,7 @@ function refer($tid, $target=null) {
&& ($f=$iform->getField('duedate'))) {
$f->configure('max', Misc::db2gmtime($ticket->getEstDueDate()));
}
$vars = array_merge($_SESSION[':form-data'], $vars);
$vars = array_merge($_SESSION[':form-data'] ?: array(), $vars);
if ($_POST) {
Draft::deleteForNamespace(
@@ -1479,6 +1872,7 @@ function refer($tid, $target=null) {
$vars['default_formdata'] = $form->getClean();
$vars['internal_formdata'] = $iform->getClean();
$desc = $form->getField('description');
$vars['description'] = $desc->getClean();
if ($desc
&& $desc->isAttachmentsEnabled()
&& ($attachments=$desc->getWidget()->getAttachments()))
@@ -1592,7 +1986,7 @@ function refer($tid, $target=null) {
// Clear attachment list
$reply_attachments_form->setSource(array());
$reply_attachments_form->getField('attachments')->reset();
Draft::deleteForNamespace('task.reply.'.$task->getId(),
Draft::deleteForNamespace('task.response.'.$task->getId(),
$thisstaff->getId());
} else {
if (!$errors['err'])
@@ -1616,22 +2010,63 @@ function refer($tid, $target=null) {
else
$queue = AdhocSearch::load($id);
if (!$queue)
Http::response(404, 'Unknown Queue');
return $this->queueExport($queue);
}
function queueExport(CustomQueue $queue) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Agent login is required');
elseif (!$queue || !$queue->checkAccess($thisstaff))
Http::response(404, 'No such saved queue');
$errors = array();
if ($_POST && is_array($_POST['fields'])) {
// Cache export preferences
$id = $queue->getId();
$_SESSION['Export:Q'.$id]['fields'] = $_POST['fields'];
$_SESSION['Export:Q'.$id]['filename'] = $_POST['filename'];
$_SESSION['Export:Q'.$id]['delimiter'] = $_POST['delimiter'];
$_SESSION['Export:Q'.$id]['delimiter'] = $_POST['csv-delimiter'];
// Save fields selection if requested
if ($queue->isSaved() && isset($_POST['save-changes']))
$queue->updateExports(array_flip($_POST['fields']));
Http::response(201, 'Export Ready');
// Filename of the report
if (isset($_POST['filename'])
&& ($parts = pathinfo($_POST['filename']))) {
$filename = $_POST['filename'];
if (strcasecmp($parts['extension'], 'csv'))
$filename ="$filename.csv";
} else {
$filename = sprintf('%s Tickets-%s.csv',
$queue->getName(),
date('Ymd'));
}
try {
$interval = 5;
$options = ['filename' => $filename,
'interval' => $interval, 'delimiter' => $_POST['csv-delimiter']];
// Create desired exporter
$exporter = new CsvExporter($options);
// Acknowledge the export
$exporter->ack();
// Phew... now we're free to do the export
// Ask the queue to export to the exporter
$queue->export($exporter);
$exporter->finalize();
// Email the export if it exists
$exporter->email($thisstaff);
// Delete the file.
@$exporter->delete();
exit;
} catch (Exception $ex) {
$errors['err'] = __('Unable to prepare the export');
}
}
include STAFFINC_DIR . 'templates/queue-export.tmpl.php';

View File

@@ -19,6 +19,7 @@ if(!defined('INCLUDE_DIR')) die('403');
include_once(INCLUDE_DIR.'class.ticket.php');
require_once INCLUDE_DIR.'class.note.php';
require_once INCLUDE_DIR.'ajax.tickets.php';
class UsersAjaxAPI extends AjaxController {
@@ -33,7 +34,7 @@ class UsersAjaxAPI extends AjaxController {
if (!$_REQUEST['q'])
return $this->json_encode($matches);
$q = $_REQUEST['q'];
$q = Format::sanitize($_REQUEST['q']);
$limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25;
$users=array();
$emails=array();
@@ -73,16 +74,18 @@ class UsersAjaxAPI extends AjaxController {
return $this->search($type, $fulltext);
}
} else {
$filter = Q::any(array(
'emails__address__contains' => $q,
'name__contains' => $q,
'org__name__contains' => $q,
'account__username__contains' => $q,
));
if (UserForm::getInstance()->getField('phone'))
$filter->add(array('cdata__phone__contains' => $q));
$users->filter($filter);
$base = clone $users;
$users->filter(array('name__contains' => $q));
$users->union($base->copy()->filter(array(
'org__name__contains' => $q)), false);
$users->union($base->copy()->filter(array(
'emails__address__contains' => $q)), false);
$users->union($base->copy()->filter(array(
'account__username__contains' => $q)), false);
if (UserForm::getInstance()->getField('phone')) {
$users->union($base->copy()->filter(array(
'cdata__phone__contains' => $q)), false);
}
}
// Omit already-imported remote users
@@ -104,7 +107,7 @@ class UsersAjaxAPI extends AjaxController {
}
$name = Format::htmlchars(new UsersName($name));
$matches[] = array('email'=>$email, 'name'=>$name, 'info'=>"$email - $name",
"id" => $id, "/bin/true" => $_REQUEST['q']);
"id" => $id, "/bin/true" => $q);
}
usort($matches, function($a, $b) { return strcmp($a['name'], $b['name']); });
}
@@ -118,7 +121,12 @@ class UsersAjaxAPI extends AjaxController {
if(!$thisstaff)
Http::response(403, 'Login Required');
elseif(!($user = User::lookup($id)))
if (!$thisstaff->hasPerm(User::PERM_DIRECTORY)
&& !$thisstaff->hasPerm(User::PERM_EDIT))
Http::response(403, 'Permission Denied');
if(!($user = User::lookup($id)))
Http::response(404, 'Unknown user');
$info = array(
@@ -137,7 +145,6 @@ class UsersAjaxAPI extends AjaxController {
}
function editUser($id) {
global $thisstaff;
@@ -167,6 +174,10 @@ class UsersAjaxAPI extends AjaxController {
Http::response(404, 'Unknown user');
$errors = array();
$form = UserForm::getUserForm()->getForm($_POST);
if (!is_string($form->getField('name')->getValue()))
Http::response(404, 'Invalid Data');
if ($user->updateInfo($_POST, $errors, true) && !$errors)
Http::response(201, $user->to_json(), 'application/json');
@@ -174,7 +185,7 @@ class UsersAjaxAPI extends AjaxController {
include(STAFFINC_DIR . 'templates/user.tmpl.php');
}
function register($id) {
static function register($id) {
global $thisstaff;
if (!$thisstaff)
@@ -269,6 +280,14 @@ class UsersAjaxAPI extends AjaxController {
}
function getUser($id=false) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Login Required');
if (!$thisstaff->hasPerm(User::PERM_DIRECTORY)
&& !$thisstaff->hasPerm(User::PERM_EDIT))
Http::response(403, 'Permission Denied');
if(($user=User::lookup(($id) ? $id : $_REQUEST['id'])))
Http::response(201, $user->to_json(), 'application/json');
@@ -282,7 +301,7 @@ class UsersAjaxAPI extends AjaxController {
return self::addUser();
}
function addUser() {
static function addUser() {
global $thisstaff;
$info = array();
@@ -296,6 +315,8 @@ class UsersAjaxAPI extends AjaxController {
$info['title'] = __('Add New User');
$form = UserForm::getUserForm()->getForm($_POST);
if (!is_string($form->getField('name')->getValue()))
Http::response(404, 'Invalid Data');
if (($user = User::fromForm($form)))
Http::response(201, $user->to_json(), 'application/json');
@@ -315,7 +336,7 @@ class UsersAjaxAPI extends AjaxController {
elseif (!$bk || !$id)
Http::response(422, 'Backend and user id required');
elseif (!($backend = AuthenticationBackend::getSearchDirectoryBackend($bk))
|| !($user_info = $backend->lookup($id)))
|| !($user_info = $backend->lookup(html_entity_decode($id))))
Http::response(404, 'User not found');
$form = UserForm::getUserForm()->getForm($user_info);
@@ -414,6 +435,8 @@ class UsersAjaxAPI extends AjaxController {
Http::response(403, 'Login Required');
elseif (!($user = User::lookup($id)))
Http::response(404, 'Unknown user');
elseif (!$thisstaff->hasPerm(User::PERM_EDIT))
Http::response(403, 'Access Denied');
$info = array();
$info['title'] = sprintf(__('Organization for %s'),
@@ -426,6 +449,9 @@ class UsersAjaxAPI extends AjaxController {
if (!($org = Organization::lookup($_POST['orgid'])))
$info['error'] = __('Unknown organization selected');
} else { //Creating new org.
if (!$thisstaff->hasPerm(Organization::PERM_CREATE))
Http::response(403, 'Permission Denied');
$form = OrganizationForm::getDefaultForm()->getForm($_POST);
if (!($org = Organization::fromForm($form)))
$info['error'] = __('Unable to create organization.')
@@ -513,5 +539,28 @@ class UsersAjaxAPI extends AjaxController {
Http::response(201, 'Successfully managed');
}
function exportTickets($id) {
global $thisstaff;
if (!$thisstaff)
Http::response(403, 'Agent login is required');
elseif (!$id)
Http::response(403, __('User ID Required'));
$user = User::lookup($id);
if (!$user)
Http::response(403, __('User Not Found'));
$queue = $user->getTicketsQueue();
if ($_POST) {
$api = new TicketsAjaxAPI();
return $api->queueExport($queue);
}
$info = array('action' => "#users/$id/tickets/export");
include STAFFINC_DIR . 'templates/queue-export.tmpl.php';
}
}
?>

View File

@@ -3,40 +3,45 @@
include_once INCLUDE_DIR.'class.cron.php';
class CronApiController extends ApiController {
function execute() {
if(!($key=$this->requireApiKey()) || !$key->canExecuteCron())
if (!($key=$this->requireApiKey()) || !$key->canExecuteCron())
return $this->exerr(401, __('API key not authorized'));
$this->run();
}
/* private */
function run() {
global $ost;
protected function run() {
Cron::run();
$ost->logDebug(__('Cron Job'),__('Cron job executed').' ['.$_SERVER['REMOTE_ADDR'].']');
// TODO: Add elapsed time to the debug log
$this->debug(__('Cron Job'),
sprintf('%s [%s]', __('Cron job executed'), $this->getRemoteAddr()));
$this->response(200,'Completed');
}
}
class LocalCronApiController extends CronApiController {
function response($code, $resp) {
public function isCli() {
return true;
}
if($code == 200) //Success - exit silently.
protected function getRemoteAddr() {
// Local Cron doesn't have IP Addr set
return 'CLI';
}
public function response($code, $response) {
if ($code == 200) //Success - exit silently.
exit(0);
//On error echo the response (error)
echo $resp;
echo $response;
exit(1);
}
function call() {
$cron = new LocalCronApiController();
static function call() {
$cron = new LocalCronApiController('cli');
$cron->run();
}
}

View File

@@ -15,7 +15,12 @@ class TicketApiController extends ApiController {
array("name", "type", "data", "encoding", "size")
),
"message", "ip", "priorityId",
"system_emails", "thread_entry_recipients"
"system_emails" => array(
"*" => "*"
),
"thread_entry_recipients" => array (
"*" => array("to", "cc")
)
);
# Fetch dynamic form field names for the given help topic and add
# the names to the supported request structure
@@ -38,15 +43,22 @@ class TicketApiController extends ApiController {
foreach ($form->getFields() as $field)
$supported[] = $field->get('name');
if(!strcasecmp($format, 'email')) {
$supported = array_merge($supported, array('header', 'mid',
'emailId', 'to-email-id', 'ticketId', 'reply-to', 'reply-to-name',
'in-reply-to', 'references', 'thread-type', 'system_emails',
'mailflags' => array('bounce', 'auto-reply', 'spam', 'viral'),
'recipients' => array('*' => array('name', 'email', 'source'))
));
$supported['attachments']['*'][] = 'cid';
switch ($format) {
case 'email':
$supported = array_merge($supported, [
'header', 'mid', 'emailId', 'to-email-id', 'ticketId', 'reply-to',
'reply-to-name', 'in-reply-to', 'references', 'thread-type', 'system_emails',
'mailflags' => ['bounce', 'auto-reply', 'spam', 'viral'],
'recipients' => ['*' => ['name', 'email', 'source']]
]);
$supported['attachments']['*'][] = 'cid';
break;
case 'json':
case 'xml':
$supported = array_merge($supported, [
'duedate', 'slaId', 'staffId'
]);
break;
}
return $supported;
@@ -73,7 +85,7 @@ class TicketApiController extends ApiController {
$data['attachments'] = array();
//Validate attachments: Do error checking... soft fail - set the error and pass on the request.
if ($data['attachments'] && is_array($data['attachments'])) {
if (isset($data['attachments']) && is_array($data['attachments'])) {
foreach($data['attachments'] as &$file) {
if ($file['encoding'] && !strcasecmp($file['encoding'], 'base64')) {
if(!($file['data'] = base64_decode($file['data'], true)))
@@ -86,7 +98,9 @@ class TicketApiController extends ApiController {
$file['id'] = $F->getId();
}
catch (FileUploadError $ex) {
$file['error'] = $file['name'] . ': ' . $ex->getMessage();
$name = $file['name'];
$file = array();
$file['error'] = Format::htmlchars($name) . ': ' . $ex->getMessage();
}
}
unset($file);
@@ -98,61 +112,84 @@ class TicketApiController extends ApiController {
function create($format) {
if(!($key=$this->requireApiKey()) || !$key->canCreateTickets())
if (!($key=$this->requireApiKey()) || !$key->canCreateTickets())
return $this->exerr(401, __('API key not authorized'));
$ticket = null;
if(!strcasecmp($format, 'email')) {
# Handle remote piped emails - could be a reply...etc.
$ticket = $this->processEmail();
if (!strcasecmp($format, 'email')) {
// Process remotely piped emails - could be a reply...etc.
$ticket = $this->processEmailRequest();
} else {
# Parse request body
// Get and Parse request body data for the format
$ticket = $this->createTicket($this->getRequest($format));
}
if(!$ticket)
return $this->exerr(500, __("Unable to create new ticket: unknown error"));
$this->response(201, $ticket->getNumber());
if ($ticket)
$this->response(201, $ticket->getNumber());
else
$this->exerr(500, _S("unknown error"));
}
/* private helper functions */
function createTicket($data) {
function createTicket($data, $source = 'API') {
# Pull off some meta-data
$alert = (bool) (isset($data['alert']) ? $data['alert'] : true);
$autorespond = (bool) (isset($data['autorespond']) ? $data['autorespond'] : true);
# Assign default value to source if not defined, or defined as NULL
$data['source'] = isset($data['source']) ? $data['source'] : 'API';
// Assign default value to source if not defined, or defined as NULL
$data['source'] ??= $source;
# Create the ticket with the data (attempt to anyway)
// Create the ticket with the data (attempt to anyway)
$errors = array();
if (($ticket = Ticket::create($data, $errors, $data['source'],
$autorespond, $alert)) && !$errors)
return $ticket;
$ticket = Ticket::create($data, $errors, $data['source'], $autorespond, $alert);
# Return errors (?)
// Ticket create failed Bigly - got errors?
$title = null;
// Got errors?
if (count($errors)) {
if(isset($errors['errno']) && $errors['errno'] == 403)
return $this->exerr(403, __('Ticket denied'));
else
return $this->exerr(
400,
__("Unable to create new ticket: validation errors").":\n"
.Format::array_implode(": ", "\n", $errors)
);
} elseif (!$ticket) {
return $this->exerr(500, __("Unable to create new ticket: unknown error"));
// Ticket denied? Say so loudly so it can standout from generic
// validation errors
if (isset($errors['errno']) && $errors['errno'] == 403) {
$title = _S('Ticket denied');
$error = sprintf("%s: %s\n\n%s",
$title, $data['email'], $errors['err']);
} else {
// unpack the errors
$error = Format::array_implode("\n", "\n", $errors);
}
} else {
// unknown reason - default
$error = _S('unknown error');
}
return $ticket;
$error = sprintf('%s :%s',
_S('Unable to create new ticket'), $error);
return $this->exerr($errors['errno'] ?: 500, $error, $title);
}
function processEmail($data=false) {
function processEmailRequest() {
return $this->processEmail();
}
if (!$data)
$data = $this->getEmailRequest();
function processEmail($data=false, array $defaults = []) {
try {
if (!$data)
$data = $this->getEmailRequest();
elseif (!is_array($data))
$data = $this->parseEmail($data);
} catch (Exception $ex) {
throw new EmailParseError($ex->getMessage());
}
$data = array_merge($defaults, $data);
$seen = false;
if (($entry = ThreadEntry::lookupByEmailHeaders($data, $seen))
&& ($message = $entry->postEmail($data))
@@ -176,18 +213,34 @@ class TicketApiController extends ApiController {
// All emails which do not appear to be part of an existing thread
// will always create new "Tickets". All other objects will need to
// be created via the web interface or the API
return $this->createTicket($data);
try {
return $this->createTicket($data, 'Email');
} catch (TicketApiError $err) {
// Check if the ticket was denied by a filter or banlist
if ($err->isDenied() && $data['mid']) {
// We need to log the Message-Id (mid) so we don't
// process the same email again in subsequent fetches
$entry = new ThreadEntry();
$entry->logEmailHeaders(0, $data['mid']);
// throw TicketDenied exception so the caller can handle it
// accordingly
throw new TicketDenied($err->getMessage());
} else {
// otherwise rethrow this bad baby as it is!
throw $err;
}
}
}
}
//Local email piping controller - no API key required!
class PipeApiController extends TicketApiController {
//Overwrite grandparent's (ApiController) response method.
// Overwrite grandparent's (ApiController) response method.
function response($code, $resp) {
//Use postfix exit codes - instead of HTTP
// It's important to use postfix exit codes for local piping instead
// of HTTP's so the piping script can process them accordingly
switch($code) {
case 201: //Success
$exitcode = 0;
@@ -212,19 +265,33 @@ class PipeApiController extends TicketApiController {
default: //Temp (unknown) failure - retry
$exitcode = 75;
}
//echo "$code ($exitcode):$resp";
//We're simply exiting - MTA will take care of the rest based on exit code!
exit($exitcode);
}
function process() {
$pipe = new PipeApiController();
if(($ticket=$pipe->processEmail()))
return $pipe->response(201, $ticket->getNumber());
static function process($sapi=null) {
$pipe = new PipeApiController($sapi);
if (($ticket=$pipe->processEmail()))
return $pipe->response(201,
is_object($ticket) ? $ticket->getNumber() : $ticket);
return $pipe->exerr(416, __('Request failed - retry again!'));
}
static function local() {
return self::process('cli');
}
}
class TicketApiError extends Exception {
// Check if exception is because of denial
public function isDenied() {
return ($this->getCode() === 403);
}
}
class TicketDenied extends Exception {}
class EmailParseError extends Exception {}
?>

263
include/class.2fa.php Normal file
View File

@@ -0,0 +1,263 @@
<?php
/**
* TwoFactorAuthentication backend
*
* Provides the basis of abstracting 2fa backends
* The authentication backend should define a validate() method which
* receives a user and OPT.
*/
abstract class TwoFactorAuthenticationBackend extends ServiceRegistry {
// Global registry
static protected $registry = array();
// Grace period in minutes before OTP is expired and user logged out
// It's hardcoded to 6 minutes here but downstream backends can make it
// configurable
protected $timeout = 6;
// Maximum number of validation attempts before the user is logged out
// It's hardcoded to 3 attempts here but downstream backends can make it
// configurable
protected $maxstrikes = 3;
// Base properties
static $id;
static $name;
static $desc;
// Forms
private $_setupform;
private $_inputform;
// Send OTP to user specified and stash it
abstract function send($user);
// validate OTP provided by user
abstract function validate($form, $user);
function getDescription() {
return __(static::$desc);
}
function getTimeout() {
return $this->timeout;
}
function getMaxStrikes() {
return $this->maxstrikes;
}
protected function getSetupOptions() {
return array();
}
protected function getInputOptions() {
return array();
}
// stash OTP info in the session
protected function store($otp) {
$store = &$_SESSION['_2fa'][$this->getId()];
$store = ['otp' => $otp, 'time' => time(), 'strikes' => 0];
return $store;
}
// Validate OPT
// On strict mode check strikes and timeout
protected function _validate($otp, $strict=true) {
$store = &$_SESSION['_2fa'][$this->getId()];
// Track and check the attempts
$store['strikes'] += 1;
if ($strict && $store['strikes'] > $this->getMaxStrikes())
throw new ExpiredOTP(__('Too many attempts'));
// Check timeout - if expired throw an exception.
if ($strict
&& ($timeout=$this->getTimeout())
&& ($store['time']+($timeout*60)) < time())
throw new ExpiredOTP(__('Expired OTP'));
// Check the OTP
return (!strcmp($store['otp'], $otp));
}
// Called on a successfull validation for house keeping e.g clear 2fa
// flags
protected function onValidate($user) {
$user->clear2FA();
}
// Get a form the user uses to setup 2fa
function getSetupForm($data=null) {
if (!$this->_setupForm) {
$this->_setupForm = new SimpleForm($this->getSetupOptions(), $data);
}
return $this->_setupForm;
}
// Get a form the user uses to input OTP
function getInputForm($data=null) {
if (!$this->_inputForm) {
$this->_inputForm = new SimpleForm($this->getInputOptions(), $data);
}
return $this->_inputForm;
}
static function register($class) {
if (is_string($class) && class_exists($class))
$class = new $class();
if (!is_object($class)
|| !($class instanceof TwoFactorAuthenticationBackend))
return false;
static::$registry[$class->getBkId()] = $class;
}
static function allRegistered() {
return array_merge(self::$registry, parent::getRegistry());
}
static function getBackend($id) {
if ($id
&& ($backends = static::allRegistered())
&& isset($backends[$id]))
return $backends[$id];
}
static function lookup($id) {
return static::getBackend($id);
}
}
class ExpiredOTP extends Exception {}
/*
* user type container classes to aid in registry segmentation
*
*/
abstract class Staff2FABackend extends TwoFactorAuthenticationBackend {
static protected $registry = array();
static function allRegistered() {
return array_merge(self::$registry, parent::allRegistered());
}
abstract function send($user);
abstract function validate($form, $user);
}
abstract class User2FABackend extends TwoFactorAuthenticationBackend {
static protected $registry = array();
static function allRegistered() {
return array_merge(self::$registry, parent::allRegistered());
}
abstract function send($user);
abstract function validate($form, $user);
}
/*
* Email2FABackend
*
* Email based two factor authentication.
*
* This is the default 2FA that works out of the box once users configure
* it.
*
*/
class Email2FABackend extends TwoFactorAuthenticationBackend {
static $id = "2fa-email";
static $name = /* @trans */ 'Email';
static $desc = /* @trans */ 'Verification codes are sent by email';
protected function getSetupOptions() {
return array(
'email' => new TextboxField(array(
'id'=>2, 'label'=>__('Email Address'), 'required'=>true, 'default'=>'',
'validator'=>'email', 'hint'=>__('Valid email address'),
'configuration'=>array('size'=>40, 'length'=>40),
)),
);
}
protected function getInputOptions() {
return array(
'token' => new TextboxField(array(
'id'=>1, 'label'=>__('Verification Code'), 'required'=>true, 'default'=>'',
'validator'=>'number',
'hint'=>__('Please enter the code you were sent'),
'configuration'=>array(
'size'=>40, 'length'=>40,
'autocomplete' => 'one-time-code',
'inputmode' => 'numeric',
'pattern' => '[0-9]*',
'validator-error' => __('Invalid Code format'),
),
)),
);
}
function validate($form, $user) {
// Make sure form is valid and token exists
if (!($form->isValid()
&& ($clean=$form->getClean())
&& $clean['token']))
return false;
// upstream validation might throw an exception due to expired token
// or too many attempts (timeout). It's the responsibility of the
// caller to catch and handle such exceptions.
if (!$this->_validate($clean['token']))
return false;
// Validator doesn't do house cleaning - it's our responsibility
$this->onValidate($user);
return true;
}
function send($user) {
global $ost, $cfg;
// Get backend configuration for this user
if (!$cfg || !($info = $user->get2FAConfig($this->getId())))
return false;
// Email to send the OTP via
if (!($email = $cfg->getAlertEmail() ?: $cfg->getDefaultEmail()))
return false;
// Generate OTP
$otp = Misc::randNumber(6);
// Stash it in the session
$this->store($otp);
$template = 'email2fa-staff';
$content = Page::lookupByType($template);
if (!$content)
return new BaseError(/* @trans */ 'Unable to retrieve two factor authentication email template');
$vars = array(
'url' => $ost->getConfig()->getBaseUrl(),
'otp' => $otp,
'staff' => $user,
'recipient' => $user,
);
$lang = $user->lang ?: $user->getExtraAttr('browser_lang');
$msg = $ost->replaceTemplateVariables(array(
'subj' => $content->getLocalName($lang),
'body' => $content->getLocalBody($lang),
), $vars);
$email->send($user->getEmail(), Format::striptags($msg['subj']),
$msg['body']);
// MD5 here is not meant to be secure here - just done to avoid plain leaks
return md5($otp);
}
}
// Register email2fa for both agents and users (parent class)
TwoFactorAuthenticationBackend::register('Email2FABackend');
?>

View File

@@ -25,12 +25,18 @@ require_once (INCLUDE_DIR.'class.api.php');
* consistency.
*/
class AjaxController extends ApiController {
function staffOnly() {
global $thisstaff;
if(!$thisstaff || !$thisstaff->isValid()) {
Http::response(401,sprintf(__('Access Denied. IP %s'),$_SERVER['REMOTE_ADDR']));
if (!$thisstaff || !$thisstaff->isValid()) {
$this->exerr(401, sprintf('%s (%s)',
__('Access Denied'), $_SERVER['REMOTE_ADDR']));
}
return true;
}
/**
* Convert a PHP array into a JSON-encoded string
*/
@@ -43,6 +49,6 @@ class AjaxController extends ApiController {
}
function get($var, $default=null) {
return (isset($_GET[$var])) ? $_GET[$var] : $default;
return $_GET[$var] ?: $default;
}
}

View File

@@ -13,6 +13,8 @@
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
include_once INCLUDE_DIR.'class.controller.php';
class API {
var $id;
@@ -91,15 +93,15 @@ class API {
}
/** Static functions **/
function add($vars, &$errors) {
static function add($vars, &$errors) {
return API::save(0, $vars, $errors);
}
function validate($key, $ip) {
static function validate($key, $ip) {
return ($key && $ip && self::getIdByKey($key, $ip));
}
function getIdByKey($key, $ip='') {
static function getIdByKey($key, $ip='') {
$sql='SELECT id FROM '.API_KEY_TABLE.' WHERE apikey='.db_input($key);
if($ip)
@@ -111,15 +113,15 @@ class API {
return $id;
}
function lookupByKey($key, $ip='') {
static function lookupByKey($key, $ip='') {
return self::lookup(self::getIdByKey($key, $ip));
}
function lookup($id) {
static function lookup($id) {
return ($id && is_numeric($id) && ($k= new API($id)) && $k->getId()==$id)?$k:null;
}
function save($id, $vars, &$errors) {
static function save($id, $vars, &$errors) {
if(!$id && (!$vars['ipaddr'] || !Validator::is_ip($vars['ipaddr'])))
$errors['ipaddr'] = __('Valid IP is required');
@@ -144,7 +146,7 @@ class API {
$sql='INSERT INTO '.API_KEY_TABLE.' SET '.$sql
.',created=NOW() '
.',ipaddr='.db_input($vars['ipaddr'])
.',apikey='.db_input(strtoupper(md5(time().$vars['ipaddr'].md5(Misc::randCode(16)))));
.',apikey='.db_input(strtoupper(Misc::randCode(48, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789')));
if(db_query($sql) && ($id=db_insert_id()))
return $id;
@@ -165,28 +167,51 @@ class API {
* API request.
*/
class ApiController {
class ApiController extends Controller {
var $apikey;
private $sapi;
private $key;
public function __construct($sapi = null) {
// Set API Interface the request is coming from
$this->sapi = $sapi ?: (osTicket::is_cli() ? 'cli' : 'http');
}
public function isCli() {
return (strcasecmp($this->sapi, 'cli') === 0);
}
private function getInputStream() {
return $this->isCli() ? 'php://stdin' : 'php://input';
}
protected function getRemoteAddr() {
return $_SERVER['REMOTE_ADDR'];
}
protected function getApiKey() {
return $_SERVER['HTTP_X_API_KEY'];
}
function requireApiKey() {
# Validate the API key -- required to be sent via the X-API-Key
# header
if(!($key=$this->getApiKey()))
// Require a valid API key sent as X-API-Key HTTP header
// see getApiKey method.
if (!($key=$this->getKey()))
return $this->exerr(401, __('Valid API key required'));
elseif (!$key->isActive() || $key->getIPAddr()!=$_SERVER['REMOTE_ADDR'])
elseif (!$key->isActive() || $key->getIPAddr() != $this->getRemoteAddr())
return $this->exerr(401, __('API key not found/active or source IP not authorized'));
return $key;
}
function getApiKey() {
function getKey() {
// Lookup record using sent API Key && IP Addr
if (!$this->key
&& ($key=$this->getApiKey())
&& ($ip=$this->getRemoteAddr()))
$this->key = API::lookupByKey($key, $ip);
if (!$this->apikey && isset($_SERVER['HTTP_X_API_KEY']) && isset($_SERVER['REMOTE_ADDR']))
$this->apikey = API::lookupByKey($_SERVER['HTTP_X_API_KEY'], $_SERVER['REMOTE_ADDR']);
return $this->apikey;
return $this->key;
}
/**
@@ -194,20 +219,28 @@ class ApiController {
* hashtable. For JSON formats, this is mostly a noop, the conversion
* work will be done for XML requests
*/
function getRequest($format) {
global $ost;
$input = osTicket::is_cli()?'php://stdin':'php://input';
function getRequest($format, $validate=true) {
$input = $this->getInputStream();
if (!($stream = @fopen($input, 'r')))
$this->exerr(400, __("Unable to read request body"));
$this->exerr(400, sprintf('%s (%s)',
__("Unable to read request body"), $input));
return $this->parseRequest($stream, $format, $validate);
}
function getEmailRequest() {
if (!($data=$this->getRequest('email', false)))
$this->exerr(400, __("Unable to read email request"));
return $data;
}
function parseRequest($stream, $format, $validate=true) {
$parser = null;
switch(strtolower($format)) {
case 'xml':
if (!function_exists('xml_parser_create'))
$this->exerr(501, __('XML extension not supported'));
return $this->exerr(501, __('XML extension not supported'));
$parser = new ApiXmlDataParser();
break;
case 'json':
@@ -217,23 +250,24 @@ class ApiController {
$parser = new ApiEmailDataParser();
break;
default:
$this->exerr(415, __('Unsupported data format'));
return $this->exerr(415, __('Unsupported data format'));
}
if (!($data = $parser->parse($stream)))
if (!($data = $parser->parse($stream)) || !is_array($data)) {
$this->exerr(400, $parser->lastError());
}
//Validate structure of the request.
$this->validate($data, $format, false);
if ($validate && $data)
$this->validate($data, $format, false);
return $data;
}
function getEmailRequest() {
return $this->getRequest('email');
function parseEmail($content) {
return $this->parseRequest($content, 'email', false);
}
/**
* Structure to validate the request against -- must be overridden to be
* useful
@@ -257,14 +291,11 @@ class ApiController {
} elseif (in_array($key, $structure)) {
continue;
}
if ($strict)
return $this->exerr(400, sprintf(__("%s: Unexpected data received in API request"), "$prefix$key"));
else
$ost->logWarning(__('API Unexpected Data'),
sprintf(__("%s: Unexpected data received in API request"), "$prefix$key"),
false);
}
$error = sprintf(__("%s: Unexpected data received in API request"),
"$prefix$key");
$this->onError(400, $error, __('Unexpected Data'), !$strict);
}
return true;
}
@@ -280,37 +311,66 @@ class ApiController {
$strict);
}
protected function debug($subj, $msg) {
return $this->log($subj, $msg, LOG_DEBUG);
}
protected function logError($subj, $msg, $fatal=false) {
// If error is not fatal then log it as a warning
return $this->log($subj, $msg, $fatal ? LOG_ERR : LOG_WARN);
}
protected function log($title, $msg, $level = LOG_WARN) {
global $ost;
switch ($level) {
case LOG_WARN:
case LOG_ERR:
// We are disabling email alerts on API errors / warnings
// due to potential abuse or loops that might cause email DOS
$ost->log($level, $title, $msg, false);
break;
case LOG_DEBUG:
default:
$ost->logDebug($title, $msg);
}
return true;
}
/**
* API error & logging and response!
*
* final - don not override downstream.
*/
final public function onError($code, $error, $title = null,
$logOnly = false) {
/* If possible - DO NOT - overwrite the method downstream */
function exerr($code, $error='') {
global $ost;
if($error && is_array($error))
// Unpack the errors to string if error is an array
if ($error && is_array($error))
$error = Format::array_implode(": ", "\n", $error);
//Log the error as a warning - include api key if available.
// Log the error
$msg = $error;
if($_SERVER['HTTP_X_API_KEY'])
$msg.="\n*[".$_SERVER['HTTP_X_API_KEY']."]*\n";
$ost->logWarning(__('API Error')." ($code)", $msg, false);
// TODO: Only include API Key when in debug mode to avoid
// potentialialy leaking a valid key in system logs
if (($key=$this->getApiKey()))
$msg .= sprintf("\n[%s]\n", Format::shroud($key, 8, 16));
if (PHP_SAPI == 'cli') {
fwrite(STDERR, "({$code}) $error\n");
}
else {
$this->response($code, $error); //Responder should exit...
}
return false;
}
$title = sprintf('%s (%s)', $title ?: __('API Error'), $code);
$this->logError($title, $msg, $logOnly);
//Default response method - can be overwritten in subclasses.
function response($code, $resp) {
Http::response($code, $resp);
exit();
// If the error is not deemed fatal then simply return
if ($logOnly)
return;
// If the API Interface is CLI then throw a TicketApiError exception
// so the caller can handle the error gracefully.
// Note that we set the error code as well
if ($this->isCli())
throw new TicketApiError($error, $code);
// Respond and exit since HTTP endpoint requests
// are considered stateless
$this->response($code, $error);
}
}
@@ -327,8 +387,8 @@ class ApiXmlDataParser extends XmlDataParser {
function fixup($current) {
global $cfg;
if($current['ticket'])
$current = $current['ticket'];
if (isset($current['ticket']))
$current = $current['ticket'];
if (!is_array($current))
return $current;
@@ -381,10 +441,10 @@ class ApiXmlDataParser extends XmlDataParser {
include_once "class.json.php";
class ApiJsonDataParser extends JsonDataParser {
function parse($stream, $tidy=false) {
return $this->fixup(parent::parse($stream));
static function parse($stream, $tidy=false) {
return self::fixup(parent::parse($stream));
}
function fixup($current) {
static function fixup($current) {
if (!is_array($current))
return $current;
foreach ($current as $key=>&$value) {
@@ -396,7 +456,7 @@ class ApiJsonDataParser extends JsonDataParser {
$value = (bool)$value;
} elseif ($key == "message") {
// Allow message specified in RFC 2397 format
$data = Format::parseRfc2397($value, 'utf-8');
$data = Format::strip_emoticons(Format::parseRfc2397($value, 'utf-8'));
if (isset($data['type']) && $data['type'] == 'text/html')
$value = new HtmlThreadEntryBody($data['data']);
@@ -434,17 +494,17 @@ class ApiEmailDataParser extends EmailDataParser {
function fixup($data) {
global $cfg;
if(!$data) return $data;
if (!$data) return $data;
$data['source'] = 'Email';
if(!$data['subject'])
if (!$data['subject'])
$data['subject'] = '[No Subject]';
if(!$data['emailId'])
if (!$data['emailId'])
$data['emailId'] = $cfg->getDefaultEmailId();
if(!$cfg->useEmailPriority())
if( !$cfg->useEmailPriority())
unset($data['priorityId']);
return $data;

View File

@@ -28,7 +28,7 @@ class Application {
array('desc'=>$desc, 'href'=>$href));
}
function getStaffApps() {
static function getStaffApps() {
return self::$staff_apps;
}
@@ -37,7 +37,7 @@ class Application {
array('desc'=>$desc, 'href'=>$href));
}
function getClientApps() {
static function getClientApps() {
return self::$client_apps;
}
@@ -46,7 +46,7 @@ class Application {
array('desc'=>$desc, 'href'=>$href));
}
function getAdminApps() {
static function getAdminApps() {
return self::$admin_apps;
}
}

View File

@@ -105,7 +105,7 @@ extends InstrumentedList {
function getId() { return $this->key['object_id']; }
function getType() { return $this->key['type']; }
function getMimeType() { return $this->getType(); }
/**
* Drop attachments whose file_id values are not in the included list,
* additionally, add new files whose IDs are in the list provided.
@@ -120,10 +120,11 @@ extends InstrumentedList {
}
$attachments = array();
// Format $new for upload() with new name
foreach ($ids as $id=>$name) {
foreach ($ids as $id=>$value) {
if (is_array($value)) list('id' => $id, 'name' => $value) = $value;
$attachments[] = array(
'id' => $id,
'name' => $name
'name' => $value
);
}
// Everything remaining in $attachments is truly new
@@ -148,7 +149,15 @@ extends InstrumentedList {
$_inline = isset($file['inline']) ? $file['inline'] : $inline;
$att = $this->add(new Attachment(array(
// Check if Attachment exists
if ($F && $this->key)
$existing = Attachment::objects()->filter(array(
'file__key' => $F->key,
'object_id' => $this->key['object_id'],
'type' => $this->key['type']
))->first();
$att = $this->add(isset($existing) ? $existing : new Attachment(array(
'file_id' => $fileId,
'inline' => $_inline ? 1 : 0,
)));
@@ -183,7 +192,7 @@ extends InstrumentedList {
function getInlines($lang=false) { return $this->_getList(false, true, $lang); }
function getSeparates($lang=false) { return $this->_getList(true, false, $lang); }
function getAll($lang=false) { return $this->_getList(true, true, $lang); }
function count($lang=false) { return count($this->getSeparates($lang)); }
function count($lang=false): int { return count($this->getSeparates($lang)); }
function _getList($separates=false, $inlines=false, $lang=false) {
$base = $this;

View File

@@ -1,16 +1,23 @@
<?php
require_once(INCLUDE_DIR.'class.2fa.php');
interface AuthenticatedUser {
/* PHP 5.3 < 5.3.8 will crash with some abstract inheritance issue
* ------------------------------------------------------------
// Get basic information
function getId();
function getUsername();
function getUserType();
// Get password reset timestamp
function getPasswdResetTimestamp();
//Backend used to authenticate the user
function getAuthBackend();
// Get 2FA Backend
function get2FABackend();
//Authentication key
function setAuthKey($key);
@@ -22,7 +29,6 @@ interface AuthenticatedUser {
// Signal method to allow performing extra things when a user is logged
// into the sysem
function onLogin($bk);
*/
}
abstract class BaseAuthenticatedUser
@@ -35,9 +41,17 @@ implements AuthenticatedUser {
abstract function getUsername();
abstract function getUserType();
// Get password reset timestamp
function getPasswdResetTimestamp() {
return null;
}
//Backend used to authenticate the user
abstract function getAuthBackend();
// Get 2FA Backend
abstract function get2FABackend();
//Authentication key
function setAuthKey($key) {
$this->authkey = $key;
@@ -120,7 +134,7 @@ class ClientCreateRequest {
function attemptAutoRegister() {
global $cfg;
if (!$cfg)
if (!$cfg || $cfg->isClientRegistrationMode(['disabled']))
return false;
// Attempt to automatically register
@@ -132,7 +146,7 @@ class ClientCreateRequest {
);
if ($bk->supportsInteractiveAuthentication())
// User can only be authenticated against this backend
$defaults['backend'] = $bk::$id;
$defaults['backend'] = $bk->getBkId();
if ($this_form->isValid(function($f) { return !$f->isVisibleToUsers(); })
&& ($U = User::fromVars($this_form->getClean()))
&& ($acct = ClientAccount::createForUser($U, $defaults))
@@ -145,6 +159,78 @@ class ClientCreateRequest {
}
}
/**
* Authorization backend
*
* Abstract service registry to provide authorization backends.
*/
abstract class OAuth2Backend extends ServiceRegistry {
static $name;
static $id;
protected $config;
static function register($bk) {
if (is_string($bk) && class_exists($bk))
$bk = new $bk();
if (!is_object($bk)
|| !($bk instanceof OAuth2Backend))
return false;
static::$registry[$bk->getBkId()] = $bk;
}
static function allRegistered() {
return self::getRegistry();
}
static function getBackend($id) {
if ($id && ($registry = static::allRegistered())
&& isset($registry[$id]))
return $registry[$id];
}
}
abstract class OAuth2AuthorizationBackend extends OAuth2Backend {
static protected $registry = array();
static function allRegistered() {
return array_merge(self::$registry, parent::allRegistered());
}
static function getBackend($id) {
if (($bk=parent::getBackend($id)))
return $bk;
// Overloaded backend load.
list($auth, $a, $i) = self::parseId($id);
if ($auth && ($bk=parent::getBackend($auth)))
return $bk;
}
static function parseId($id) {
return preg_split('/(?(?<=oauth2):(?!\w+)|:)/', $id);
}
abstract function getConfigForm($configId);
abstract function triggerEmailAuth($id);
abstract function callback($resp, $ref);
}
abstract class OAuth2AuthenticationBackend extends OAuth2Backend {
static protected $registry = array();
static function allRegistered() {
return array_merge(self::$registry, parent::allRegistered());
}
static function getBackend($id) {
if (($bk=parent::getBackend($id)))
return $bk;
}
}
/**
* Authentication backend
*
@@ -160,41 +246,61 @@ class ClientCreateRequest {
* receives a username and optional password. If the authentication
* succeeds, an instance deriving from <User> should be returned.
*/
abstract class AuthenticationBackend {
static protected $registry = array();
abstract class AuthenticationBackend extends ServiceRegistry {
static $name;
static $id;
protected $config;
static function register($bk) {
if (is_string($bk) && class_exists($bk))
$bk = new $bk();
/* static */
static function register($class) {
if (is_string($class) && class_exists($class))
$class = new $class();
if (!is_object($class)
|| !($class instanceof AuthenticationBackend))
if (!is_object($bk)
|| !($bk instanceof AuthenticationBackend))
return false;
return static::_register($class);
}
static function _register($class) {
// XXX: Raise error if $class::id is already in the registry
static::$registry[$class::$id] = $class;
static::$registry[$bk->getBkId()] = $bk;
}
static function allRegistered() {
return static::$registry;
return self::getRegistry();
}
static function getInteractive() {
$backends = [];
foreach (static::allRegistered() as $bk)
if ($bk->isInteractive())
$backends[] = $bk;
return $backends;
}
static function getExternal() {
$backends = [];
foreach (static::allRegistered() as $bk)
if ($bk->isExternal())
$backends[] = $bk;
return $backends;
}
static function getBackend($id) {
if ($id
&& ($backends = static::allRegistered())
&& isset($backends[$id]))
return $backends[$id];
}
static function lookupBackend($id, $class=null) {
// Lookup both registries
if (!($bk = StaffAuthenticationBackend::getBackend($id)))
$bk = UserAuthenticationBackend::getBackend($id);
// See if specific type is requesred.
if ($class && !($bk instanceof $class))
return null;
return $bk;
}
static function getSearchDirectoryBackend($id) {
if ($id
@@ -224,7 +330,7 @@ abstract class AuthenticationBackend {
foreach (static::allRegistered() as $bk) {
if ($backends //Allowed backends
&& $bk->supportsInteractiveAuthentication()
&& !in_array($bk::$id, $backends))
&& !in_array($bk->getBkId(), $backends))
// User cannot be authenticated against this backend
continue;
@@ -266,7 +372,7 @@ abstract class AuthenticationBackend {
* $forcedAuth - indicate if authentication is required.
*
*/
function processSignOn(&$errors, $forcedAuth=true) {
static function processSignOn(&$errors, $forcedAuth=true) {
foreach (static::allRegistered() as $bk) {
// All backends are queried here, even if they don't support
@@ -307,13 +413,13 @@ abstract class AuthenticationBackend {
$backends = array();
foreach (StaffAuthenticationBackend::allRegistered() as $bk)
if ($bk instanceof AuthDirectorySearch)
$backends[$bk::$id] = $bk;
$backends[$bk->getBkId()] = $bk;
foreach (UserAuthenticationBackend::allRegistered() as $bk)
if ($bk instanceof AuthDirectorySearch)
$backends[$bk::$id] = $bk;
$backends[$bk->getBkId()] = $bk;
return array_unique($backends);
return array_unique($backends, SORT_REGULAR);
}
static function searchUsers($query) {
@@ -324,13 +430,6 @@ abstract class AuthenticationBackend {
return $users;
}
/**
* Fetches the friendly name of the backend
*/
function getName() {
return static::$name;
}
/**
* Indicates if the backed supports authentication. Useful if the
* backend is used for logging or lockout only
@@ -339,6 +438,21 @@ abstract class AuthenticationBackend {
return true;
}
/**
* Alias for supportsInteractiveAuthentication()
*
*/
function isInteractive() {
return $this->supportsInteractiveAuthentication();
}
/**
* Indicates of the backend is External Authentication
*/
function isExternal() {
return ($this instanceof ExternalAuthentication);
}
/**
* Indicates if the backend supports changing a user's password. This
* would be done in two fashions. Either the currently-logged in user
@@ -350,6 +464,15 @@ abstract class AuthenticationBackend {
return false;
}
/**
* Get supported password policies for the backend.
*
*/
function getPasswordPolicies($user=null) {
return PasswordPolicy::allActivePolicies();
}
/**
* Request the backend to update the password for a user. This method is
* the main entry for password updates so that password policies can be
@@ -361,7 +484,9 @@ abstract class AuthenticationBackend {
* PasswordUpdateFailed — if backend failed to update the password
*/
function setPassword($user, $password, $current=false) {
PasswordPolicy::checkPassword($password, $current);
foreach ($this->getPasswordPolicies($user) as $P)
$P->onSet($password, $current);
$rv = $this->syncPassword($user, $password);
if ($rv) {
$info = array('password' => $password, 'current' => $current);
@@ -370,6 +495,17 @@ abstract class AuthenticationBackend {
return $rv;
}
/*
* Request the backend to check the policies for a just logged
* in user.
* Throws: BadPassword & ExpiredPassword - for password related failures
*/
function checkPolicies($user, $password) {
// Password policies
foreach ($this->getPasswordPolicies($user) as $P)
$P->onLogin($user, $password);
}
/**
* Request the backend to update the user's password with the password
* given. This method should only be used if the backend advertises
@@ -401,7 +537,7 @@ abstract class AuthenticationBackend {
abstract function authenticate($username, $password);
abstract function login($user, $bk);
abstract static function getUser(); //Validates authenticated users.
abstract function getAllowedBackends($userid);
abstract static function getAllowedBackends($userid);
abstract protected function getAuthKey($user);
abstract static function signOut($user);
}
@@ -424,6 +560,13 @@ interface ExternalAuthentication {
*/
function renderExternalLink();
/**
* Function: getServiceName
*
* Called to get the service name displayed on login page.
*/
function getServiceName();
/**
* Function: triggerAuth
*
@@ -435,26 +578,33 @@ interface ExternalAuthentication {
}
abstract class StaffAuthenticationBackend extends AuthenticationBackend {
static private $_registry = array();
static function _register($class) {
static::$_registry[$class::$id] = $class;
}
static protected $registry = array();
static function allRegistered() {
return array_merge(self::$_registry, parent::allRegistered());
return array_merge(self::$registry, parent::allRegistered());
}
function isBackendAllowed($staff, $bk) {
static function isBackendAllowed($staff, $bk) {
if (!($backends=self::getAllowedBackends($staff->getId())))
return true; //No restrictions
return in_array($bk::$id, array_map('strtolower', $backends));
return in_array($bk->getBkId(), array_map('strtolower', $backends));
}
function getAllowedBackends($userid) {
function getPasswordPolicies($user=null) {
global $cfg;
$policies = PasswordPolicy::allActivePolicies();
if ($cfg && ($policy = $cfg->getStaffPasswordPolicy())) {
foreach ($policies as $P)
if ($policy == $P->getBkId())
return array($P);
}
return $policies;
}
static function getAllowedBackends($userid) {
$backends =array();
//XXX: Only one backend can be specified at the moment.
@@ -488,24 +638,38 @@ abstract class StaffAuthenticationBackend extends AuthenticationBackend {
sprintf(_S("%s logged in [%s], via %s"), $staff->getUserName(),
$_SERVER['REMOTE_ADDR'], get_class($bk))); //Debug.
// Tag the authkey.
$authkey = $bk::$id.':'.$authkey;
$agent = Staff::lookup($staff->getId());
$type = array('type' => 'login');
Signal::send('person.login', $agent, $type);
// Check if the agent has 2fa enabled
$auth2fa = null;
if (($_2fa = $staff->get2FABackend())
&& ($token=$_2fa->send($staff))) {
$auth2fa = sprintf('%s:%s:%s',
$_2fa->getId(), md5($token.$staff->getId()), time());
}
// Tag the authkey.
$authkey = $bk->getBkId().':'.$authkey;
// Now set session crap and lets roll baby!
$authsession = &$_SESSION['_auth']['staff'];
$authsession = array(); //clear.
$authsession['id'] = $staff->getId();
$authsession['key'] = $authkey;
$authsession['2fa'] = $auth2fa;
// Set TIME_BOMB to regenerate the session 10 seconds after login
$_SESSION['TIME_BOMB'] = time() + 10;
// Set session token
$staff->setSessionToken();
// Set Auth Key
$staff->setAuthKey($authkey);
$staff->refreshSession(true); //set the hash.
Signal::send('auth.login.succeeded', $staff);
if ($bk->supportsInteractiveAuthentication())
$staff->cancelResetTokens();
// Update last-used language, login time, etc
$staff->onLogin($bk);
@@ -528,6 +692,9 @@ abstract class StaffAuthenticationBackend extends AuthenticationBackend {
$staff->getUserName(),
$_SERVER['REMOTE_ADDR'])); //Debug.
$agent = Staff::lookup($staff->getId());
$type = array('type' => 'logout');
Signal::send('person.logout', $agent, $type);
Signal::send('auth.logout', $staff);
}
@@ -543,6 +710,7 @@ abstract class StaffAuthenticationBackend extends AuthenticationBackend {
if (!($bk=static::getBackend($id)) //get the backend
|| !($staff = $bk->validate($auth)) //Get AuthicatedUser
|| !($staff instanceof Staff)
|| !$staff->isActive()
|| $staff->getId() != $_SESSION['_auth']['staff']['id'] // check ID
)
return null;
@@ -567,7 +735,9 @@ abstract class StaffAuthenticationBackend extends AuthenticationBackend {
protected function validate($authkey) {
if (($staff = StaffSession::lookup($authkey)) && $staff->getId())
if (($staff = StaffSession::lookup($authkey))
&& $staff->getId()
&& $staff->isActive())
return $staff;
}
}
@@ -580,19 +750,28 @@ abstract class ExternalStaffAuthenticationBackend
static $sign_in_image_url = false;
static $service_name = "External";
function renderExternalLink() { ?>
<a class="external-sign-in" title="Sign in with <?php echo static::$service_name; ?>"
href="login.php?do=ext&amp;bk=<?php echo urlencode(static::$id); ?>">
function getServiceName() {
return __(static::$service_name);
}
function renderExternalLink() {
$service = sprintf('%s %s',
__('Sign in with'),
$this->getServiceName());
?>
<a class="external-sign-in" title="<?php echo $service; ?>"
href="login.php?do=ext&amp;bk=<?php echo
urlencode($this->getBkId()); ?>">
<?php if (static::$sign_in_image_url) { ?>
<img class="sign-in-image" src="<?php echo static::$sign_in_image_url;
?>" alt="Sign in with <?php echo static::$service_name; ?>"/>
?>" alt="<?php echo $service; ?>"/>
<?php } else { ?>
<div class="external-auth-box">
<span class="external-auth-icon">
<i class="icon-<?php echo static::$fa_icon; ?> icon-large icon-fixed-with"></i>
</span>
<span class="external-auth-name">
Sign in with <?php echo static::$service_name; ?>
<?php echo $service; ?>
</span>
</div>
<?php } ?>
@@ -600,15 +779,17 @@ abstract class ExternalStaffAuthenticationBackend
}
function triggerAuth() {
$_SESSION['ext:bk:id'] = $this->getBkId();
// For legacy plugins prior to v1.17
$_SESSION['ext:bk:class'] = get_class($this);
}
}
Signal::connect('api', function($dispatcher) {
$dispatcher->append(
url('^/auth/ext$', function() {
if ($class = $_SESSION['ext:bk:class']) {
$bk = StaffAuthenticationBackend::getBackend($class::$id)
?: UserAuthenticationBackend::getBackend($class::$id);
if ($id = $_SESSION['ext:bk:id']) {
$bk = StaffAuthenticationBackend::getBackend($id)
?: UserAuthenticationBackend::getBackend($id);
if ($bk instanceof ExternalAuthentication)
$bk->triggerAuth();
}
@@ -617,18 +798,25 @@ Signal::connect('api', function($dispatcher) {
});
abstract class UserAuthenticationBackend extends AuthenticationBackend {
static private $_registry = array();
static function _register($class) {
static::$_registry[$class::$id] = $class;
}
static protected $registry = array();
static function allRegistered() {
return array_merge(self::$_registry, parent::allRegistered());
return array_merge(self::$registry, parent::allRegistered());
}
function getAllowedBackends($userid) {
function getPasswordPolicies($user=null) {
global $cfg;
$policies = PasswordPolicy::allActivePolicies();
if ($cfg && ($policy = $cfg->getClientPasswordPolicy())) {
foreach ($policies as $P)
if ($policy == $P->getId())
return array($P);
}
return $policies;
}
static function getAllowedBackends($userid) {
$backends = array();
$sql = 'SELECT A1.backend FROM '.USER_ACCOUNT_TABLE
.' A1 INNER JOIN '.USER_EMAIL_TABLE.' A2 ON (A2.user_id = A1.user_id)'
@@ -649,7 +837,7 @@ abstract class UserAuthenticationBackend extends AuthenticationBackend {
global $ost;
if (!$user || !$bk
|| !$bk::$id //Must have ID
|| !$bk->getBkId() //Must have ID
|| !($authkey = $bk->getAuthKey($user)))
return false;
@@ -664,19 +852,24 @@ abstract class UserAuthenticationBackend extends AuthenticationBackend {
// Tag the user and associated ticket in the SESSION
$this->setAuthKey($user, $bk, $authkey);
// Set Session Token
$user->setSessionToken();
//The backend used decides the format of the auth key.
// XXX: encrypt to hide the bk??
$user->setAuthKey($authkey);
$user->refreshSession(true); //set the hash.
//Log login info...
$msg=sprintf(_S('%1$s (%2$s) logged in [%3$s]'
/* Tokens are <username>, <id>, and <ip> */),
$user->getUserName(), $user->getId(), $_SERVER['REMOTE_ADDR']);
$ost->logDebug(_S('User login'), $msg);
$u = $user->getSessionUser()->getUser();
$type = array('type' => 'login');
Signal::send('person.login', $u, $type);
// Set TIME_BOMB to regenerate the session 10 seconds after login
$_SESSION['TIME_BOMB'] = time() + 10;
if ($bk->supportsInteractiveAuthentication() && ($acct=$user->getAccount()))
$acct->cancelResetTokens();
@@ -690,7 +883,7 @@ abstract class UserAuthenticationBackend extends AuthenticationBackend {
$authkey = $key ?: $bk->getAuthKey($user);
//Tag the authkey.
$authkey = $bk::$id.':'.$authkey;
$authkey = $bk->getBkId().':'.$authkey;
//Set the session goodies
$authsession = &$_SESSION['_auth']['user'];
@@ -712,6 +905,10 @@ abstract class UserAuthenticationBackend extends AuthenticationBackend {
$ost->logDebug(_S('User logout'),
sprintf(_S("%s logged out [%s]" /* Tokens are <username> and <ip> */),
$user->getUserName(), $_SERVER['REMOTE_ADDR']));
$u = $user->getSessionUser()->getUser();
$type = array('type' => 'logout');
Signal::send('person.logout', $u, $type);
}
protected function getAuthKey($user) {
@@ -733,6 +930,9 @@ abstract class UserAuthenticationBackend extends AuthenticationBackend {
)
return null;
if (($account=$user->getAccount()) && !$account->isActive())
return null;
$user->setAuthKey($_SESSION['_auth']['user']['key']);
return $user;
@@ -741,7 +941,9 @@ abstract class UserAuthenticationBackend extends AuthenticationBackend {
protected function validate($userid) {
if (!($user = User::lookup($userid)))
return false;
elseif (!$user->getAccount())
elseif (!($account=$user->getAccount()))
return false;
elseif (!$account->isActive())
return false;
return new ClientSession(new EndUser($user));
@@ -756,19 +958,29 @@ abstract class ExternalUserAuthenticationBackend
static $sign_in_image_url = false;
static $service_name = "External";
function renderExternalLink() { ?>
<a class="external-sign-in" title="<?php echo sprintf(__('Sign in with %s'), __(static::$service_name)); ?>"
href="login.php?do=ext&amp;bk=<?php echo urlencode(static::$id); ?>">
function getServiceName() {
return __(static::$service_name);
}
function renderExternalLink() {
$service = sprintf('%s %s',
__('Sign in with'),
$this->getServiceName());
?>
<a class="external-sign-in" title="<?php echo $service; ?>"
href="login.php?do=ext&amp;bk=<?php echo
urlencode($this->getBkId()); ?>">
<?php if (static::$sign_in_image_url) { ?>
<img class="sign-in-image" src="<?php echo static::$sign_in_image_url;
?>" alt="<?php echo sprintf(__('Sign in with %s'), __(static::$service_name)); ?>"/>
?>" alt="<?php echo $service; ?>"/>
<?php } else { ?>
<div class="external-auth-box">
<span class="external-auth-icon">
<i class="icon-<?php echo static::$fa_icon; ?> icon-large icon-fixed-with"></i>
</span>
<span class="external-auth-name">
<?php echo sprintf(__('Sign in with %s'), __(static::$service_name)); ?>
<?php echo $service; ?>
</span>
</div>
<?php } ?>
@@ -776,6 +988,8 @@ abstract class ExternalUserAuthenticationBackend
}
function triggerAuth() {
$_SESSION['ext:bk:id'] = $this->getBkId();
// Legacy for plugins prior to v1.17
$_SESSION['ext:bk:class'] = get_class($this);
}
}
@@ -821,7 +1035,7 @@ abstract class AuthStrikeBackend extends AuthenticationBackend {
return false;
}
function getAllowedBackends($userid) {
static function getAllowedBackends($userid) {
return array();
}
@@ -838,22 +1052,23 @@ abstract class AuthStrikeBackend extends AuthenticationBackend {
}
abstract function authStrike($credentials);
abstract function authTimeout();
abstract static function authStrike($credentials);
abstract static function authTimeout();
}
/*
* Backend to monitor staff's failed login attempts
*/
class StaffAuthStrikeBackend extends AuthStrikeBackend {
static $id = "authstrike.staff";
function authTimeout() {
static function authTimeout() {
global $ost;
$cfg = $ost->getConfig();
$authsession = &$_SESSION['_auth']['staff'];
if (!$authsession['laststrike'])
if (!isset($authsession['laststrike']))
return;
//Veto login due to excessive login attempts.
@@ -868,7 +1083,7 @@ class StaffAuthStrikeBackend extends AuthStrikeBackend {
$authsession['strikes']=0;
}
function authstrike($credentials) {
static function authstrike($credentials) {
global $ost;
$cfg = $ost->getConfig();
@@ -890,6 +1105,13 @@ class StaffAuthStrikeBackend extends AuthStrikeBackend {
$admin_alert = ($cfg->alertONLoginError() == 1) ? TRUE : FALSE;
$ost->logWarning(sprintf(_S('Excessive login attempts (%s)'),$username),
$alert, $admin_alert);
if ($username) {
$agent = Staff::lookup($username);
$type = array('type' => 'login', 'msg' => sprintf('Excessive login attempts (%s)', $authsession['strikes']));
Signal::send('person.login', $agent, $type);
}
return new AccessDenied(__('Forgot your login info? Contact Admin.'));
//Log every other third failed login attempt as a warning.
} elseif($authsession['strikes']%3==0) {
@@ -908,8 +1130,9 @@ StaffAuthenticationBackend::register('StaffAuthStrikeBackend');
* Backend to monitor user's failed login attempts
*/
class UserAuthStrikeBackend extends AuthStrikeBackend {
static $id = "authstrike.user";
function authTimeout() {
static function authTimeout() {
global $ost;
$cfg = $ost->getConfig();
@@ -930,7 +1153,7 @@ class UserAuthStrikeBackend extends AuthStrikeBackend {
$authsession['strikes']=0;
}
function authstrike($credentials) {
static function authstrike($credentials) {
global $ost;
$cfg = $ost->getConfig();
@@ -950,6 +1173,21 @@ class UserAuthStrikeBackend extends AuthStrikeBackend {
_S('Attempts').": {$authsession['strikes']}";
$admin_alert = ($cfg->alertONLoginError() == 1 ? TRUE : FALSE);
$ost->logError(_S('Excessive login attempts (user)'), $alert, $admin_alert);
if ($username) {
$account = UserAccount::lookupByUsername($username);
$id = UserEmailModel::getIdByEmail($username);
if ($account)
$user = User::lookup($account->user_id);
elseif ($id)
$user = User::lookup($id);
if ($user) {
$type = array('type' => 'login', 'msg' => sprintf('Excessive login attempts (%s)', $authsession['strikes']));
Signal::send('person.login', $user, $type);
}
}
return new AccessDenied(__('Access denied'));
} elseif($authsession['strikes']%3==0) { //Log every third failed login attempt as a warning.
$alert=_S('Username').": {$username}\n".
@@ -964,21 +1202,18 @@ class UserAuthStrikeBackend extends AuthStrikeBackend {
UserAuthenticationBackend::register('UserAuthStrikeBackend');
class osTicketAuthentication extends StaffAuthenticationBackend {
class osTicketStaffAuthentication extends StaffAuthenticationBackend {
static $name = "Local Authentication";
static $id = "local";
function authenticate($username, $password) {
if (($user = StaffSession::lookup($username)) && $user->getId() &&
$user->check_passwd($password)) {
//update last login && password reset stuff.
$sql='UPDATE '.STAFF_TABLE.' SET lastlogin=NOW() ';
if($user->isPasswdResetDue() && !$user->isAdmin())
$sql.=',change_passwd=1';
$sql.=' WHERE staff_id='.db_input($user->getId());
db_query($sql);
try {
$this->checkPolicies($user, $password);
} catch (BadPassword | ExpiredPassword $ex) {
$user->change_passwd = 1;
}
return $user;
}
}
@@ -991,8 +1226,12 @@ class osTicketAuthentication extends StaffAuthenticationBackend {
$staff->passwd = Passwd::hash($password);
}
static function checkPassword($new, $current) {
PasswordPolicy::checkPassword($new, $current, new self());
}
}
StaffAuthenticationBackend::register('osTicketAuthentication');
StaffAuthenticationBackend::register('osTicketStaffAuthentication');
class PasswordResetTokenBackend extends StaffAuthenticationBackend {
static $id = "pwreset.staff";
@@ -1016,7 +1255,7 @@ class PasswordResetTokenBackend extends StaffAuthenticationBackend {
|| $id != $staff->getId())
$errors['msg'] = __('Invalid reset token');
elseif (!($ts = $_config->lastModified($_POST['token']))
&& ($ost->getConfig()->getPwResetWindow() < (time() - strtotime($ts))))
|| ($ost->getConfig()->getPwResetWindow() < (time() - strtotime($ts))))
$errors['msg'] = __('Invalid reset token');
elseif (!$staff->forcePasswdRest())
$errors['msg'] = __('Unable to reset password');
@@ -1063,7 +1302,8 @@ class AuthTokenAuthentication extends UserAuthenticationBackend {
if (($ticket = Ticket::lookupByNumber($_GET['t'], $_GET['e']))
// Using old ticket auth code algo - hardcoded here because it
// will be removed in ticket class in the upcoming rewrite
&& !strcasecmp($_GET['a'], md5($ticket->getId() . strtolower($_GET['e']) . SECRET_SALT))
&& strcasecmp((string) $_GET['a'], md5($ticket->getId()
. strtolower($_GET['e']) . SECRET_SALT)) === 0
&& ($owner = $ticket->getOwner()))
$user = new ClientSession($owner);
}
@@ -1208,11 +1448,15 @@ class osTicketClientAuthentication extends UserAuthenticationBackend {
if (($client = new ClientSession(new EndUser($acct->getUser())))
&& !$client->getId())
return false;
elseif (!$acct->checkPassword($password))
elseif (!$acct->check_passwd($password))
return false;
else
return $client;
}
static function checkPassword($new, $current) {
PasswordPolicy::checkPassword($new, $current, new self());
}
}
UserAuthenticationBackend::register('osTicketClientAuthentication');
@@ -1238,7 +1482,7 @@ class ClientPasswordResetTokenBackend extends UserAuthenticationBackend {
|| $id != 'c'.$client->getId())
$errors['msg'] = __('Invalid reset token');
elseif (!($ts = $_config->lastModified($_POST['token']))
&& ($ost->getConfig()->getPwResetWindow() < (time() - strtotime($ts))))
|| ($ost->getConfig()->getPwResetWindow() < (time() - strtotime($ts))))
$errors['msg'] = __('Invalid reset token');
elseif (!$acct->forcePasswdReset())
$errors['msg'] = __('Unable to reset password');
@@ -1284,26 +1528,40 @@ UserAuthenticationBackend::register('ClientAcctConfirmationTokenBackend');
// ----- Password Policy --------------------------------------
class BadPassword extends Exception {}
class ExpiredPassword extends Exception {}
class PasswordUpdateFailed extends Exception {}
abstract class PasswordPolicy {
static protected $registry = array();
abstract class PasswordPolicy extends ServiceRegistry {
static $id;
static $name;
/**
* Check a password and throw BadPassword with a meaningful message if
* the password cannot be accepted.
*/
abstract function processPassword($new, $current);
abstract function onset($new, $current);
static function checkPassword($new, $current) {
foreach (static::allActivePolicies() as $P) {
$P->processPassword($new, $current);
}
/*
* Called on login to enforce policies & check for expired passwords
*/
abstract function onLogin($user, $password);
/*
* Check a password aganist all available policies
*/
static function checkPassword($new, $current, $bk=null) {
if ($bk && is_a($bk, 'AuthenticationBackend'))
$policies = $bk->getPasswordPolicies();
else
$policies = self::allActivePolicies();
foreach ($policies as $P)
$P->onSet($new, $current);
}
static function allActivePolicies() {
$policies = array();
foreach (static::$registry as $P) {
foreach (array_reverse(self::getRegistry()) as $P) {
if (is_string($P) && class_exists($P))
$P = new $P();
if ($P instanceof PasswordPolicy)
@@ -1312,10 +1570,6 @@ abstract class PasswordPolicy {
return $policies;
}
static function register($policy) {
static::$registry[] = $policy;
}
static function cleanSessions($model, $user=null) {
$criteria = array();
@@ -1328,7 +1582,7 @@ abstract class PasswordPolicy {
Q::not(array('session_id' => $user->session->session_id)));
break;
case ($model instanceof User):
$regexp = '_auth\|.*"user";[a-z]+:[0-9]+:{[a-z]+:[0-9]+:"id";[a-z]+:'.$model->getId();
$regexp = '_auth\|.*"user";[a-z]+:[0-9]+:\{[a-z]+:[0-9]+:"id";[a-z]+:'.$model->getId();
$criteria['user_id'] = 0;
$criteria['session_data__regex'] = $regexp;
@@ -1340,17 +1594,41 @@ abstract class PasswordPolicy {
return false;
}
return SessionData::objects()->filter($criteria)->delete();
return DatabaseSessionRecord::objects()->filter($criteria)->delete();
}
}
Signal::connect('auth.clean', array('PasswordPolicy', 'cleanSessions'));
/*
* Basic default password policy that ships with osTicket.
*
*/
class osTicketPasswordPolicy
extends PasswordPolicy {
function processPassword($passwd, $current) {
if (strlen($passwd) < 6) {
static $id = "basic";
static $name = /* @trans */ "Default Basic Policy";
function onLogin($user, $password) {
global $cfg;
// Check for possible password expiration
// Check is only here for legacy reasons - password management
// policies are now done via plugins.
if ($cfg && $user
&& ($period=$cfg->getPasswdResetPeriod())
&& ($time=$user->getPasswdResetTimestamp())
&& $time < time()-($period*2629800))
throw new ExpiredPassword(__('Expired password'));
}
function onSet($passwd, $current) {
$pwdlen = strlen($passwd);
if ($pwdlen < 6) {
throw new BadPassword(
__('Password must be at least 6 characters'));
} elseif ($pwdlen > 128) {
throw new BadPassword(
sprintf('%s - %s', __('Password is too long'), __('maximum of 128 characters allowed')));
}
// XXX: Changing case is technicall changing the password
if (0 === strcasecmp($passwd, $current)) {

View File

@@ -52,7 +52,7 @@ abstract class AvatarSource {
$this->mode = $mode;
}
function getName() {
static function getName() {
return __(static::$name);
}
@@ -107,12 +107,17 @@ class LocalAvatar
extends Avatar {
var $mode;
var $code;
var $size;
function __construct($user, $mode) {
parent::__construct($user);
$this->mode = $mode;
}
function setSize($size) {
$this->size = $size;
}
function getUrl($size) {
$code = $this->code;
if (!$code && method_exists($this->user, 'getExtraAttr'))
@@ -124,8 +129,12 @@ extends Avatar {
// Generate a random string of 0-6 chars for the avatar signature
$uid = md5(strtolower($this->user->getEmail()));
return ROOT_PATH . 'avatar.php?'.Http::build_query(array('uid'=>$uid,
'mode' => $this->mode));
$args = array('uid'=>$uid, 'mode' => $this->mode);
if ($this->size)
$args['size'] = $this->size;
return ROOT_PATH . 'avatar.php?' . Http::build_query($args);
}
function toggle() {
@@ -152,7 +161,7 @@ class RandomAvatar {
$this->mode = $mode;
}
function makeAvatar($uid) {
function makeAvatar($uid, $size=null) {
$sprite = self::$sprites[$this->mode];
if (!$sprite || !is_readable(ROOT_DIR . $sprite['file']) || !extension_loaded('gd'))
Http::redirect(ROOT_PATH.'images/mystery-oscar.png');
@@ -172,6 +181,11 @@ class RandomAvatar {
imagecopy($avatar, $source, 0, 0, $idx*$grid, $i*$grid, $grid, $grid);
}
// Resize the avatar (if applicable)
if ($size) {
$avatar = imagescale($avatar, $size, $size);
}
return $avatar;
}
}

View File

@@ -17,11 +17,11 @@
require_once "class.filter.php";
class Banlist {
function add($email,$submitter='') {
static function add($email,$submitter='') {
return self::getSystemBanList()->addRule('email','equal',$email);
}
function remove($email) {
static function remove($email) {
return self::getSystemBanList()->removeRule('email','equal',$email);
}
@@ -52,11 +52,11 @@ class Banlist {
return false;
}
function includes($email) {
static function includes($email) {
return self::getSystemBanList()->containsRule('email','equal',$email);
}
function ensureSystemBanList() {
static function ensureSystemBanList() {
if (!($id=Filter::getByName('SYSTEM BAN LIST')))
$id=self::createSystemBanList();
@@ -64,7 +64,7 @@ class Banlist {
return $id;
}
function createSystemBanList() {
static function createSystemBanList() {
# XXX: Filter::create should return the ID!!!
$errors=array();
return Filter::create(array(
@@ -80,8 +80,8 @@ class Banlist {
), $errors);
}
function getSystemBanList() {
return new Filter(self::ensureSystemBanList());
static function getSystemBanList() {
return self::ensureSystemBanList();
}
static function getFilter() {

View File

@@ -20,7 +20,7 @@ class Base32 {
* to double performance
*/
function encode($inString)
static function encode($inString)
{
$outString = "";
$compBits = "";
@@ -68,7 +68,7 @@ class Base32 {
*
*/
function decode($inString) {
static function decode($inString) {
/* declaration */
$deCompBits = '';
$outString = '';

View File

@@ -0,0 +1,195 @@
<?php
/*********************************************************************
class.businesshours.php
Peter Rotich <peter@osticket.com>
Copyright (c) 2019 osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
include_once INCLUDE_DIR.'class.schedule.php';
/*
* BusinessHours utility class
*
*/
class BusinessHours {
// Schedule
protected $schedule;
// Options
protected $options;
// Occurrence buckets
protected $workhours;
protected $holidays;
// Timeline log
protected $timeline;
function __construct(BusinessHoursSchedule $schedule,
$options=array()) {
$this->schedule = $schedule;
$this->options = $options;
}
function __onload() {
$this->workhours = array();
$this->holidays = array();
$this->timeline = array();
}
public function getSchedule() {
return $this->schedule;
}
// Intitialize occurrenses buckets
private function initOccurrences(Datetime $date, $grace_period_hrs=72) {
$dt = clone $date;
// Start from next day if current date is already processed
if (isset($this->workhours[$dt->format('Y-m-d')]))
$dt->modify('+1 day');
// Apply grace period
$period = clone $dt;
$period->modify("+$grace_period_hrs hour");
// Reset occurrense buckets
$this->workhours = $this->holidays = array();
// Init workhours
foreach ($this->getSchedule()->getEntries() as $entry)
$this->workhours += $entry->getOccurrences($dt,
$period->format('Y-m-d'));
ksort($this->workhours);
// Init holidays taking into account end date of the workhours in
// the current scope.
$enddate = array_pop(array_keys($this->workhours));
foreach ($this->getSchedule()->getHolidaysSchedules() as $schedule) {
foreach ($schedule->getEntries() as $entry)
$this->holidays += $entry->getOccurrences($dt, $enddate);
}
ksort($this->holidays);
// Return number of work hours occurrences
return count($this->workhours);
}
// Add requesed Working Hours to a given date in accordance to schedule
public function addWorkingHours(Datetime $date, $hours, &$auditlog=array()) {
// We ain't doing shit without hours
if (!$hours || !is_numeric($hours))
return $date;
// If the schedule has no entries then return false - indicating an
// error to the caller
if (!$this->getSchedule()->getNumEntries())
return false;
// Set timezone to schedule's one
$date->setTimezone($this->getSchedule()->getDatetimeZone());
$this->timeline(sprintf('*** Add %d Working Hours to %s ***',
$hours, $date->format('Y-m-d H:i:s')));
$seconds = $hours*3600; // Requested hours in seconds
$_seconds = 0; // Bucker to collect working hours in seconds
while ($_seconds < $seconds) {
// Initialize occurrences of schedule entries from this date.
if (!$this->initOccurrences($date))
break;
// Loop thro' business hours while accounting for requested
// working hours
foreach ($this->workhours as $d => $e) {
$partial = false;
// Handle edge case where we're starting with a date that
// might or not be within Schedule Entry hours.
if ($d == $date->format('Y-m-d')) {
// If it's after hours then continue to the next working
// day
if ($e->isAfterHours($date))
continue;
// If we're already into the day then we need to do
// partial / remaining hours
if (!$e->isBeforeHours($date))
$partial = true;
} elseif (strtotime("$d ".$e->getEndsTime()) <
$date->getTimestamp()) {
// Entry is out of scope
continue;
}
// Handle holidays - if within scope of current work day
$leadtime =0;
if (($holiday=$this->holidays[$d])) {
$this->timeline(sprintf('%s -> Skip %f Holiday Hours from %s [%s]',
$d,
$holiday->getHours(),
$holiday->getSchedule()->getName(),
$holiday->getDesc()));
//Move the date to end of the day of the holiday
$date->modify("$d ".$holiday->getEndsTime());
// If the holiday is a full day then assume the day is a goner
if ($holiday->isFullDay()) continue;
$partial = true;
// See if we need to recover any time prior to start of
// holiday e.g if the day starts at 8am but the holiday
// starts at 10am. Not typical but I foresee people
// using holiday concept to account for lunch hours.
$hstarts = strtotime($holiday->getStartsTime());
$dstarts = strtotime($e->getStartsTime());
if ($hstarts > $dstarts)
$leadtime = $hstarts-$dstarts;
}
// Add time to the bucket.
$time = $partial ? ($e->diffTime($date) + $leadtime) : $e->diff();
$_seconds += $time;
// Advance the date to end of this business day
$date->modify("$d ".$e->getEndsTime());
$this->timeline(sprintf('%s -> Apply %f Working Hours from %s
- %s (%d)',
$d, $time/3600, $e->getName(),
$date->format('Y-m-d H:i:s'),
($_seconds/3600)));
// Back track if the quota is met and break out of the loop.
if ($_seconds > $seconds) {
// TODO: Guard aganist backtracking to non working
// hours.
$time = intval(round(($_seconds-$seconds)));
$interval = new DateInterval('PT'.$time.'S');
$date->sub($interval);
$this->timeline(sprintf('%s -> Backtrack %f Hours %s (%s)',
$d, ($time)/3600,
$date->format('Y-m-d H:i:s'), ($seconds/3600)));
break;
}
}
}
$this->timeline(sprintf('*** Final Datetime %s ***',
$date->format('Y-m-d H:i:s')));
return $date;
}
// Log of the timeline for audit purposes
private function timeline($log) {
$this->timeline[] = $log;
}
public function getTimeline() {
return $this->timeline;
}
}
?>

View File

@@ -203,6 +203,9 @@ extends VerySimpleModel {
if (!parent::delete())
return false;
$type = array('type' => 'deleted');
Signal::send('object.deleted', $this, $type);
$this->attachments->deleteAll();
return true;
@@ -226,11 +229,22 @@ extends VerySimpleModel {
}
static function getCannedResponses($deptId=0, $explicit=false) {
global $thisstaff;
$canned = static::objects()
->filter(array('isenabled' => true))
->order_by('title')
->values_flat('canned_id', 'title');
if ($thisstaff) {
$staffDepts = array();
$staffDepts = $thisstaff->getDepts();
$staffDepts[] = 0;
$canned->filter(array('dept_id__in' => $staffDepts));
}
if ($deptId) {
$depts = array($deptId);
if (!$explicit)
@@ -247,7 +261,7 @@ extends VerySimpleModel {
return $responses;
}
function responsesByDeptId($deptId, $explicit=false) {
static function responsesByDeptId($deptId, $explicit=false) {
return self::getCannedResponses($deptId, $explicit);
}
@@ -297,6 +311,12 @@ extends VerySimpleModel {
return true;
}
function staffCanAccess($staff) {
if (!$staff instanceof Staff)
return false;
return (!$this->dept || (($role = $staff->getRole($this->dept)) && $role->hasPerm(Canned::PERM_MANAGE)));
}
}
RolePermission::register( /* @trans */ 'Knowledgebase', Canned::getPermissions());

View File

@@ -211,11 +211,13 @@ class Category extends VerySimpleModel {
function delete() {
try {
parent::delete();
$this->faqs->expunge();
}
catch (OrmException $e) {
return false;
}
$type = array('type' => 'deleted');
Signal::send('object.deleted', $this, $type);
return true;
}

View File

@@ -29,7 +29,8 @@ class Charset {
// ks_c_5601-1987: Korean alias for cp949
case preg_match('`^ks_c_5601-1987`i', $charset):
return 'cp949';
case preg_match('`^iso-?(\S+)$`i', $charset, $match):
// Remove trailing junk from ISO charset
case preg_match('`^iso-?(\S+[^i])(-i)?$`i', $charset, $match):
return "ISO-".$match[1];
// GBK superceded gb2312 and is backward compatible
case preg_match('`^gb2312`i', $charset):
@@ -73,7 +74,7 @@ class Charset {
}
//Wrapper for utf-8 transcoding.
function utf8($text, $charset=null) {
static function utf8($text, $charset=null) {
return self::transcode($text, $charset, self::UTF8);
}
}

View File

@@ -53,34 +53,36 @@ implements EmailContact, ITicketUser, TemplateVariable {
}
function getVar($tag) {
global $cfg;
switch (strtolower($tag)) {
case 'ticket_link':
$qstr = array();
if ($cfg && $cfg->isAuthTokenEnabled()
&& ($ticket=$this->getTicket())) {
if (!$ticket->getThread()->getNumCollaborators()) {
$qstr['auth'] = $ticket->getAuthToken($this);
return sprintf('%s/view.php?%s',
$cfg->getBaseUrl(),
Http::build_query($qstr, false)
);
}
else {
return sprintf('%s/tickets.php?id=%s',
$cfg->getBaseUrl(),
$ticket->getId()
);
}
}
$ticket = $this->getTicket();
return $this->getTicketLink(($ticket &&
!$ticket->getNumCollaborators()));
break;
}
}
function getTicketLink($authtoken=true) {
global $cfg;
$ticket = $this->getTicket();
if ($authtoken
&& $ticket
&& $cfg->isAuthTokenEnabled()) {
$qstr = array();
$qstr['auth'] = $ticket->getAuthToken($this);
return sprintf('%s/view.php?%s',
$cfg->getBaseUrl(),
Http::build_query($qstr, false)
);
}
return sprintf('%s/view.php?id=%s',
$cfg->getBaseUrl(),
$ticket ? $ticket->getId() : 0
);
}
function getId() { return ($this->user) ? $this->user->getId() : null; }
function getEmail() { return ($this->user) ? $this->user->getEmail() : null; }
function getName() {
@@ -149,6 +151,19 @@ implements EmailContact, ITicketUser, TemplateVariable {
return $this->user->getId();
}
function getEmailAddress() {
$emailaddr = (string) $this->getEmail();
if (($name=$this->getName()))
$emailaddr = sprintf('"%s" <%s>',
(string) $name,
$emailaddr);
return $emailaddr;
}
function __toString() {
return $this->getEmailAddress();
}
abstract function getTicketId();
abstract function getTicket();
}
@@ -245,6 +260,11 @@ class EndUser extends BaseAuthenticatedUser {
return UserAuthenticationBackend::getBackend($authkey);
}
function get2FABackend() {
//TODO: support 2FA on client portal
return null;
}
function getTicketStats() {
if (!isset($this->_stats))
$this->_stats = $this->getStats();
@@ -316,6 +336,13 @@ class EndUser extends BaseAuthenticatedUser {
return $this->_account;
}
function getUser() {
if ($this->user === false)
$this->user = User::lookup($this->getId());
return $this->user;
}
function getLanguage($flags=false) {
if ($acct = $this->getAccount())
return $acct->getLanguage($flags);
@@ -372,7 +399,7 @@ class EndUser extends BaseAuthenticatedUser {
class ClientAccount extends UserAccount {
function checkPassword($password, $autoupdate=true) {
function check_passwd($password, $autoupdate=true) {
/*bcrypt based password match*/
if(Passwd::cmp($password, $this->get('passwd')))
@@ -393,7 +420,7 @@ class ClientAccount extends UserAccount {
}
function hasCurrentPassword($password) {
return $this->checkPassword($password, false);
return $this->check_passwd($password, false);
}
function cancelResetTokens() {
@@ -422,32 +449,37 @@ class ClientAccount extends UserAccount {
return parent::update($vars, $errors);
$rtoken = $_SESSION['_client']['reset-token'];
if ($vars['passwd1'] || $vars['passwd2'] || $vars['cpasswd'] || $rtoken) {
if ($rtoken) {
$_config = new Config('pwreset');
if ($_config->get($rtoken) != 'c'.$this->getUserId())
$errors['err'] =
__('Invalid reset token. Logout and try again');
elseif (!($ts = $_config->lastModified($rtoken))
&& ($cfg->getPwResetWindow() < (time() - strtotime($ts))))
$errors['err'] =
__('Invalid reset token. Logout and try again');
} elseif ($vars['passwd1'] || $vars['passwd2'] || $vars['cpasswd']) {
if (!$vars['passwd1'])
$errors['passwd1']=__('New password is required');
elseif ($vars['passwd1'] && strlen($vars['passwd1'])<6)
$errors['passwd1']=__('Password must be at least 6 characters');
elseif ($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2']))
$errors['passwd2']=__('Passwords do not match');
if ($rtoken) {
$_config = new Config('pwreset');
if ($_config->get($rtoken) != 'c'.$this->getUserId())
$errors['err'] =
__('Invalid reset token. Logout and try again');
elseif (!($ts = $_config->lastModified($rtoken))
&& ($cfg->getPwResetWindow() < (time() - strtotime($ts))))
$errors['err'] =
__('Invalid reset token. Logout and try again');
}
elseif ($this->get('passwd')) {
if (!$vars['cpasswd'])
$errors['cpasswd']=__('Current password is required');
elseif (!$this->hasCurrentPassword($vars['cpasswd']))
$errors['cpasswd']=__('Invalid current password!');
elseif (!strcasecmp($vars['passwd1'], $vars['cpasswd']))
$errors['passwd1']=__('New password MUST be different from the current password!');
}
// Check password policies
if (!$errors) {
try {
UserAccount::checkPassword($vars['passwd1'], @$vars['cpasswd']);
} catch (BadPassword $ex) {
$errors['passwd1'] = $ex->getMessage();
}
}
}
@@ -465,7 +497,7 @@ class ClientAccount extends UserAccount {
if ($vars['backend']) {
$this->set('backend', $vars['backend']);
if ($vars['username'])
$this->set('username', $vars['username']);
$this->set('username', Format::sanitize($vars['username']));
}
if ($vars['passwd1']) {

View File

@@ -37,12 +37,8 @@ implements EmailContact, ITicketUser {
const FLAG_ACTIVE = 0x0001;
const FLAG_CC = 0x0002;
function __toString() {
return Format::htmlchars($this->toString());
}
function toString() {
return sprintf('"%s" <%s>', $this->getName(), $this->getEmail());
}
var $active;
function getId() {
return $this->id;
@@ -61,7 +57,7 @@ implements EmailContact, ITicketUser {
}
function getTicketId() {
if ($this->thread->object_type == ObjectModel::OBJECT_TYPE_TICKET)
if ($this->thread && $this->thread->object_type == ObjectModel::OBJECT_TYPE_TICKET)
return $this->thread->object_id;
}
@@ -79,6 +75,16 @@ implements EmailContact, ITicketUser {
function getEmail() {
return $this->user->getEmail();
}
function getEmailAddress() {
$emailaddr = (string) $this->getEmail();
if (($name=$this->getName()))
$emailaddr = sprintf('"%s" <%s>',
(string) $name,
$emailaddr);
return $emailaddr;
}
function getName() {
return $this->user->getName();
}
@@ -133,6 +139,10 @@ implements EmailContact, ITicketUser {
return $this->user_id;
}
function __toString() {
return Format::htmlchars($this->getEmailAddress());
}
function hasFlag($flag) {
return ($this->get('flags', 0) & $flag) != 0;
}
@@ -144,8 +154,8 @@ implements EmailContact, ITicketUser {
$this->flags &= ~$flag;
}
public function setCc() {
$this->setFlag(Collaborator::FLAG_ACTIVE, true);
public function setCc($active=true) {
$this->setFlag(Collaborator::FLAG_ACTIVE, $active);
$this->setFlag(Collaborator::FLAG_CC, true);
$this->save();
}

View File

@@ -31,14 +31,13 @@ class Config {
var $defaults = array(); # List of default values
function __construct($section=null, $defaults=array()) {
if ($defaults)
$this->defaults = $defaults;
if ($section)
$this->section = $section;
if ($this->section === null)
return false;
if ($defaults)
$this->defaults = $defaults;
if (isset($_SESSION['cfg:'.$this->section]))
$this->session = &$_SESSION['cfg:'.$this->section];
@@ -62,6 +61,10 @@ class Config {
return $info;
}
function toArray() {
return $this->getInfo();
}
function get($key, $default=null) {
if (isset($this->session) && isset($this->session[$key]))
return $this->session[$key];
@@ -74,7 +77,12 @@ class Config {
}
function exists($key) {
return $this->get($key, null) ? true : false;
if ((isset($this->session) && array_key_exists($key, $this->session))
|| array_key_exists($key, $this->config)
|| array_key_exists($key, $this->defaults))
return true;
return false;
}
function set($key, $value) {
@@ -116,7 +124,14 @@ class Config {
return $this->create($key, $value);
$item = $this->config[$key];
$before = $item->value;
$item->value = $value;
if ($before != $item->value) {
$type = array('type' => 'edited', 'key' => $item->ht['key']);
Signal::send('object.edited', $item, $type);
}
return $item->save();
}
@@ -179,6 +194,25 @@ extends VerySimpleModel {
'updated__lt' => SqlFunction::NOW()->minus(SqlInterval::SECOND($period)),
))->delete();
}
static function getConfigsByNamespace(?string $namespace, $key, $value=false) {
$filter = array();
$filter['key'] = $key;
if ($namespace)
$filter['namespace'] = $namespace;
if ($value)
$filter['value'] = $value;
$token = ConfigItem::objects()
->filter($filter);
return $namespace ? $token[0] : $token;
}
}
class OsticketConfig extends Config {
@@ -187,6 +221,7 @@ class OsticketConfig extends Config {
var $defaultDept; //Default Department
var $defaultSLA; //Default SLA
var $defaultSchedule; // Default Schedule
var $defaultEmail; //Default Email
var $alertEmail; //Alert Email
var $defaultSMTPEmail; //Default SMTP Email
@@ -200,7 +235,9 @@ class OsticketConfig extends Config {
'agent_name_format' => 'full', # First Last
'client_name_format' => 'original', # As entered
'auto_claim_tickets'=> true,
'auto_refer_closed' => true,
'collaborator_ticket_visibility' => true,
'disable_agent_collabs' => false,
'require_topic_to_close' => false,
'system_language' => 'en_US',
'default_storage_bk' => 'D',
@@ -219,6 +256,8 @@ class OsticketConfig extends Config {
'ticket_lock' => 2, // Lock on activity
'max_open_tickets' => 0,
'files_req_auth' => 1,
'force_https' => '',
'allow_external_images' => 0,
);
function __construct($section=null) {
@@ -334,14 +373,38 @@ class OsticketConfig extends Config {
}
/* Date & Time Formats */
function getTimeFormat() {
function getTimeFormat($propogate=false) {
global $cfg;
if ($this->get('date_formats') == 'custom')
return $this->get('time_format');
if ($propogate) {
$format = 'h:i a'; // Default
if (class_exists('IntlDateFormatter')) {
$formatter = new IntlDateFormatter(
Internationalization::getCurrentLocale(),
IntlDateFormatter::NONE,
IntlDateFormatter::SHORT,
$this->getTimezone(),
IntlDateFormatter::GREGORIAN
);
$format = $formatter->getPattern();
}
// Check if we're forcing 24 hrs format
if ($cfg && $cfg->isForce24HourTime() && $format)
$format = trim(str_replace(array('a', 'h'), array('', 'H'),
$format));
return $format;
}
return '';
}
function isForce24HourTime() {
return $this->get('date_formats') == '24';
}
/**
* getDateFormat
*
@@ -368,10 +431,8 @@ class OsticketConfig extends Config {
);
return $formatter->getPattern();
}
else {
// Use a standard
return 'y-M-d';
}
// Use a standard
return 'y-M-d';
}
return '';
}
@@ -379,6 +440,11 @@ class OsticketConfig extends Config {
function getDateTimeFormat() {
if ($this->get('date_formats') == 'custom')
return $this->get('datetime_format');
if (class_exists('IntlDateFormatter'))
return sprintf('%s %s', $this->getDateFormat(true),
$this->getTimeFormat(true));
return '';
}
@@ -412,14 +478,59 @@ class OsticketConfig extends Config {
return $this->get('overdue_grace_period');
}
// This is here for legacy reasons - default osTicket Password Policy
// uses it, if previously set.
function getPasswdResetPeriod() {
return $this->get('passwd_reset_period');
}
function getStaffPasswordPolicy() {
return $this->get('agent_passwd_policy');
}
function getClientPasswordPolicy() {
return $this->get('client_passwd_policy');
}
function require2FAForAgents() {
return $this->get('require_agent_2fa');
}
function isRichTextEnabled() {
return $this->get('enable_richtext');
}
function getAllowIframes() {
return str_replace(array(', ', ','), array(' ', ' '), $this->get('allow_iframes')) ?: "'self'";
}
function getIframeWhitelist() {
$whitelist = array_filter(explode(',', str_replace(' ', '', $this->get('embedded_domain_whitelist'))));
return !empty($whitelist) ? $whitelist : null;
}
function getACL() {
if (!($acl = $this->get('acl')))
return null;
return explode(',', str_replace(' ', '', $acl));
}
function getACLBackendOpts() {
return array(
0 => __('Disabled'),
1 => __('All'),
2 => __('Client Portal'),
3 => __('Staff Panel')
);
}
function getACLBackend() {
return $this->get('acl_backend') ?: 0;
}
function isAvatarsEnabled() {
return $this->get('enable_avatars');
}
@@ -533,6 +644,18 @@ class OsticketConfig extends Config {
return $this->defaultSLA;
}
function getDefaultScheduleId() {
return $this->get('schedule_id');
}
function getDefaultSchedule() {
if (!isset($this->defaultSchedule) && $this->getDefaultScheduleId())
$this->defaultSchedule = BusinessHoursSchedule::lookup(
$this->getDefaultScheduleId());
return $this->defaultSchedule;
}
function getAlertEmailId() {
return $this->get('alert_email_id');
}
@@ -546,12 +669,15 @@ class OsticketConfig extends Config {
return $this->alertEmail;
}
function getDefaultSMTPEmail() {
function getDefaultSmtpAccount() {
if (!$this->defaultSmtpAccount && $this->get('default_smtp_id'))
$this->defaultSmtpAccount = SmtpAccount::lookup($this->get('default_smtp_id'));
if(!$this->defaultSMTPEmail && $this->get('default_smtp_id'))
$this->defaultSMTPEmail = Email::lookup($this->get('default_smtp_id'));
return $this->defaultSmtpAccount;
}
return $this->defaultSMTPEmail;
function getDefaultMTA() {
return $this->getDefaultSmtpAccount();
}
function getDefaultPriorityId() {
@@ -577,6 +703,10 @@ class OsticketConfig extends Config {
return $this->get('help_topic_sort_mode');
}
function forceHttps() {
return $this->get('force_https') == 'on';
}
function setTopicSortMode($mode) {
$modes = static::allTopicSortModes();
if (!isset($modes[$mode]))
@@ -707,6 +837,13 @@ class OsticketConfig extends Config {
return $this->get('client_registration');
}
function isClientRegistrationMode($modes) {
if (!is_array($modes))
$modes = array($modes);
return in_array($this->getClientRegistrationMode(), $modes);
}
function isClientEmailVerificationRequired() {
return $this->get('client_verify_email');
}
@@ -928,16 +1065,28 @@ class OsticketConfig extends Config {
return $this->get('auto_claim_tickets');
}
function autoReferTicketsOnClose() {
return $this->get('auto_refer_closed');
}
function collaboratorTicketsVisibility() {
return $this->get('collaborator_ticket_visibility');
}
function disableAgentCollaborators() {
return $this->get('disable_agent_collabs');
}
function requireTopicToClose() {
return $this->get('require_topic_to_close');
}
function allowExternalImages() {
return ($this->get('allow_external_images'));
}
function getDefaultTicketQueueId() {
return $this->get('default_ticket_queue');
return $this->get('default_ticket_queue', 1);
}
function hideStaffName() {
@@ -1120,6 +1269,9 @@ class OsticketConfig extends Config {
$f['helpdesk_title']=array('type'=>'string', 'required'=>1, 'error'=>__('Helpdesk title is required'));
$f['default_dept_id']=array('type'=>'int', 'required'=>1, 'error'=>__('Default Department is required'));
$f['autolock_minutes']=array('type'=>'int', 'required'=>1, 'error'=>__('Enter lock time in minutes'));
$f['allow_iframes']=array('type'=>'cs-url', 'required'=>0, 'error'=>__('Enter comma separated list of urls'));
$f['embedded_domain_whitelist']=array('type'=>'cs-domain', 'required'=>0, 'error'=>__('Enter comma separated list of domains'));
$f['acl']=array('type'=>'ipaddr', 'required'=>0, 'error'=>__('Enter comma separated list of IP addresses'));
//Date & Time Options
$f['time_format']=array('type'=>'string', 'required'=>1, 'error'=>__('Time format is required'));
$f['date_format']=array('type'=>'string', 'required'=>1, 'error'=>__('Date format is required'));
@@ -1130,6 +1282,18 @@ class OsticketConfig extends Config {
$vars = Format::htmlchars($vars, true);
// ACL Checks
if ($vars['acl']) {
// Check if Admin's IP is in the list, if not, return error
// to avoid locking self out
if (!in_array($vars['acl_backend'], array(0,2))) {
$acl = explode(',', str_replace(' ', '', $vars['acl']));
if (!in_array(osTicket::get_client_ip(), $acl))
$errors['acl'] = __('Cowardly refusing to lock out active administrator');
}
} elseif ((int) $vars['acl_backend'] !== 0)
$errors['acl'] = __('IP address required when selecting panel');
// Make sure the selected backend is valid
$storagebk = null;
if (isset($vars['default_storage_bk'])) {
@@ -1161,6 +1325,7 @@ class OsticketConfig extends Config {
'helpdesk_title'=>$vars['helpdesk_title'],
'helpdesk_url'=>$vars['helpdesk_url'],
'default_dept_id'=>$vars['default_dept_id'],
'force_https'=>$vars['force_https'] ? 'on' : '',
'max_page_size'=>$vars['max_page_size'],
'log_level'=>$vars['log_level'],
'log_graceperiod'=>$vars['log_graceperiod'],
@@ -1170,6 +1335,7 @@ class OsticketConfig extends Config {
'daydatetime_format'=>$vars['daydatetime_format'],
'date_formats'=>$vars['date_formats'],
'default_timezone'=>$vars['default_timezone'],
'schedule_id' => $vars['schedule_id'],
'default_locale'=>$vars['default_locale'],
'system_language'=>$vars['system_language'],
'secondary_langs'=>$secondary_langs,
@@ -1178,6 +1344,10 @@ class OsticketConfig extends Config {
'enable_avatars' => isset($vars['enable_avatars']) ? 1 : 0,
'enable_richtext' => isset($vars['enable_richtext']) ? 1 : 0,
'files_req_auth' => isset($vars['files_req_auth']) ? 1 : 0,
'allow_iframes' => Format::sanitize($vars['allow_iframes']),
'embedded_domain_whitelist' => Format::sanitize($vars['embedded_domain_whitelist']),
'acl' => Format::sanitize($vars['acl']),
'acl_backend' => Format::sanitize((int) $vars['acl_backend']) ?: 0,
));
}
@@ -1196,16 +1366,18 @@ class OsticketConfig extends Config {
return false;
return $this->updateAll(array(
'passwd_reset_period'=>$vars['passwd_reset_period'],
'agent_passwd_policy'=>$vars['agent_passwd_policy'],
'staff_max_logins'=>$vars['staff_max_logins'],
'staff_login_timeout'=>$vars['staff_login_timeout'],
'staff_session_timeout'=>$vars['staff_session_timeout'],
'staff_ip_binding'=>isset($vars['staff_ip_binding'])?1:0,
'allow_pw_reset'=>isset($vars['allow_pw_reset'])?1:0,
'pw_reset_window'=>$vars['pw_reset_window'],
'require_agent_2fa'=> isset($vars['require_agent_2fa']) ? 1 : 0,
'agent_name_format'=>$vars['agent_name_format'],
'hide_staff_name'=>isset($vars['hide_staff_name']) ? 1 : 0,
'agent_avatar'=>$vars['agent_avatar'],
'disable_agent_collabs'=>isset($vars['disable_agent_collabs'])?1:0,
));
}
@@ -1222,6 +1394,7 @@ class OsticketConfig extends Config {
return false;
return $this->updateAll(array(
'client_passwd_policy'=>$vars['client_passwd_policy'],
'client_max_logins'=>$vars['client_max_logins'],
'client_login_timeout'=>$vars['client_login_timeout'],
'client_session_timeout'=>$vars['client_session_timeout'],
@@ -1289,12 +1462,14 @@ class OsticketConfig extends Config {
'max_open_tickets'=>$vars['max_open_tickets'],
'enable_captcha'=>isset($vars['enable_captcha'])?1:0,
'auto_claim_tickets'=>isset($vars['auto_claim_tickets'])?1:0,
'auto_refer_closed' => isset($vars['auto_refer_closed']) ? 1 : 0,
'collaborator_ticket_visibility'=>isset($vars['collaborator_ticket_visibility'])?1:0,
'require_topic_to_close'=>isset($vars['require_topic_to_close'])?1:0,
'show_related_tickets'=>isset($vars['show_related_tickets'])?1:0,
'allow_client_updates'=>isset($vars['allow_client_updates'])?1:0,
'ticket_lock' => $vars['ticket_lock'],
'default_ticket_queue'=>$vars['default_ticket_queue'],
'allow_external_images'=>isset($vars['allow_external_images'])?1:0,
));
}
@@ -1525,11 +1700,6 @@ class OsticketConfig extends Config {
function updateKBSettings($vars, &$errors) {
if ($vars['restrict_kb'] && !$this->isClientRegistrationEnabled())
$errors['restrict_kb'] =
__('The knowledge base cannot be restricted unless client registration is enabled');
if ($errors) return false;
return $this->updateAll(array(
@@ -1621,7 +1791,7 @@ class OsticketConfig extends Config {
}
//Used to detect version prior to 1.7 (useful during upgrade)
/* static */ function getDBVersion() {
static function getDBVersion() {
$sql='SELECT `ostversion` FROM '.TABLE_PREFIX.'config '
.'WHERE id=1';
return db_result(db_query($sql));

View File

@@ -0,0 +1,44 @@
<?php
/*********************************************************************
class.controller.php
Peter Rotich
Copyright (c) osTicket
http://www.osticket.com
Released under the GNU General Public License WITHOUT ANY WARRANTY.
See LICENSE.TXT for details.
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
abstract class Controller {
/*
* access
*
* This routine can be defined downstream to check if user has
* permission to call routines in the controller.
*
*/
function access() {
return true;
}
// Wrapper for onFatalError
public function exerr($code, $error='') {
return $this->onFatalError($code, $error);
}
public function onFatalError($code, $error) {
$this->onError($code, $error);
// On error should exit but we're making doubly sure
$this->response($code, $error);
exit();
}
protected function response($code, $response) {
Http::response($code, $response);
exit();
}
abstract function onError($code, $error, $title=null, $logOnly=false);
}

View File

@@ -20,12 +20,12 @@ require_once INCLUDE_DIR.'class.signal.php';
class Cron {
function MailFetcher() {
require_once(INCLUDE_DIR.'class.mailfetch.php');
MailFetcher::run(); //Fetch mail..frequency is limited by email account setting.
static function MailFetcher() {
require_once(INCLUDE_DIR.'class.email.php');
osTicket\Mail\Fetcher::run(); //Fetch mail..frequency is limited by email account setting.
}
function TicketMonitor() {
static function TicketMonitor() {
require_once(INCLUDE_DIR.'class.ticket.php');
Ticket::checkOverdue(); //Make stale tickets overdue
// Cleanup any expired locks
@@ -34,34 +34,34 @@ class Cron {
}
function PurgeLogs() {
static function PurgeLogs() {
global $ost;
// Once a day on a 5-minute cron
if (rand(1,300) == 42)
if($ost) $ost->purgeLogs();
}
function PurgeDrafts() {
static function PurgeDrafts() {
require_once(INCLUDE_DIR.'class.draft.php');
Draft::cleanup();
}
function CleanOrphanedFiles() {
static function CleanOrphanedFiles() {
require_once(INCLUDE_DIR.'class.file.php');
AttachmentFile::deleteOrphans();
}
function CleanExpiredSessions() {
static function CleanExpiredSessions() {
require_once(INCLUDE_DIR.'class.ostsession.php');
DbSessionBackend::cleanup();
osTicketSession::cleanup();
}
function CleanPwResets() {
static function CleanPwResets() {
require_once(INCLUDE_DIR.'class.config.php');
ConfigItem::cleanPwResets();
}
function MaybeOptimizeTables() {
static function MaybeOptimizeTables() {
// Once a week on a 5-minute cron
$chance = rand(1,2000);
switch ($chance) {
@@ -102,7 +102,7 @@ class Cron {
}
}
function run(){ //called by outside cron NOT autocron
static function run(){ //called by outside cron NOT autocron
global $ost;
if (!$ost || $ost->isUpgradePending())
return;

View File

@@ -104,7 +104,7 @@ class Crypto {
list(, $crypt, $ciphertext) = explode('$', $ciphertext, 3);
//Get crypto.... based on crypt tag.
if(!$crypt || !($crypto=Crypto::get($crypt)) || !$crypto->exists())
if(!$crypt || !($crypto=Crypto::get($crypt)))
return false;
$crypto->setKeys($key, $skey);
@@ -221,8 +221,7 @@ class Crypto {
* decrypt() which will perform the respective operations on the text
* subjects using a specific library.
*/
/* abstract */
class CryptoAlgo {
abstract class CryptoAlgo {
var $master_key;
var $sub_key;
@@ -300,8 +299,7 @@ class CryptoAlgo {
* available and supported. This method is abstract and should be
* defined in extension classes.
*/
/* abstract */
function exists() { return false; }
abstract static function exists();
}
@@ -341,7 +339,7 @@ Class CryptoMcrypt extends CryptoAlgo {
return ($c
&& $c['name']
&& $c['mode']
&& $this->exists()
&& self::exists()
&& mcrypt_module_open($c['name'], '', $c['mode'], '')
);
}
@@ -357,7 +355,7 @@ Class CryptoMcrypt extends CryptoAlgo {
*/
function encrypt($text, $cid=0) {
if(!$this->exists()
if(!self::exists()
|| !$text
|| !($cipher=$this->getCipher($cid))
|| !$cipher['cid'])
@@ -394,7 +392,7 @@ Class CryptoMcrypt extends CryptoAlgo {
*/
function decrypt($ciphertext) {
if(!$this->exists()
if(!self::exists()
|| !$ciphertext
|| $ciphertext[0] != '$'
)
@@ -431,7 +429,7 @@ Class CryptoMcrypt extends CryptoAlgo {
return $plaintext;
}
function exists() {
static function exists() {
return (extension_loaded('mcrypt')
&& function_exists('mcrypt_module_open'));
}
@@ -473,7 +471,7 @@ class CryptoOpenSSL extends CryptoAlgo {
return ($c
&& $c['method']
&& $this->exists()
&& self::exists()
&& openssl_cipher_iv_length($c['method'])
);
}
@@ -489,7 +487,7 @@ class CryptoOpenSSL extends CryptoAlgo {
*/
function encrypt($text, $cid=0) {
if(!$this->exists()
if(!self::exists()
|| !$text
|| !($cipher=$this->getCipher($cid)))
return false;
@@ -517,7 +515,7 @@ class CryptoOpenSSL extends CryptoAlgo {
function decrypt($ciphertext) {
if(!$this->exists() || !$ciphertext || $ciphertext[0] != '$')
if(!self::exists() || !$ciphertext || $ciphertext[0] != '$')
return false;
list(, $cid, $ciphertext) = explode('$', $ciphertext, 3);
@@ -539,7 +537,7 @@ class CryptoOpenSSL extends CryptoAlgo {
return $plaintext;
}
function exists() {
static function exists() {
return (extension_loaded('openssl') && function_exists('openssl_cipher_iv_length'));
}
}
@@ -595,7 +593,7 @@ class CryptoPHPSecLib extends CryptoAlgo {
function encrypt($text, $cid=0) {
if(!$this->exists()
if(!self::exists()
|| !$text
|| !($cipher=$this->getCipher($cid))
|| !($crypto=$this->getCrypto($cipher['cid']))
@@ -612,7 +610,7 @@ class CryptoPHPSecLib extends CryptoAlgo {
function decrypt($ciphertext) {
if(!$this->exists() || !$ciphertext || $ciphertext[0] != '$')
if(!self::exists() || !$ciphertext || $ciphertext[0] != '$')
return false;
list(, $cid, $ciphertext) = explode('$', $ciphertext, 3);
@@ -634,7 +632,7 @@ class CryptoPHPSecLib extends CryptoAlgo {
return $crypto->decrypt($ciphertext);
}
function exists() {
static function exists() {
return class_exists('Crypt_AES');
}
}

View File

@@ -60,7 +60,7 @@ Class CSRF {
function getToken() {
if (!$this->csrf['token'] || $this->isExpired()) {
if ((!is_array($this->csrf) || !$this->csrf['token']) || $this->isExpired()) {
$this->rotate();
} else {
//Reset the timer

View File

@@ -14,6 +14,7 @@
vim: expandtab sw=4 ts=4 sts=4:
**********************************************************************/
require_once INCLUDE_DIR . 'class.search.php';
require_once INCLUDE_DIR.'class.role.php';
class Dept extends VerySimpleModel
implements TemplateVariable, Searchable {
@@ -31,7 +32,7 @@ implements TemplateVariable, Searchable {
'null' => true,
),
'sla' => array(
'constraint' => array('sla_id' => 'SLA.sla_id'),
'constraint' => array('sla_id' => 'SLA.id'),
'null' => true,
),
'manager' => array(
@@ -58,6 +59,8 @@ implements TemplateVariable, Searchable {
var $_groupids;
var $config;
var $schedule;
var $template;
var $autorespEmail;
@@ -65,12 +68,24 @@ implements TemplateVariable, Searchable {
const DISPLAY_DISABLED = 2;
const ALERTS_DEPT_AND_EXTENDED = 1;
const ALERTS_DEPT_ONLY = 0;
const ALERTS_ADMIN_ONLY = 3;
const FLAG_ASSIGN_MEMBERS_ONLY = 0x0001;
const FLAG_DISABLE_AUTO_CLAIM = 0x0002;
const FLAG_ACTIVE = 0x0004;
const FLAG_ARCHIVED = 0x0008;
const FLAG_ASSIGN_PRIMARY_ONLY = 0x0010;
const FLAG_DISABLE_REOPEN_AUTO_ASSIGN = 0x0020;
const PERM_DEPT = 'visibility.departments';
static protected $perms = array(
self::PERM_DEPT => array(
'title' => /* @trans */ 'Department',
'desc' => /* @trans */ 'Ability to see all Departments',
'primary' => true,
),
);
function asVar() {
return $this->getName();
@@ -165,28 +180,6 @@ implements TemplateVariable, Searchable {
return !!($this->flags & self::FLAG_ACTIVE);
}
function clearInactiveDept($dept_id) {
global $cfg;
$topics = Topic::objects()->filter(array('dept_id'=>$dept_id))->values_flat('topic_id');
if ($topics) {
foreach ($topics as $topic_id) {
$topic = Topic::lookup($topic_id[0]);
$topic->dept_id = $cfg->getDefaultDeptId();
$topic->save();
}
}
$emails = Email::objects()->filter(array('dept_id'=>$dept_id))->values_flat('email_id');
if ($emails) {
foreach ($emails as $email_id) {
$email = Email::lookup($email_id[0]);
$email->dept_id = $cfg->getDefaultDeptId();
$email->save();
}
}
}
function getEmailId() {
return $this->email_id;
}
@@ -282,26 +275,29 @@ implements TemplateVariable, Searchable {
}
// Get eligible members only
function getAssignees() {
function getAssignees($criteria=array()) {
if (!$this->assignPrimaryOnly() && !$this->assignMembersOnly()) {
// this is for if all agents is set - assignment is not restricted
// based on department membership.
$members = Staff::objects()->filter(array(
'onvacation' => 0,
'isactive' => 1,
));
} else {
//this gets just the members of the dept including extended access
$members = clone $this->getAvailableMembers();
//this is for if all members is set
if (!$this->assignPrimaryOnly() && !$this->assignMembersOnly()) {
$members = Staff::objects()->filter(array(
'onvacation' => 0,
'isactive' => 1,
));
//Restrict to the primary members only
if ($this->assignPrimaryOnly())
$members->filter(array('dept_id' => $this->getId()));
}
// Restrict agents based on visibility of the assigner
if (($staff=$criteria['staff']))
$members = $staff->applyDeptVisibility($members);
// Sort based on set name format
return Staff::nsort($members);
}
//this gets just the members of the dept
$members = clone $this->getAvailableMembers();
//this gets just the primary members of the dept
if ($this->assignPrimaryOnly())
$members->filter(array('dept_id' => $this->getId()));
return Staff::nsort($members);
}
function getMembersForAlerts() {
@@ -326,6 +322,10 @@ implements TemplateVariable, Searchable {
return $rv;
}
function getNumMembersForAlerts() {
return count($this->getMembersForAlerts());
}
function getSLAId() {
return $this->sla_id;
}
@@ -334,6 +334,18 @@ implements TemplateVariable, Searchable {
return $this->sla;
}
function getScheduleId() {
return $this->schedule_id;
}
function getSchedule() {
if (!isset($this->schedule) && $this->getScheduleId())
$this->schedule = BusinessHoursSchedule::lookup(
$this->getScheduleId());
return $this->schedule;
}
function getTemplateId() {
return $this->tpl_id;
}
@@ -460,6 +472,10 @@ implements TemplateVariable, Searchable {
return $this->flags & self::FLAG_DISABLE_AUTO_CLAIM;
}
function disableReopenAutoAssign() {
return $this->flags & self::FLAG_DISABLE_REOPEN_AUTO_ASSIGN;
}
function isGroupMembershipEnabled() {
return $this->group_membership;
}
@@ -473,7 +489,7 @@ implements TemplateVariable, Searchable {
$ht['disable_auto_claim'] = $this->disableAutoClaim();
$ht['status'] = $this->getStatus();
$ht['assignment_flag'] = $this->getAssignmentFlag();
$ht['disable_reopen_auto_assign'] = $this->disableReopenAutoAssign();
return $ht;
}
@@ -495,6 +511,9 @@ implements TemplateVariable, Searchable {
$id = $this->getId();
if (parent::delete()) {
$type = array('type' => 'deleted');
Signal::send('object.deleted', $this, $type);
// DO SOME HOUSE CLEANING
//Move tickets to default Dept. TODO: Move one ticket at a time and send alerts + log notes.
Ticket::objects()
@@ -514,22 +533,11 @@ implements TemplateVariable, Searchable {
// Clear any settings using dept to default back to system default
Topic::objects()
->filter(array('dept_id' => $id))
->delete();
->update(array('dept_id' => 0));
Email::objects()
->filter(array('dept_id' => $id))
->delete();
foreach(FilterAction::objects()
->filter(array('type' => FA_RouteDepartment::$type)) as $fa
) {
$config = $fa->getConfiguration();
if ($config && $config['dept_id'] == $id) {
$config['dept_id'] = 0;
// FIXME: Move this code into FilterAction class
$fa->set('configuration', JsonDataEncoder::encode($config));
$fa->save();
}
}
->update(array('dept_id' => 0));
// Delete extended access entries
StaffDeptAccess::objects()
@@ -586,7 +594,17 @@ implements TemplateVariable, Searchable {
$this->flags &= ~$flag;
}
function export($dept, $criteria=null, $filename='') {
function hasFlag($flag) {
return ($this->get('flags', 0) & $flag) != 0;
}
function flagChanged($flag, $var) {
if (($this->hasFlag($flag) && !$var) ||
(!$this->hasFlag($flag) && $var))
return true;
}
static function export($dept, $criteria=null, $filename='') {
include_once(INCLUDE_DIR.'class.error.php');
$members = $dept->getMembers();
@@ -607,12 +625,21 @@ implements TemplateVariable, Searchable {
return $row ? $row[0] : 0;
}
function getNameById($id) {
static function getEmailIdById($id) {
$row = static::objects()
->filter(array('id' => $id))
->values_flat('email_id')
->first();
return $row ? $row[0] : 0;
}
static function getNameById($id) {
$names = Dept::getDepartments();
return $names[$id];
}
function getDefaultDeptName() {
static function getDefaultDeptName() {
global $cfg;
return ($cfg
@@ -629,7 +656,11 @@ implements TemplateVariable, Searchable {
// XXX: This will upset the static $depts array
$depts = array();
$query = self::objects();
if (isset($criteria['publiconly']))
if (isset($criteria['publiconly']) && $criteria['publiconly'])
$query->filter(array(
'ispublic' => ($criteria['publiconly'] ? 1 : 0)));
if (isset($criteria['activeonly']) && $criteria['activeonly'])
$query->filter(array(
'flags__hasbit' => Dept::FLAG_ACTIVE));
@@ -713,6 +744,15 @@ implements TemplateVariable, Searchable {
return $depts;
}
static function getActiveDepartments() {
$depts =null;
if (!$depts)
$depts = self::getDepartments(array('activeonly'=>true));
return $depts;
}
static function create($vars=false, &$errors=array()) {
$dept = new static($vars);
$dept->created = SqlFunction::NOW();
@@ -758,8 +798,12 @@ implements TemplateVariable, Searchable {
$errors['pid'] = __('Department selection is required');
$dept = Dept::lookup($vars['pid']);
if($dept && !$dept->isActive())
$errors['dept_id'] = sprintf(__('%s selected must be active'), __('Parent Department'));
if ($dept) {
if (!$dept->isActive())
$errors['dept_id'] = sprintf(__('%s selected must be active'), __('Parent Department'));
elseif (strpos($dept->getFullPath(), '/'.$this->getId().'/') !== false)
$errors['pid'] = sprintf(__('%s cannot contain the current %s'), __('Parent Department'), __('Department'));
}
if ($vars['sla_id'] && !SLA::lookup($vars['sla_id']))
$errors['sla_id'] = __('Invalid SLA');
@@ -789,11 +833,34 @@ implements TemplateVariable, Searchable {
if ($errors)
return false;
$vars['disable_auto_claim'] = isset($vars['disable_auto_claim']) ? 1 : 0;
if ($this->getId()) {
//flags
$disableAutoClaim = $this->flagChanged(self::FLAG_DISABLE_AUTO_CLAIM, $vars['disable_auto_claim']);
$disableAutoAssign = $this->flagChanged(self::FLAG_DISABLE_REOPEN_AUTO_ASSIGN, $vars['disable_reopen_auto_assign']);
$ticketAssignment = ($this->getAssignmentFlag() != $vars['assignment_flag']);
foreach ($vars as $key => $value) {
if ($key == 'status' && $this->getStatus() && strtolower($this->getStatus()) != $value) {
$type = array('type' => 'edited', 'status' => ucfirst($value));
Signal::send('object.edited', $this, $type);
} elseif ((isset($this->$key) && ($this->$key != $value) && $key != 'members') ||
($disableAutoClaim && $key == 'disable_auto_claim') ||
$ticketAssignment && $key == 'assignment_flag' ||
$disableAutoAssign && $key == 'disable_reopen_auto_assign') {
$type = array('type' => 'edited', 'key' => $key);
Signal::send('object.edited', $this, $type);
}
}
}
if ($vars['disable_auto_claim'] !== 1)
unset($vars['disable_auto_claim']);
$this->pid = $vars['pid'] ?: null;
$this->ispublic = isset($vars['ispublic']) ? (int) $vars['ispublic'] : 0;
$this->email_id = isset($vars['email_id']) ? (int) $vars['email_id'] : 0;
$this->tpl_id = isset($vars['tpl_id']) ? (int) $vars['tpl_id'] : 0;
$this->sla_id = isset($vars['sla_id']) ? (int) $vars['sla_id'] : 0;
$this->schedule_id = isset($vars['schedule_id']) ? (int) $vars['schedule_id'] : 0;
$this->autoresp_email_id = isset($vars['autoresp_email_id']) ? (int) $vars['autoresp_email_id'] : 0;
$this->manager_id = $vars['manager_id'] ?: 0;
$this->name = Format::striptags($vars['name']);
@@ -805,12 +872,16 @@ implements TemplateVariable, Searchable {
$this->setFlag(self::FLAG_ASSIGN_MEMBERS_ONLY, isset($vars['assign_members_only']));
$this->setFlag(self::FLAG_DISABLE_AUTO_CLAIM, isset($vars['disable_auto_claim']));
$this->setFlag(self::FLAG_DISABLE_REOPEN_AUTO_ASSIGN, isset($vars['disable_reopen_auto_assign']));
$filter_actions = FilterAction::objects()->filter(array('type' => 'dept', 'configuration' => '{"dept_id":'. $this->getId().'}'));
if ($filter_actions && $vars['status'] == 'active')
FilterAction::setFilterFlag($filter_actions, 'dept', false);
FilterAction::setFilterFlags($filter_actions, 'Filter::FLAG_INACTIVE_DEPT', false);
else
FilterAction::setFilterFlag($filter_actions, 'dept', true);
FilterAction::setFilterFlags($filter_actions, 'Filter::FLAG_INACTIVE_DEPT', true);
if ($cfg && ($this->getId() == $cfg->getDefaultDeptId()))
$vars['status'] = 'active';
switch ($vars['status']) {
case 'active':
@@ -828,8 +899,6 @@ implements TemplateVariable, Searchable {
$this->setFlag(self::FLAG_ARCHIVED, true);
}
$this->setFlag(self::FLAG_DISABLE_AUTO_CLAIM, isset($vars['disable_auto_claim']));
switch ($vars['assignment_flag']) {
case 'all':
$this->setFlag(self::FLAG_ASSIGN_MEMBERS_ONLY, false);
@@ -872,7 +941,8 @@ implements TemplateVariable, Searchable {
$dropped = array();
foreach ($this->extended as $DA)
$dropped[$DA->staff_id] = 1;
while (list(, list($staff_id, $role_id, $alerts)) = each($access)) {
foreach ($access as $acc) {
list ($staff_id, $role_id, $alerts) = $acc;
unset($dropped[$staff_id]);
if (!$role_id || !Role::lookup($role_id))
$errors['members'][$staff_id] = __('Select a valid role');
@@ -894,6 +964,8 @@ implements TemplateVariable, Searchable {
'staff_id' => $staff_id, 'role_id' => $role_id
));
$this->extended->add($da);
$type = array('type' => 'edited', 'key' => 'Staff Added');
Signal::send('object.edited', $this, $type);
}
else {
$da->role_id = $role_id;
@@ -906,6 +978,8 @@ implements TemplateVariable, Searchable {
return false;
if ($dropped) {
$type = array('type' => 'edited', 'key' => 'Staff Removed');
Signal::send('object.edited', $this, $type);
$this->extended->saveAll();
$this->extended
->filter(array('staff_id__in' => array_keys($dropped)))
@@ -918,7 +992,12 @@ implements TemplateVariable, Searchable {
return true;
}
static function getPermissions() {
return self::$perms;
}
}
RolePermission::register(/* @trans */ 'Miscellaneous', Dept::getPermissions());
class DepartmentQuickAddForm
extends Form {

View File

@@ -29,10 +29,14 @@ class Dispatcher {
function resolve($url, $args=null) {
if ($this->file) { $this->lazy_load(); }
# Support HTTP method emulation with the _method GET argument
if (isset($_GET['_method'])) {
$_SERVER['REQUEST_METHOD'] = strtoupper($_GET['_method']);
unset($_GET['_method']);
if ($_SERVER['REQUEST_METHOD'] == 'POST'
&& isset($_POST['_method'])
&& in_array(strtoupper($_POST['_method']), array('PUT', 'PATCH', 'DELETE'))) {
$_SERVER['REQUEST_METHOD'] = strtoupper($_POST['_method']);
unset($_POST['_method']);
}
// Decode URL for accurate matching
$url = urldecode($url);
foreach ($this->urls as $matcher) {
if ($matcher->matches($url)) {
return $matcher->dispatch($url, $args);
@@ -105,7 +109,7 @@ class UrlMatcher {
$f = array_filter(array_keys($this->matches), 'is_numeric');
$this->matches = array_intersect_key($this->matches, array_flip($f));
if (@get_class($this->func) == "Dispatcher") {
if (is_object($this->func) && (@get_class($this->func) == "Dispatcher")) {
# Trim the leading match off the $url and call the
# sub-dispatcher. This will be the case for lines in the URL
# file like
@@ -136,7 +140,13 @@ class UrlMatcher {
if ($class) {
# Create instance of the class, which is the first item,
# then call the method which is the second item
$func = array(new $class, $func);
$class = new $class;
# Check access at the controller level
if (!$class->access())
Http::response(403, __('Access Denied!!!'));
# Create callable function, class is the first item,
# then call the method is the second item
$func = array($class, $func);
}
if (!is_callable($func))
@@ -160,7 +170,7 @@ class UrlMatcher {
if (strpos($class, ":")) {
list($file, $class) = explode(":", $class, 2);
include $file;
include_once $file;
}
return array($class, $func);
}

View File

@@ -65,16 +65,14 @@ class Draft extends VerySimpleModel {
$draft_body = $draft->getBody();
}
$attrs[] = sprintf('data-draft-original="%s"',
Format::htmlchars(Format::viewableImages($original)));
Format::viewableImages($original, [], true));
return array(Format::htmlchars(Format::viewableImages($draft_body)),
return array(Format::viewableImages($draft_body, [], true),
implode(' ', $attrs));
}
function getAttachmentIds($body=false) {
static function getAttachmentIds($body=false) {
$attachments = array();
if (!$body)
$body = $this->getBody();
$body = Format::localizeInlineImages($body);
$matches = array();
if (preg_match_all('/"cid:([\\w.-]{32})"/', $body, $matches)) {
@@ -83,6 +81,7 @@ class Draft extends VerySimpleModel {
foreach ($files as $F) {
$attachments[] = array(
'id' => $F->getId(),
'name' => $F->getName(),
'inline' => true
);
}

View File

@@ -121,14 +121,23 @@ class DynamicForm extends VerySimpleModel {
$fields = $this->getFields();
$form = new SimpleForm($fields, $source, array(
'title' => $this->getLocal('title'),
'instructions' => $this->getLocal('instructions'),
'instructions' => Format::htmldecode($this->getLocal('instructions')),
'id' => $this->getId(),
'type' => $this->type ?: null,
));
return $form;
}
function hasFlag($flag) {
return (isset($this->flags) && ($this->flags & $flag) != 0);
}
function isDeleted() {
return $this->hasFlag(self::FLAG_DELETED);
}
function isDeletable() {
return $this->flags & self::FLAG_DELETABLE;
return $this->hasFlag(self::FLAG_DELETABLE);
}
function setFlag($flag) {
@@ -185,7 +194,7 @@ class DynamicForm extends VerySimpleModel {
function save($refetch=false) {
if (count($this->dirty))
$this->set('updated', new SqlFunction('NOW'));
if ($rv = parent::save($refetch | $this->dirty))
if ($rv = parent::save($refetch || $this->dirty))
return $this->saveTranslations();
return $rv;
}
@@ -197,6 +206,8 @@ class DynamicForm extends VerySimpleModel {
// Soft Delete: Mark the form as deleted.
$this->setFlag(self::FLAG_DELETED);
$type = array('type' => 'deleted');
Signal::send('object.deleted', $this, $type);
return $this->save();
}
@@ -280,14 +291,51 @@ class DynamicForm extends VerySimpleModel {
return true;
}
static function ensureDynamicDataView() {
static function getNewInstance() {
return static::objects()
->one()
->instanciate();
}
static function rebuildDynamicDataViews() {
// Flush the object cache
ModelInstanceManager::flushCache();
return self::ensureDynamicDataViews(true, true);
}
// ensure cdata tables exists
static function ensureDynamicDataViews($build=true, $force=false) {
$forms = ['TicketForm', 'TaskForm', 'UserForm', 'OrganizationForm'];
foreach ($forms as $form) {
if ($force && $build)
$form::dropDynamicDataView(false);
$form::ensureDynamicDataView($build);
}
}
static function ensureCdataTables($obj, $data) {
// Only perfrom check on real cron call, not autocrons triggered on
// agents activity.
if ($data['autocron'] === false)
self::ensureDynamicDataViews(true);
}
static function ensureDynamicDataView($build=false, $croak=true) {
if (!($cdata=static::$cdata) || !$cdata['table'])
return false;
$sql = 'SHOW TABLES LIKE \''.$cdata['table'].'\'';
if (!db_num_rows(db_query($sql)))
return static::buildDynamicDataView($cdata);
// Return true if the cdata table exists
if (db_num_rows(db_query($sql)))
return true;
if (!$build && $croak)
die(sprintf('%s. %s.',
__('Missing CDATA table'),
__('Get technical support')));
return $build ? static::buildDynamicDataView($cdata) : false;
}
static function buildDynamicDataView($cdata) {
@@ -297,8 +345,17 @@ class DynamicForm extends VerySimpleModel {
db_query($sql);
}
static function dropDynamicDataView($table) {
db_query('DROP TABLE IF EXISTS `'.$table.'`');
static function dropDynamicDataView($rebuild=true) {
if (!($cdata=static::$cdata) || !$cdata['table'])
return false;
$sql = 'DROP TABLE IF EXISTS `'.$cdata['table'].'`';
if (!db_query($sql))
return false;
return $rebuild ? static::ensureDynamicDataView($rebuild, false) :
true;
}
static function updateDynamicDataView($answer, $data) {
@@ -329,8 +386,7 @@ class DynamicForm extends VerySimpleModel {
$cdata['object_id'],
db_input($answer->getEntry()->get('object_id')))
.' ON DUPLICATE KEY UPDATE '.$fields;
if (!db_query($sql))
return self::dropDynamicDataView($cdata['table']);
db_query($sql);
}
static function updateDynamicFormEntryAnswer($answer, $data) {
@@ -358,13 +414,13 @@ class DynamicForm extends VerySimpleModel {
switch ($field->form->get('type')) {
case 'T':
return TicketForm::dropDynamicDataView(TicketForm::$cdata['table']);
return TicketForm::dropDynamicDataView();
case 'A':
return TaskForm::dropDynamicDataView(TaskForm::$cdata['table']);
return TaskForm::dropDynamicDataView();
case 'U':
return UserForm::dropDynamicDataView(UserForm::$cdata['table']);
return UserForm::dropDynamicDataView();
case 'O':
return OrganizationForm::dropDynamicDataView(OrganizationForm::$cdata['table']);
return OrganizationForm::dropDynamicDataView();
}
}
@@ -383,7 +439,7 @@ class DynamicForm extends VerySimpleModel {
// @see http://code.google.com/p/flexviews/
static function getDynamicDataViewFields($exclude) {
$fields = array();
foreach (static::getInstance()->getFields() as $f) {
foreach (static::getNewInstance()->getFields() as $f) {
if ($exclude && in_array($f->get('name'), $exclude))
continue;
@@ -437,13 +493,7 @@ class UserForm extends DynamicForm {
static function getInstance() {
if (!isset(static::$instance))
static::$instance = static::getUserForm()->instanciate();
return static::$instance;
}
static function getNewInstance() {
$o = static::objects()->one();
static::$instance = $o->instanciate();
static::$instance = self::getNewInstance();
return static::$instance;
}
}
@@ -479,16 +529,9 @@ class TicketForm extends DynamicForm {
static function getInstance() {
if (!isset(static::$instance))
self::getNewInstance();
static::$instance = self::getNewInstance();
return static::$instance;
}
static function getNewInstance() {
$o = static::objects()->one();
static::$instance = $o->instanciate();
return static::$instance;
}
}
// Add fields from the standard ticket form to the ticket filterable fields
Filter::addSupportedMatches(/* @trans */ 'Ticket Data', function() {
@@ -529,6 +572,9 @@ Signal::connect('model.updated',
function($o, $d) { return isset($d['dirty'])
&& (isset($d['dirty']['name']) || isset($d['dirty']['type'])); });
// Check to make sure cdata tables exists
Signal::connect('cron', array('DynamicForm', 'ensureCdataTables'));
Filter::addSupportedMatches(/* trans */ 'Custom Forms', function() {
$matches = array();
foreach (DynamicForm::objects()->filter(array('type'=>'G')) as $form) {
@@ -657,7 +703,7 @@ class DynamicFormField extends VerySimpleModel {
// See if field impl. need to save or override anything
$config = $this->getImpl()->to_config($config);
$this->set('configuration', JsonDataEncoder::encode($config));
$this->set('hint', Format::sanitize($vars['hint']));
$this->set('hint', Format::sanitize($vars['hint']) ?: NULL);
return true;
}
@@ -748,7 +794,7 @@ class DynamicFormField extends VerySimpleModel {
* flags which should be set on the new field to implement the
* requirement / visibility mode.
*/
function allRequirementModes() {
static function allRequirementModes() {
return array(
'a' => array('desc' => __('Optional'),
'flags' => self::FLAG_CLIENT_VIEW | self::FLAG_AGENT_VIEW
@@ -868,7 +914,7 @@ class DynamicFormField extends VerySimpleModel {
/* `variable` is used for automation. Internally it's called `name` */
), "name");
}
if (preg_match('/[.{}\'"`; ]/u', $this->get('name')))
if ($this->get('name') && !preg_match('/^(?!\d)([[:alnum:]]|_)+$/u', $this->get('name')))
$this->addError(__(
'Invalid character in variable name. Please use letters and numbers only.'
), 'name');
@@ -988,6 +1034,10 @@ class DynamicFormEntry extends VerySimpleModel {
return $this->form->getInstructions();
}
function getNotice() {
return $this->form->getNotice();
}
function getDynamicForm() {
return $this->form;
}
@@ -1008,6 +1058,7 @@ class DynamicFormEntry extends VerySimpleModel {
'title' => $this->getTitle(),
'instructions' => $this->getInstructions(),
'id' => $this->form_id,
'type' => $this->getDynamicForm()->type ?: null,
);
$this->_form = new CustomForm($fields, $source, $options);
}
@@ -1151,7 +1202,7 @@ class DynamicFormEntry extends VerySimpleModel {
return $vars;
}
function forTicket($ticket_id, $force=false) {
static function forTicket($ticket_id, $force=false) {
static $entries = array();
if (!isset($entries[$ticket_id]) || $force) {
$stuff = DynamicFormEntry::objects()
@@ -1163,6 +1214,23 @@ class DynamicFormEntry extends VerySimpleModel {
}
return $entries[$ticket_id];
}
static function forTask($id, $force=false) {
static $entries = array();
if (!isset($entries[$id]) || $force) {
$stuff = DynamicFormEntry::objects()->filter(array(
'object_id' => $id,
'object_type' => ObjectModel::OBJECT_TYPE_TASK
));
// If forced, don't cache the result
if ($force)
return $stuff;
$entries[$id] = &$stuff;
}
return $entries[$id];
}
function setTicketId($ticket_id) {
$this->object_type = 'T';
$this->object_id = $ticket_id;
@@ -1177,14 +1245,13 @@ class DynamicFormEntry extends VerySimpleModel {
$this->object_id = $object_id;
}
function forObject($object_id, $object_type) {
static function forObject($object_id, $object_type) {
return DynamicFormEntry::objects()
->filter(array('object_id'=>$object_id, 'object_type'=>$object_type));
}
function render($options=array()) {
if (is_array($options))
$options += array('staff' => true);
$options += array('staff' => true);
return $this->getForm()->render($options);
}
@@ -1194,11 +1261,10 @@ class DynamicFormEntry extends VerySimpleModel {
$field = $a->getField();
if (!$field->hasData() || $field->isPresentationOnly())
continue;
$after = $field->to_database($field->getClean());
$before = $field->to_database($a->getValue());
if ($before == $after)
$changes = $field->getChanges();
if (!$changes)
continue;
$fields[$field->get('id')] = array($before, $after);
$fields[$field->get('id')] = $changes;
}
return $fields;
}
@@ -1282,7 +1348,18 @@ class DynamicFormEntry extends VerySimpleModel {
try {
$field->setForm($this);
$val = $field->to_database($field->getClean());
//for form entry values of file upload fields, we want to save the value as
//json with the file id(s) and file name(s) of each file stored in the field
//so that they display correctly within tasks/tickets
if (get_class($field) == 'FileUploadField') {
//use getChanges if getClean returns an empty array
$fieldClean = $field->getClean() ?: $field->getChanges();
if (is_array($fieldClean) && $fieldClean[0])
$fieldClean = is_string($fieldClean[0]) ? json_decode($fieldClean[0], true) : $fieldClean[0];
} else
$fieldClean = $field->getClean();
$val = $field->to_database($fieldClean);
}
catch (FieldUnchanged $e) {
// Don't update the answer.
@@ -1516,7 +1593,7 @@ class SelectionField extends FormField {
$selection = array();
if ($value && !is_array($value))
$value = array($value);
$value = JsonDataParser::parse($value) ?: array($value);
if ($value && is_array($value)) {
foreach ($value as $k=>$v) {
@@ -1556,6 +1633,7 @@ class SelectionField extends FormField {
$values = array();
$choices = $this->getChoices();
foreach (explode(',', $value) as $V) {
$V = trim($V);
if (isset($choices[$V]))
$values[$V] = $choices[$V];
}
@@ -1656,6 +1734,7 @@ class SelectionField extends FormField {
?: __('Unknown or invalid input');
}
} elseif ($config['typeahead']
&& $entry
&& ($entered = $this->getWidget()->getEnteredValue())
&& !in_array($entered, $entry)
&& $entered != $entry) {
@@ -1731,7 +1810,7 @@ class SelectionField extends FormField {
return $config;
}
function getChoices($verbose=false) {
function getChoices($verbose=false, $options=array()) {
if (!$this->_choices || $verbose) {
$choices = array();
foreach ($this->getList()->getItems() as $i)
@@ -1797,7 +1876,8 @@ class SelectionField extends FormField {
// Add in the properties for all selected list items in sub
// labeled by their field id
foreach ($v as $id=>$L) {
if (!($li = DynamicListItem::lookup($id)))
if (!($li = DynamicListItem::lookup($id))
|| !$li->getListId())
continue;
foreach ($li->getFilterData() as $prop=>$value) {
if (!isset($data[$prop]))
@@ -1838,7 +1918,7 @@ class SelectionField extends FormField {
$name = $name ?: $this->get('name');
$val = $value;
if ($value && is_array($value))
$val = '"?'.implode('("|,|$)|"?', array_keys($value)).'("|,|$)';
$val = '"?(?<![0-9])'.implode('("|,|$)|"?(?<![0-9])', array_keys($value)).'("|,|$)';
switch ($method) {
case '!includes':
return Q::not(array("{$name}__regex" => $val));

File diff suppressed because it is too large Load Diff

View File

@@ -25,12 +25,15 @@ class BaseError extends Exception {
global $ost;
parent::__construct(__($message));
$message = str_replace(ROOT_DIR, '(root)/', _S($message));
if ($ost && $ost->getConfig()->getLogLevel() == 3)
$message .= "\n\n" . $this->getBacktrace();
if ($ost) {
$message = str_replace(ROOT_DIR, '(root)/', _S($message));
$ost->logError($this->getTitle(), $message, static::$sendAlert);
if ($ost->getConfig()->getLogLevel() == 3)
$message .= "\n\n" . $this->getBacktrace();
$ost->logError($this->getTitle(), $message, static::$sendAlert);
}
}
function getTitle() {

View File

@@ -30,7 +30,7 @@ class Export {
'json' => 'JsonResultsExporter'
);
$exp = new $exporters[$how]($sql, $headers, $options);
return $exp->dump();
return $exp->dump($options['tmp'] ? true : false);
}
# XXX: Think about facilitated exporting. For instance, we might have a
@@ -259,7 +259,7 @@ class Export {
// Filename or stream to export agents to
$filename = $filename ?: sprintf('Agents-%s.csv',
strftime('%Y%m%d'));
date('Ymd'));
Http::download($filename, "text/$how");
$depts = Dept::getDepartments(null, true, Dept::DISPLAY_DISABLED);
echo self::dumpQuery($agents, array(
@@ -296,7 +296,7 @@ static function departmentMembers($dept, $agents, $filename='', $how='csv') {
// Filename or stream to export depts' agents to
$filename = $filename ?: sprintf('%s-%s.csv', $dept->getName(),
strftime('%Y%m%d'));
date('Ymd'));
Http::download($filename, "text/$how");
echo self::dumpQuery($agents, array(
'::getName' => 'Name',
@@ -321,8 +321,313 @@ static function departmentMembers($dept, $agents, $filename='', $how='csv') {
);
exit;
}
static function audits($type, ?string $filename, ?string $tableInfo, ?string $object, ?string $how='csv', ?bool $show_viewed=true, ?array $data=array(), CsvExporter $exporter) {
$headings = array('Description', 'Timestamp', 'IP');
switch ($type) {
case 'audit':
$sql = AuditEntry::objects()->filter(array('object_type'=>$data['type']));
if ($data['state'] && $data['state'] != 'All') {
$eventId = Event::getIdByName(strtolower($data['state']));
$sql = $sql->filter(array('event_id'=>$eventId));
}
if ($data['startDate'] && $data['endDate'])
$sql = $sql->filter(array('timestamp__range' =>
array('"'.$data['startDate'].'"', '"'.$data['endDate'].'"', true)));
$sql = $sql->order_by('-timestamp');
$tableInfo = $sql;
break;
case 'user':
$sql = AuditEntry::objects()->filter(array('user_id'=>$object))->order_by('-timestamp');
break;
case 'staff':
$sql = AuditEntry::objects()->filter(array('staff_id'=>$object))->order_by('-timestamp');
break;
case 'ticket':
$sql = AuditEntry::objects()->filter(array('object_id'=>$object, 'object_type'=>'T'))->order_by('-timestamp');
break;
}
if (!$show_viewed)
$sql = $sql->filter(Q::not(array('event_id'=>Event::getIdByName('viewed'))))->order_by('-timestamp');
$exporter->write($headings);
$row = array();
foreach ($sql as $key => $value) {
if (is_object($value)) {
$description = AuditEntry::getDescription($value, true);
$value = $value->ht;
}
$row[0] = $description;
$row[1] = Format::datetime($value['timestamp']);
$row[2] = $value['ip'];
$exporter->write($row);
}
}
}
/*
* Exporter Interface
*
*/
abstract class Exporter {
protected $id; // Export ID (random code)
protected $fp; // stream: file pointer for $file
protected $file; // File name / path for the export
protected $fileObj; // FileObject class
protected $options;
abstract function write($data);
abstract function init();
function __construct($options=array()) {
$this->id = $options['id'] ?: self::generateId();
if (isset($options['file']))
$this->file = $options['file'];
$this->options = $options;
$this->open();
}
function isAvailable() {
return file_exists($this->getFile());
}
function isReady() {
return ($this->isAvailable() && $this->lock());
}
private function open($mode='a+') {
if ($this->fp)
return $this->fp;
try {
if (($file=$this->getFile())) {
if (!($this->fp=fopen($file, $mode)))
throw new Exception();
} else {
// We don't have a file create one in temp directory
$prefix = Format::filename(Misc::randCode(6));
if (!($temp=tempnam(sys_get_temp_dir(), $prefix))
|| !($this->fp=fopen($temp, $mode))
|| !($meta=stream_get_meta_data($this->fp))) {
throw new Exception();
}
// get filename from mera
$this->file = $meta['uri'];
$this->init();
}
} catch(Exception $ex) {
@fclose($this->fp);
@unlink($temp);
throw new Exception();
}
return $this->fp;
}
// Close / unlock the file.
function close() {
@fclose($this->fp);
}
function delete() {
@unlink($this->getFile());
}
function getId() {
return $this->id;
}
function getStream() {
return $this->fp;
}
function getFile() {
return $this->file;
}
function getFilename() {
return $this->options['filename'] ?: 'Export';
}
function getFileType() {
return mime_content_type($this->getFile());
}
function getFileSize() {
return filesize($this->getFile());
}
function getFileObject() {
if (!isset($this->fileObj)) {
$this->fileObj = new FileObject($this->getFile());
// Set the real filename
$this->fileObj->setFilename($this->getFilename());
// Set mime type
$this->fileObj->setMimeType($this->getFileType());
}
return $this->fileObj;
}
function getOptions() {
return $this->options;
}
// Check interval in seconds
function getInterval() {
return @$this->options['interval'] ?: 5;
}
function lock() {
return $this->fp ? flock($this->fp, LOCK_EX | LOCK_NB) : false;
}
function unlock() {
fflush($this->fp);
flock($this->fp, LOCK_UN);
}
// Acknowledge the export and close the session
// This is important when the export would be taking a long time or when
// it's being emailed out in the background
function ack() {
// Register the export in the session
self::register($this);
// Flush response / return export id and check interval
Http::flush(201, json_encode(['eid' =>
$this->getId(), 'interval' => $this->getInterval()]));
// Phew... now we're free to do the export
session_write_close(); // Release session for other requests
ignore_user_abort(1); // Leave us alone bro!
@set_time_limit(0); // Useless when safe_mode is on
// Ask the queue to export to the exporter
}
// Finilize the export - unlock the file and close the ponter
function finalize($delay=true) {
$this->unlock();
$this->close();
// Sleep 3 times the interval to allow time for file download
if ($delay) sleep($this->getInterval()*3);
}
function download($filename=false, $delete=true) {
$this->close();
$filename = $filename ?: $this->getFilename();
Http::download($filename, 'application/octet-stream', null, 'attachment');
header('Content-Length: '.$this->getFileSize());
readfile($this->getFile());
// Delete the file if requsted
if ($delete) @$this->delete();
exit;
}
function email(Staff $staff) {
global $cfg;
if (!file_exists($this->getFile())
|| !($file=$this->getFileObject())
|| !($email=$cfg->getDefaultEmail()))
return false;
$mailer = new osTicket\Mail\Mailer($email);
$mailer->addFileObject($file);
$subject = __("Export");
$body = __("Attached is file containing the export you asked us to send you!");
return $mailer->send(array($staff), $subject, $body);
}
// Generate an alphanumeric url safe id/code
static function generateId($len=6) {
$id = substr(str_replace('%', '', urlencode(Misc::randCode($len))),
0, $len);
if (isset($_SESSION['Exports'][$id]))
return self::generateId($len);
return $id;
}
static function register($exporter, $extra=array()) {
if (!$exporter instanceof Exporter)
return false;
$_SESSION['Exports'][$exporter->getId()] = $exporter->getOptions() + array(
'file' => $exporter->getFile(),
'class' => get_class($exporter)) + $extra ?: $extra;
}
static function load($id) {
if (!isset($_SESSION['Exports'][$id])
|| !file_exists($_SESSION['Exports'][$id]['file']))
return null;
try {
$info = $_SESSION['Exports'][$id];
$class = $info['class'];
$exporter = new $class(array('id' => $id) + $info);
} catch (Exception $ex) {
return null;
}
return $exporter;
}
}
/*
* CsvExporter - expects an open file
*/
class CsvExporter extends Exporter {
protected $mimetype = 'text/csv';
function __construct($options=array()) {
try {
parent::__construct($options);
} catch (Exception $ex) {
throw new Exception();
}
}
function init() {
$this->lock();
// Output a UTF-8 BOM (byte order mark)
fputs($this->fp, chr(0xEF) . chr(0xBB) . chr(0xBF));
}
function getFileType() {
return $this->mimetype;
}
function getDelimiter() {
if (isset($this->options['delimiter'])
&& $this->options['delimiter'])
return $this->options['delimiter'];
return Internationalization::getCSVDelimiter();
}
function escape($data) {
return $data;
// Escape formula, commands etc.
return array_map(function($v) {
if (preg_match('/^[=\-+@].*/', $v))
return "'".$v;
return $v;
}, $data);
}
function write($data) {
fputcsv($this->fp, $this->escape($data), $this->getDelimiter(), "\"", "");
}
}
/*
* Given SQL query export results based on subclass.
*/
class ResultSetExporter {
var $output;
@@ -375,7 +680,7 @@ class ResultSetExporter {
}
}
// Evalutate :: function call on target current
if ($func && (method_exists($current, $func) || method_exists($current, '__call'))) {
if (($current && $func) && (method_exists($current, $func) || method_exists($current, '__call'))) {
$current = $current->{$func}();
}
@@ -413,32 +718,36 @@ class CsvResultsExporter extends ResultSetExporter {
return Internationalization::getCSVDelimiter();
}
function dump() {
function dump($tmp=false) {
if (!$this->output)
$this->output = fopen('php://output', 'w');
$delimiter = $this->getDelimiter();
// Output a UTF-8 BOM (byte order mark)
fputs($this->output, chr(0xEF) . chr(0xBB) . chr(0xBF));
fputcsv($this->output, $this->getHeaders(), $delimiter);
fputcsv($this->output, $this->getHeaders(), $delimiter, "\"", "");
while ($row=$this->next())
fputcsv($this->output, $row, $delimiter);
fputcsv($this->output, array_map(
function($v){
if (preg_match('/^[=\-+@].*/', $v))
return "'".$v;
return $v;
}, $row),
$delimiter, "\"", "");
fclose($this->output);
if (!$tmp)
fclose($this->output);
}
}
class JsonResultsExporter extends ResultSetExporter {
function dump() {
require_once(INCLUDE_DIR.'class.json.php');
$exp = new JsonDataEncoder();
$rows = array();
while ($row=$this->nextArray()) {
$rows[] = $row;
}
echo $exp->encode($rows);
echo JsonDataEncoder::encode($rows);
}
}
@@ -454,15 +763,16 @@ class DatabaseExporter {
var $stream;
var $options;
var $tables = array(CONFIG_TABLE, SYSLOG_TABLE, FILE_TABLE,
FILE_CHUNK_TABLE, STAFF_TABLE, DEPT_TABLE, TOPIC_TABLE, GROUP_TABLE,
FILE_CHUNK_TABLE, STAFF_TABLE, DEPT_TABLE, TOPIC_TABLE,
STAFF_DEPT_TABLE, TEAM_TABLE, TEAM_MEMBER_TABLE, FAQ_TABLE,
FAQ_TOPIC_TABLE, FAQ_CATEGORY_TABLE, DRAFT_TABLE,
CANNED_TABLE, TICKET_TABLE, ATTACHMENT_TABLE,
THREAD_TABLE, THREAD_ENTRY_TABLE, THREAD_ENTRY_EMAIL_TABLE,
LOCK_TABLE, THREAD_EVENT_TABLE, TICKET_PRIORITY_TABLE,
EMAIL_TABLE, EMAIL_TEMPLATE_TABLE, EMAIL_TEMPLATE_GRP_TABLE,
THREAD_ENTRY_MERGE_TABLE, LOCK_TABLE, THREAD_EVENT_TABLE,
TICKET_PRIORITY_TABLE, EMAIL_TABLE, EMAIL_TEMPLATE_TABLE,
EMAIL_TEMPLATE_GRP_TABLE,
FILTER_TABLE, FILTER_RULE_TABLE, SLA_TABLE, API_KEY_TABLE,
TIMEZONE_TABLE, SESSION_TABLE, PAGE_TABLE,
SESSION_TABLE, PAGE_TABLE,
FORM_SEC_TABLE, FORM_FIELD_TABLE, LIST_TABLE, LIST_ITEM_TABLE,
FORM_ENTRY_TABLE, FORM_ANSWER_TABLE, USER_TABLE, USER_EMAIL_TABLE,
PLUGIN_TABLE, THREAD_COLLABORATOR_TABLE, TRANSLATION_TABLE,
@@ -555,3 +865,126 @@ class DatabaseExporter {
$this->write_block(array('end-table'));
}
}
class TicketZipExporter {
var $ticket;
var $tmpfiles;
function __construct(Ticket $ticket) {
$this->ticket = $ticket;
$this->tmpfiles = array();
}
function addTicket($ticket, $zip, $prefix, $notes=true, $psize=null) {
require_once(INCLUDE_DIR.'class.pdf.php');
$pdf_file = $this->tmpfiles[] = tempnam(sys_get_temp_dir(), 'zip');
$pdf = new Ticket2PDF($ticket, $psize, $notes);
$pdf->output($pdf_file, 'F');
$zip->addFile($pdf_file, "{$ticket->getNumber()}.pdf");
// Include all the (non-inline) attachments
// XXX: Handle attachments with duplicate filenames between entry posts
$attachments = Attachment::objects()
->filter([
'thread_entry__thread' => $ticket->getThread(),
'inline' => 0
])
->order_by('thread_entry__created')
->select_related('file');
foreach ($attachments as $att) {
$zip->addFromString("{$prefix}/{$att->getFilename()}",
$att->getFile()->getData());
}
// Include custom fields attachments
foreach (DynamicFormEntry::forTicket($ticket->getId()) as $form) {
$answers = $form->getAnswers()->filter(
array('field__type' => 'files'));
foreach ($answers as $answer) {
$field = $answer->getField();
foreach ($field->getAttachments() as $a)
$zip->addFromString("{$prefix}/{$a->getFilename()}",
$a->getFile()->getData());
}
}
}
function addTask($task, $zip, $prefix, $notes=true, $psize=null) {
require_once(INCLUDE_DIR.'class.pdf.php');
$pdf_file = $this->tmpfiles[] = tempnam(sys_get_temp_dir(), 'zip');
$pdf = new Task2PDF($task, ['psize' => $psize]);
$pdf->output($pdf_file, 'F');
$zip->addFile($pdf_file, "{$prefix}/{$task->getNumber()}.pdf");
// Include all the (non-inline) attachments
// XXX: Handle attachments with duplicate filenames between entry posts
$attachments = Attachment::objects()
->filter([
'thread_entry__thread' => $task->getThread(),
'inline' => 0
])
->order_by('thread_entry__created')
->select_related('file');
foreach ($attachments as $att) {
$zip->addFromString("{$prefix}/{$task->getNumber()}/{$att->getFilename()}",
$att->getFile()->getData());
}
// Include custom fields attachments
foreach (DynamicFormEntry::forTask($task->getId()) as $form) {
$answers = $form->getAnswers()->filter(
array('field__type' => 'files'));
foreach ($answers as $answer) {
$field = $answer->getField();
foreach ($field->getAttachments() as $a)
$zip->addFromString("{$prefix}/{$task->getNumber()}/{$a->getFilename()}",
$a->getFile()->getData());
}
}
}
function download($options = array()) {
global $thisstaff;
$notes = isset($options['notes']) ? $options['notes'] : false;
$tasks = isset($options['tasks']) ? $options['tasks'] : false;
// TODO: Use a streaming ZIP library
$zipfile = tempnam(sys_get_temp_dir(), 'zip');
try {
$zip = new ZipArchive();
if (!$zip->open($zipfile, ZipArchive::CREATE))
return;
$prefix = "{$this->ticket->getNumber()}";
// Include a PDF of the ticket thread (with optional notes)
if (!$thisstaff || !($psize = $thisstaff->getDefaultPaperSize()))
$psize = 'Letter';
$this->addTicket($this->ticket, $zip, $prefix, $notes, $psize);
if ($tasks) {
foreach ($this->ticket->tasks as $task)
$this->addTask($task, $zip, "{$prefix}/tasks", $notes, $psize);
}
$zip->close();
Http::download("ticket-{$this->ticket->getNumber()}.zip", "application/zip",
null, 'attachment');
$fp = fopen($zipfile, 'r');
fpassthru($fp);
fclose($fp);
}
finally {
foreach ($this->tmpfiles as $T)
@unlink($T);
unlink($zipfile);
}
}
}

View File

@@ -155,7 +155,8 @@ class FAQ extends VerySimpleModel {
include STAFFINC_DIR . 'templates/faq-print.tmpl.php';
$html = ob_get_clean();
$pdf = new mPDFWithLocalImages('', $paper);
$pdf = new mPDFWithLocalImages(['mode' => 'utf-8', 'format' =>
$paper, 'tempDir'=>sys_get_temp_dir()]);
// Setup HTML writing and load default thread stylesheet
$pdf->WriteHtml(
'<style>
@@ -301,8 +302,10 @@ class FAQ extends VerySimpleModel {
function delete() {
try {
parent::delete();
$type = array('type' => 'deleted');
Signal::send('object.deleted', $this, $type);
// Cleanup help topics.
$this->topics->delete();
$this->topics->expunge();
// Cleanup attachments.
$this->attachments->deleteAll();
}
@@ -344,7 +347,7 @@ class FAQ extends VerySimpleModel {
static function getFeatured() {
return self::objects()
->filter(array('ispublished__in'=>array(1,2), 'category__ispublic'=>1))
->filter(array('ispublished'=>2, 'category__ispublic__in'=>[1,2]))
->order_by('-ispublished');
}
@@ -392,11 +395,11 @@ class FAQ extends VerySimpleModel {
$this->notes = Format::sanitize($vars['notes']);
$this->keywords = ' ';
$this->updateTopics($vars['topics']);
if (!$this->save())
return false;
$this->updateTopics($vars['topics']);
// General attachments (for all languages)
// ---------------------
// Delete removed attachments.

View File

@@ -15,6 +15,19 @@ require_once(INCLUDE_DIR.'class.signal.php');
require_once(INCLUDE_DIR.'class.error.php');
/**
* FileObject Interface
*
* Methods File Objects should support
**/
interface FileObjectInterface {
function getUId();
function getKey();
function getName();
function getData();
function getMimeType();
}
/**
* Represents a file stored in a storage backend. It is generally attached
* to something; however company logos, login page backdrops, and other
@@ -29,8 +42,8 @@ require_once(INCLUDE_DIR.'class.error.php');
* - 'L' => Logo
* - 'B' => Backdrop
*/
class AttachmentFile extends VerySimpleModel {
class AttachmentFile extends VerySimpleModel
implements FileObjectInterface {
static $meta = array(
'table' => FILE_TABLE,
'pk' => array('id'),
@@ -71,16 +84,20 @@ class AttachmentFile extends VerySimpleModel {
return $this->id;
}
function getUId() {
return $this->getId();
}
function getType() {
return $this->type;
}
function getBackend() {
return $this->bk;
function getMimeType() {
return $this->getType();
}
function getMime() {
return $this->getType();
function getBackend() {
return $this->bk;
}
function getSize() {
@@ -95,6 +112,10 @@ class AttachmentFile extends VerySimpleModel {
return $this->key;
}
function getAttrs() {
return $this->attrs;
}
function getSignature($cascade=false) {
$sig = $this->signature;
if (!$sig && $cascade) return $this->getKey();
@@ -109,9 +130,9 @@ class AttachmentFile extends VerySimpleModel {
return FileStorageBackend::getInstance($this);
}
function sendData($redirect=true, $disposition='inline') {
function sendData($redirect=true, $ttl=false, $disposition='inline') {
$bk = $this->open();
if ($redirect && $bk->sendRedirectUrl($disposition))
if ($redirect && $bk->sendRedirectUrl($disposition, $ttl))
return;
@ini_set('zlib.output_compression', 'Off');
@@ -153,11 +174,15 @@ class AttachmentFile extends VerySimpleModel {
Http::cacheable($this->getSignature(true), $this->lastModified(), $ttl);
}
function display($scale=false) {
$this->makeCacheable();
function display($scale=false, $ttl=86400) {
// Force download if not safe viewable image
if (!$this->isInlineSafeImage())
return $this->download(false, 'attachment');
if ($scale && extension_loaded('gd')) {
$image = imagecreatefromstring($this->getData());
$this->makeCacheable($ttl);
if ($scale && extension_loaded('gd')
&& ($image = imagecreatefromstring($this->getData()))) {
$width = imagesx($image);
if ($scale <= $width) {
$height = imagesy($image);
@@ -180,6 +205,7 @@ class AttachmentFile extends VerySimpleModel {
}
header('Content-Type: '.($this->getType()?$this->getType():'application/octet-stream'));
header('Content-Length: '.$this->getSize());
header("Content-Security-Policy: default-src 'self'");
$this->sendData();
exit();
}
@@ -192,6 +218,12 @@ class AttachmentFile extends VerySimpleModel {
'type' => $options['type']))))
$options['id'] = $a->getId();
// Force attachment disposition if not inline-safe image
if (isset($options['disposition'])
&& strcasecmp($options['disposition'], 'inline') == 0
&& !$this->isInlineSafeImage())
$options['disposition'] = 'attachment';
return static::generateDownloadUrl($this->getId(),
strtolower($this->getKey()), $this->getSignature(),
$options);
@@ -202,7 +234,7 @@ class AttachmentFile extends VerySimpleModel {
function getExternalDownloadUrl($options=array()) {
global $cfg;
$download = self::getDownloadUrl($options);
$download = $this->getDownloadUrl($options);
// Separate URL handle and args
list($handle, $args) = explode('file.php?', $download);
@@ -245,7 +277,8 @@ class AttachmentFile extends VerySimpleModel {
$check = static::_genUrlSignature($this->getId(), $this->getKey(),
$this->getSignature(), $expires);
return $signature == $check;
return hash_equals($check, $signature);
}
static function _genUrlSignature($id, $key, $signature, $expires) {
@@ -261,24 +294,25 @@ class AttachmentFile extends VerySimpleModel {
}
function download($name=false, $disposition=false, $expires=false) {
$disposition = $disposition ?: 'inline';
$bk = $this->open();
if ($bk->sendRedirectUrl($disposition))
return;
$thisstaff = StaffAuthenticationBackend::getUser();
$inline = ($thisstaff ? ($thisstaff->getImageAttachmentView() === 'inline') : false);
$disposition = ((($disposition && strcasecmp($disposition, 'inline') == 0)
|| $inline)
&& $this->isInlineSafeImage())
? 'inline' : 'attachment';
$ttl = ($expires) ? $expires - Misc::gmtime() : false;
$bk = $this->open();
if ($bk->sendRedirectUrl($disposition, $ttl))
return;
$this->makeCacheable($ttl);
$type = $this->getType() ?: 'application/octet-stream';
if (isset($_REQUEST['overridetype']))
$type = $_REQUEST['overridetype'];
elseif (!strcasecmp($disposition, 'attachment'))
$type = 'application/octet-stream';
Http::download($name ?: $this->getName(), $type, null, $disposition);
header('Content-Length: '.$this->getSize());
$this->sendData(false);
exit();
}
function _getKeyAndHash($data=false, $file=false) {
static function _getKeyAndHash($data=false, $file=false) {
if ($file) {
$sha1 = base64_encode(sha1_file($data, true));
$md5 = base64_encode(md5_file($data, true));
@@ -343,6 +377,7 @@ class AttachmentFile extends VerySimpleModel {
case IMAGETYPE_GIF:
case IMAGETYPE_JPEG:
case IMAGETYPE_PNG:
case IMAGETYPE_WEBP:
break;
default:
$error = __('Invalid image file type');
@@ -364,6 +399,7 @@ class AttachmentFile extends VerySimpleModel {
case IMAGETYPE_GIF:
case IMAGETYPE_JPEG:
case IMAGETYPE_PNG:
case IMAGETYPE_WEBP:
break;
default:
$error = __('Invalid image file type');
@@ -387,12 +423,15 @@ class AttachmentFile extends VerySimpleModel {
$file['data'] = base64_decode($file['data']);
}
}
if (isset($file['data'])) {
if (!isset($file['data']) && isset($file['data_cbk'])
&& is_callable($file['data_cbk'])) {
// Allow a callback function to delay or avoid reading or
// fetching ihe file contents
if (is_callable($file['data']))
$file['data'] = $file['data']();
$file['data'] = $file['data_cbk']();
}
if (isset($file['data'])) {
list($key, $file['signature'])
= self::_getKeyAndHash($file['data']);
if (!$file['key'])
@@ -468,9 +507,11 @@ class AttachmentFile extends VerySimpleModel {
elseif ($bk->write($file['data']) && $bk->flush()) {
$succeeded = true; break;
}
}
catch (Exception $e) {
} catch (Throwable $t) {
// Try next backend
// Backends can throw an exception or error.
// TODO: Log any exceptions and errors for debugging
// purposes.
}
// Fallthrough to default backend if different?
}
@@ -480,6 +521,7 @@ class AttachmentFile extends VerySimpleModel {
}
$f->bk = $bk->getBkChar();
$f->attrs = $bk->getAttrs() ?: NULL;
if (!isset($file['size'])) {
if ($size = $bk->getSize())
@@ -563,6 +605,7 @@ class AttachmentFile extends VerySimpleModel {
}
$this->bk = $target->getBkChar();
$this->attrs = $target->getAttrs() ?: NULL;
if (!$this->save())
return false;
@@ -599,9 +642,16 @@ class AttachmentFile extends VerySimpleModel {
static function lookupByHash($hash) {
if (isset(static::$keyCache[$hash]))
return static::$keyCache[$hash];
// Cache a negative lookup if no such file exists
return parent::lookup(array('key' => $hash));
try {
return parent::lookup(array('key' => $hash));
} catch (ObjectNotUnique $e) {
// TODO: Figure out why key collission might be happening AND
// make key (hash) unique field in the file table as a
// protection measure. For now we're returning null to avoid possible wrong file
// being displayed.
return null;
}
}
static function lookup($id) {
@@ -613,7 +663,7 @@ class AttachmentFile extends VerySimpleModel {
/*
Method formats http based $_FILE uploads - plus basic validation.
*/
function format($files) {
static function format($files) {
global $ost;
if(!$files || !is_array($files))
@@ -629,6 +679,8 @@ class AttachmentFile extends VerySimpleModel {
//Basic validation.
foreach($attachments as $i => &$file) {
$file['name'] = Format::sanitize($file['name']);
//skip no file upload "error" - why PHP calls it an error is beyond me.
if($file['error'] && $file['error']==UPLOAD_ERR_NO_FILE) {
unset($attachments[$i]);
@@ -680,6 +732,29 @@ class AttachmentFile extends VerySimpleModel {
->filter(array('ft' => 'B'))
->order_by('created');
}
/**
* Determines whether a MIME type is safe to render inline as a passive image.
*
* @param string $type
* @return bool
*/
static function isInlineSafeImageType($type) {
$type = strtolower(trim((string) $type));
return strpos($type, 'image/') === 0
&& $type !== 'image/svg+xml'
&& $type !== 'image/svg';
}
/**
* Determines whether this file is safe to render inline as a passive image.
*
* @return bool
*/
function isInlineSafeImage() {
return static::isInlineSafeImageType($this->getType());
}
}
class FileStorageBackend {
@@ -813,7 +888,7 @@ class FileStorageBackend {
* false to indicate that the read() method should be used to retrieve
* the data and broker it to the user agent.
*/
function sendRedirectUrl($disposition='inline') {
function sendRedirectUrl($disposition='inline', $ttl=false) {
return false;
}
@@ -855,6 +930,16 @@ class FileStorageBackend {
function getSize() {
return false;
}
/**
* getAttrs
*
* Get backend storage attributes.
*
*/
function getAttrs() {
return false;
}
}
@@ -995,4 +1080,93 @@ class OneSixAttachments extends FileStorageBackend {
}
}
FileStorageBackend::register('6', 'OneSixAttachments');
// FileObject - wrapper for SplFileObject class
class FileObject extends SplFileObject
implements FileObjectInterface {
protected $_key;
protected $_sig;
protected $_filename;
function __construct($file, $mode='r') {
parent::__construct($file, $mode);
}
function getUId() {
return $this->getKey();
}
function getKey() {
if (!isset($this->_key))
list($this->_key, $this->_sig) = AttachmentFile::_getKeyAndHash(
$this->getContents());
return $this->_key;
}
/* This allows us to set REAL file name as opposed to basename of the
* FS file in question
*/
function setFilename($filename) {
$this->_filename = $filename;
}
function getFilename() {
return $this->_filename ?: parent::getFilename();
}
function getName() {
return $this->getFilename();
}
/*
* Set mime type - well formated mime is expected.
*/
function setMimeType($type) {
$this->_mimetype = $type;
}
function getMimeType() {
if (!isset($this->_mimetype))
$this->_mimetype = self::mime_type($this->getRealPath());
return $this->_mimetype;
}
function getContents() {
$this->fseek(0);
return $this->fread($this->getSize());
}
/*
* XXX: Needed for mailer attachments interface
*/
function getData() {
return $this->getContents();
}
/*
* Given a filepath - auto detect the mime type
*
*/
static function mime_type($filepath) {
// Try to to auto-detect mime type
$type = null;
if (function_exists('finfo_open')) {
$finfo = finfo_open(FILEINFO_MIME_TYPE);
$type = finfo_file($finfo, $filepath);
finfo_close($finfo);
}
return $type ?: mime_content_type($filepath);
}
/*
* Compare mime type of file content to a given mime
*/
static function mimecmp($filepath, $mime) {
return strcasecmp(self::mime_type($filepath), $mime) !== 0;
}
}
?>

View File

@@ -34,6 +34,7 @@ extends VerySimpleModel {
const FLAG_INACTIVE_HT = 0x0001;
const FLAG_INACTIVE_DEPT = 0x0002;
const FLAG_DELETED_OBJECT = 0x0004;
static $match_types = array(
/* @trans */ 'User Information' => array(
@@ -164,6 +165,58 @@ extends VerySimpleModel {
return ($this->use_replyto_email);
}
static function disableFilters($object) {
switch (get_class($object)) {
case 'Topic':
$object_id = 'topic_id';
$FAClass = 'FA_AssignTopic';
break;
case 'Dept':
$object_id = 'dept_id';
$FAClass = 'FA_RouteDepartment';
break;
case 'Staff':
$object_id = 'staff_id';
$FAClass = 'FA_AssignAgent';
break;
case 'Team':
$object_id = 'team_id';
$FAClass = 'FA_AssignTeam';
break;
case 'SLA':
$object_id = 'sla_id';
$FAClass = 'FA_AssignSLA';
break;
case 'TicketStatus':
$object_id = 'status_id';
$FAClass = 'FA_SetStatus';
break;
case 'Email':
$object_id = 'from';
$FAClass = 'FA_SendEmail';
break;
case 'Canned':
$object_id = 'canned_id';
$FAClass = 'FA_AutoCannedResponse';
default:
return false;
}
$id = $object->getId();
$actions = FilterAction::objects()
->filter(array('type' => $FAClass::$type,
'configuration__like' => sprintf('%%"%s":%s}', $object_id, $id)));
foreach($actions as $fa) {
// Put a flag on the filter
FilterAction::setFilterFlags($fa, 'Filter::FLAG_DELETED_OBJECT', true);
$fa->save();
// Disable the filter
$filter = Filter::lookup($fa->filter_id);
$filter->isactive = 0;
$filter->save();
}
}
function disableAlerts() {
return ($this->disable_autoresponder);
}
@@ -181,10 +234,14 @@ extends VerySimpleModel {
}
function addRule($what, $how, $val,$extra=array()) {
if (isset($extra['notes']))
$extra['notes'] = Format::sanitize($extra['notes']);
$rule = array_merge($extra,array('what'=>$what, 'how'=>$how, 'val'=>$val));
$rule = new FilterRule($rule);
$rule->created = SqlFunction::NOW();
$this->rules->add($rule);
$rule->save();
if ($rule->save())
return true;
}
function removeRule($what, $how, $val) {
@@ -200,7 +257,7 @@ extends VerySimpleModel {
}
function getRuleById($id) {
return FilterRule::lookup($id, $this->getId());
return FilterRule::lookup(array('id'=>$id, 'filter_id'=>$this->getId()));
}
function containsRule($what, $how, $val) {
@@ -277,8 +334,14 @@ extends VerySimpleModel {
* If the matches() method returns TRUE, send the initial ticket to this
* method to apply the filter actions defined
*/
function apply(&$ticket, $vars) {
function apply(&$ticket, $vars, $postCreate=false) {
foreach ($this->getActions() as $a) {
//control when certain actions should be applied
//if action is send email and postCreate == false, skip
//if action is not send email and postCreate == true, skip
if ((($a->type == 'email') ? !$postCreate : $postCreate))
continue;
$a->setFilter($this);
$a->apply($ticket, $vars);
}
@@ -312,7 +375,7 @@ extends VerySimpleModel {
return $keys;
}
/* static */ function getSupportedMatchTypes() {
static function getSupportedMatchTypes() {
return array(
'equal'=> __('Equal'),
'not_equal'=> __('Not Equal'),
@@ -330,6 +393,8 @@ extends VerySimpleModel {
if (!self::validate_actions($vars, $errors))
return false;
$vars['flags'] = $this->flags;
if(!$vars['execorder'])
$errors['execorder'] = __('Order required');
elseif(!is_numeric($vars['execorder']))
@@ -340,7 +405,7 @@ extends VerySimpleModel {
elseif(($filter=static::getByName($vars['name'])) && $filter->id!=$this->id)
$errors['name'] = __('Name already in use');
if(!$errors && !self::validate_rules($vars,$errors) && !$errors['rules'])
if(!$errors && !$this->validate_rules($vars,$errors) && !$errors['rules'])
$errors['rules'] = __('Unable to validate rules as entered');
$targets = self::getTargets();
@@ -399,6 +464,8 @@ extends VerySimpleModel {
function delete() {
try {
parent::delete();
$type = array('type' => 'deleted');
Signal::send('object.deleted', $this, $type);
$this->rules->expunge();
$this->actions->expunge();
}
@@ -409,7 +476,7 @@ extends VerySimpleModel {
}
/** static functions **/
function getTargets() {
static function getTargets() {
return array(
'Any' => __('Any'),
'Web' => __('Web Forms'),
@@ -422,7 +489,7 @@ extends VerySimpleModel {
}
function validate_rules($vars,&$errors) {
$matches = array_keys(self::getSupportedMatchFields());
$matches = self::getSupportedMatchFields();
$types = array_keys(self::getSupportedMatchTypes());
$rules = array();
foreach ($vars['rules'] as $i=>$rule) {
@@ -435,36 +502,34 @@ extends VerySimpleModel {
if (is_array($rule)) {
if($rule["w"] || $rule["h"]) {
// Check for REGEX compile errors
if (in_array($rule["h"], array('match','not_match'))) {
$wrapped = "/".$rule["v"]."/iu";
if (false === @preg_match($rule["v"], ' ')
&& (false !== @preg_match($wrapped, ' ')))
$rule["v"] = $wrapped;
// Check for REGEX compile errors
if (in_array($rule["h"], array('match','not_match'))) {
$wrapped = "/".$rule["v"]."/iu";
if (false === @preg_match($rule["v"], ' ')
&& (false !== @preg_match($wrapped, ' ')))
$rule["v"] = $wrapped;
}
if(!$rule["w"] || !in_array($rule["w"],$matches))
$errors["rule_$i"]=__('Invalid match selection');
elseif(!$rule["h"] || !in_array($rule["h"],$types))
$errors["rule_$i"]=__('Invalid match type selection');
elseif(!$rule["v"])
$errors["rule_$i"]=__('Value required');
elseif($rule["w"]=='email'
&& $rule["h"]=='equal'
&& !Validator::is_email($rule["v"]))
$errors["rule_$i"]=__('Valid email required for the match type');
elseif (in_array($rule["h"], array('match','not_match'))
&& (false === @preg_match($rule["v"], ' ')))
$errors["rule_$i"] = sprintf(__('Regex compile error: (#%s)'),
preg_last_error());
else //for everything-else...we assume it's valid.
$rules[]=array('what'=>$rule["w"],
'how'=>$rule["h"],'val'=>trim($rule["v"]));
} elseif($rule["v"]) {
$errors["rule_$i"]=__('Incomplete selection');
}
if(!$rule["w"] || !in_array($rule["w"],$matches))
$errors["rule_$i"]=__('Invalid match selection');
elseif(!$rule["h"] || !in_array($rule["h"],$types))
$errors["rule_$i"]=__('Invalid match type selection');
elseif(!$rule["v"])
$errors["rule_$i"]=__('Value required');
elseif($rule["w"]=='email'
&& $rule["h"]=='equal'
&& !Validator::is_email($rule["v"]))
$errors["rule_$i"]=__('Valid email required for the match type');
elseif (in_array($rule["h"], array('match','not_match'))
&& (false === @preg_match($rule["v"], ' ')))
$errors["rule_$i"] = sprintf(__('Regex compile error: (#%s)'),
preg_last_error());
else //for everything-else...we assume it's valid.
$rules[]=array('what'=>$rule["w"],
'how'=>$rule["h"],'val'=>trim($rule["v"]));
}elseif($rule["v"]) {
$errors["rule_$i"]=__('Incomplete selection');
}
}
}
@@ -499,20 +564,29 @@ extends VerySimpleModel {
return parent::save($refetch || $this->dirty);
}
static function __create($vars,&$errors) {
$filter = new static($vars);
if ($filter->save()) {
$filter->save_rules($vars, $errors);
$filter->save_actions($filter->getId(), $vars, $errors);
return $filter;
}
}
static function create($vars,&$errors) {
$filter = new static($vars);
if ($filter->save())
return $filter;
}
function validate_actions($vars, &$errors) {
static function validate_actions($vars, &$errors) {
//allow the save if it is to set a filter flag
if ($vars['pass'])
return true;
if (!is_array(@$vars['actions']))
return;
foreach ($vars['actions'] as $sort=>$v) {
foreach ($vars['actions'] as $sort=>$v) {
if (is_array($v)) {
$info = $v['type'];
$sort = $v['sort'] ?: $sort;
@@ -522,18 +596,38 @@ extends VerySimpleModel {
'type'=>$info,
'sort' => (int) $sort,
));
$errors = array();
$action->setConfiguration($errors, $vars);
$err = array();
$action->setConfiguration($err, $vars);
$config = json_decode($action->ht['configuration'], true);
if (is_numeric($action->ht['type'])) {
foreach ($config as $key => $value) {
if ($key == 'topic_id') {
$action->ht['type'] = 'topic';
$config['topic_id'] = $value;
}
if ($key == 'dept_id') {
$action->ht['type'] = 'dept';
$config['dept_id'] = $value;
switch ($key) {
case 'topic_id':
$action->ht['type'] = 'topic';
$config['topic_id'] = $value;
break;
case 'dept_id':
$action->ht['type'] = 'dept';
$config['dept_id'] = $value;
break;
case 'sla_id':
$action->ht['type'] = __('SLA');
break;
case 'team_id':
$action->ht['type'] = __('Team');
break;
case 'staff_id':
$action->ht['type'] = __('Agent');
break;
case 'status_id':
$action->ht['type'] = __('Ticket Status');
break;
case 'canned_id':
$action->ht['type'] = __('Canned Response');
break;
default:
$action->ht['type'] = __('All Actions');
break;
}
}
}
@@ -555,14 +649,25 @@ extends VerySimpleModel {
break;
default:
foreach ($config as $key => $value) {
if (!$value) {
$errors['err'] = sprintf(__('Unable to save: Please insert a value for %s'), ucfirst($action->ht['type']));
if (!$value || is_null($value)) {
$errors['err'] = sprintf(__('Unable to save: Please insert a value for %s'), $action->ht['type']);
return 1;
}
}
break;
}
}
}
if (count($errors) == 0) {
$fa = FilterAction::lookup($info);
if ($fa) {
$filter = Filter::lookup($fa->getFilterId());
//Clear flags that may have been set on a successful save
$filter->setFlag(constant('Filter::FLAG_DELETED_OBJECT'), false);
$filter->setFlag(constant('Filter::FLAG_INACTIVE_DEPT'), false);
$filter->setFlag(constant('Filter::FLAG_INACTIVE_HT'), false);
}
}
return count($errors) == 0;
}
@@ -604,6 +709,7 @@ extends VerySimpleModel {
}
}
}
Signal::connect('object.deleted', array('Filter', 'disableFilters'));
class FilterRule
extends VerySimpleModel {
@@ -758,9 +864,9 @@ class TicketFilter {
* should be rejected, the first filter that matches and has reject
* ticket set is returned.
*/
function apply(&$ticket) {
function apply(&$ticket, $postCreate=false) {
foreach ($this->getMatchingFilterList() as $filter) {
$filter->apply($ticket, $this->vars);
$filter->apply($ticket, $this->vars, $postCreate);
if ($filter->stopOnMatch()) break;
}
}
@@ -799,7 +905,7 @@ class TicketFilter {
'Precedence' => array('AUTO_REPLY', 'BULK', 'JUNK', 'LIST'),
'X-Precedence' => array('AUTO_REPLY', 'BULK', 'JUNK', 'LIST'),
'X-Autoreply' => 'YES',
'X-Auto-Response-Suppress' => array('ALL', 'DR', 'RN', 'NRN', 'OOF', 'AutoReply'),
'X-Auto-Response-Suppress' => array('AutoReply'),
'X-Autoresponse' => '*',
'X-AutoReply-From' => '*',
'X-Autorespond' => '*',
@@ -809,6 +915,7 @@ class TicketFilter {
);
foreach ($auto_headers as $header=>$find) {
$header = strtolower($header);
if(!isset($headers[$header])) continue;
$value = strtoupper($headers[$header]);
@@ -832,8 +939,7 @@ class TicketFilter {
}
static function isBounce($headers) {
if($headers && !is_array($headers))
if ($headers && !is_array($headers))
$headers = Mail_Parse::splitHeaders($headers);
$bounce_headers = array(
@@ -848,6 +954,7 @@ class TicketFilter {
);
foreach ($bounce_headers as $header => $find) {
$header = strtolower($header);
if(!isset($headers[$header])) continue;
@list($func, $searches, $pos, $neg) = $find;
@@ -869,7 +976,7 @@ class TicketFilter {
* Normalize ticket source to supported filter target
*
*/
function origin2target($origin) {
static function origin2target($origin) {
$sources=array('web' => 'Web', 'email' => 'Email', 'phone' => 'Web', 'staff' => 'Web', 'api' => 'API');
return $sources[strtolower($origin)];

View File

@@ -28,6 +28,11 @@ class FilterAction extends VerySimpleModel {
function setFilter($filter) {
$this->_filter = $filter;
}
function getFilterId() {
return $this->filter_id;
}
function getFilter() {
return $this->_filter;
}
@@ -84,14 +89,17 @@ class FilterAction extends VerySimpleModel {
return $this->_impl;
}
function setFilterFlag($actions, $flag, $bool) {
foreach ($actions as $action) {
$filter = Filter::lookup($action->filter_id);
if ($filter && ($flag == 'dept') && ($filter->hasFlag(Filter::FLAG_INACTIVE_DEPT) != $bool))
$filter->setFlag(Filter::FLAG_INACTIVE_DEPT, $bool);
if ($filter && ($flag == 'topic') && ($filter->hasFlag(Filter::FLAG_INACTIVE_HT) != $bool))
$filter->setFlag(Filter::FLAG_INACTIVE_HT, $bool);
}
static function setFilterFlags(?object $actions, $flag, $bool) {
$flag = constant($flag);
if ($actions)
foreach ($actions as $action)
$action->setFilterFlag($flag, $bool);
}
function setFilterFlag($flag, $bool) {
$filter = Filter::lookup($this->filter_id);
if ($filter && ($filter->hasFlag($flag) != $bool))
$filter->setFlag($flag, $bool);
}
function apply(&$ticket, array $info) {
@@ -152,6 +160,10 @@ abstract class TriggerAction {
return array();
}
function getEventDescription($action, $filterName) {
return null;
}
function getConfigurationForm($source=false) {
if (!$this->_cform) {
$config = $this->getConfiguration();
@@ -305,11 +317,25 @@ class FA_RouteDepartment extends TriggerAction {
if ($config['dept_id']) {
$dept = Dept::lookup($config['dept_id']);
if ($dept->isActive())
if ($dept && $dept->isActive())
$ticket['deptId'] = $config['dept_id'];
}
}
function getEventDescription($action, $filterName) {
$config = $action->getConfiguration();
$info = array();
if ($config['dept_id']) {
$dept = Dept::lookup($config['dept_id']);
$info = array('type' => 'edited',
'desc' => array('value' => $dept ? $dept->getName() : false,
'filter' => $filterName, 'type' => 'Department'));
}
return $info;
}
function getConfigurationOptions() {
$depts = Dept::getDepartments(null, true, false);
@@ -349,6 +375,20 @@ class FA_AssignPriority extends TriggerAction {
$ticket['priorityId'] = $config['priority'];
}
function getEventDescription($action, $filterName) {
$config = $action->getConfiguration();
$info = array();
if ($config['priority']) {
$priority = Priority::lookup($config['priority']);
$info = array('type' => 'edited',
'desc' => array('value' => $priority ? $priority->getDesc() : false,
'filter' => $filterName, 'type' => 'Priority'));
}
return $info;
}
function getConfigurationOptions() {
$sql = 'SELECT priority_id, priority_desc FROM '.PRIORITY_TABLE
.' ORDER BY priority_urgency DESC';
@@ -377,6 +417,21 @@ class FA_AssignSLA extends TriggerAction {
$ticket['slaId'] = $config['sla_id'];
}
function getEventDescription($action, $filterName) {
$config = $action->getConfiguration();
$info = array();
if ($config['sla_id']) {
$sla = SLA::lookup($config['sla_id']);
$info = array('type' => 'edited',
'desc' => array('value' => $sla ? $sla->getName() : false,
'filter' => $filterName, 'type' => 'SLA'));
}
return $info;
}
function getConfigurationOptions() {
$choices = SLA::getSLAs();
return array(
@@ -399,6 +454,20 @@ class FA_AssignTeam extends TriggerAction {
$ticket['teamId'] = $config['team_id'];
}
function getEventDescription($action, $filterName) {
$config = $action->getConfiguration();
$info = array();
if ($config['team_id']) {
$team = Team::lookup($config['team_id']);
$info = array('type' => 'edited',
'desc' => array('value' => $team ? $team->getName() : false,
'filter' => $filterName, 'type' => 'Team'));
}
return $info;
}
function getConfigurationOptions() {
$choices = Team::getTeams();
return array(
@@ -430,6 +499,20 @@ class FA_AssignAgent extends TriggerAction {
$ticket['staffId'] = $config['staff_id'];
}
function getEventDescription($action, $filterName) {
$config = $action->getConfiguration();
$info = array();
if ($config['staff_id']) {
$staff = Staff::lookup($config['staff_id']);
$info = array('type' => 'edited',
'desc' => array('value' => $staff ? $staff->getName()->name : false,
'filter' => $filterName, 'type' => 'Agent'));
}
return $info;
}
function getConfigurationOptions() {
$choices = Staff::getStaffMembers();
return array(
@@ -450,12 +533,25 @@ class FA_AssignTopic extends TriggerAction {
$config = $this->getConfiguration();
if ($config['topic_id']) {
$topic = Topic::lookup($config['topic_id']);
if ($topic->isActive())
if ($topic && $topic->isActive())
$ticket['topicId'] = $config['topic_id'];
}
}
function getEventDescription($action, $filterName) {
$config = $action->getConfiguration();
$info = array();
if ($config['topic_id']) {
$topic = Topic::lookup($config['topic_id']);
$info = array('type' => 'edited',
'desc' => array('value' => $topic ? $topic->getName() : false,
'filter' => $filterName, 'type' => 'Topic'));
}
return $info;
}
function getConfigurationOptions() {
$choices = Topic::getHelpTopics(false, false);
@@ -486,6 +582,20 @@ class FA_SetStatus extends TriggerAction {
$ticket['statusId'] = $config['status_id'];
}
function getEventDescription($action, $filterName) {
$config = $action->getConfiguration();
$info = array();
if ($config['status_id']) {
$status = Team::lookup($config['status_id']);
$info = array('type' => 'edited',
'desc' => array('value' => $status ? $status->getName() : false,
'filter' => $filterName, 'type' => 'Ticket Status'));
}
return $info;
}
function getConfigurationOptions() {
$choices = array();
foreach (TicketStatusList::getStatuses(array(
@@ -516,16 +626,23 @@ class FA_SendEmail extends TriggerAction {
function apply(&$ticket, array $info) {
global $ost;
if (!$ticket['ticket'])
return false;
$config = $this->getConfiguration();
$info = array('subject' => $config['subject'],
'message' => $config['message']);
$info = $ost->replaceTemplateVariables(
$info, array('ticket' => $ticket)
$vars = array(
'url' => $ost->getConfig()->getBaseUrl(),
'ticket' => $ticket['ticket'],
'recipient' => $ticket['ticket']->getOwner(),
);
$info = $ost->replaceTemplateVariables(array(
'subject' => $config['subject'],
'message' => $config['message'],
), $vars);
// Honor FROM address settings
if (!$config['from'] || !($mailer = Email::lookup($config['from'])))
$mailer = new Mailer();
$mailer = new osTicket\Mail\Mailer();
// Allow %{user} in the To: line
$replacer = new VariableReplacer();
@@ -534,10 +651,9 @@ class FA_SendEmail extends TriggerAction {
));
$to = $replacer->replaceVars($config['recipients']);
require_once PEAR_DIR . 'Mail/RFC822.php';
require_once PEAR_DIR . 'PEAR.php';
if (!($mails = Mail_RFC822::parseAddressList($to)) || PEAR::isError($mails))
if (!($mails = Mail_Parse::parseAddressList($to)) || PEAR::isError($mails))
return false;
// Allow %{recipient} in the body
@@ -549,7 +665,6 @@ class FA_SendEmail extends TriggerAction {
$I = $replacer->replaceVars($info);
$mailer->send($recipient, $I['subject'], $I['message']);
}
}
static function getVarScope() {
@@ -577,7 +692,7 @@ class FA_SendEmail extends TriggerAction {
'size' => 80, 'length' => 1000,
),
'validators' => function($self, $value) {
if (!($mails = Mail_RFC822::parseAddressList($value)) || PEAR::isError($mails))
if (!($mails = Mail_Parse::parseAddressList($value)) || PEAR::isError($mails))
$self->addError('Unable to parse address list. '
.'Use commas to separate addresses.');

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