diff --git a/README.md b/README.md index 9946aeb3d85e6c3715b57f9347d10ccdc4edb244..f09b94d050780ec31d5953b61118b417edb6c6eb 100644 --- a/README.md +++ b/README.md @@ -47,3 +47,20 @@ Create your own fork of the project and use [git-flow](https://github.com/nvie/gitflow) to create a new feature. Once the feature is published in your fork, send a pull request to begin the conversation of integrating your new feature into osTicket. + +License +------- +osTicket is released under the GPL2 license. See the included LICENSE.txt +file for the gory details of the General Public License. + +osTicket is supported by several magical open source projects including: + + * [HTMLawed](http://www.bioinformatics.org/phplabware/internal_utilities/htmLawed) + * [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) + * [phplint](http://antirez.com/page/phplint.html) diff --git a/WHATSNEW.md b/WHATSNEW.md index 522bc605e475837fe6c321c75a57d2fe086880dd..ed656f683a7c03dc708939991227ef9829dbd270 100644 --- a/WHATSNEW.md +++ b/WHATSNEW.md @@ -1,3 +1,7 @@ +New stuff in 1.7-dpr3 +====================== + + New stuff in 1.7-dpr2 ====================== diff --git a/assets/default/css/theme.css b/assets/default/css/theme.css index c6a6242df3d461805e06d366f451d3abf34a29ff..88c4898a80b62ae5be6ede550948a3e217fd3a8a 100644 --- a/assets/default/css/theme.css +++ b/assets/default/css/theme.css @@ -254,6 +254,9 @@ body { height: 20px; background: url('../images/nav_bg.png') top left repeat-x; border-top: 1px solid #aaa; + box-shadow:0 3px 2px rgba(0, 0, 0, 0.4); + -moz-box-shadow:0 3px 2px rgba(0, 0, 0, 0.4); + -webkit-box-shadow:0 3px 2px rgba(0, 0, 0, 0.4); } #nav li { margin: 0; @@ -304,19 +307,11 @@ body { #content { padding: 20px 0; margin: 0 20px; - background: url('../images/content_bg.png') top left repeat-x; -} - -#cnbg { - padding: 5px 0; - margin: 0 20px; height: auto !important; height: 350px; min-height: 350px; - background: none; } - #footer { text-align: center; font-size: 11px; @@ -384,19 +379,33 @@ body { font-size: 15px; margin-left: 0; padding-left: 0; + border-top:1px solid #ddd; } #faq ol li { list-style: none; - margin: 0 0 10px 0; + margin: 0; + padding:0; color: #999; } #faq ol li a { - display: block; - height: 16px; + display:block; + padding:5px 0; + height:auto !important; + overflow:hidden; + margin:0; + border-bottom:1px solid #ddd; line-height: 16px; padding-left: 24px; background: url('../images/icons/page.png?1319579499') 0 50% no-repeat; } +#faq ol li a:hover { + background-color:#e9f5ff; +} + +.article-meta { + padding:5px; + background:#fafafa; +} /* Knowledgebase */ #kb { @@ -406,12 +415,21 @@ body { } #kb > li { - margin: 0 0 5px 0; - padding: 10px; - width: auto; - float: left; - clear: both; - list-style: none; + padding:10px; + height:auto !important; + overflow:hidden; + margin:0; + background:url(../images/kb_category_bg.png) bottom left repeat-x; + border-bottom:1px solid #ddd; +} + +#kb li i { + display:block; + width:32px; + height:32px; + float:left; + margin-right:6px; + background:url(../images/kb_large_folder.png) top left no-repeat; } #kb > li h4 { @@ -425,10 +443,51 @@ body { #kb > li h4 a { font-size: 14px; - padding-left: 24px; - background: url('../images/icons/page.png?1319579499') 0 50% no-repeat; } +#kb-search { + padding:10px 0; + overflow:hidden; +} + +#kb-search div { + clear:both; + overflow:hidden; + padding-top:5px; +} + +#kb-search #query { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; +} + +#kb-search #cid { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; + position:relative; + top:2px; +} + +#kb-search #topic-id { + margin:0; + display:inline-block; + float:left; + width:410px; +} + +#kb-search #searchSubmit { + margin:0; + display:inline-block; + float:left; + position:relative; + top:2px; +} #breadcrumbs { color: #333; @@ -649,6 +708,13 @@ a.refresh { font-size: 12px; padding: 5px; } + +#ticketThread table th span { + font-weight:normal; + color:#888; + padding-left:20px; +} + #ticketThread table td { padding: 5px; } @@ -707,3 +773,35 @@ a.refresh { margin-right: 20px; background: url('../images/icons/file.gif') 0 50% no-repeat; } + +.button, .button:visited { + background: #222; + display: inline-block; + font-size: 16px; + padding: 8px 16px 6px 16px; + width:160px; + text-align:center; + color: #fff; + font-weight:bold; + text-decoration: none; + border-radius: 5px; + -moz-border-radius: 5px; + -webkit-border-radius: 5px; + box-shadow: 0 1px 3px rgba(0,0,0,0.5); + -moz-box-shadow: 0 1px 3px rgba(0,0,0,0.5); + -webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.5); + text-shadow: 0 -1px 1px rgba(0,0,0,0.25); + border-bottom: 1px solid rgba(0,0,0,0.25); + position: relative; + cursor: pointer; + font-family:helvetica, arial, sans-serif; +} + +.button:hover { background-color: #111; color: #fff; } +.button:active { top: 1px; box-shadow:none; -moz-box-shadow:none; -webkit-box-shadow:none; } +.button, .button:visited, +.green.button, .green.button:visited { background-color: #91bd09; } +.green.button:hover { background-color: #749a02; } +.blue.button, .blue.button:visited { background-color: #00AEEF; } +.blue.button:hover { background-color: #0299d2; } + diff --git a/assets/default/images/kb_category_bg.png b/assets/default/images/kb_category_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..174d675f4c491060a413232bdef7e0e9298df60e Binary files /dev/null and b/assets/default/images/kb_category_bg.png differ diff --git a/assets/default/images/kb_large_folder.png b/assets/default/images/kb_large_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..144fa828a3fc83613dd7a5b29368b6da290fd09d Binary files /dev/null and b/assets/default/images/kb_large_folder.png differ diff --git a/client.inc.php b/client.inc.php index b714e93b44bd587f4d10a2f292b2d4890bc63a3f..3b450e9e2491653ec44c65f346ef79758cc1d1a8 100644 --- a/client.inc.php +++ b/client.inc.php @@ -28,21 +28,12 @@ define('OSTCLIENTINC',TRUE); define('ASSETS_PATH',ROOT_PATH.'assets/default/'); - //Check the status of the HelpDesk. -if(!is_object($cfg) || !$cfg->getId() || $cfg->isHelpDeskOffline()) { +if(!is_object($cfg) || !$cfg->getId() || $cfg->isHelpDeskOffline() || $cfg->isUpgradePending()) { include('./offline.php'); exit; } -//Forced upgrade? Version mismatch. -if(defined('THIS_VERSION') && strcasecmp($cfg->getVersion(),THIS_VERSION)) { - die('System is offline for an upgrade.'); - exit; -} - - - /* include what is needed on client stuff */ require_once(INCLUDE_DIR.'class.client.php'); require_once(INCLUDE_DIR.'class.ticket.php'); diff --git a/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png b/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png new file mode 100644 index 0000000000000000000000000000000000000000..954e22dbd99e8c6dd7091335599abf2d10bf8003 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_diagonals-thick_18_b81900_40x40.png differ diff --git a/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png b/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png new file mode 100644 index 0000000000000000000000000000000000000000..64ece5707d91a6edf9fad4bfcce0c4dbcafcf58d Binary files /dev/null and b/css/ui-lightness/images/ui-bg_diagonals-thick_20_666666_40x40.png differ diff --git a/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png b/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png new file mode 100644 index 0000000000000000000000000000000000000000..abdc01082bf3534eafecc5819d28c9574d44ea89 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_flat_10_000000_40x100.png differ diff --git a/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png b/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..9b383f4d2eab09c0f2a739d6b232c32934bc620b Binary files /dev/null and b/css/ui-lightness/images/ui-bg_glass_100_f6f6f6_1x400.png differ diff --git a/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png b/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..a23baad25b1d1ff36e17361eab24271f2e9b7326 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_glass_100_fdf5ce_1x400.png differ diff --git a/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png b/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png new file mode 100644 index 0000000000000000000000000000000000000000..42ccba269b6e91bef12ad0fa18be651b5ef0ee68 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_glass_65_ffffff_1x400.png differ diff --git a/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png b/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png new file mode 100644 index 0000000000000000000000000000000000000000..39d5824d6af5456f1e89fc7847ea3599ea5fd815 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_gloss-wave_35_f6a828_500x100.png differ diff --git a/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png b/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..f1273672d253263b7564e9e21d69d7d9d0b337d9 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_highlight-soft_100_eeeeee_1x100.png differ diff --git a/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png b/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png new file mode 100644 index 0000000000000000000000000000000000000000..359397acffdd84bd102f0e8a951c9d744f278db5 Binary files /dev/null and b/css/ui-lightness/images/ui-bg_highlight-soft_75_ffe45c_1x100.png differ diff --git a/css/ui-lightness/images/ui-icons_222222_256x240.png b/css/ui-lightness/images/ui-icons_222222_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..b273ff111d219c9b9a8b96d57683d0075fb7871a Binary files /dev/null and b/css/ui-lightness/images/ui-icons_222222_256x240.png differ diff --git a/css/ui-lightness/images/ui-icons_228ef1_256x240.png b/css/ui-lightness/images/ui-icons_228ef1_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..a641a371afa0fbb08ba599dc7ddf14b9bfc3c84f Binary files /dev/null and b/css/ui-lightness/images/ui-icons_228ef1_256x240.png differ diff --git a/css/ui-lightness/images/ui-icons_ef8c08_256x240.png b/css/ui-lightness/images/ui-icons_ef8c08_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..85e63e9f604ce042d59eb06a8428eeb7cb7896c9 Binary files /dev/null and b/css/ui-lightness/images/ui-icons_ef8c08_256x240.png differ diff --git a/css/ui-lightness/images/ui-icons_ffd27a_256x240.png b/css/ui-lightness/images/ui-icons_ffd27a_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..e117effa3dca24e7978cfc5f8b967f661e81044f Binary files /dev/null and b/css/ui-lightness/images/ui-icons_ffd27a_256x240.png differ diff --git a/css/ui-lightness/images/ui-icons_ffffff_256x240.png b/css/ui-lightness/images/ui-icons_ffffff_256x240.png new file mode 100644 index 0000000000000000000000000000000000000000..42f8f992c727ddaa617da224a522e463df690387 Binary files /dev/null and b/css/ui-lightness/images/ui-icons_ffffff_256x240.png differ diff --git a/css/ui-lightness/jquery-ui-1.8.18.custom.css b/css/ui-lightness/jquery-ui-1.8.18.custom.css new file mode 100755 index 0000000000000000000000000000000000000000..d9e8e3a5a914d18948c9ebddfcb3b8d50929bd3a --- /dev/null +++ b/css/ui-lightness/jquery-ui-1.8.18.custom.css @@ -0,0 +1,354 @@ +/* + * jQuery UI CSS Framework 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { display: none; } +.ui-helper-hidden-accessible { position: absolute !important; clip: rect(1px 1px 1px 1px); clip: rect(1px,1px,1px,1px); } +.ui-helper-reset { margin: 0; padding: 0; border: 0; outline: 0; line-height: 1.3; text-decoration: none; font-size: 100%; list-style: none; } +.ui-helper-clearfix:before, .ui-helper-clearfix:after { content: ""; display: table; } +.ui-helper-clearfix:after { clear: both; } +.ui-helper-clearfix { zoom: 1; } +.ui-helper-zfix { width: 100%; height: 100%; top: 0; left: 0; position: absolute; opacity: 0; filter:Alpha(Opacity=0); } + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { cursor: default !important; } + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { display: block; text-indent: -99999px; overflow: hidden; background-repeat: no-repeat; } + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; } + + +/* + * jQuery UI CSS Framework 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Theming/API + * + * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS,%20Tahoma,%20Verdana,%20Arial,%20sans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=03_highlight_soft.png&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=02_glass.png&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=02_glass.png&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=03_highlight_soft.png&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=08_diagonals_thick.png&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=08_diagonals_thick.png&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=01_flat.png&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px + */ + + +/* Component containers +----------------------------------*/ +.ui-widget { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1.1em; } +.ui-widget .ui-widget { font-size: 1em; } +.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Trebuchet MS, Tahoma, Verdana, Arial, sans-serif; font-size: 1em; } +.ui-widget-content { border: 1px solid #dddddd; background: #eeeeee url(images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; color: #333333; } +.ui-widget-content a { color: #333333; } +.ui-widget-header { border: 1px solid #e78f08; background: #f6a828 url(images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; color: #ffffff; font-weight: bold; } +.ui-widget-header a { color: #ffffff; } + +/* Interaction states +----------------------------------*/ +.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #cccccc; background: #f6f6f6 url(images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #1c94c4; } +.ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #1c94c4; text-decoration: none; } +.ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #fbcb09; background: #fdf5ce url(images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #c77405; } +.ui-state-hover a, .ui-state-hover a:hover { color: #c77405; text-decoration: none; } +.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #fbd850; background: #ffffff url(images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; font-weight: bold; color: #eb8f00; } +.ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #eb8f00; text-decoration: none; } +.ui-widget :active { outline: none; } + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fed22f; background: #ffe45c url(images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; color: #363636; } +.ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636; } +.ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #b81900 url(images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; color: #ffffff; } +.ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; } +.ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; } +.ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; } +.ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; } +.ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; } + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png); } +.ui-widget-header .ui-icon {background-image: url(images/ui-icons_ffffff_256x240.png); } +.ui-state-default .ui-icon { background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-active .ui-icon {background-image: url(images/ui-icons_ef8c08_256x240.png); } +.ui-state-highlight .ui-icon {background-image: url(images/ui-icons_228ef1_256x240.png); } +.ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_ffd27a_256x240.png); } + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-off { background-position: -96px -144px; } +.ui-icon-radio-on { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, .ui-corner-top, .ui-corner-left, .ui-corner-tl { -moz-border-radius-topleft: 4px; -webkit-border-top-left-radius: 4px; -khtml-border-top-left-radius: 4px; border-top-left-radius: 4px; } +.ui-corner-all, .ui-corner-top, .ui-corner-right, .ui-corner-tr { -moz-border-radius-topright: 4px; -webkit-border-top-right-radius: 4px; -khtml-border-top-right-radius: 4px; border-top-right-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-left, .ui-corner-bl { -moz-border-radius-bottomleft: 4px; -webkit-border-bottom-left-radius: 4px; -khtml-border-bottom-left-radius: 4px; border-bottom-left-radius: 4px; } +.ui-corner-all, .ui-corner-bottom, .ui-corner-right, .ui-corner-br { -moz-border-radius-bottomright: 4px; -webkit-border-bottom-right-radius: 4px; -khtml-border-bottom-right-radius: 4px; border-bottom-right-radius: 4px; } + +/* Overlays */ +.ui-widget-overlay { background: #666666 url(images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; opacity: .50;filter:Alpha(Opacity=50); } +.ui-widget-shadow { margin: -5px 0 0 -5px; padding: 5px; background: #000000 url(images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; opacity: .20;filter:Alpha(Opacity=20); -moz-border-radius: 5px; -khtml-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/* + * jQuery UI Datepicker 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Datepicker#theming + */ +.ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; } +.ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; } +.ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; } +.ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; } +.ui-datepicker .ui-datepicker-prev { left:2px; } +.ui-datepicker .ui-datepicker-next { right:2px; } +.ui-datepicker .ui-datepicker-prev-hover { left:1px; } +.ui-datepicker .ui-datepicker-next-hover { right:1px; } +.ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; } +.ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; } +.ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; } +.ui-datepicker select.ui-datepicker-month-year {width: 100%;} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { width: 49%;} +.ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; } +.ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; } +.ui-datepicker td { border: 0; padding: 1px; } +.ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; } +.ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; } +.ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; } +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; } + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { width:auto; } +.ui-datepicker-multi .ui-datepicker-group { float:left; } +.ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; } +.ui-datepicker-multi-2 .ui-datepicker-group { width:50%; } +.ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; } +.ui-datepicker-multi-4 .ui-datepicker-group { width:25%; } +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; } +.ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; } +.ui-datepicker-row-break { clear:both; width:100%; font-size:0em; } + +/* RTL support */ +.ui-datepicker-rtl { direction: rtl; } +.ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; } +.ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; } +.ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; } +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; } +.ui-datepicker-rtl .ui-datepicker-group { float:right; } +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; } +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; } + +/* IE6 IFRAME FIX (taken from datepicker 1.5.3 */ +.ui-datepicker-cover { + display: none; /*sorry for IE5*/ + display/**/: block; /*sorry for IE5*/ + position: absolute; /*must have*/ + z-index: -1; /*must have*/ + filter: mask(); /*must have*/ + top: -4px; /*must have*/ + left: -4px; /*must have*/ + width: 200px; /*must have*/ + height: 200px; /*must have*/ +} diff --git a/include/ajax.config.php b/include/ajax.config.php index 7dcfd9972717e9c8cd5cb14a217b0e3b361dd9ee..fc9fb2c3fc8622108054052828b7e6bb9a42dcd6 100644 --- a/include/ajax.config.php +++ b/include/ajax.config.php @@ -19,7 +19,7 @@ if(!defined('INCLUDE_DIR')) die('!'); class ConfigAjaxAPI extends AjaxController { //config info UI might need. - function ui() { + function scp_ui() { global $thisstaff, $cfg; $config=array('ticket_lock_time'=>($cfg->getLockTime()*3600), diff --git a/include/ajax.tickets.php b/include/ajax.tickets.php index 458e430ea83192703bea52c026413af63c4edb63..f67581005194848131dbaf1c709b8c238c8e404a 100644 --- a/include/ajax.tickets.php +++ b/include/ajax.tickets.php @@ -20,11 +20,11 @@ include_once(INCLUDE_DIR.'class.ticket.php'); class TicketsAjaxAPI extends AjaxController { - function search() { + function lookup() { global $thisstaff; if(!is_numeric($_REQUEST['q'])) - return self::searchByEmail(); + return self::lookupByEmail(); $limit = isset($_REQUEST['limit']) ? (int) $_REQUEST['limit']:25; @@ -53,7 +53,7 @@ class TicketsAjaxAPI extends AjaxController { return $this->json_encode($tickets); } - function searchByEmail() { + function lookupByEmail() { global $thisstaff; @@ -84,6 +84,100 @@ class TicketsAjaxAPI extends AjaxController { return $this->json_encode($tickets); } + function search() { + global $thisstaff; + + $result=array(); + $select = 'SELECT count(ticket.ticket_id) as tickets '; + $from = ' FROM '.TICKET_TABLE.' ticket '; + $where = ' WHERE 1 '; + + //Access control. + $where.=' AND ( ticket.staff_id='.db_input($thisstaff->getId()); + + if(($teams=$thisstaff->getTeams()) && count(array_filter($teams))) + $where.=' OR ticket.team_id IN('.implode(',', array_filter($teams)).')'; + + if(!$thisstaff->showAssignedOnly() && ($depts=$thisstaff->getDepts())) + $where.=' OR ticket.dept_id IN ('.implode(',', $depts).')'; + + $where.=' ) '; + + //Department + if($_REQUEST['deptId']) + $where.=' AND ticket.dept_id='.db_input($_REQUEST['deptId']); + + //Status + switch(strtolower($_REQUEST['status'])) { + case 'open'; + $where.=' AND ticket.status="open" '; + break; + case 'overdue': + $where.=' AND ticket.status="open" AND ticket.isoverdue=1 '; + break; + case 'closed': + $where.=' AND ticket.status="closed" '; + break; + } + + //Assignee + if($_REQUEST['assignee'] && strcasecmp($_REQUEST['status'], 'closed')) { + $id=preg_replace("/[^0-9]/", "", $_REQUEST['assignee']); + $assignee = $_REQUEST['assignee']; + $where.= ' AND ( '; + if($assignee[0]=='t') + $where.=' (ticket.team_id='.db_input($id). ' AND ticket.status="open") '; + elseif($assignee[0]=='s') + $where.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + else + $where.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + + if($_REQUEST['staffId'] && !$_REQUEST['status']) //Assigned TO + Closed By + $where.= ' OR (ticket.staff_id='.db_input($_REQUEST['staffId']). ' AND ticket.status="closed") '; + + $where.= ' ) '; + } elseif($_REQUEST['staffId']) { + $where.=' AND (ticket.staff_id='.db_input($_REQUEST['staffId']).' AND ticket.status="closed") '; + } + + //dates + $startTime =($_REQUEST['startDate'] && (strlen($_REQUEST['startDate'])>=8))?strtotime($_REQUEST['startDate']):0; + $endTime =($_REQUEST['endDate'] && (strlen($_REQUEST['endDate'])>=8))?strtotime($_REQUEST['endDate']):0; + if( ($startTime && $startTime>time()) or ($startTime>$endTime && $endTime>0)) + $startTime=$endTime=0; + + if($startTime) + $where.=' AND ticket.created>=FROM_UNIXTIME('.$startTime.')'; + + if($endTime) + $where.=' AND ticket.created<=FROM_UNIXTIME('.$endTime.')'; + + //Query + if($_REQUEST['query']) { + $queryterm=db_real_escape($_REQUEST['query'], false); + + $from.=' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON (ticket.ticket_id=thread.ticket_id )'; + $where.=" AND ( ticket.email LIKE '%$queryterm%'" + ." OR ticket.name LIKE '%$queryterm%'" + ." OR ticket.subject LIKE '%$queryterm%'" + ." OR thread.title LIKE '%$queryterm%'" + ." OR thread.body LIKE '%$queryterm%'" + .' )'; + $groupby = 'GROUP BY ticket.ticket_id '; + } + + $sql="$select $from $where $groupby"; + if(($tickets=db_result(db_query($sql)))) { + $result['success'] =sprintf("Search criteria matched %s - <a href='tickets.php?%s'>view</a>", + ($tickets>1?"$tickets tickets":"$tickets ticket"), + str_replace(array('&', '&'), array('&', '&'), $_SERVER['QUERY_STRING'])); + } else { + $result['fail']='No tickets found matching your search criteria.'; + } + + return $this->json_encode($result); + } + function acquireLock($tid) { global $cfg,$thisstaff; diff --git a/include/class.attachment.php b/include/class.attachment.php index 8644d671c4986f6b5541e6b9b592fa06fde91652..442c9865e495d8e6d32e380f712524b66c5ef0e6 100644 --- a/include/class.attachment.php +++ b/include/class.attachment.php @@ -93,10 +93,12 @@ class Attachment { return db_result(db_query($sql)); } - function lookup($id,$tid=0) { - $id=is_numeric($id)?$id:self::getIdByFileHash($hash,$tid); + function lookup($var,$tid=0) { + $id=is_numeric($var)?$var:self::getIdByFileHash($var,$tid); - return ($id && is_numeric($id) && ($attach = new Attachment($id,$tid)) && $attach->getId()==$id)?$attach:null; + return ($id && is_numeric($id) + && ($attach = new Attachment($id,$tid)) + && $attach->getId()==$id)?$attach:null; } } diff --git a/include/class.canned.php b/include/class.canned.php index 6c6c1ac1c75bcbc25b7c288c2e49909e30b4876a..51d39ca48024410bdefecba03f20b7b030f30649 100644 --- a/include/class.canned.php +++ b/include/class.canned.php @@ -130,6 +130,7 @@ class Canned { */ function uploadAttachments($files) { + $i=0; foreach($files as $file) { if(($fileId=is_numeric($file)?$file:AttachmentFile::upload($file)) && is_numeric($fileId)) { $sql ='INSERT INTO '.CANNED_ATTACHMENT_TABLE @@ -174,7 +175,7 @@ class Canned { return self::save(0,$vars,$errors); } - function getIdByTitle($titke) { + function getIdByTitle($title) { $sql='SELECT canned_id FROM '.CANNED_TABLE.' WHERE title='.db_input($title); if(($res=db_query($sql)) && db_num_rows($res)) list($id)=db_fetch_row($res); diff --git a/include/class.config.php b/include/class.config.php index c51814bebc73aef1ae3a9052db364d2702798c04..626e11c9a0e3eb466046f3539b9ed16ecb7c0c7e 100644 --- a/include/class.config.php +++ b/include/class.config.php @@ -67,22 +67,35 @@ class Config { return !$this->isSystemOnline(); } + function isHelpDeskOnline() { + return $this->isSystemOnline(); + } + function isSystemOnline() { - return ($this->config['isonline']); + return ($this->config['isonline'] && !$this->isUpgradePending()); } - function isKnowledgebaseEnabled() { + function isUpgradePending() { + return (defined('SCHEMA_SIGNATURE') && strcasecmp($this->getSchemaSignature(), SCHEMA_SIGNATURE)); + } + function isKnowledgebaseEnabled() { require_once(INCLUDE_DIR.'class.faq.php'); return ($this->config['enable_kb'] && FAQ::countPublishedFAQs()); } function getVersion() { - return '1.7-DPR2'; + return THIS_VERSION; } function getSchemaSignature() { - return $this->config['schema_signature']; + + if($this->config['schema_signature']) + return $this->config['schema_signature']; + elseif($this->config['ostversion']) //old version 1.6 st. + return md5(strtoupper($this->config['ostversion'])); + + return null; } function setMysqlTZ($tz) { @@ -155,6 +168,10 @@ class Config { function showRelatedTickets() { return $this->config['show_related_tickets']; } + + function showNotesInline(){ + return $this->config['show_notes_inline']; + } function getClientTimeout() { return $this->getClientSessionTimeout(); @@ -300,7 +317,7 @@ class Config { } function canFetchMail() { - return ($this->config['enable_mail_fetch']); + return ($this->config['enable_mail_polling']); } function enableStaffIPBinding() { @@ -662,6 +679,7 @@ class Config { ',show_assigned_tickets='.db_input(isset($vars['show_assigned_tickets'])?1:0). ',show_answered_tickets='.db_input(isset($vars['show_answered_tickets'])?1:0). ',show_related_tickets='.db_input(isset($vars['show_related_tickets'])?1:0). + ',show_notes_inline='.db_input(isset($vars['show_notes_inline'])?1:0). ',hide_staff_name='.db_input(isset($vars['hide_staff_name'])?1:0); return (db_query($sql)); diff --git a/include/class.dept.php b/include/class.dept.php index 8bd575116a421dba88b82dd236243829aeadfc32..bf82b76526b7ce77abbdcdbaa213c939207ca4ad 100644 --- a/include/class.dept.php +++ b/include/class.dept.php @@ -47,6 +47,7 @@ class Dept { $this->id=$this->ht['dept_id']; $this->email=$this->sla=$this->manager=null; $this->getEmail(); //Auto load email struct. + $this->members=array(); return true; } @@ -88,6 +89,21 @@ class Dept { return $this->getNumStaff(); } + function getAvailableMembers(){ + + if(!$this->members && $this->getNumStaff()){ + $sql='SELECT m.staff_id FROM '.STAFF_TABLE.' m ' + .'WHERE m.dept_id='.db_input($this->getId()) + .' AND s.staff_id IS NOT NULL ' + .'ORDER BY s.lastname, s.firstname'; + if(($res=db_query($sql)) && db_num_rows($res)){ + while(list($id)=db_fetch_row($res)) + if($staff= Staff::lookup($id) && $staff->isAvailable()) + $this->members[]= $staff; + } + } + return $this->members; + } function getSLAId(){ return $this->ht['sla_id']; diff --git a/include/class.faq.php b/include/class.faq.php index 7e23803dc458272ed7f81184c190213ddabd0e85..b0fdc4ac2b0890895f0adfa3a3268f5e63531221 100644 --- a/include/class.faq.php +++ b/include/class.faq.php @@ -127,7 +127,7 @@ class FAQ { /* Same as update - but mainly called after one or more setters are changed. */ function apply() { //XXX: set errors and add ->getErrors() & ->getError() - return $this->update($this->ht, $errors); + return $this->update($this->ht, $errors); # nolint } function updateTopics($ids){ @@ -204,6 +204,7 @@ class FAQ { function uploadAttachments($files) { + $i=0; foreach($files as $file) { if(($fileId=is_numeric($file)?$file:AttachmentFile::upload($file)) && is_numeric($fileId)) { $sql ='INSERT INTO '.FAQ_ATTACHMENT_TABLE diff --git a/include/class.filter.php b/include/class.filter.php index 4f18e96514c307077b7300a02674f8ad1698039e..9c3065c10aba5aa1e359e4c36a67e4de83aec9fe 100644 --- a/include/class.filter.php +++ b/include/class.filter.php @@ -156,7 +156,7 @@ class Filter { $rule= array_merge($extra,array('w'=>$what, 'h'=>$how, 'v'=>$val)); $rule['filter_id']=$this->getId(); - return FilterRule::create($rule,$errors); + return FilterRule::create($rule,$errors); # nolint } function removeRule($what, $how, $val) { @@ -419,7 +419,8 @@ class Filter { if($errors || !$id) return false; //Success with update/create...save the rules. We can't recover from any errors at this point. - self::save_rules($id,$vars,$xerrors); + # Don't care about errors stashed in $xerrors + self::save_rules($id,$vars,$xerrors); # nolint return true; } diff --git a/include/class.format.php b/include/class.format.php index 45f4301913072fa49d93d7dc3a10019b82536563..a3461bf9d615c857382763c62b8ff49562352648 100644 --- a/include/class.format.php +++ b/include/class.format.php @@ -104,7 +104,11 @@ class Format { $text=Format::clickableurls($text); //Wrap long words... - $text=preg_replace_callback('/\w{75,}/',create_function('$matches','return wordwrap($matches[0],70,"\n",true);'),$text); + $text=preg_replace_callback('/\w{75,}/', + create_function( + '$matches', # nolint + 'return wordwrap($matches[0],70,"\n",true);'), # nolint + $text); return nl2br($text); } @@ -122,7 +126,7 @@ class Format { $text=preg_replace("/(^|[ \\n\\r\\t])(www\.([a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+)(\/[^\/ \\n\\r]*)*)/", '\\1<a href="l.php?url=http://\\2" target="_blank">\\2</a>', $text); $text=preg_replace("/(^|[ \\n\\r\\t])([_\.0-9a-z-]+@([0-9a-z][0-9a-z-]+\.)+[a-z]{2,4})/", - '\\1<a href="l.php?url=mailto:\\2" target="_blank">\\2</a>', $text); + '\\1<a href="mailto:\\2" target="_blank">\\2</a>', $text); return $text; } diff --git a/include/class.knowledgebase.php b/include/class.knowledgebase.php index d8a64689168de48014011bf46c45e029056efdea..6bb67898f7a94f7b6f95c547b646241aa45c2699 100644 --- a/include/class.knowledgebase.php +++ b/include/class.knowledgebase.php @@ -55,9 +55,11 @@ class Knowledgebase { function publish() { $this->published = true; } function unpublish() { $this->published = false; } function setPublished($val) { $this->published = !!$val; } + function setEnabled($val) { $this->enabled = !!$val; } function setTitle($title) { $this->title = $title; } function setKeywords($words) { $this->keywords = $words; } function setAnswer($text) { $this->answer = $text; } + function setDepartment($id) { $this->department = $id; } /* -------------> Validation and Clean methods <------------ */ function validate(&$errors, $what=null) { diff --git a/include/class.mailfetch.php b/include/class.mailfetch.php index 5f97775930f25da87f80261cc20b66cdad947b8f..f25d72b26236471dd6b14e365a1745067ffe6f3e 100644 --- a/include/class.mailfetch.php +++ b/include/class.mailfetch.php @@ -242,7 +242,7 @@ class MailFetcher { function getBody($mid) { $body =''; - if(!($body = $this->getpart($mid,'TEXT/PLAIN',$this->charset))) { + if(!($body = $this->getPart($mid,'TEXT/PLAIN',$this->charset))) { if(($body = $this->getPart($mid,'TEXT/HTML',$this->charset))) { //Convert tags of interest before we striptags $body=str_replace("</DIV><DIV>", "\n", $body); @@ -346,7 +346,7 @@ class MailFetcher { } - function fetchTickets($emailid,$max=20,$deletemsgs=false){ + function fetchTickets($emailid,$max=20,$deletemsgs=false,$archivefolder){ $nummsgs=imap_num_msg($this->mbox); //echo "New Emails: $nummsgs\n"; @@ -354,7 +354,7 @@ class MailFetcher { for($i=$nummsgs; $i>0; $i--){ //process messages in reverse. Latest first. FILO. if($this->createTicket($i,$emailid)){ imap_setflag_full($this->mbox, imap_uid($this->mbox,$i), "\\Seen", ST_UID); //IMAP only?? - if($deletemsgs) + if((!$archivefolder || !imap_mail_move($this->mbox,$i,$archivefolder)) && $deletemsgs) imap_delete($this->mbox,$i); $msgs++; $errors=0; //We are only interested in consecutive errors. @@ -384,7 +384,7 @@ class MailFetcher { $MAX_ERRORS=5; //Max errors before we start delayed fetch attempts - hardcoded for now. - $sql=' SELECT email_id,mail_host,mail_port,mail_protocol,mail_encryption,mail_delete,mail_errors,userid,userpass FROM '.EMAIL_TABLE. + $sql=' SELECT email_id,mail_host,mail_port,mail_protocol,mail_encryption,mail_delete,mail_archivefolder,mail_errors,userid,userpass FROM '.EMAIL_TABLE. ' WHERE mail_active=1 AND (mail_errors<='.$MAX_ERRORS.' OR (TIME_TO_SEC(TIMEDIFF(NOW(),mail_lasterror))>5*60) )'. ' AND (mail_lastfetch IS NULL OR TIME_TO_SEC(TIMEDIFF(NOW(),mail_lastfetch))>mail_fetchfreq*60) '; //echo $sql; @@ -396,7 +396,7 @@ class MailFetcher { $fetcher = new MailFetcher($row['userid'],Misc::decrypt($row['userpass'],SECRET_SALT), $row['mail_host'],$row['mail_port'],$row['mail_protocol'],$row['mail_encryption']); if($fetcher->connect()){ - $fetcher->fetchTickets($row['email_id'],$row['mail_fetchmax'],$row['mail_delete']?true:false); + $fetcher->fetchTickets($row['email_id'],$row['mail_fetchmax'],$row['mail_delete']?true:false,$row['mail_archivefolder']); $fetcher->close(); db_query('UPDATE '.EMAIL_TABLE.' SET mail_errors=0, mail_lastfetch=NOW() WHERE email_id='.db_input($row['email_id'])); }else{ diff --git a/include/class.mailparse.php b/include/class.mailparse.php index 88648367615c7141e2c87b4534f3df683d4ef081..f56006fa9c1e35c88d67165302a7797f43f562d7 100644 --- a/include/class.mailparse.php +++ b/include/class.mailparse.php @@ -50,8 +50,10 @@ class Mail_Parse { function splitBodyHeader() { - if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s",$this->mime_message, $match)) { - $this->header=$match[1]; + if (preg_match("/^(.*?)\r?\n\r?\n(.*)/s", + $this->mime_message, + $match)) { # nolint + $this->header=$match[1]; # nolint } } /** diff --git a/include/class.nav.php b/include/class.nav.php index a3b719f08d6bec16f6a2a7bb3fb264b1730c2f13..ce3623d37acccb57d0eae500360a5579789683b5 100644 --- a/include/class.nav.php +++ b/include/class.nav.php @@ -42,16 +42,16 @@ class StaffNav { function isStaffPanel() { return (!$this->isAdminPanel()); } - + function setTabActive($tab){ - + if($this->tabs[$tab]){ $this->tabs[$tab]['active']=true; if($this->activetab && $this->activetab!=$tab && $this->tabs[$this->activetab]) $this->tabs[$this->activetab]['active']=false; $this->activetab=$tab; - + return true; } @@ -73,9 +73,9 @@ class StaffNav { function getActiveMenu() { return $this->activeMenu; } - + function addSubMenu($item,$active=false){ - + $this->submenus[$this->getPanel().'.'.$this->activetab][]=$item; if($active) $this->activeMenu=sizeof($this->submenus[$this->getPanel().'.'.$this->activetab]); @@ -105,7 +105,7 @@ class StaffNav { $subnav[]=array('desc'=>'Tickets','href'=>'tickets.php','iconclass'=>'Ticket', 'droponly'=>true); if($staff) { if(($assigned=$staff->getNumAssignedTickets())) - $subnav[]=array('desc'=>"My Tickets ($assigned)", + $subnav[]=array('desc'=>"My Tickets ($assigned)", 'href'=>'tickets.php?status=assigned', 'iconclass'=>'assignedTickets', 'droponly'=>true); @@ -123,19 +123,19 @@ class StaffNav { $subnav[]=array('desc'=>'My Profile','href'=>'profile.php','iconclass'=>'users'); break; case 'kbase': - $subnav[]=array('desc'=>'Knowledgebase','href'=>'kb.php', 'urls'=>array('faq.php'), 'iconclass'=>'premade'); + $subnav[]=array('desc'=>'Knowledgebase','href'=>'kb.php', 'urls'=>array('faq.php'), 'iconclass'=>'kb'); if($staff) { if($staff->canManageFAQ()) - $subnav[]=array('desc'=>'Categories','href'=>'categories.php','iconclass'=>'premade'); + $subnav[]=array('desc'=>'Categories','href'=>'categories.php','iconclass'=>'kb-categories'); if($staff->canManageCannedResponses()) - $subnav[]=array('desc'=>'Canned Replies','href'=>'canned.php','iconclass'=>'premade'); + $subnav[]=array('desc'=>'Canned Replies','href'=>'canned.php','iconclass'=>'canned'); } break; } if($subnav) $submenus[$this->getPanel().'.'.strtolower($k)]=$subnav; } - + return $submenus; } @@ -170,7 +170,7 @@ class AdminNav extends StaffNav{ $tabs['depts']=array('desc'=>'Departments','href'=>'departments.php','title'=>'Departments'); $this->tabs=$tabs; } - + return $this->tabs; } @@ -226,12 +226,12 @@ class AdminNav extends StaffNav{ } class UserNav { - + var $navs=array(); var $activenav; var $user; - + function UserNav($user=null, $active=''){ $this->user=$user; @@ -257,7 +257,7 @@ class UserNav { function getNavLinks(){ global $cfg; - + //Paths are based on the root dir. if(!$this->navs){ diff --git a/include/class.pagenate.php b/include/class.pagenate.php index b182db517e579a9a7f4921a086e57825cea026a5..baad19b09fc6012fe352b5d7b4da3a251b73ee6f 100644 --- a/include/class.pagenate.php +++ b/include/class.pagenate.php @@ -15,37 +15,37 @@ **********************************************************************/ class PageNate { - var $start; - var $limit; - var $total; - var $page; - var $pages; - + var $start; + var $limit; + var $total; + var $page; + var $pages; + - function PageNate($total,$page,$limit=20,$url='') { - $this->total = intval($total); - $this->limit = max($limit, 1 ); - $this->page = max($page, 1 ); - $this->start = max((($page-1)*$this->limit),0); - $this->pages = ceil( $this->total / $this->limit ); - - if (($this->limit > $this->total) || ($this->page>ceil($this->total/$this->limit))) { - $this->start = 0; - } - if (($this->limit-1)*$this->start > $this->total) { - $this->start -= $this->start % $this->limit; - } - $this->setURL($url); - } - function setURL($url='',$vars=''){ - if($url){ - if(strpos($url,'?')===false) - $url=$url.'?'; - }else{ - $url=THISPAGE.'?'; - } - $this->url=$url.$vars; - } + function PageNate($total,$page,$limit=20,$url='') { + $this->total = intval($total); + $this->limit = max($limit, 1 ); + $this->page = max($page, 1 ); + $this->start = max((($page-1)*$this->limit),0); + $this->pages = ceil( $this->total / $this->limit ); + + if (($this->limit > $this->total) || ($this->page>ceil($this->total/$this->limit))) { + $this->start = 0; + } + if (($this->limit-1)*$this->start > $this->total) { + $this->start -= $this->start % $this->limit; + } + $this->setURL($url); + } + function setURL($url='',$vars=''){ + if($url){ + if(strpos($url,'?')===false) + $url=$url.'?'; + }else{ + $url=THISPAGE.'?'; + } + $this->url=$url.$vars; + } function getStart() { return $this->start; @@ -64,34 +64,34 @@ class PageNate { return ceil(($this->start+1)/$this->limit); } - function showing() { - $html = ''; - $from= $this->start+1; - if ($this->start + $this->limit < $this->total) { - $to= $this->start + $this->limit; - } else { - $to= $this->total; - } + function showing() { + $html = ''; + $from= $this->start+1; + if ($this->start + $this->limit < $this->total) { + $to= $this->start + $this->limit; + } else { + $to= $this->total; + } $html=" Showing "; - if ($this->total > 0) { + if ($this->total > 0) { $html .= "$from - $to of " .$this->total; - }else{ - $html .= " 0 "; - } - return $html; - } + }else{ + $html .= " 0 "; + } + return $html; + } - function getPageLinks() { - $html = ''; - $file =$this->url; - $displayed_span = 5; - $total_pages = ceil( $this->total / $this->limit ); - $this_page = ceil( ($this->start+1) / $this->limit ); + function getPageLinks() { + $html = ''; + $file =$this->url; + $displayed_span = 5; + $total_pages = ceil( $this->total / $this->limit ); + $this_page = ceil( ($this->start+1) / $this->limit ); $last=$this_page-1; $next=$this_page+1; - $start_loop = floor($this_page-$displayed_span); + $start_loop = floor($this_page-$displayed_span); $stop_loop = ceil($this_page + $displayed_span); @@ -107,14 +107,14 @@ class PageNate { $html .= "\n<a href=\"$file&p=$lastspan\" ><strong>«</strong></a>"; } - for ($i=$start_loop; $i <= $stop_loop; $i++) { - $page = ($i - 1) * $this->limit; - if ($i == $this_page) { - $html .= "\n<b>[$i]</b>"; - } else { - $html .= "\n<a href=\"$file&p=$i\" ><b>$i</b></a>"; - } - } + for ($i=$start_loop; $i <= $stop_loop; $i++) { + $page = ($i - 1) * $this->limit; + if ($i == $this_page) { + $html .= "\n<b>[$i]</b>"; + } else { + $html .= "\n<a href=\"$file&p=$i\" ><b>$i</b></a>"; + } + } if($stop_loop<$total_pages){ $nextspan=($stop_loop+$displayed_span>$total_pages)?$total_pages-$displayed_span:$stop_loop+$displayed_span; $html .= "\n<a href=\"$file&p=$nextspan\" ><strong>»</strong></a>"; @@ -122,8 +122,8 @@ class PageNate { - return $html; - } + return $html; + } } ?> diff --git a/include/class.staff.php b/include/class.staff.php index 878c0333efc1cc5ad8416dba744c02ebc0c379f5..00554157935ba0d82aa77596bf9c912f0fcf5ad5 100644 --- a/include/class.staff.php +++ b/include/class.staff.php @@ -177,7 +177,7 @@ class Staff { function getDept() { - if(!$this->dept && $this->getDeptIf()) + if(!$this->dept && $this->getDeptId()) $this->dept= Dept::lookup($this->getDeptId()); return $this->dept; @@ -220,7 +220,7 @@ class Staff { return $this->showAssignedOnly(); } - function isadmin() { + function isAdmin() { return ($this->ht['isadmin']); } @@ -261,7 +261,7 @@ class Staff { } function canManageTickets() { - return ($this->isadmin() + return ($this->isAdmin() || $this->canDeleteTickets() || $this->canCloseTickets()); } @@ -495,7 +495,7 @@ class Staff { } function login($username, $passwd, &$errors, $strike=true) { - global $cfg; + global $cfg, $session; if($_SESSION['_staff']['laststrike']) { @@ -552,7 +552,7 @@ class Staff { } function create($vars, &$errors) { - if(($id=self::save(0, $vars, $errors)) && $vars['teams'] && ($self=Staff::lookup($id))) + if(($id=self::save(0, $vars, $errors)) && $vars['teams'] && ($staff=Staff::lookup($id))) $staff->updateTeams($vars['teams']); return $id; @@ -623,6 +623,7 @@ class Staff { .' ,dept_id='.db_input($vars['dept_id']) .' ,group_id='.db_input($vars['group_id']) .' ,timezone_id='.db_input($vars['timezone_id']) + .' ,daylight_saving='.db_input(isset($vars['daylight_saving'])?1:0) .' ,username='.db_input($vars['username']) .' ,firstname='.db_input($vars['firstname']) .' ,lastname='.db_input($vars['lastname']) diff --git a/include/class.sys.php b/include/class.sys.php index ab10cd99442fa640bd36a6a329b6cc27e18f1b7f..33b5c830407f1b56fb1ef8eff47657e1296bb97a 100644 --- a/include/class.sys.php +++ b/include/class.sys.php @@ -96,7 +96,7 @@ class Sys { function purgeLogs(){ global $cfg; - if($cfg && ($gp=$cfg->getLogGraceperiod()) && is_numeric($gp)) { + if($cfg && ($gp=$cfg->getLogGracePeriod()) && is_numeric($gp)) { $sql='DELETE FROM '.SYSLOG_TABLE.' WHERE DATE_ADD(created, INTERVAL '.$gp.' MONTH)<=NOW()'; db_query($sql); } diff --git a/include/class.team.php b/include/class.team.php index 7aada43a3b13a6529822ef8a764ba958b7f838d8..b3f996d28fc658ed03d5e458679fc97953de000b 100644 --- a/include/class.team.php +++ b/include/class.team.php @@ -200,7 +200,6 @@ class Team { $sql='SET updated=NOW(),isenabled='.db_input($vars['isenabled']). ',name='.db_input($vars['name']). - ',isenabled='.db_input($vars['isenabled']). ',noalerts='.db_input(isset($vars['noalerts'])?$vars['noalerts']:0). ',notes='.db_input($vars['notes']); diff --git a/include/class.template.php b/include/class.template.php index ef53d7ed59ff1c404e525f2d903107118b923709..36d9b2f4845d3ca14ad564c9a8c829c11b9ab083 100644 --- a/include/class.template.php +++ b/include/class.template.php @@ -28,11 +28,12 @@ class Template { if(!$id && !($id=$this->getId())) return false; - + $sql='SELECT tpl.*,count(dept.tpl_id) as depts ' .' FROM '.EMAIL_TEMPLATE_TABLE.' tpl ' .' LEFT JOIN '.DEPT_TABLE.' dept USING(tpl_id) ' - .' WHERE tpl_id='.db_input($id); + .' WHERE tpl.tpl_id='.db_input($id) + .' GROUP BY tpl.tpl_id'; if(!($res=db_query($sql))|| !db_num_rows($res)) return false; diff --git a/include/class.ticket.php b/include/class.ticket.php index d01f438d791c6d5c104a594e65299ac2e5ce2deb..6a27d981bb24bdc7f05a6c8adec30615f0f7ed24 100644 --- a/include/class.ticket.php +++ b/include/class.ticket.php @@ -195,7 +195,8 @@ class Ticket{ if(!strcasecmp($client->getEmail(),$this->getEmail())) return true; - return ($cfg && $cfg->showRelatedTickets() && $client->getTicketId()==$ticket->getExtId()); + return ($cfg && $cfg->showRelatedTickets() + && $client->getTicketId()==$this->getExtId()); } //Getters @@ -526,68 +527,67 @@ class Ticket{ return $this->ht['notes']; } - function getNotes($order='') { + function getMessages() { + return $this->getThreadByType('M'); + } - if(!$order || !in_array($order, array('DESC','ASC'))) - $order='DESC'; - - $sql ='SELECT note.*, count(DISTINCT attach.attach_id) as attachments ' - .' FROM '.TICKET_THREAD_TABLE.' note ' - .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach - ON (note.ticket_id=attach.ticket_id AND note.id=attach.ref_id AND ref_type="N") ' - .' WHERE note.ticket_id='.db_input($this->getId()) - .' AND note.thread_type="N"' - .' GROUP BY note.id ' - .' ORDER BY note.created '.$order; - - $notes=array(); - if(($res=db_query($sql)) && db_num_rows($res)) - while($rec=db_fetch_array($res)) - $notes[]=$rec; + function getResponses($msgId=0) { + return $this->getThreadByType('R', $msgID); + } - return $notes; + function getNotes() { + return $this->getThreadByType('N'); } - function getMessages() { + function getClientThread() { + return $this->getThreadwithoutNotes(); + } - $sql='SELECT msg.id, msg.created, msg.body ' - .' ,count(DISTINCT attach.attach_id) as attachments ' - .' ,count( DISTINCT resp.id) as responses ' - .' FROM '.TICKET_THREAD_TABLE.' msg ' - .' LEFT JOIN '.TICKET_THREAD_TABLE.' resp ON (' - .'resp.pid=msg.id AND resp.thread_type = "R") ' - .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ' - .'ON (msg.ticket_id=attach.ticket_id AND msg.id=attach.ref_id AND ref_type="M") ' - .' WHERE msg.ticket_id='.db_input($this->getId()) - .' AND msg.thread_type="M"' - .' GROUP BY msg.id ' - .' ORDER BY msg.created ASC '; - - $messages=array(); - if(($res=db_query($sql)) && db_num_rows($res)) - while($rec=db_fetch_array($res)) - $messages[] = $rec; - - return $messages; + function getThreadWithNotes() { + return $this->getThread(true); + } + + function getThreadWithoutNotes() { + return $this->getThread(false); + } + + function getThread($includeNotes=false, $order='') { + + $treadtypes=array('M', 'R'); // messages and responses. + if($includeNotes) //Include notes?? + $treadtypes[] = 'N'; + + return $this->getThreadbyType($treadtypes, $order); } + + function getThreadByType($type, $order='ASC') { - function getResponses($msgId) { + if(!$order || !in_array($order, array('DESC','ASC'))) + $order='ASC'; - $sql='SELECT resp.*, count(DISTINCT attach.attach_id) as attachments ' - .' FROM '.TICKET_THREAD_TABLE. ' resp ' + $sql='SELECT thread.* ' + .' ,count(DISTINCT attach.attach_id) as attachments ' + .' FROM '.TICKET_THREAD_TABLE.' thread ' .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach - ON (resp.ticket_id=attach.ticket_id AND resp.id=attach.ref_id AND ref_type="R") ' - .' WHERE resp.ticket_id='.db_input($this->getId()) - .' AND resp.thread_type="R"' - .' GROUP BY resp.id ' - .' ORDER BY resp.created'; + ON (thread.ticket_id=attach.ticket_id + AND thread.id=attach.ref_id + AND thread.thread_type=attach.ref_type) ' + .' WHERE thread.ticket_id='.db_input($this->getId()); + + if($type && is_array($type)) + $sql.=" AND thread.thread_type IN('".implode("','", $type)."')"; + else + $sql.=' AND thread.thread_type='.db_input($type); - $responses=array(); + $sql.=' GROUP BY thread.id ' + .' ORDER BY thread.created '.$order; + + $thread=array(); if(($res=db_query($sql)) && db_num_rows($res)) - while($rec= db_fetch_array($res)) - $responses[] = $rec; - - return $responses; + while($rec=db_fetch_array($res)) + $thread[] = $rec; + + return $thread; } function getAttachments($refId=0, $type=null) { @@ -648,7 +648,7 @@ class Ticket{ .', priority_id='.db_input($priorityId) .' WHERE ticket_id='.db_input($this->getId()); - return (db_query($sql) && db_affected_rows($res)); + return (($res=db_query($sql)) && db_affected_rows($res)); } //DeptId can NOT be 0. No orphans please! @@ -801,7 +801,7 @@ class Ticket{ //TODO: log reopen event here - $this->logEvent('reopened'); + $this->logEvent('reopened', 'closed'); return (db_query($sql) && db_affected_rows()); } @@ -891,7 +891,7 @@ class Ticket{ $msg=sprintf('Max open tickets (%d) reached for %s ', $cfg->getMaxOpenTickets(), $this->getEmail()); sys::log(LOG_WARNING, 'Max. Open Tickets Limit ('.$this->getEmail().')', $msg); - if(!$sendNotice || !$cfg->sendOverlimitNotice()) return true; + if(!$sendNotice || !$cfg->sendOverLimitNotice()) return true; //Send notice to user. $dept = $this->getDept(); @@ -971,14 +971,14 @@ class Ticket{ $email=$cfg->getDefaultEmail(); if($email) { - $email->send($this->getEMail(),$subj,$body); + $email->send($this->getEmail(),$subj,$body); } } } function onAssign($note, $alert=true) { - global $cfg; + global $cfg, $thisstaff; if($this->isClosed()) $this->reopen(); //Assigned tickets must be open - otherwise why assign? @@ -1014,12 +1014,12 @@ class Ticket{ $recipients=array(); //Assigned staff or team... if any // Assigning a ticket to a team when already assigned to staff disables alerts to the team (!)) - if($cfg->alertStaffONAssign() && $this->getStaffId()) + if($cfg->alertStaffONAssignment() && $this->getStaffId()) $recipients[]=$this->getStaff(); elseif($this->getTeamId() && ($team=$this->getTeam())) { - if($cfg->alertTeamMembersOnAssignment() && ($members=$team->getMembers())) + if($cfg->alertTeamMembersONAssignment() && ($members=$team->getMembers())) $recipients+=$members; - elseif($cfg->alertTeamLeadOnAssignment() && ($lead=$team->getTeamLead())) + elseif($cfg->alertTeamLeadONAssignment() && ($lead=$team->getTeamLead())) $recipients[]=$lead; } //Send the alerts. @@ -1035,7 +1035,7 @@ class Ticket{ return true; } - function onOverdue($whine=true) { + function onOverdue($whine=true, $comments="") { global $cfg; if($whine && ($sla=$this->getSLA()) && !$sla->alertOnOverdue()) @@ -1045,8 +1045,9 @@ class Ticket{ if(!$whine || !$cfg->alertONOverdueTicket()) return true; - //Get template. - if(!($tpl = $dept->getTemplate())) + $dept = $this->getDept(); + //Get department-defined or default template. + if(!$dept || !($tpl = $dept->getTemplate())) $tpl= $cfg->getDefaultTemplate(); //Email to use! @@ -1308,7 +1309,7 @@ class Ticket{ if ($emsgid !== null) { $sql='INSERT INTO '.TICKET_EMAIL_INFO_TABLE - .' SET msg_id='.db_input($msgid) + .' SET message_id='.db_input($msgid) .', email_mid='.db_input($emsgid) .', headers='.db_input($headers); @@ -1385,7 +1386,7 @@ class Ticket{ .' ,pid='.db_input($vars['msgId']) .' ,body='.db_input(Format::striptags($vars['response'])) .' ,staff_id='.db_input($thisstaff->getId()) - .' ,staff_name='.db_input($thisstaff->getName()) + .' ,poster='.db_input($thisstaff->getName()) .' ,ip_address='.db_input($thisstaff->getIP()); if(!db_query($sql) || !($respId=db_insert_id())) @@ -1413,16 +1414,17 @@ class Ticket{ $this->onResponse(); //do house cleaning.. $this->reload(); - $dept = $this->getDept(); /* email the user?? - if disabled - the bail out */ if(!$alert) return $respId; + $dept = $this->getDept(); + if(!($tpl = $dept->getTemplate())) $tpl= $cfg->getDefaultTemplate(); - if(!($email=$cfg->getAlertEmail())) - $email =$cfg->getDefaultEmail(); + if(!$dept || !($email=$dept->getEmail())) + $email = $cfg->getDefaultEmail(); if($tpl && ($msg=$tpl->getReplyMsgTemplate()) && $email) { $body=$this->replaceTemplateVars($msg['body']); @@ -1461,13 +1463,21 @@ class Ticket{ } // History log -- used for statistics generation (pretty reports) - function logEvent($state, $staff=null) { + function logEvent($state, $annul=null, $staff=null) { global $thisstaff; if ($staff === null) { if ($thisstaff) $staff=$thisstaff->getUserName(); else $staff='SYSTEM'; # XXX: Security Violation ? } + # Annul previous entries if requested (for instance, reopening a + # ticket will annul an 'closed' entry). This will be useful to + # easily prevent repeated statistics. + if ($annul) { + db_query('UPDATE '.TICKET_EVENT_TABLE.' SET annulled=1' + .' WHERE ticket_id='.db_input($this->getId()) + .' AND state='.db_input($annul)); + } return db_query('INSERT INTO '.TICKET_EVENT_TABLE .' SET ticket_id='.db_input($this->getId()) @@ -1708,7 +1718,7 @@ class Ticket{ return 0; $sql='SELECT ticket.ticket_id FROM '.TICKET_TABLE. ' ticket '. - ' LEFT JOIN '.TICKE_THREAD_TABLE.' msg USING(ticket_id) '. + ' LEFT JOIN '.TICKET_THREAD_TABLE.' msg USING(ticket_id) '. ' INNER JOIN '.TICKET_EMAIL_INFO_TABLE.' emsg ON (msg.id = emsg.message_id) '. ' WHERE email_mid='.db_input($mid).' AND email='.db_input($email); $id=0; @@ -1809,7 +1819,7 @@ class Ticket{ if($cfg->getMaxOpenTickets()>0 && strcasecmp($origin,'staff') && ($client=Client::lookupByEmail($vars['email'])) && ($openTickets=$client->getNumOpenTickets()) - && ($opentickets>=$cfg->getMaxOpenTickets()) ) { + && ($openTickets>=$cfg->getMaxOpenTickets()) ) { $errors['err']="You've reached the maximum open tickets allowed."; Sys::log(LOG_WARNING, 'Ticket denied -'.$vars['email'], @@ -2012,8 +2022,8 @@ class Ticket{ else $vars['message']=$vars['issue']; - if($var['source'] && !in_array(strtolower($var['source']),array('email','phone','other'))) - $errors['source']='Invalid source - '.Format::htmlchars($var['source']); + if($vars['source'] && !in_array(strtolower($vars['source']),array('email','phone','other'))) + $errors['source']='Invalid source - '.Format::htmlchars($vars['source']); if(!($ticket=Ticket::create($vars, $errors, 'staff', false, (!$vars['assignId'])))) return false; @@ -2031,7 +2041,7 @@ class Ticket{ } } //Post Internal note - if($var['assignId'] && $thisstaff->canAssignTickets()) { //Assign ticket to staff or team. + if($vars['assignId'] && $thisstaff->canAssignTickets()) { //Assign ticket to staff or team. $ticket->assign($vars['assignId'],$vars['note']); } elseif($vars['note']) { //Not assigned...save optional note if any $ticket->postNote('New Ticket',$vars['note'],false); diff --git a/include/class.validator.php b/include/class.validator.php index ea2dc62d0e079513940885b8f1734c4025bb178f..d41bf027fe826c855893146dfee680c578598feb 100644 --- a/include/class.validator.php +++ b/include/class.validator.php @@ -147,20 +147,21 @@ class Validator { $urlregex = "^(https?)\:\/\/"; // USER AND PASS (optional) - $urlregex .= "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?"; + $urlregex .= "([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?"; # nolint // HOSTNAME OR IP - $urlregex .= "[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)*"; // http://x = allowed (ex. http://localhost, http://routerlogin) + // http://x = allowed (ex. http://localhost, http://routerlogin) + $urlregex .= "[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)*"; # nolint //$urlregex .= "[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)+"; // http://x.x = minimum //$urlregex .= "([a-z0-9+\$_-]+\.)*[a-z0-9+\$_-]{2,3}"; // http://x.xx(x) = minimum //use only one of the above // PORT (optional) $urlregex .= "(\:[0-9]{2,5})?"; // PATH (optional) - $urlregex .= "(\/([a-z0-9+\$_-]\.?)+)*\/?"; + $urlregex .= "(\/([a-z0-9+\$_-]\.?)+)*\/?"; # nolint // GET Query (optional) - $urlregex .= "(\?[a-z+&\$_.-][a-z0-9;:@/&%=+\$_.-]*)?"; + $urlregex .= "(\?[a-z+&\$_.-][a-z0-9;:@/&%=+\$_.-]*)?"; # nolint // ANCHOR (optional) - $urlregex .= "(#[a-z_.-][a-z0-9+\$_.-]*)?\$"; + $urlregex .= "(#[a-z_.-][a-z0-9+\$_.-]*)?\$"; # nolint return eregi($urlregex, $url)?true:false; } diff --git a/include/client/faq.inc.php b/include/client/faq.inc.php index c944f8316f58fb1b1ff59854bb7a63c05d505de5..65f770e9673083d2474d2a9eb260771492541d41 100644 --- a/include/client/faq.inc.php +++ b/include/client/faq.inc.php @@ -6,7 +6,7 @@ $category=$faq->getCategory(); ?> <h1>Frequently Asked Questions</h1> <div id="breadcrumbs"> - <a href="index.php">All Categories</a> + <a href="index.php">All Categories</a> » <a href="faq.php?cid=<? echo $category->getId(); ?>"><? echo $category->getName(); ?></a> </div> <div style="width:700;padding-top:2px; float:left;"> @@ -23,7 +23,8 @@ if($faq->getNumAttachments()) { ?> <div><span class="faded"><b>Attachments:</b></span> <?php echo $faq->getAttachmentsLinks(); ?></div> <? }?> -<div><span class="faded"><b>Help Topics:</b></span> + +<div class="article-meta"><span class="faded"><b>Help Topics:</b></span> <?php echo ($topics=$faq->getHelpTopics())?implode(', ',$topics):' '; ?> </div> </p> diff --git a/include/client/header.inc.php b/include/client/header.inc.php index beefb3bf3c74581da257a6ef684ed5553d5d96c1..969e9e66b8d977256e8087fc8cba2dadebb8fc62 100644 --- a/include/client/header.inc.php +++ b/include/client/header.inc.php @@ -9,7 +9,7 @@ header("Content-Type: text/html; charset=UTF-8\r\n"); <title><?php echo Format::htmlchars($title); ?></title> <meta name="description" content="customer support platform"> <meta name="keywords" content="osTicket, Customer support system, support ticket system"> - <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> + <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <link rel="stylesheet" href="<?php echo ASSETS_PATH; ?>css/theme.css" media="screen"> <link rel="stylesheet" href="<?php echo ASSETS_PATH; ?>css/print.css" media="print"> <script src="./js/jquery-1.7.2.min.js"></script> @@ -21,19 +21,19 @@ header("Content-Type: text/html; charset=UTF-8\r\n"); <a id="logo" href="<?php echo ROOT_PATH; ?>index.php" title="Support Center"><img src="<?php echo ASSETS_PATH; ?>images/logo.png" border=0 alt="Support Center"></a> <p> <?php - if($thisclient && is_object($thisclient) && $thisclient->isValid()) { + if($thisclient && is_object($thisclient) && $thisclient->isValid()) { echo $thisclient->getName().' - '; ?> <?php if($cfg->showRelatedTickets()) {?> - <a href="<?php echo ROOT_PATH; ?>tickets.php">My Tickets <b>(<?php echo $thisclient->getNumTickets(); ?>)</b></a> - + <a href="<?php echo ROOT_PATH; ?>tickets.php">My Tickets <b>(<?php echo $thisclient->getNumTickets(); ?>)</b></a> - <?php } ?> <a href="<?php echo ROOT_PATH; ?>logout.php">Log Out</a> - <?php + <?php }elseif($nav){ ?> Guest User - <a href="<?php echo ROOT_PATH; ?>login.php">Log In</a> - <?php + <?php } ?> </p> </div> @@ -47,14 +47,13 @@ header("Content-Type: text/html; charset=UTF-8\r\n"); } } ?> </ul> - <div id="content"> <?php }else{ ?> <hr> - <div id="cnbg"> <?php } ?> - + <div id="content"> + <?php if($errors['err']) { ?> <div id="msg_error"><?php echo $errors['err']; ?></div> <?php }elseif($msg) { ?> diff --git a/include/client/knowledgebase.inc.php b/include/client/knowledgebase.inc.php index 83484e95de818d732a67fed39b980fd5e9262e95..d8f402e7b5d191b224dc638b54f3a3177bddce85 100644 --- a/include/client/knowledgebase.inc.php +++ b/include/client/knowledgebase.inc.php @@ -3,61 +3,53 @@ if(!defined('OSTCLIENTINC')) die('Access Denied'); ?> <h1>Frequently Asked Questions</h1> -<form action="index.php" method="get" style="padding-top:15px;"> +<form action="index.php" method="get" id="kb-search"> <input type="hidden" name="a" value="search"> - <table border="0" cellspacing="0" cellpadding="3"> - <tr> - <td width="440"> - <input id="query" type="text" size="20" name="q" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> - <select name="cid"> - <option value="">— All Categories —</option> - <?php - $sql='SELECT category_id, name, count(faq.category_id) as faqs ' - .' FROM '.FAQ_CATEGORY_TABLE.' cat ' - .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) ' - .' WHERE cat.ispublic=1 AND faq.ispublished=1 ' - .' GROUP BY cat.category_id ' - .' HAVING faqs>0 ' - .' ORDER BY cat.name DESC '; - if(($res=db_query($sql)) && db_num_rows($res)) { - while($row=db_fetch_array($res)) - echo sprintf('<option value="%d" %s>%s (%d)</option>', - $row['category_id'], - ($_REQUEST['cid'] && $row['category_id']==$_REQUEST['cid']?'selected="selected"':''), - $row['name'], - $row['faqs']); - } - ?> - </select> - </td> - <td width="100" rowspan="2" style="text-align:left;vertical-align: middle;"> - <input id="searchSubmit" type="submit" value="Search"> - </td> - </tr> - <tr> - <td width="400"> - <select name="topicId" style="width:350px;"> - <option value="">— All Help Topics —</option> - <?php - $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs ' - .' FROM '.TOPIC_TABLE.' ht ' - .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) ' - .' WHERE ht.ispublic=1 ' - .' GROUP BY ht.topic_id ' - .' HAVING faqs>0 ' - .' ORDER BY ht.topic DESC '; - if(($res=db_query($sql)) && db_num_rows($res)) { - while($row=db_fetch_array($res)) - echo sprintf('<option value="%d" %s>%s (%d)</option>', - $row['topic_id'], - ($_REQUEST['topicId'] && $row['topic_id']==$_REQUEST['topicId']?'selected="selected"':''), - $row['topic'], $row['faqs']); - } - ?> - </select> - </td> - </tr> - </table> + <div> + <input id="query" type="text" size="20" name="q" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> + <select name="cid" id="cid"> + <option value="">— All Categories —</option> + <?php + $sql='SELECT category_id, name, count(faq.category_id) as faqs ' + .' FROM '.FAQ_CATEGORY_TABLE.' cat ' + .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) ' + .' WHERE cat.ispublic=1 AND faq.ispublished=1 ' + .' GROUP BY cat.category_id ' + .' HAVING faqs>0 ' + .' ORDER BY cat.name DESC '; + if(($res=db_query($sql)) && db_num_rows($res)) { + while($row=db_fetch_array($res)) + echo sprintf('<option value="%d" %s>%s (%d)</option>', + $row['category_id'], + ($_REQUEST['cid'] && $row['category_id']==$_REQUEST['cid']?'selected="selected"':''), + $row['name'], + $row['faqs']); + } + ?> + </select> + <input id="searchSubmit" type="submit" value="Search"> + </div> + <div> + <select name="topicId" id="topic-id"> + <option value="">— All Help Topics —</option> + <?php + $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs ' + .' FROM '.TOPIC_TABLE.' ht ' + .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) ' + .' WHERE ht.ispublic=1 ' + .' GROUP BY ht.topic_id ' + .' HAVING faqs>0 ' + .' ORDER BY ht.topic DESC '; + if(($res=db_query($sql)) && db_num_rows($res)) { + while($row=db_fetch_array($res)) + echo sprintf('<option value="%d" %s>%s (%d)</option>', + $row['topic_id'], + ($_REQUEST['topicId'] && $row['topic_id']==$_REQUEST['topicId']?'selected="selected"':''), + $row['topic'], $row['faqs']); + } + ?> + </select> + </div> </form> <hr> <div> @@ -100,9 +92,10 @@ if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search. echo '<div>Click on the category to browse FAQs.</div> <ul id="kb">'; while($row=db_fetch_array($res)) { - + echo sprintf(' <li> + <i></i> <h4><a href="faq.php?cid=%d">%s (%d)</a></h4> %s </li>',$row['category_id'], diff --git a/include/client/view.inc.php b/include/client/view.inc.php index f67e6d94bd3a4456e30b17797254dff49204b960..debddc4ed4713aeb3dec50b48e1fcb5bfe2f9ccc 100644 --- a/include/client/view.inc.php +++ b/include/client/view.inc.php @@ -59,46 +59,25 @@ if(!$dept || !$dept->isPublic()) <span class="Icon thread">Ticket Thread</span> <div id="ticketThread"> <?php -if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) { - - foreach($messages as $message) {?> - - <table class="message" cellspacing="0" cellpadding="1" width="800" border="0"> - - <tr><th><?php echo Format::db_datetime($message['created']); ?></th></tr> - - <tr><td><?php echo Format::display($message['body']); ?></td></tr> - +if($ticket->getThreadCount() && ($thread=$ticket->getClientThread())) { + $threadType=array('M' => 'message', 'R' => 'response'); + foreach($thread as $entry) { + //Making sure internal notes are not displayed due to backend MISTAKES! + if(!$threadType[$entry['thread_type']]) continue; + $poster = $entry['poster']; + if($entry['thread_type']=='R' && $cfg->hideStaffName()) + $poster = ' '; + ?> + <table class="<?php echo $threadType[$entry['thread_type']]; ?>" cellspacing="0" cellpadding="1" width="800" border="0"> + <tr><th><?php echo Format::db_datetime($entry['created']); ?> <span><?php echo $poster; ?></span></th></tr> + <tr><td><?php echo Format::display($entry['body']); ?></td></tr> <?php - - if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['id'],'M'))) { ?> - + if($entry['attachments'] && ($links=$ticket->getAttachmentsLinks($entry['id'], $entry['thread_type']))) { ?> <tr><td class="info"><?php echo $links; ?></td></tr> - <?php - } ?> - </table> - <?php - if($message['responses'] && ($responses=$ticket->getResponses($message['id']))) { - foreach($responses as $resp) { - $staff=$cfg->hideStaffName()?'staff':Format::htmlchars($resp['staff_name']); - ?> - <table class="response" cellspacing="0" cellpadding="1" width="100%" border="0"> - <tr> - <th><?php echo Format::db_datetime($resp['created']);?> - <?php echo $staff; ?></th> - </tr> - <tr><td><?php echo Format::display($resp['body']); ?></td></tr> - <?php - if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['id'],'R'))) {?> - <tr><td class="info"><?php echo $links; ?></td></tr> - <?php - }?> - </table> - <? - } - } + <?php } } ?> diff --git a/include/mysql.php b/include/mysql.php index 192859af970722c9127e1c57c7596085e98290f5..47f5ab5c8854e7ce4f6cdea47cd5ebd7dccd2fc4 100644 --- a/include/mysql.php +++ b/include/mysql.php @@ -46,8 +46,10 @@ function db_version(){ $version=0; - if(preg_match('/(\d{1,2}\.\d{1,2}\.\d{1,2})/', mysql_result(db_query('SELECT VERSION()'),0,0),$matches)) - $version=$matches[1]; + if(preg_match('/(\d{1,2}\.\d{1,2}\.\d{1,2})/', + mysql_result(db_query('SELECT VERSION()'),0,0), + $matches)) # nolint + $version=$matches[1]; # nolint return $version; } diff --git a/include/pear/Mail/mimeDecode.php b/include/pear/Mail/mimeDecode.php index b7984d681e38a30e5e546d2846019b93b38f3c33..59b6e1923c32d5ea5a3816e5c14821b1913fd3bf 100644 --- a/include/pear/Mail/mimeDecode.php +++ b/include/pear/Mail/mimeDecode.php @@ -721,6 +721,7 @@ class Mail_mimeDecode extends PEAR $this->_decode_headers = FALSE; $headerlist =$this->_parseHeaders($this->_header); $to = ""; + $header = array(); if (!$headerlist) { return $this->raiseError("Message did not contain headers"); } diff --git a/include/staff/api.inc.php b/include/staff/api.inc.php deleted file mode 100644 index 21eac469162af3d2cc9652d8e8255f230ee18460..0000000000000000000000000000000000000000 --- a/include/staff/api.inc.php +++ /dev/null @@ -1,147 +0,0 @@ -<?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); - - -$info['phrase']=($errors && $_POST['phrase'])?Format::htmlchars($_POST['phrase']):$cfg->getAPIPassphrase(); -$select='SELECT * '; -$from='FROM '.API_KEY_TABLE; -$where=''; -$sortOptions=array('date'=>'created','ip'=>'ipaddr'); -$orderWays=array('DESC'=>'DESC','ASC'=>'ASC'); -//Sorting options... -if($_REQUEST['sort']) { - $order_column =$sortOptions[$_REQUEST['sort']]; -} - -if($_REQUEST['order']) { - $order=$orderWays[$_REQUEST['order']]; -} -$order_column=$order_column?$order_column:'ipaddr'; -$order=$order?$order:'ASC'; -$order_by=" ORDER BY $order_column $order "; - -$total=db_count('SELECT count(*) '.$from.' '.$where); -$pagelimit=1000;//No limit. TODO: Add limit. -$page=($_GET['p'] && is_numeric($_GET['p']))?$_GET['p']:1; -$pageNav=new Pagenate($total,$page,$pagelimit); -$pageNav->setURL('admin.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&order='.urlencode($_REQUEST['order'])); -$query="$select $from $where $order_by"; -//echo $query; -$result = db_query($query); -$showing=db_num_rows($result)?$pageNav->showing():''; -$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting.. -$deletable=0; -?> -<div class="msg">API Keys</div> -<hr> -<div><b><?php echo $showing; ?></b></div> - <table width="100%" border="0" cellspacing=1 cellpadding=2> - <form action="admin.php?t=api" method="POST" name="api" onSubmit="return checkbox_checker(document.forms['api'],1,0);"> - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='mass_process'> - <tr><td> - <table border="0" cellspacing=0 cellpadding=2 class="dtable" align="center" width="100%"> - <tr> - <th width="7px"> </th> - <th>API Key</th> - <th width="10" nowrap>Active</th> - <th width="100" nowrap> IP Address</th> - <th width="150" nowrap> - <a href="admin.php?t=api&sort=date&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Create Date <?php echo $negorder; ?>">Created</a></th> - </tr> - <?php - $class = 'row1'; - $total=0; - $active=$inactive=0; - $sids=($errors && is_array($_POST['ids']))?$_POST['ids']:null; - if($result && db_num_rows($result)): - $dtpl=$cfg->getDefaultTemplateId(); - while ($row = db_fetch_array($result)) { - $sel=false; - $disabled=''; - if($row['isactive']) - $active++; - else - $inactive++; - - if($sids && in_array($row['id'],$sids)){ - $class="$class highlight"; - $sel=true; - } - ?> - <tr class="<?php echo $class; ?>" id="<?php echo $row['id']; ?>"> - <td width=7px> - <input type="checkbox" name="ids[]" value="<?php echo $row['id']; ?>" <?php echo $sel?'checked':''; ?> - onClick="highLight(this.value,this.checked);"> - <td> <?php echo $row['apikey']; ?></td> - <td><?php echo $row['isactive']?'<b>Yes</b>':'No'; ?></td> - <td> <?php echo $row['ipaddr']; ?></td> - <td> <?php echo Format::db_datetime($row['created']); ?></td> - </tr> - <?php - $class = ($class =='row2') ?'row1':'row2'; - } //end of while. - else: //nothin' found!! ?> - <tr class="<?php echo $class; ?>"><td colspan=5><b>Query returned 0 results</b> <a href="admin.php?t=templates">Index list</a></td></tr> - <?php - endif; ?> - - </table> - </td></tr> - <?php - if(db_num_rows($result)>0): //Show options.. - ?> - <tr> - <td align="center"> - <?php - if($inactive) { ?> - <input class="button" type="submit" name="enable" value="Enable" - onClick='return confirm("Are you sure you want to ENABLE selected keys?");'> - <?php - } - if($active){ ?> - - <input class="button" type="submit" name="disable" value="Disable" - onClick='return confirm("Are you sure you want to DISABLE selected keys?");'> - <?php } ?> - - <input class="button" type="submit" name="delete" value="Delete" - onClick='return confirm("Are you sure you want to DELETE selected keys?");'> - </td> - </tr> - <?php - endif; - ?> - </form> - </table> - <br/> - <div class="msg">Add New IP</div> - <hr> - <div> - Add a new IP address. <font class="error"><?php echo $errors['ip']; ?></font> - <form action="admin.php?t=api" method="POST" > - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='add'> - New IP: - <input name="ip" size=30 value="<?php echo ($errors['ip'])?Format::htmlchars($_REQUEST['ip']):''; ?>" /> - <font class="error">* </font> - <input class="button" type="submit" name="add" value="Add"> - </form> - </div> - <br/> - <div class="msg">API Passphrase</div> - <hr> - <div> - Passphrase must be at least 3 words. Required to generate the api keys.<br/> - <form action="admin.php?t=api" method="POST" > - <input type=hidden name='t' value='api'> - <input type=hidden name='do' value='update_phrase'> - Phrase: - <input name="phrase" size=50 value="<?php echo Format::htmlchars($info['phrase']); ?>" /> - <font class="error">* <?php echo $errors['phrase']; ?></font> - <input class="button" type="submit" name="update" value="Submit"> - </form> - <br/><br/> - <div><i>Please note that changing the passprase does NOT invalidate existing keys. To regerate a key you need to delete and readd it.</i></div> - </div> - diff --git a/include/staff/apikey.inc.php b/include/staff/apikey.inc.php index 5a82ee39bf264a821de957a779c0a73087f78bd9..7bcac1cb03e257feb855fbf0436769b8b3a3650e 100644 --- a/include/staff/apikey.inc.php +++ b/include/staff/apikey.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($api && $_REQUEST['a']!='add'){ diff --git a/include/staff/apikeys.inc.php b/include/staff/apikeys.inc.php index d7063c749ce92c04cddc36f20902b88181ab51d4..3deccb941222f8d771eb120ea90ab7e27557203c 100644 --- a/include/staff/apikeys.inc.php +++ b/include/staff/apikeys.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT * FROM '.API_KEY_TABLE.' WHERE 1'; diff --git a/include/staff/attachment.inc.php b/include/staff/attachment.inc.php index 17819867e69a458517e7c312075c07ffe3eeb06c..5951b87c0b0788767b34c98d1a7290a7c1debcdd 100644 --- a/include/staff/attachment.inc.php +++ b/include/staff/attachment.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); //Get the config info. $config=($errors && $_POST)?Format::input($_POST):$cfg->getConfig(); ?> diff --git a/include/staff/banlist.inc.php b/include/staff/banlist.inc.php index ecef00ba4325e18339b4f733d82a34b38466b950..430b51f4835bbf7038941109621774b409485b2e 100644 --- a/include/staff/banlist.inc.php +++ b/include/staff/banlist.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin() || !$filter) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin() || !$filter) die('Access Denied'); $qstr=''; $select='SELECT rule.* '; diff --git a/include/staff/banrule.inc.php b/include/staff/banrule.inc.php index bd28d19dea8368b395122beeb861045205d7ddff..0560b4a4d6268961220dad69de5d7b73617afec2 100644 --- a/include/staff/banrule.inc.php +++ b/include/staff/banrule.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; diff --git a/include/staff/cannedreplies.inc.php b/include/staff/cannedreplies.inc.php index 601e27d37f49646b4043b57a717abb64cb626b96..39aaaae815a8479233e3959c26b4dc28764b1ef0 100644 --- a/include/staff/cannedreplies.inc.php +++ b/include/staff/cannedreplies.inc.php @@ -50,7 +50,7 @@ else <h2>Canned Replies</h2> </div> <div style="float:right;text-align:right;padding-top:5px;padding-right:5px;"> - <b><a href="canned.php?a=add" class="Icon newHelpTopic">Add New Reply</a></b></div> + <b><a href="canned.php?a=add" class="Icon newReply">Add New Reply</a></b></div> <div class="clear"></div> <form action="canned.php" method="POST" name="canned" onSubmit="return checkbox_checker(this,1,0);"> <input type="hidden" name="do" value="mass_process" > @@ -58,7 +58,7 @@ else <caption><?php echo $showing; ?></caption> <thead> <tr> - <th width="7"> </th> + <th width="7"> </th> <th width="500"><a <?php echo $title_sort; ?> href="canned.php?<?php echo $qstr; ?>&sort=title">Title</a></th> <th width="80"><a <?php echo $status_sort; ?> href="canned.php?<?php echo $qstr; ?>&sort=status">Status</a></th> <th width="200"><a <?php echo $dept_sort; ?> href="canned.php?<?php echo $qstr; ?>&sort=dept">Department</a></th> @@ -81,7 +81,7 @@ else ?> <tr id="<?php echo $row['canned_id']; ?>"> <td width=7px> - <input type="checkbox" name="ids[]" value="<?php echo $row['canned_id']; ?>" + <input type="checkbox" name="ids[]" value="<?php echo $row['canned_id']; ?>" <?php echo $sel?'checked="checked"':''; ?> <?php echo $default?'disabled="disabled"':''; ?> onClick="highLight(this.value,this.checked);"> </td> <td> diff --git a/include/staff/categories.inc.php b/include/staff/categories.inc.php index a437338c20a156550487faf891324e2a16406562..9e90869c0d24acd79eabced4a1eed76c133681cc 100644 --- a/include/staff/categories.inc.php +++ b/include/staff/categories.inc.php @@ -44,7 +44,7 @@ else <h2>FAQ Categories</h2> </div> <div style="float:right;text-align:right;padding-top:5px;padding-right:5px;"> - <b><a href="categories.php?a=add" class="Icon newHelpTopic">Add New Category</a></b></div> + <b><a href="categories.php?a=add" class="Icon newCategory">Add New Category</a></b></div> <div class="clear"></div> <form action="categories.php" method="POST" name="cat" onSubmit="return checkbox_checker(this,1,0);"> <input type="hidden" name="do" value="mass_process" > @@ -52,7 +52,7 @@ else <caption><?php echo $showing; ?></caption> <thead> <tr> - <th width="7"> </th> + <th width="7"> </th> <th width="500"><a <?php echo $name_sort; ?> href="categories.php?<?php echo $qstr; ?>&sort=name">Name</a></th> <th width="150"><a <?php echo $type_sort; ?> href="categories.php?<?php echo $qstr; ?>&sort=type">Type</a></th> <th width="80"><a <?php echo $faqs_sort; ?> href="categories.php?<?php echo $qstr; ?>&sort=faqs">FAQs</a></th> @@ -78,7 +78,7 @@ else ?> <tr id="<?php echo $row['category_id']; ?>"> <td width=7px> - <input type="checkbox" name="ids[]" value="<?php echo $row['category_id']; ?>" + <input type="checkbox" name="ids[]" value="<?php echo $row['category_id']; ?>" <?php echo $sel?'checked="checked"':''; ?> <?php echo $default?'disabled="disabled"':''; ?> onClick="highLight(this.value,this.checked);"> </td> <td><a href="categories.php?id=<?php echo $row['category_id']; ?>"><?php echo Format::truncate($row['name'],200); ?></a> </td> diff --git a/include/staff/department.inc.php b/include/staff/department.inc.php index fa32ec2795d1ab1635fa126ab639a5d1259f3258..521cee9bf9e9eb7446420c26c4e0ab03a1c3ad69 100644 --- a/include/staff/department.inc.php +++ b/include/staff/department.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($dept && $_REQUEST['a']!='add'){ diff --git a/include/staff/departments.inc.php b/include/staff/departments.inc.php index 805b7ec20706c7cbbfa1bb2dd331068aa3bc8154..71b702a0676cff5f6824c933fc458882fff9e991 100644 --- a/include/staff/departments.inc.php +++ b/include/staff/departments.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT dept.dept_id,dept_name,email.email_id,email.email,email.name as email_name,ispublic,count(staff.staff_id) as users '. diff --git a/include/staff/editticket.inc.php b/include/staff/editticket.inc.php deleted file mode 100644 index 20accf0e4d70883861b51e2c6518fa6bce060cdc..0000000000000000000000000000000000000000 --- a/include/staff/editticket.inc.php +++ /dev/null @@ -1,142 +0,0 @@ -<?php -if(!defined('OSTSCPINC') || !is_object($ticket) || !is_object($thisstaff) || !$thisstaff->isStaff()) die('Access Denied'); - -if(!($thisstaff->canEditTickets() || ($thisstaff->isManager() && $ticket->getDeptId()==$thisstaff->getDeptId()))) die('Access Denied. Perm error.'); - -if($_POST && $errors){ - $info=Format::input($_POST); -}else{ - $info=array('email'=>$ticket->getEmail(), - 'name' =>$ticket->getName(), - 'phone'=>$ticket->getPhone(), - 'phone_ext'=>$ticket->getPhoneExt(), - 'pri'=>$ticket->getPriorityId(), - 'topicId'=>$ticket->getTopicId(), - 'topic'=>$ticket->getHelpTopic(), - 'subject' =>$ticket->getSubject(), - 'duedate' =>$ticket->getDueDate()?(Format::userdate('m/d/Y',Misc::db2gmtime($ticket->getDueDate()))):'', - 'time'=>$ticket->getDueDate()?(Format::userdate('G:i',Misc::db2gmtime($ticket->getDueDate()))):'', - ); - /*Note: Please don't make me explain how dates work - it is torture. Trust me! */ -} - -?> -<div width="100%"> - <?php if($errors['err']) { ?> - <p align="center" id="errormessage"><?php echo $errors['err']; ?></p> - <?php }elseif($msg) { ?> - <p align="center" class="infomessage"><?php echo $msg; ?></p> - <?php }elseif($warn) { ?> - <p class="warnmessage"><?php echo $warn; ?></p> - <?php } ?> -</div> -<table width="100%" border="0" cellspacing=1 cellpadding=2> - <form action="tickets.php?id=<?php echo $ticket->getId(); ?>" method="post"> - <input type='hidden' name='id' value='<?php echo $ticket->getId(); ?>'> - <input type='hidden' name='a' value='update'> - <tr><td align="left" colspan=2 class="msg"> - Update Ticket #<?php echo $ticket->getExtId(); ?> (<a href="tickets.php?id=<?php echo $ticket->getId(); ?>" style="color:black;">View Ticket</a>)<br></td></tr> - <tr> - <td align="left" nowrap width="120"><b>Email Address:</b></td> - <td> - <input type="text" id="email" name="email" size="25" value="<?php echo $info['email']; ?>"> - <font class="error"><b>*</b> <?php echo $errors['email']; ?></font> - </td> - </tr> - <tr> - <td align="left" ><b>Full Name:</b></td> - <td> - <input type="text" id="name" name="name" size="25" value="<?php echo $info['name']; ?>"> - <font class="error"><b>*</b> <?php echo $errors['name']; ?></font> - </td> - </tr> - <tr> - <td align="left"><b>Subject:</b></td> - <td> - <input type="text" name="subject" size="35" value="<?php echo $info['subject']; ?>"> - <font class="error">* <?php echo $errors['subject']; ?></font> - </td> - </tr> - <tr> - <td align="left">Telephone:</td> - <td><input type="text" name="phone" size="25" value="<?php echo $info['phone']; ?>"> - Ext <input type="text" name="phone_ext" size="6" value="<?php echo $info['phone_ext']; ?>"> - <font class="error"> <?php echo $errors['phone']; ?></font></td> - </tr> - <tr height=1px><td align="left" colspan=2 > </td></tr> - <tr> - <td align="left" valign="top">Due Date:</td> - <td> - <i>Time is based on your time zone (GM <?php echo $thisstaff->getTZoffset(); ?>)</i> <font class="error"> <?php echo $errors['time']; ?></font><br> - <input id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('duedate')); return false;"><img src='images/cal.png'border=0 alt=""></a> - - <?php - $min=$hr=null; - if($info['time']) - list($hr,$min)=explode(':',$info['time']); - echo Misc::timeDropdown($hr,$min,'time'); - ?> - <font class="error"> <?php echo $errors['duedate']; ?></font> - </td> - </tr> - <?php - $sql='SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE.' ORDER BY priority_urgency DESC'; - if(($priorities=db_query($sql)) && db_num_rows($priorities)){ ?> - <tr> - <td align="left">Priority:</td> - <td> - <select name="pri"> - <?php - while($row=db_fetch_array($priorities)){ ?> - <option value="<?php echo $row['priority_id']; ?>" <?php echo $info['pri']==$row['priority_id']?'selected':''; ?> ><?php echo $row['priority_desc']; ?></option> - <?php } ?> - </select> - </td> - </tr> - <?php } ?> - - <?php - $services= db_query('SELECT topic_id,topic,isactive FROM '.TOPIC_TABLE.' ORDER BY topic'); - if($services && db_num_rows($services)){ ?> - <tr> - <td align="left" valign="top">Help Topic:</td> - <td> - <select name="topicId"> - <option value="0" selected >None</option> - <?php if(!$info['topicId'] && $info['topic']){ //old helptopic ?> - <option value="0" selected ><?php echo $info['topic']; ?> (deleted)</option> - <?php - } - while (list($topicId,$topic,$active) = db_fetch_row($services)){ - $selected = ($info['topicId']==$topicId)?'selected':''; - $status=$active?'Active':'Inactive'; - ?> - <option value="<?php echo $topicId; ?>"<?php echo $selected; ?>><?php echo $topic; ?> (<?php echo $status; ?>)</option> - <?php - } ?> - </select> - (optional)<font class="error"> <?php echo $errors['topicId']; ?></font> - </td> - </tr> - <?php - } ?> - <tr> - <td align="left" valign="top"><b>Internal Note:</b></td> - <td> - <i>Reasons for the edit.</i><font class="error"><b>* <?php echo $errors['note']; ?></b></font><br/> - <textarea name="note" cols="45" rows="5" wrap="soft"><?php echo $info['note']; ?></textarea></td> - </tr> - <tr height=2px><td align="left" colspan=2 > </td></tr> - <tr> - <td></td> - <td> - <input class="button" type="submit" name="submit_x" value="Update Ticket"> - <input class="button" type="reset" value="Reset"> - <input class="button" type="button" name="cancel" value="Cancel" onClick='window.location.href="tickets.php?id=<?php echo $ticket->getId(); ?>"'> - </td> - </tr> - </form> -</table> - diff --git a/include/staff/email.inc.php b/include/staff/email.inc.php index 4f2d695b09304c4dcd5fc850e32ede734c514bbf..2fd2b8857494c64c061524a5bd294e4433299ee4 100644 --- a/include/staff/email.inc.php +++ b/include/staff/email.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($email && $_REQUEST['a']!='add'){ diff --git a/include/staff/emails.inc.php b/include/staff/emails.inc.php index 65d34d7b9bfb0b10acd983bfe41e5671932d3060..8d5f221177051e484fcaff4457c5f9f60bffbc99 100644 --- a/include/staff/emails.inc.php +++ b/include/staff/emails.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT email.*,dept.dept_name as department,priority_desc as priority '. diff --git a/include/staff/filter.inc.php b/include/staff/filter.inc.php index 91f74501661cda00d97aada035b28559a9961d41..6f8cce2c41a1e6acd8f4810b3cdc7e643a9a4471 100644 --- a/include/staff/filter.inc.php +++ b/include/staff/filter.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $matches=array('name'=>"Sender's Name",'email'=>"Sender's Email",'subject'=>'Email Subject','body'=>'Email Body/Text','header'=>'Email Header'); $match_types=array('equal'=>'Equal','not_equal'=>'Not Equal','contains'=>'Contains','dn_contain'=>'Does Not Contain'); diff --git a/include/staff/filters.inc.php b/include/staff/filters.inc.php index fb8a48d268a7705d5eb3a49b4076a6dcdb3b0b17..b5534bdde77a12ffe88a8f2362046c5d2e64fce2 100644 --- a/include/staff/filters.inc.php +++ b/include/staff/filters.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT filter.*,count(rule.id) as rules '. diff --git a/include/staff/group.inc.php b/include/staff/group.inc.php index 87921a63cb18aad7a2c73ab73ab5a2c7fb3d8acd..afb574f5f3cea7ff161dc34e90c05fa77f955b51 100644 --- a/include/staff/group.inc.php +++ b/include/staff/group.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($group && $_REQUEST['a']!='add'){ diff --git a/include/staff/groups.inc.php b/include/staff/groups.inc.php index 15b9b6610916c203cdf25e902228dd8d5281ba5a..ed5e3638a8d0528908584ddfad5320d885a38e4d 100644 --- a/include/staff/groups.inc.php +++ b/include/staff/groups.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; diff --git a/include/staff/header.inc.php b/include/staff/header.inc.php index 58d4f28dcdf77cbe3fa184e8a4979982b01de0fe..46722948c5aae7309c921623dfeaa57aa2c32a0b 100644 --- a/include/staff/header.inc.php +++ b/include/staff/header.inc.php @@ -14,19 +14,20 @@ </style> <![endif]--> <script type="text/javascript" src="../js/jquery-1.7.2.min.js"></script> - <script type="text/javascript" src="./js/calendar.js"></script> + <script type="text/javascript" src="../js/jquery-ui-1.8.18.custom.min.js"></script> <script type="text/javascript" src="./js/tips.js"></script> <script type="text/javascript" src="./js/nicEdit.js"></script> <script type="text/javascript" src="./js/bootstrap-typeahead.js"></script> <script type="text/javascript" src="./js/scp.js"></script> <link rel="stylesheet" href="./css/scp.css" media="screen"> <link rel="stylesheet" href="./css/typeahead.css" media="screen"> + <link type="text/css" href="../css/ui-lightness/jquery-ui-1.8.18.custom.css" rel="stylesheet" /> </head> <body> <div id="container"> <div id="header"> <a href="index.php" id="logo">osTicket - Customer Support System</a> - <p id="info">Welcome back, <strong><?php echo $thisstaff->getUsername(); ?></strong> + <p id="info">Howdy, <strong><?php echo $thisstaff->getUserName(); ?></strong> <?php if($thisstaff->isAdmin() && !defined('ADMINPAGE')) { ?> | <a href="admin.php">Admin Panel</a> diff --git a/include/staff/helptopic.inc.php b/include/staff/helptopic.inc.php index ad9f808bcfd6afedfabec510dda920ca2abaae0a..c0fdcd34010266a802bbffdd3f31c741c36f0b9a 100644 --- a/include/staff/helptopic.inc.php +++ b/include/staff/helptopic.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($topic && $_REQUEST['a']!='add'){ diff --git a/include/staff/helptopics.inc.php b/include/staff/helptopics.inc.php index 27ffde9bdacac59c2687b30b5046dde4255b1537..b3d58c777517753e02b41d1aaa703ed6e5500c01 100644 --- a/include/staff/helptopics.inc.php +++ b/include/staff/helptopics.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT topic.*,dept.dept_name as department,priority_desc as priority '. diff --git a/include/staff/kb-categories.inc.php b/include/staff/kb-categories.inc.php index 0ab8b03fc1e6326eac435768954c049dc0b3aa64..eb673a735678e3ebd867f3019b34443822a4b178 100644 --- a/include/staff/kb-categories.inc.php +++ b/include/staff/kb-categories.inc.php @@ -3,59 +3,51 @@ if(!defined('OSTSTAFFINC') || !$thisstaff) die('Access Denied'); ?> <h2>Frequently Asked Questions</h2> -<form id="kbSearch" action="kb.php" method="get" style="padding-top:15px;"> +<form id="kbSearch" action="kb.php" method="get"> <input type="hidden" name="a" value="search"> - <table border="0" cellspacing="0" cellpadding="3"> - <tr> - <td width="440"> - <input id="query" type="text" size="20" name="q" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> - <select name="cid"> - <option value="">— All Categories —</option> - <?php - $sql='SELECT category_id, name, count(faq.category_id) as faqs ' - .' FROM '.FAQ_CATEGORY_TABLE.' cat ' - .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) ' - .' GROUP BY cat.category_id ' - .' HAVING faqs>0 ' - .' ORDER BY cat.name DESC '; - if(($res=db_query($sql)) && db_num_rows($res)) { - while($row=db_fetch_array($res)) - echo sprintf('<option value="%d" %s>%s (%d)</option>', - $row['category_id'], - ($_REQUEST['cid'] && $row['category_id']==$_REQUEST['cid']?'selected="selected"':''), - $row['name'], - $row['faqs']); - } - ?> - </select> - </td> - <td width="100" rowspan="2"> - <input id="searchSubmit" type="submit" value="Search"> - </td> - </tr> - <tr> - <td width="400"> - <select name="topicId" style="width:350px;"> - <option value="">— All Help Topics —</option> - <?php - $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs ' - .' FROM '.TOPIC_TABLE.' ht ' - .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) ' - .' GROUP BY ht.topic_id ' - .' HAVING faqs>0 ' - .' ORDER BY ht.topic DESC '; - if(($res=db_query($sql)) && db_num_rows($res)) { - while($row=db_fetch_array($res)) - echo sprintf('<option value="%d" %s>%s (%d)</option>', - $row['topic_id'], - ($_REQUEST['topicId'] && $row['topic_id']==$_REQUEST['cid']?'selected="selected"':''), - $row['topic'], $row['faqs']); - } - ?> - </select> - </td> - </tr> - </table> + <div> + <input id="query" type="text" size="20" name="q" value="<?php echo Format::htmlchars($_REQUEST['q']); ?>"> + <select name="cid" id="cid"> + <option value="">— All Categories —</option> + <?php + $sql='SELECT category_id, name, count(faq.category_id) as faqs ' + .' FROM '.FAQ_CATEGORY_TABLE.' cat ' + .' LEFT JOIN '.FAQ_TABLE.' faq USING(category_id) ' + .' GROUP BY cat.category_id ' + .' HAVING faqs>0 ' + .' ORDER BY cat.name DESC '; + if(($res=db_query($sql)) && db_num_rows($res)) { + while($row=db_fetch_array($res)) + echo sprintf('<option value="%d" %s>%s (%d)</option>', + $row['category_id'], + ($_REQUEST['cid'] && $row['category_id']==$_REQUEST['cid']?'selected="selected"':''), + $row['name'], + $row['faqs']); + } + ?> + </select> + <input id="searchSubmit" type="submit" value="Search"> + </div> + <div> + <select name="topicId" style="width:350px;" id="topic-id"> + <option value="">— All Help Topics —</option> + <?php + $sql='SELECT ht.topic_id, ht.topic, count(faq.topic_id) as faqs ' + .' FROM '.TOPIC_TABLE.' ht ' + .' LEFT JOIN '.FAQ_TOPIC_TABLE.' faq USING(topic_id) ' + .' GROUP BY ht.topic_id ' + .' HAVING faqs>0 ' + .' ORDER BY ht.topic DESC '; + if(($res=db_query($sql)) && db_num_rows($res)) { + while($row=db_fetch_array($res)) + echo sprintf('<option value="%d" %s>%s (%d)</option>', + $row['topic_id'], + ($_REQUEST['topicId'] && $row['topic_id']==$_REQUEST['cid']?'selected="selected"':''), + $row['topic'], $row['faqs']); + } + ?> + </select> + </div> </form> <hr> <div> @@ -96,7 +88,7 @@ if($_REQUEST['q'] || $_REQUEST['cid'] || $_REQUEST['topicId']) { //Search. echo '<div>Click on the category to browse FAQs.</div> <ul id="kb">'; while($row=db_fetch_array($res)) { - + echo sprintf(' <li> <h4><a href="kb.php?cid=%d">%s (%d)</a> - <span>%s</span></h4> diff --git a/include/staff/kb-category.inc.php b/include/staff/kb-category.inc.php index 65c428a2f703f0b58332bbd416426c50cec765e7..e7013192e995738c2f9be4f249c3292acac9ab53 100644 --- a/include/staff/kb-category.inc.php +++ b/include/staff/kb-category.inc.php @@ -11,23 +11,23 @@ if(!defined('OSTSTAFFINC') || !$category || !$thisstaff) die('Access Denied'); <div> <strong><?php echo $category->getName() ?></strong> <span>(<?php echo $category->isPublic()?'Public':'Internal'; ?>)</span> - <br> - <div class="faded"> Last updated <?php echo Format::db_daydatetime($category->getUpdateDate()); ?></div> + <time>Last updated <?php echo Format::db_daydatetime($category->getUpdateDate()); ?></time> </div> -<p> +<div class="cat-desc"> <?php echo Format::safe_html($category->getDescription()); ?> -</p> +</div> <?php if($thisstaff->canManageFAQ()) { - echo sprintf('<a href="categories.php?id=%d" class="Icon newHelpTopic">Edit Category</a> - | <a href="categories.php" class="Icon newHelpTopic">Delete Category</a> - | <a href="faq.php?cid=%d&a=add" class="Icon newHelpTopic">Add New FAQ</a>', + echo sprintf('<div class="cat-manage-bar"><a href="categories.php?id=%d" class="Icon editCategory">Edit Category</a> + <a href="categories.php" class="Icon deleteCategory">Delete Category</a> + <a href="faq.php?cid=%d&a=add" class="Icon newFAQ">Add New FAQ</a></div>', $category->getId(), $category->getId()); -} +} else { ?> <hr> <?php +} $sql='SELECT faq.faq_id, question, ispublished, count(attach.file_id) as attachments ' .' FROM '.FAQ_TABLE.' faq ' @@ -39,7 +39,7 @@ if(($res=db_query($sql)) && db_num_rows($res)) { <ol>'; while($row=db_fetch_array($res)) { echo sprintf(' - <li><a href="faq.php?id=%d" class="previewfaq">%s</a> - <span>%s</span></li>', + <li><a href="faq.php?id=%d" class="previewfaq">%s <span>- %s</span></a></li>', $row['faq_id'],$row['question'],$row['ispublished']?'Published':'Internal'); } echo ' </ol> diff --git a/include/staff/newticket.inc.php b/include/staff/newticket.inc.php deleted file mode 100644 index 42afb7c3e07ac579516750ac60b9826a19d0eb4e..0000000000000000000000000000000000000000 --- a/include/staff/newticket.inc.php +++ /dev/null @@ -1,224 +0,0 @@ -<?php -if(!defined('OSTSCPINC') || !is_object($thisstaff) || !$thisstaff->isStaff()) die('Access Denied'); -$info=($_POST && $errors)?Format::input($_POST):array(); //on error...use the post data -?> -<div width="100%"> - <?php if($errors['err']) { ?> - <p align="center" id="errormessage"><?php echo $errors['err']; ?></p> - <?php }elseif($msg) { ?> - <p align="center" class="infomessage"><?php echo $msg; ?></p> - <?php }elseif($warn) { ?> - <p class="warnmessage"><?php echo $warn; ?></p> - <?php } ?> -</div> -<table width="80%" border="0" cellspacing=1 cellpadding=2> - <form action="tickets.php" method="post" enctype="multipart/form-data"> - <input type='hidden' name='a' value='open'> - <tr><td align="left" colspan=2>Please fill in the form below to open a new ticket.</td></tr> - <tr> - <td align="left" nowrap width="20%"><b>Email Address:</b></td> - <td> - <input type="text" id="email" name="email" size="25" value="<?php echo $info['email']; ?>"> - <font class="error"><b>*</b> <?php echo $errors['email']; ?></font> - <?php if($cfg->notifyONNewStaffTicket()) { ?> - - <input type="checkbox" name="alertuser" <?php echo (!$errors || $info['alertuser'])? 'checked': ''; ?>>Send alert to user. - <?php } ?> - </td> - </tr> - <tr> - <td align="left" ><b>Full Name:</b></td> - <td> - <input type="text" id="name" name="name" size="25" value="<?php echo $info['name']; ?>"> - <font class="error"><b>*</b> <?php echo $errors['name']; ?></font> - </td> - </tr> - <tr> - <td align="left">Telephone:</td> - <td><input type="text" name="phone" size="25" value="<?php echo $info['phone']; ?>"> - Ext <input type="text" name="phone_ext" size="6" value="<?php echo $info['phone_ext']; ?>"> - <font class="error"> <?php echo $errors['phone']; ?></font></td> - </tr> - <tr height=2px><td align="left" colspan=2 > </td</tr> - <tr> - <td align="left"><b>Ticket Source:</b></td> - <td> - <select name="source"> - <option value="" selected >Select Source</option> - <option value="Phone" <?php echo ($info['source']=='Phone')?'selected':''; ?>>Phone</option> - <option value="Email" <?php echo ($info['source']=='Email')?'selected':''; ?>>Email</option> - <option value="Other" <?php echo ($info['source']=='Other')?'selected':''; ?>>Other</option> - </select> - <font class="error"><b>*</b> <?php echo $errors['source']; ?></font> - </td> - </tr> - <tr> - <td align="left"><b>Department:</b></td> - <td> - <select name="deptId"> - <option value="" selected >Select Department</option> - <?php - $services= db_query('SELECT dept_id,dept_name FROM '.DEPT_TABLE.' ORDER BY dept_name'); - while (list($deptId,$dept) = db_fetch_row($services)){ - $selected = ($info['deptId']==$deptId)?'selected':''; ?> - <option value="<?php echo $deptId; ?>"<?php echo $selected; ?>><?php echo $dept; ?></option> - <?php - } ?> - </select> - <font class="error"><b>*</b> <?php echo $errors['deptId']; ?></font> - </td> - </tr> - <tr> - <td align="left"><b>Subject:</b></td> - <td> - <input type="text" name="subject" size="35" value="<?php echo $info['subject']; ?>"> - <font class="error">* <?php echo $errors['subject']; ?></font> - </td> - </tr> - <tr> - <td align="left" valign="top"><b>Issue Summary:</b></td> - <td> - <i>Visible to client/customer.</i><font class="error"><b>* <?php echo $errors['issue']; ?></b></font><br/> - <?php - $sql='SELECT canned_id,title FROM '.CANNED_TABLE.' WHERE isenabled=1'; - - if(($res=db_query($sql)) && db_num_rows($res)) { - ?> - Premade: - <select id="canned" name="canned" - onChange="getCannedResponse(this.options[this.selectedIndex].value,this.form,'issue');this.selectedIndex='0';" > - <option value="0" selected="selected">Select a premade reply/issue</option> - <?php while(list($cannedId,$title)=db_fetch_row($res)) { ?> - <option value="<?php echo $cannedId; ?>" ><?php echo Format::htmlchars($title); ?></option> - <?php } ?> - </select> <label><input type='checkbox' value='1' name=append checked="true" />Append</label> - <?php } ?> - <textarea name="issue" cols="55" rows="8" wrap="soft"><?php echo $info['issue']; ?></textarea></td> - </tr> - <?php if($cfg->canUploadFiles()) { - ?> - <tr> - <td>Attachment:</td> - <td> - <input type="file" name="attachment"><font class="error"> <?php echo $errors['attachment']; ?></font> - </td> - </tr> - <?php } ?> - <tr> - <td align="left" valign="top">Internal Note:</td> - <td> - <i>Optional Internal note(s).</i><font class="error"><b> <?php echo $errors['note']; ?></b></font><br/> - <textarea name="note" cols="55" rows="5" wrap="soft"><?php echo $info['note']; ?></textarea></td> - </tr> - - <tr> - <td align="left" valign="top">Due Date:</td> - <td> - <i>Time is based on your time zone (GM <?php echo $thisstaff->getTZoffset(); ?>)</i> <font class="error"> <?php echo $errors['time']; ?></font><br> - <input id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('duedate')); return false;"><img src='images/cal.png'border=0 alt=""></a> - - <?php - $min=$hr=null; - if($info['time']) - list($hr,$min)=explode(':',$info['time']); - echo Misc::timeDropdown($hr,$min,'time'); - ?> - <font class="error"> <?php echo $errors['duedate']; ?></font> - </td> - </tr> - <?php - $sql='SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE.' ORDER BY priority_urgency DESC'; - if(($priorities=db_query($sql)) && db_num_rows($priorities)){ ?> - <tr> - <td align="left">Priority:</td> - <td> - <select name="pri"> - <?php - $info['pri']=$info['pri']?$info['pri']:$cfg->getDefaultPriorityId(); - while($row=db_fetch_array($priorities)){ ?> - <option value="<?php echo $row['priority_id']; ?>" <?php echo $info['pri']==$row['priority_id']?'selected':''; ?> ><?php echo $row['priority_desc']; ?></option> - <?php } ?> - </select> - </td> - </tr> - <?php } ?> - <?php - $services= db_query('SELECT topic_id,topic FROM '.TOPIC_TABLE.' WHERE isactive=1 ORDER BY topic'); - if($services && db_num_rows($services)){ ?> - <tr> - <td align="left" valign="top">Help Topic:</td> - <td> - <select name="topicId"> - <option value="" selected >Select One</option> - <?php - while (list($topicId,$topic) = db_fetch_row($services)){ - $selected = ($info['topicId']==$topicId)?'selected':''; ?> - <option value="<?php echo $topicId; ?>"<?php echo $selected; ?>><?php echo $topic; ?></option> - <?php - } ?> - </select> - <font class="error"> <?php echo $errors['topicId']; ?></font> - </td> - </tr> - <?php - } ?> - <tr> - <td>Assign To:</td> - <td> - <select id="staffId" name="staffId"> - <option value="0" selected="selected">-Assign To Staff-</option> - <?php - //TODO: make sure the user's group is also active....DO a join. - $sql=' SELECT staff_id,CONCAT_WS(", ",lastname,firstname) as name FROM '.STAFF_TABLE.' WHERE isactive=1 AND onvacation=0 '; - $depts= db_query($sql.' ORDER BY lastname,firstname '); - while (list($staffId,$staffName) = db_fetch_row($depts)){ - $selected = ($info['staffId']==$staffId)?'selected':''; ?> - <option value="<?php echo $staffId; ?>"<?php echo $selected; ?>><?php echo $staffName; ?></option> - <?php - } ?> - </select><font class='error'> <?php echo $errors['staffId']; ?></font> - - <input type="checkbox" name="alertstaff" <?php echo (!$errors || $info['alertstaff'])? 'checked': ''; ?>>Send alert to assigned staff. - </td> - </tr> - <tr> - <td>Signature:</td> - <td> <?php - $appendStaffSig=$thisstaff->appendMySignature(); - $info['signature']=!$info['signature']?'none':$info['signature']; //change 'none' to 'mine' to default to staff signature. - ?> - <div style="margin-top: 2px;"> - <label><input type="radio" name="signature" value="none" checked > None</label> - <?php if($appendStaffSig) { ?> - <label> <input type="radio" name="signature" value="mine" <?php echo $info['signature']=='mine'?'checked':''; ?> > My signature</label> - <?php } ?> - <label><input type="radio" name="signature" value="dept" <?php echo $info['signature']=='dept'?'checked':''; ?> > Dept Signature (if any)</label> - </div> - </td> - </tr> - <tr height=2px><td align="left" colspan=2 > </td</tr> - <tr> - <td></td> - <td> - <input class="button" type="submit" name="submit_x" value="Submit Ticket"> - <input class="button" type="reset" value="Reset"> - <input class="button" type="button" name="cancel" value="Cancel" onClick='window.location.href="tickets.php"'> - </td> - </tr> - </form> -</table> -<script type="text/javascript"> - - var options = { - script:"ajax.php?api=tickets&f=searchbyemail&limit=10&", - varname:"input", - json: true, - shownoresults:false, - maxresults:10, - callback: function (obj) { document.getElementById('email').value = obj.id; document.getElementById('name').value = obj.info; return false;} - }; - var autosug = new bsn.AutoSuggest('email', options); -</script> - diff --git a/include/staff/preference.inc.php b/include/staff/preference.inc.php index d956d011dff2c15ad87c7e023f69303a87034353..054d592a7555f8d16f436f9cc5c9c66a91b6f27b 100644 --- a/include/staff/preference.inc.php +++ b/include/staff/preference.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); //Get the config info. $config=($errors && $_POST)?Format::input($_POST):Format::htmlchars($cfg->getConfig()); diff --git a/include/staff/settings-tickets.inc.php b/include/staff/settings-tickets.inc.php index bcf7347a74cf6d5bf5e9c60cfbe1b28729bbaffd..5ada80f48bca4edfb7221e6916aa5e46efb85d94 100644 --- a/include/staff/settings-tickets.inc.php +++ b/include/staff/settings-tickets.inc.php @@ -1,140 +1,148 @@ -<form action="settings.php?t=tickets" method="post" id="save"> -<input type="hidden" name="t" value="tickets" > -<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2"> - <thead> - <tr> - <th colspan="2"> - <h4>Ticket Settings and Options</h4> - <em>Global ticket settings and options.</em> - </th> - </tr> - </thead> - <tbody> - <tr><td width="220" class="required">Ticket IDs:</td> - <td> - <input type="radio" name="random_ticket_ids" value="0" <?php echo !$config['random_ticket_ids']?'checked="checked"':''; ?> /> - Sequential - <input type="radio" name="random_ticket_ids" value="1" <?php echo $config['random_ticket_ids']?'checked="checked"':''; ?> /> - Random <em>(highly recommended)</em> - </td> - </tr> - - <tr> - <td width="180" class="required"> - Default SLA: - </td> - <td> - <select name="default_sla_id"> - <option value="0">— None —</option> - <?php - $sql='SELECT id,name FROM '.SLA_TABLE.' sla ORDER by name'; - if(($res=db_query($sql)) && db_num_rows($res)){ - while(list($id,$name)=db_fetch_row($res)){ - $selected=($config['default_sla_id'] && $id==$config['default_sla_id'])?'selected="selected"':''; - echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name); - } - } - ?> - </select> - <span class="error">* <?php echo $errors['default_sla_id']; ?></span> - </td> - </tr> - <tr> - <td width="180" class="required">Default Priority:</td> - <td> - <select name="default_priority_id"> +<form action="settings.php?t=tickets" method="post" id="save"> +<input type="hidden" name="t" value="tickets" > +<table class="form_table settings_table" width="940" border="0" cellspacing="0" cellpadding="2"> + <thead> + <tr> + <th colspan="2"> + <h4>Ticket Settings and Options</h4> + <em>Global ticket settings and options.</em> + </th> + </tr> + </thead> + <tbody> + <tr><td width="220" class="required">Ticket IDs:</td> + <td> + <input type="radio" name="random_ticket_ids" value="0" <?php echo !$config['random_ticket_ids']?'checked="checked"':''; ?> /> + Sequential + <input type="radio" name="random_ticket_ids" value="1" <?php echo $config['random_ticket_ids']?'checked="checked"':''; ?> /> + Random <em>(highly recommended)</em> + </td> + </tr> + + <tr> + <td width="180" class="required"> + Default SLA: + </td> + <td> + <select name="default_sla_id"> + <option value="0">— None —</option> <?php - $priorities= db_query('SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE); - while (list($id,$tag) = db_fetch_row($priorities)){ ?> - <option value="<?php echo $id; ?>"<?php echo ($config['default_priority_id']==$id)?'selected':''; ?>><?php echo $tag; ?></option> + $sql='SELECT id,name FROM '.SLA_TABLE.' sla ORDER by name'; + if(($res=db_query($sql)) && db_num_rows($res)){ + while(list($id,$name)=db_fetch_row($res)){ + $selected=($config['default_sla_id'] && $id==$config['default_sla_id'])?'selected="selected"':''; + echo sprintf('<option value="%d" %s>%s</option>',$id,$selected,$name); + } + } + ?> + </select> + <span class="error">* <?php echo $errors['default_sla_id']; ?></span> + </td> + </tr> + <tr> + <td width="180" class="required">Default Priority:</td> + <td> + <select name="default_priority_id"> <?php - } ?> - </select> - <span class="error">* <?php echo $errors['default_priority_id']; ?></span> - </td> - </tr> - <tr> - <td width="180">Web Tickets Priority</td> - <td> - <input type="checkbox" name="allow_priority_change" value="1" <?php echo $config['allow_priority_change'] ?'checked="checked"':''; ?>> - <em>(Allow user to overwrite/set priority)</em> - </td> - </tr> - <tr> - <td width="180">Emailed Tickets Priority</td> - <td> - <input type="checkbox" name="use_email_priority" value="1" <?php echo $config['use_email_priority'] ?'checked="checked"':''; ?> > - <em>(Use email priority when available)</em> - </td> - </tr> - <tr> - <td width="180">Show Related Tickets</td> - <td> - <input type="checkbox" name="show_related_tickets" value="1" <?php echo $config['show_related_tickets'] ?'checked="checked"':''; ?> > - <em>(Show all related tickets on user login - otherwise access is restricted to one ticket view per login)</em> - </td> - </tr> - <tr> - <td>Human Verification:</td> - <td> - <input type="checkbox" name="enable_captcha" <?php echo $config['enable_captcha']?'checked="checked"':''; ?>> - Enable CAPTCHA on new web tickets.<em>(requires GDLib)</em> <font class="error"> <?php echo $errors['enable_captcha']; ?></font><br/> - </td> - </tr> - <tr> - <td>Maximum <b>Open</b> Tickets:</td> - <td> - <input type="text" name="max_open_tickets" size=4 value="<?php echo $config['max_open_tickets']; ?>"> - per email/user. <em>(Helps with spam and email flood control - enter 0 for unlimited)</em> - </td> - </tr> - <tr> - <td>Ticket Auto-lock Time:</td> - <td> - <input type="text" name="autolock_minutes" size=4 value="<?php echo $config['autolock_minutes']; ?>"> - <font class="error"><?php echo $errors['autolock_minutes']; ?></font> - <em>(Minutes to lock a ticket on activity - enter 0 to disable locking)</em> - </td> - </tr> - <tr> - <td>Reopened Tickets:</td> - <td> - <input type="checkbox" name="auto_assign_reopened_tickets" <?php echo $config['auto_assign_reopened_tickets']?'checked="checked"':''; ?>> - Auto-assign reopened tickets to the last available respondent. - </td> - </tr> - <tr> - <td>Assigned Tickets:</td> - <td> - <input type="checkbox" name="show_assigned_tickets" <?php echo $config['show_assigned_tickets']?'checked="checked"':''; ?>> - Show assigned tickets on open queue. - </td> - </tr> - <tr> - <td>Answered Tickets:</td> - <td> - <input type="checkbox" name="show_answered_tickets" <?php echo $config['show_answered_tickets']?'checked="checked"':''; ?>> - Show answered tickets on open queue. - </td> - </tr> - <tr> - <td>Ticket Activity Log:</td> - <td> - <input type="checkbox" name="log_ticket_activity" <?php echo $config['log_ticket_activity']?'checked="checked"':''; ?>> - Log ticket activity as internal notes. - </td> - </tr> - <tr> - <td>Staff Identity Masking:</td> - <td> - <input type="checkbox" name="hide_staff_name" <?php echo $config['hide_staff_name']?'checked="checked"':''; ?>> - Hide staff's name on responses. - </td> - </tr> - </tbody> -</table> -<p style="padding-left:250px;"> - <input class="button" type="submit" name="submit" value="Save Changes"> - <input class="button" type="reset" name="reset" value="Reset Changes"> -</p> -</form> + $priorities= db_query('SELECT priority_id,priority_desc FROM '.TICKET_PRIORITY_TABLE); + while (list($id,$tag) = db_fetch_row($priorities)){ ?> + <option value="<?php echo $id; ?>"<?php echo ($config['default_priority_id']==$id)?'selected':''; ?>><?php echo $tag; ?></option> + <?php + } ?> + </select> + <span class="error">* <?php echo $errors['default_priority_id']; ?></span> + </td> + </tr> + <tr> + <td width="180">Web Tickets Priority</td> + <td> + <input type="checkbox" name="allow_priority_change" value="1" <?php echo $config['allow_priority_change'] ?'checked="checked"':''; ?>> + <em>(Allow user to overwrite/set priority)</em> + </td> + </tr> + <tr> + <td width="180">Emailed Tickets Priority</td> + <td> + <input type="checkbox" name="use_email_priority" value="1" <?php echo $config['use_email_priority'] ?'checked="checked"':''; ?> > + <em>(Use email priority when available)</em> + </td> + </tr> + <tr> + <td width="180">Show Related Tickets</td> + <td> + <input type="checkbox" name="show_related_tickets" value="1" <?php echo $config['show_related_tickets'] ?'checked="checked"':''; ?> > + <em>(Show all related tickets on user login - otherwise access is restricted to one ticket view per login)</em> + </td> + </tr> + <tr> + <td width="180">Show Notes Inline</td> + <td> + <input type="checkbox" name="show_notes_inline" value="1" <?php echo $config['show_notes_inline'] ?'checked="checked"':''; ?> > + <em>(Show internal notes inline)</em> + </td> + </tr> + <tr> + <td>Human Verification:</td> + <td> + <input type="checkbox" name="enable_captcha" <?php echo $config['enable_captcha']?'checked="checked"':''; ?>> + Enable CAPTCHA on new web tickets.<em>(requires GDLib)</em> <font class="error"> <?php echo $errors['enable_captcha']; ?></font><br/> + </td> + </tr> + <tr> + <td>Maximum <b>Open</b> Tickets:</td> + <td> + <input type="text" name="max_open_tickets" size=4 value="<?php echo $config['max_open_tickets']; ?>"> + per email/user. <em>(Helps with spam and email flood control - enter 0 for unlimited)</em> + </td> + </tr> + <tr> + <td>Ticket Auto-lock Time:</td> + <td> + <input type="text" name="autolock_minutes" size=4 value="<?php echo $config['autolock_minutes']; ?>"> + <font class="error"><?php echo $errors['autolock_minutes']; ?></font> + <em>(Minutes to lock a ticket on activity - enter 0 to disable locking)</em> + </td> + </tr> + <tr> + <td>Reopened Tickets:</td> + <td> + <input type="checkbox" name="auto_assign_reopened_tickets" <?php echo $config['auto_assign_reopened_tickets']?'checked="checked"':''; ?>> + Auto-assign reopened tickets to the last available respondent. + </td> + </tr> + <tr> + <td>Assigned Tickets:</td> + <td> + <input type="checkbox" name="show_assigned_tickets" <?php echo $config['show_assigned_tickets']?'checked="checked"':''; ?>> + Show assigned tickets on open queue. + </td> + </tr> + <tr> + <td>Answered Tickets:</td> + <td> + <input type="checkbox" name="show_answered_tickets" <?php echo $config['show_answered_tickets']?'checked="checked"':''; ?>> + Show answered tickets on open queue. + </td> + </tr> + <tr> + <td>Ticket Activity Log:</td> + <td> + <input type="checkbox" name="log_ticket_activity" <?php echo $config['log_ticket_activity']?'checked="checked"':''; ?>> + Log ticket activity as internal notes. + </td> + </tr> + <tr> + <td>Staff Identity Masking:</td> + <td> + <input type="checkbox" name="hide_staff_name" <?php echo $config['hide_staff_name']?'checked="checked"':''; ?>> + Hide staff's name on responses. + </td> + </tr> + </tbody> +</table> +<p style="padding-left:250px;"> + <input class="button" type="submit" name="submit" value="Save Changes"> + <input class="button" type="reset" name="reset" value="Reset Changes"> +</p> +</form> + diff --git a/include/staff/slaplan.inc.php b/include/staff/slaplan.inc.php index 91d896d639d688813389ed0582ecd800beb2a842..70db620e84d83dc66a53cf6c08e1d97ea2b31f24 100644 --- a/include/staff/slaplan.inc.php +++ b/include/staff/slaplan.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($sla && $_REQUEST['a']!='add'){ diff --git a/include/staff/slaplans.inc.php b/include/staff/slaplans.inc.php index 5dea61f69b8ccaeaec3b84411185fbe4a26da886..b8997b6a34be75b697624384e0e39006c5c16feb 100644 --- a/include/staff/slaplans.inc.php +++ b/include/staff/slaplans.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT * FROM '.SLA_TABLE.' sla WHERE 1'; diff --git a/include/staff/staff.inc.php b/include/staff/staff.inc.php index 8883397f51fe86c6b46c5207a099ad33ec50ec31..39651227105158adcadf5283517589ff8dc52ce8 100644 --- a/include/staff/staff.inc.php +++ b/include/staff/staff.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; @@ -210,7 +210,7 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); </tr> <tr> <td width="180" class="required"> - User Default Time Zone: + Staff's Time Zone: </td> <td> <select name="timezone_id" id="timezone_id"> @@ -228,6 +228,16 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); <span class="error">* <?php echo $errors['timezone_id']; ?></span> </td> </tr> + <tr> + <td width="180"> + Daylight Saving: + </td> + <td> + <input type="checkbox" name="daylight_saving" value="1" <?php echo $info['daylight_saving']?'checked="checked"':''; ?>> + Observe daylight saving + <em>(Current Time: <strong><?php echo Format::date($cfg->getDateTimeFormat(),Misc::gmtime(),$info['tz_offset'],$info['daylight_saving']); ?></strong>)</em> + </td> + </tr> <tr> <td width="180"> Limited Access: diff --git a/include/staff/staffmembers.inc.php b/include/staff/staffmembers.inc.php index aa41b1bbf4a00a6143bb8bd0961d8a8ab4a801b0..b01e3387ff28da3e2f8e419b4e728293fe851254 100644 --- a/include/staff/staffmembers.inc.php +++ b/include/staff/staffmembers.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $select='SELECT staff.*,CONCAT_WS(" ",firstname,lastname) as name, grp.group_name, dept.dept_name as dept,count(m.team_id) as teams '; $from='FROM '.STAFF_TABLE.' staff '. diff --git a/include/staff/syslogs.inc.php b/include/staff/syslogs.inc.php index 482dd429c3738faea83e49df05a09c8dd391a7e2..e0f5d2098717dfd360b16fce6959b4a222fd241b 100644 --- a/include/staff/syslogs.inc.php +++ b/include/staff/syslogs.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; if($_REQUEST['type']) { @@ -45,9 +45,10 @@ if( ($startTime && $startTime>time()) or ($startTime>$endTime && $endTime>0)){ $qstr.='&endDate='.urlencode($_REQUEST['endDate']); } } -$sortOptions=array('title'=>'log.title','type'=>'log_type','ip'=>'log.ip_address','date'=>'log.created','created'=>'log.created','updated'=>'log.updated'); +$sortOptions=array('id'=>'log.log_id', 'title'=>'log.title','type'=>'log_type','ip'=>'log.ip_address' + ,'date'=>'log.created','created'=>'log.created','updated'=>'log.updated'); $orderWays=array('DESC'=>'DESC','ASC'=>'ASC'); -$sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'date'; +$sort=($_REQUEST['sort'] && $sortOptions[strtolower($_REQUEST['sort'])])?strtolower($_REQUEST['sort']):'id'; //Sorting options... if($sort && $sortOptions[$sort]) { $order_column =$sortOptions[$sort]; @@ -87,13 +88,9 @@ else <form action="syslogs.php" method="get"> <div style="padding-left:2px;"> <b>Date Span</b>: - From <input class="dp" id="sd" size=15 name="startDate" value="<?php echo Format::htmlchars($_REQUEST['startDate']); ?>" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('sd')); return false;"><img src='images/cal.png'border=0 alt=""></a> + From <input class="dp" id="sd" size=15 name="startDate" value="<?php echo Format::htmlchars($_REQUEST['startDate']); ?>" autocomplete=OFF> to - <input class="dp" id="ed" size=15 name="endDate" value="<?php echo Format::htmlchars($_REQUEST['endDate']); ?>" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF > - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('ed')); return false;"><img src='images/cal.png'border=0 alt=""></a> + <input class="dp" id="ed" size=15 name="endDate" value="<?php echo Format::htmlchars($_REQUEST['endDate']); ?>" autocomplete=OFF> Type: <select name='type'> diff --git a/include/staff/team.inc.php b/include/staff/team.inc.php index 7f8c409decba5de347d3cac28b848ce3ad78fa44..51b06ce2d1fa51344dbef35258a72cc68ddbf60b 100644 --- a/include/staff/team.inc.php +++ b/include/staff/team.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; if($team && $_REQUEST['a']!='add'){ diff --git a/include/staff/teams.inc.php b/include/staff/teams.inc.php index 1aa6dc4ed0554692b67449970caf0d799673f709..ab3a2f58d4a88e94ea4d08653b853352d37be680 100644 --- a/include/staff/teams.inc.php +++ b/include/staff/teams.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT team.*,count(m.staff_id) as members,CONCAT_WS(" ",lead.firstname,lead.lastname) as team_lead '. diff --git a/include/staff/template.inc.php b/include/staff/template.inc.php index 15881945e369c2fa541163008b3c9f4c9ce2352f..ac5c09a744879021e7286f116dc91e18a26df95f 100644 --- a/include/staff/template.inc.php +++ b/include/staff/template.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff || !$thisstaff->isAdmin()) die('Access Denied'); $info=array(); $qstr=''; diff --git a/include/staff/templates.inc.php b/include/staff/templates.inc.php index 7f82f656f12cafe984de35ff205eb62bfef2b1a7..f60e3b010ec7efe053fd1a73df1cefe9366b9daa 100644 --- a/include/staff/templates.inc.php +++ b/include/staff/templates.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $qstr=''; $sql='SELECT tpl.*,count(dept.tpl_id) as depts '. diff --git a/include/staff/ticket-edit.inc.php b/include/staff/ticket-edit.inc.php index db80cf2f73fc53853905be23eaa6430e7eefd1de..7bbf0921e5ed97a076e0dc5df4aa61dde44e27fb 100644 --- a/include/staff/ticket-edit.inc.php +++ b/include/staff/ticket-edit.inc.php @@ -139,18 +139,17 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$ticket->getUpdateInfo()); Due Date: </td> <td> - <input id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" size="10" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('duedate')); return false;"><img src='images/cal.png'border=0 alt=""></a> + <input class="dp" id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" size="12" autocomplete=OFF> <?php $min=$hr=null; if($info['time']) - list($hr,$min)=explode(':',$info['time']); - echo Misc::timeDropdown($hr,$min,'time'); + list($hr, $min)=explode(':', $info['time']); + + echo Misc::timeDropdown($hr, $min, 'time'); ?> <font class="error"> <?=$errors['duedate']?> <?php echo $errors['time']; ?></font> - <em>Time is based on your time zone (GM <?php echo $thisstaff->getTZoffset(); ?>)</em> + <em>Time is based on your time zone (GMT <?php echo $thisstaff->getTZoffset(); ?>)</em> </td> </tr> <tr> diff --git a/include/staff/ticket-open.inc.php b/include/staff/ticket-open.inc.php index 4ec32b3423abb2c4fa424552ec4b6730a8418e9a..680fbad151ba038104410a3a778f3371841d4ed1 100644 --- a/include/staff/ticket-open.inc.php +++ b/include/staff/ticket-open.inc.php @@ -203,18 +203,17 @@ $info=Format::htmlchars(($errors && $_POST)?$_POST:$info); Due Date: </td> <td> - <input id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" size="10" - onclick="event.cancelBubble=true;calendar(this);" autocomplete=OFF> - <a href="#" onclick="event.cancelBubble=true;calendar(getObj('duedate')); return false;"><img src='images/cal.png'border=0 alt=""></a> + <input class="dp" id="duedate" name="duedate" value="<?php echo Format::htmlchars($info['duedate']); ?>" size="12" autocomplete=OFF> <?php $min=$hr=null; if($info['time']) - list($hr,$min)=explode(':',$info['time']); - echo Misc::timeDropdown($hr,$min,'time'); + list($hr, $min)=explode(':', $info['time']); + + echo Misc::timeDropdown($hr, $min, 'time'); ?> <font class="error"> <?=$errors['duedate']?> <?php echo $errors['time']; ?></font> - <em>Time is based on your time zone (GM <?php echo $thisstaff->getTZoffset(); ?>)</em> + <em>Time is based on your time zone (GMT <?php echo $thisstaff->getTZoffset(); ?>)</em> </td> </tr> <tr> diff --git a/include/staff/ticket-view.inc.php b/include/staff/ticket-view.inc.php index faac0f86ef791a8726c266a8121a980860ddc267..a299b04fc1afcbe5039ba45809e655378f4d8cac 100644 --- a/include/staff/ticket-view.inc.php +++ b/include/staff/ticket-view.inc.php @@ -171,11 +171,21 @@ if($ticket->isOverdue()) </tr> </table> <div class="clear" style="padding-bottom:10px;"></div> +<?php +$tcount = $ticket->getThreadCount(); +if($cfg->showNotesInline()) + $tcount+= $ticket->getNumNotes(); +?> <ul id="threads"> - <li><a class="active" id="toggle_ticket_thread" href="#">Ticket Thread (<?php echo $ticket->getThreadCount(); ?>)</a></li> + <li><a class="active" id="toggle_ticket_thread" href="#">Ticket Thread (<?php echo $tcount; ?>)</a></li> + <?php + if(!$cfg->showNotesInline()) {?> <li><a id="toggle_notes" href="#">Internal Notes (<?php echo $ticket->getNumNotes(); ?>)</a></li> + <?php + }?> </ul> - +<?php +if(!$cfg->showNotesInline()) { ?> <div id="ticket_notes"> <?php /* Internal Notes */ @@ -189,14 +199,14 @@ if($ticket->isOverdue()) <?php echo sprintf('%s <em>posted by <b>%s</b></em>', Format::htmlchars($note['title']), - Format::htmlchars($note['source'])); + Format::htmlchars($note['poster'])); ?> </th> <th class="date" width="300"><?php echo Format::db_datetime($note['created']); ?></th> </tr> <tr> <td colspan="2"> - <?php echo Format::htmlchars($note['body']); ?> + <?php echo Format::display($note['body']); ?> </td> </tr> <?php @@ -213,45 +223,32 @@ if($ticket->isOverdue()) echo "<p>No internal notes found.</p>"; }?> </div> +<?php +} ?> <div id="ticket_thread"> <?php - /* -------- Messages & Responses -------------*/ - if($ticket->getThreadCount() && ($messages = $ticket->getMessages())) { - foreach($messages as $message) {?> - <table class="message" cellspacing="0" cellpadding="1" width="940" border="0"> - <tr><th><?php echo Format::db_datetime($message['created']); ?></th></tr> - <tr><td><?php echo Format::display($message['body']); ?></td></tr> + $threadTypes=array('M'=>'message','R'=>'response', 'N'=>'note'); + /* -------- Messages & Responses & Notes (if inline)-------------*/ + if(($thread=$ticket->getThread($cfg->showNotesInline()))) { + foreach($thread as $entry) { + ?> + <table class="<?php echo $threadTypes[$entry['thread_type']]; ?>" cellspacing="0" cellpadding="1" width="940" border="0"> + <tr> + <th width="200"><?php echo Format::db_datetime($entry['created']);?></th> + <th width="440"><span><?php echo Format::htmlchars($entry['title']); ?></span></th> + <th width="300" class="tmeta"><?php echo Format::htmlchars($entry['poster']); ?></th></tr> + <tr><td colspan=2><?php echo Format::display($entry['body']); ?></td></tr> <?php - if($message['attachments'] && ($links=$ticket->getAttachmentsLinks($message['id'],'M'))) {?> + if($entry['attachments'] && ($links=$ticket->getAttachmentsLinks($entry['id'], $entry['thread_type']))) {?> <tr> - <td class="info"><?php echo $links; ?></td> + <td class="info" colspan=2><?php echo $links; ?></td> </tr> <?php }?> </table> <?php - /* --------- Responses ------------ */ - if($message['responses'] && ($responses=$ticket->getResponses($message['id']))) { - foreach($responses as $resp) {?> - <table class="response" cellspacing="0" cellpadding="1" width="100%" border="0"> - <tr> - <th><?php echo Format::db_datetime($resp['created']); ?> - <?php echo Format::htmlchars($resp['staff_name']); ?></th> - </tr> - <tr> - <td><?php echo Format::display($resp['body']); ?></td> - </tr> - <?php - if($resp['attachments'] && ($links=$ticket->getAttachmentsLinks($resp['id'],'R'))) {?> - <tr> - <td class="info"><?php echo $links; ?></td> - </tr> - <?php - }?> - </table> - <?php - } - } - $msgId=$message['id']; + if($entry['thread_type']=='M') + $msgId=$entry['id']; } } else { echo '<p>Error fetching ticket thread - get technical help.</p>'; diff --git a/include/staff/tickets.inc.php b/include/staff/tickets.inc.php index bb05de08a3ef9477d7c92be63013cbdcd7b38660..bd4801c445cadc40677b3dcdb3bf163b280abfc8 100644 --- a/include/staff/tickets.inc.php +++ b/include/staff/tickets.inc.php @@ -42,6 +42,7 @@ switch(strtolower($_REQUEST['status'])){ //Status is overloaded case 'assigned': $status='open'; $staffId=$thisstaff->getId(); + $results_type='My Tickets'; break; case 'answered': $status='open'; @@ -97,9 +98,6 @@ $deep_search=false; if($search): $qstr.='&a='.urlencode($_REQUEST['a']); $qstr.='&t='.urlencode($_REQUEST['t']); - if(isset($_REQUEST['advance_search'])){ //advance search box! - $qstr.='&advance_search=Search'; - } //query if($searchTerm){ @@ -133,15 +131,36 @@ if($search): } } //department - if($_REQUEST['dept'] && in_array($_REQUEST['dept'],$thisstaff->getDepts())) { + if($_REQUEST['deptId'] && in_array($_REQUEST['deptId'],$thisstaff->getDepts())) { //This is dept based search..perm taken care above..put the sucker in. - $qwhere.=' AND ticket.dept_id='.db_input($_REQUEST['dept']); - $qstr.='&dept='.urlencode($_REQUEST['dept']); + $qwhere.=' AND ticket.dept_id='.db_input($_REQUEST['deptId']); + $qstr.='&deptId='.urlencode($_REQUEST['deptId']); } - //Teams - if($_REQUEST['team'] && ($thisuser->isadmin() || in_array($_REQUEST['team'],$thisuser->getTeams()))) { - $qwhere.=' AND ticket.team_id='.db_input($_REQUEST['team']); - $qstr.='&team='.urlencode($_REQUEST['team']); + + //Assignee + if($_REQUEST['assignee'] && strcasecmp($_REQUEST['status'], 'closed')) { + $id=preg_replace("/[^0-9]/", "", $_REQUEST['assignee']); + $assignee = $_REQUEST['assignee']; + $qstr.='&assignee='.urlencode($_REQUEST['assignee']); + $qwhere.= ' AND ( '; + + if($assignee[0]=='t') + $qwhere.=' (ticket.team_id='.db_input($id). ' AND ticket.status="open") '; + elseif($assignee[0]=='s') + $qwhere.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + else + $qwhere.=' (ticket.staff_id='.db_input($id). ' AND ticket.status="open") '; + + + if($_REQUEST['staffId'] && !$_REQUEST['status']) { //Assigned TO + Closed By + $qwhere.= ' OR (ticket.staff_id='.db_input($_REQUEST['staffId']). ' AND ticket.status="closed") '; + $qstr.='&staffId='.urlencode($_REQUEST['staffId']); + } + + $qwhere.= ' ) '; + } elseif($_REQUEST['staffId']) { + $qwhere.=' AND (ticket.staff_id='.db_input($_REQUEST['staffId']).' AND ticket.status="closed") '; + $qstr.='&staffId='.urlencode($_REQUEST['staffId']); } //dates @@ -161,7 +180,7 @@ if($search): $qwhere.=' AND ticket.created<=FROM_UNIXTIME('.$endTime.')'; $qstr.='&endDate='.urlencode($_REQUEST['endDate']); } -} + } endif; @@ -218,9 +237,7 @@ $pageNav->setURL('tickets.php',$qstr.'&sort='.urlencode($_REQUEST['sort']).'&ord //ADD attachment,priorities, lock and other crap $qselect.=' ,count(attach.attach_id) as attachments ' - .' ,count(DISTINCT message.id) as messages ' - .' ,count(DISTINCT response.id) as responses ' - .' ,count(DISTINCT note.id) as notes ' + .' ,count(DISTINCT thread.id) as thread_count ' .' ,IF(ticket.reopened is NULL,IF(ticket.lastmessage is NULL,ticket.created,ticket.lastmessage),ticket.reopened) as effective_date ' .' ,CONCAT_WS(" ", staff.firstname, staff.lastname) as staff, team.name as team ' .' ,IF(staff.staff_id IS NULL,team.name,CONCAT_WS(" ", staff.lastname, staff.firstname)) as assigned '; @@ -229,12 +246,7 @@ $qfrom.=' LEFT JOIN '.TICKET_PRIORITY_TABLE.' pri ON (ticket.priority_id=pri.pri .' LEFT JOIN '.TICKET_LOCK_TABLE.' tlock ON (ticket.ticket_id=tlock.ticket_id AND tlock.expire>NOW() AND tlock.staff_id!='.db_input($thisstaff->getId()).') ' .' LEFT JOIN '.TICKET_ATTACHMENT_TABLE.' attach ON (ticket.ticket_id=attach.ticket_id) ' - .' LEFT JOIN '.TICKET_THREAD_TABLE.' message ON (' - .'ticket.ticket_id=message.ticket_id AND message.thread_type="M") ' - .' LEFT JOIN '.TICKET_THREAD_TABLE.' response ON (' - .'ticket.ticket_id=response.ticket_id AND response.thread_type="R") ' - .' LEFT JOIN '.TICKET_THREAD_TABLE.' note ON (' - .'ticket.ticket_id=note.ticket_id AND note.thread_type="N") ' + .' LEFT JOIN '.TICKET_THREAD_TABLE.' thread ON ( ticket.ticket_id=thread.ticket_id) ' .' LEFT JOIN '.STAFF_TABLE.' staff ON (ticket.staff_id=staff.staff_id) ' .' LEFT JOIN '.TEAM_TABLE.' team ON (ticket.team_id=team.team_id) '; @@ -244,17 +256,18 @@ $hash = md5($query); $_SESSION['search_'.$hash] = $query; $res = db_query($query); $showing=db_num_rows($res)?$pageNav->showing():""; -if(!$results_type) { - $results_type=($search)?'Search Results':ucfirst($status).' Tickets'; -} -$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting.. +if(!$results_type) + $results_type = ucfirst($status).' Tickets'; -$basic_display=!isset($_REQUEST['advance_search'])?true:false; +if($search) + $results_type.= ' (Search Results)'; + +$negorder=$order=='DESC'?'ASC':'DESC'; //Negate the sorting.. //YOU BREAK IT YOU FIX IT. ?> <!-- SEARCH FORM START --> -<div id='basic' style="display:<?php echo $basic_display?'block':'none'; ?>"> +<div id='basic_search'> <form action="tickets.php" method="get"> <input type="hidden" name="a" value="search"> <table> @@ -262,6 +275,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; <td><input type="text" id="basic-ticket-search" name="query" size=30 value="<?php echo Format::htmlchars($_REQUEST['query']); ?>" autocomplete="off" autocorrect="off" autocapitalize="off"></td> <td><input type="submit" name="basic_search" class="button" value="Search"></td> + <td> <a href="" id="go-advanced">[advanced]</a></td> </tr> </table> </form> @@ -299,7 +313,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; title="Sort By Status <?php echo $negorder; ?>">Status</a></th> <?php } else { ?> - <th width="60" <?=$pri_sort?>> + <th width="60" <?php echo $pri_sort;?>> <a <?php echo $pri_sort; ?> href="tickets.php?sort=pri&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Priority <?php echo $negorder; ?>">Priority</a></th> <?php @@ -309,15 +323,18 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; <th width="150"> <a <?php echo $assignee_sort; ?> href="tickets.php?sort=assignee&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Assignee <?php echo $negorder;?>">Assigned To</a></th> - <?}elseif(!strcasecmp($status,'closed')){?> + <?php + } elseif(!strcasecmp($status,'closed')) { ?> <th width="150"> <a <?php echo $staff_sort; ?> href="tickets.php?sort=staff&order=<?php echo $negorder; ?><?php echo $qstr; ?>" title="Sort By Closing Staff Name <?php echo $negorder; ?>">Closed By</a></th> - <?}else{?> + <?php + } else { ?> <th width="150"> - <a <?=$dept_sort?> href="tickets.php?sort=dept&order=<?=$negorder?><?=$qstr?>" - title="Sort By Department <?=$negorder?>">Department</a></th> - <?}?> + <a <?php echo $dept_sort; ?> href="tickets.php?sort=dept&order=<?php echo $negorder;?><?php echo $qstr; ?>" + title="Sort By Department <?php echo $negorder; ?>">Department</a></th> + <?php + } ?> </tr> </thead> <tbody> @@ -346,7 +363,7 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; } $tid=$row['ticketID']; $subject = Format::truncate($row['subject'],40); - $threadcount=$row['messages']+$row['responses']; + $threadcount=$row['thread_count']; if(!strcasecmp($row['status'],'open') && !$row['isanswered'] && !$row['lock_id']) { $tid=sprintf('<b>%s</b>',$tid); } @@ -448,3 +465,89 @@ $basic_display=!isset($_REQUEST['advance_search'])?true:false; } ?> </form> </div> +<div id="overlay"></div> +<div style="display:none;" id="advanced-search"> + <h3>Advanced Ticket Search</h3> + <a class="close" href="">×</a> + <form action="tickets.php" method="post" id="search" name="search"> + <input type="hidden" name="a" value="search"> + <fieldset class="query"> + <label for="query">Keyword:</label> + <input type="input" id="query" name="query" size="20"> <em>Optional</em> + </fieldset> + <fieldset> + <label for="status">Status:</label> + <select id="status" name="status"> + <option value="">— Any Status —</option> + <option value="open">Open</option> + <option value="overdue">Overdue</option> + <option value="closed">Closed</option> + </select> + <label for="deptId">Dept:</label> + <select id="deptId" name="deptId"> + <option value="">— All Departments —</option> + <?php + if(($mydepts = $thisstaff->getDepts()) && ($depts=Dept::getDepartments())) { + foreach($depts as $id =>$name) { + if(!in_array($id, $mydepts)) continue; + echo sprintf('<option value="%d">%s</option>', $id, $name); + } + } + ?> + </select> + </fieldset> + <fieldset class="owner"> + <label for="assignee">Assigned To:</label> + <select id="assignee" name="assignee"> + <option value="0">— Anyone —</option> + <?php + if(($users=Staff::getStaffMembers())) { + echo '<OPTGROUP label="Staff Members ('.count($users).')">'; + foreach($users as $id => $name) { + $k="s$id"; + echo sprintf('<option value="%s">%s</option>', $k, $name); + } + echo '</OPTGROUP>'; + } + + if(($teams=Team::getTeams())) { + echo '<OPTGROUP label="Teams ('.count($teams).')">'; + foreach($teams as $id => $name) { + $k="t$id"; + echo sprintf('<option value="%s">%s</option>', $k, $name); + } + echo '</OPTGROUP>'; + } + ?> + </select> + <label for="staffId">Closed By:</label> + <select id="staffId" name="staffId"> + <option value="0">— Anyone —</option> + <?php + if(($users=Staff::getStaffMembers())) { + foreach($users as $id => $name) + echo sprintf('<option value="%d">%s</option>', $id, $name); + } + ?> + </select> + </fieldset> + <fieldset class="date_range"> + <label>Date Range:</label> + <input class="dp" type="input" size="20" name="startDate"> + <span>TO</span> + <input class="dp" type="input" size="20" name="endDate"> + </fieldset> + <p> + <span class="buttons"> + <input type="submit" value="Search"> + <input type="reset" value="Reset"> + <input type="button" value="Cancel" class="close"> + </span> + <span class="spinner"> + <img src="./images/ajax-loader.gif" width="16" height="16"> + </span> + </p> + </form> + <div id="result-count"> + </div> +</div> diff --git a/include/staff/topic.inc.php b/include/staff/topic.inc.php index 6504c5443200a4a3bd82624fec18c27c0ff3ea24..f0f895409d99ebd2c39c4013572b1ee455887090 100644 --- a/include/staff/topic.inc.php +++ b/include/staff/topic.inc.php @@ -1,5 +1,5 @@ <?php -if(!defined('OSTADMININC') || !$thisstaff->isadmin()) die('Access Denied'); +if(!defined('OSTADMININC') || !$thisstaff->isAdmin()) die('Access Denied'); $info=($_POST && $errors)?Format::input($_POST):array(); //Re-use the post info on error...savekeyboards.org if($topic && $_REQUEST['a']!='new'){ diff --git a/index.php b/index.php index ac4fe04a014455d083aacab299fdace3a045e529..db492a87048158ba17c55deb90e19ba167261997 100644 --- a/index.php +++ b/index.php @@ -26,23 +26,25 @@ require(CLIENTINC_DIR.'header.inc.php'); <div id="new_ticket"> <h3>Open A New Ticket</h3> - <form method="get" action="open.php"> - <div>Please provide as much detail as possible so we can best assist you. To update a previously submitted ticket, please login.</div> - <input type="submit" value="Open a New Ticket"> - </form> + <br> + <div>Please provide as much detail as possible so we can best assist you. To update a previously submitted ticket, please login.</div> + <p> + <a href="open.php" class="green button">Open a New Ticket</a> + </p> </div> <div id="check_status"> <h3>Check Ticket Status</h3> - <form class="status_form" action="view.php" method="get"> - <div>We provide archives and history of all your current and past support requests complete with responses.</div> - <input type="submit" value="Check Ticket Status"> - </form> + <br> + <div>We provide archives and history of all your current and past support requests complete with responses.</div> + <p> + <a href="view.php" class="blue button">Check Ticket Status</a> + </p> </div> </div> <div class="clear"></div> <?php -if($cfg && $cfg->isKnowledgebaseEnabled()){ +if($cfg && $cfg->isKnowledgebaseEnabled()){ //FIXME: provide ability to feature or select random FAQs ?? ?> <p>Be sure to browse our <a href="kb/index.php">Frequently Asked Questions (FAQs)</a>, before opening a ticket.</p> diff --git a/js/jquery-ui-1.8.18.custom.min.js b/js/jquery-ui-1.8.18.custom.min.js new file mode 100755 index 0000000000000000000000000000000000000000..81486fc8e6f8a32d847668911188813b107536de --- /dev/null +++ b/js/jquery-ui-1.8.18.custom.min.js @@ -0,0 +1,21 @@ +/*! + * jQuery UI 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI + */(function(a,b){function d(b){return!a(b).parents().andSelf().filter(function(){return a.curCSS(this,"visibility")==="hidden"||a.expr.filters.hidden(this)}).length}function c(b,c){var e=b.nodeName.toLowerCase();if("area"===e){var f=b.parentNode,g=f.name,h;if(!b.href||!g||f.nodeName.toLowerCase()!=="map")return!1;h=a("img[usemap=#"+g+"]")[0];return!!h&&d(h)}return(/input|select|textarea|button|object/.test(e)?!b.disabled:"a"==e?b.href||c:c)&&d(b)}a.ui=a.ui||{};a.ui.version||(a.extend(a.ui,{version:"1.8.18",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}}),a.fn.extend({propAttr:a.fn.prop||a.fn.attr,_focus:a.fn.focus,focus:function(b,c){return typeof b=="number"?this.each(function(){var d=this;setTimeout(function(){a(d).focus(),c&&c.call(d)},b)}):this._focus.apply(this,arguments)},scrollParent:function(){var b;a.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?b=this.parents().filter(function(){return/(relative|absolute|fixed)/.test(a.curCSS(this,"position",1))&&/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0):b=this.parents().filter(function(){return/(auto|scroll)/.test(a.curCSS(this,"overflow",1)+a.curCSS(this,"overflow-y",1)+a.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!b.length?a(document):b},zIndex:function(c){if(c!==b)return this.css("zIndex",c);if(this.length){var d=a(this[0]),e,f;while(d.length&&d[0]!==document){e=d.css("position");if(e==="absolute"||e==="relative"||e==="fixed"){f=parseInt(d.css("zIndex"),10);if(!isNaN(f)&&f!==0)return f}d=d.parent()}}return 0},disableSelection:function(){return this.bind((a.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}}),a.each(["Width","Height"],function(c,d){function h(b,c,d,f){a.each(e,function(){c-=parseFloat(a.curCSS(b,"padding"+this,!0))||0,d&&(c-=parseFloat(a.curCSS(b,"border"+this+"Width",!0))||0),f&&(c-=parseFloat(a.curCSS(b,"margin"+this,!0))||0)});return c}var e=d==="Width"?["Left","Right"]:["Top","Bottom"],f=d.toLowerCase(),g={innerWidth:a.fn.innerWidth,innerHeight:a.fn.innerHeight,outerWidth:a.fn.outerWidth,outerHeight:a.fn.outerHeight};a.fn["inner"+d]=function(c){if(c===b)return g["inner"+d].call(this);return this.each(function(){a(this).css(f,h(this,c)+"px")})},a.fn["outer"+d]=function(b,c){if(typeof b!="number")return g["outer"+d].call(this,b);return this.each(function(){a(this).css(f,h(this,b,!0,c)+"px")})}}),a.extend(a.expr[":"],{data:function(b,c,d){return!!a.data(b,d[3])},focusable:function(b){return c(b,!isNaN(a.attr(b,"tabindex")))},tabbable:function(b){var d=a.attr(b,"tabindex"),e=isNaN(d);return(e||d>=0)&&c(b,!e)}}),a(function(){var b=document.body,c=b.appendChild(c=document.createElement("div"));c.offsetHeight,a.extend(c.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0}),a.support.minHeight=c.offsetHeight===100,a.support.selectstart="onselectstart"in c,b.removeChild(c).style.display="none"}),a.extend(a.ui,{plugin:{add:function(b,c,d){var e=a.ui[b].prototype;for(var f in d)e.plugins[f]=e.plugins[f]||[],e.plugins[f].push([c,d[f]])},call:function(a,b,c){var d=a.plugins[b];if(!!d&&!!a.element[0].parentNode)for(var e=0;e<d.length;e++)a.options[d[e][0]]&&d[e][1].apply(a.element,c)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(b,c){if(a(b).css("overflow")==="hidden")return!1;var d=c&&c==="left"?"scrollLeft":"scrollTop",e=!1;if(b[d]>0)return!0;b[d]=1,e=b[d]>0,b[d]=0;return e},isOverAxis:function(a,b,c){return a>b&&a<b+c},isOver:function(b,c,d,e,f,g){return a.ui.isOverAxis(b,d,f)&&a.ui.isOverAxis(c,e,g)}}))})(jQuery);/* + * jQuery UI Datepicker 1.8.18 + * + * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about) + * Dual licensed under the MIT or GPL Version 2 licenses. + * http://jquery.org/license + * + * http://docs.jquery.com/UI/Datepicker + * + * Depends: + * jquery.ui.core.js + */(function($,undefined){function isArray(a){return a&&($.browser.safari&&typeof a=="object"&&a.length||a.constructor&&a.constructor.toString().match(/\Array\(\)/))}function extendRemove(a,b){$.extend(a,b);for(var c in b)if(b[c]==null||b[c]==undefined)a[c]=b[c];return a}function bindHover(a){var b="button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";return a.bind("mouseout",function(a){var c=$(a.target).closest(b);!c.length||c.removeClass("ui-state-hover ui-datepicker-prev-hover ui-datepicker-next-hover")}).bind("mouseover",function(c){var d=$(c.target).closest(b);!$.datepicker._isDisabledDatepicker(instActive.inline?a.parent()[0]:instActive.input[0])&&!!d.length&&(d.parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover"),d.addClass("ui-state-hover"),d.hasClass("ui-datepicker-prev")&&d.addClass("ui-datepicker-prev-hover"),d.hasClass("ui-datepicker-next")&&d.addClass("ui-datepicker-next-hover"))})}function Datepicker(){this.debug=!1,this._curInst=null,this._keyEvent=!1,this._disabledInputs=[],this._datepickerShowing=!1,this._inDialog=!1,this._mainDivId="ui-datepicker-div",this._inlineClass="ui-datepicker-inline",this._appendClass="ui-datepicker-append",this._triggerClass="ui-datepicker-trigger",this._dialogClass="ui-datepicker-dialog",this._disableClass="ui-datepicker-disabled",this._unselectableClass="ui-datepicker-unselectable",this._currentClass="ui-datepicker-current-day",this._dayOverClass="ui-datepicker-days-cell-over",this.regional=[],this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su","Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:!1,showMonthAfterYear:!1,yearSuffix:""},this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:!1,hideIfNoPrevNext:!1,navigationAsDateFormat:!1,gotoCurrent:!1,changeMonth:!1,changeYear:!1,yearRange:"c-10:c+10",showOtherMonths:!1,selectOtherMonths:!1,showWeek:!1,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:!0,showButtonPanel:!1,autoSize:!1,disabled:!1},$.extend(this._defaults,this.regional[""]),this.dpDiv=bindHover($('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>'))}$.extend($.ui,{datepicker:{version:"1.8.18"}});var PROP_NAME="datepicker",dpuuid=(new Date).getTime(),instActive;$.extend(Datepicker.prototype,{markerClassName:"hasDatepicker",maxRows:4,log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){extendRemove(this._defaults,a||{});return this},_attachDatepicker:function(target,settings){var inlineSettings=null;for(var attrName in this._defaults){var attrValue=target.getAttribute("date:"+attrName);if(attrValue){inlineSettings=inlineSettings||{};try{inlineSettings[attrName]=eval(attrValue)}catch(err){inlineSettings[attrName]=attrValue}}}var nodeName=target.nodeName.toLowerCase(),inline=nodeName=="div"||nodeName=="span";target.id||(this.uuid+=1,target.id="dp"+this.uuid);var inst=this._newInst($(target),inline);inst.settings=$.extend({},settings||{},inlineSettings||{}),nodeName=="input"?this._connectDatepicker(target,inst):inline&&this._inlineDatepicker(target,inst)},_newInst:function(a,b){var c=a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1");return{id:c,input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:b?bindHover($('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')):this.dpDiv}},_connectDatepicker:function(a,b){var c=$(a);b.append=$([]),b.trigger=$([]);c.hasClass(this.markerClassName)||(this._attachments(c,b),c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),this._autoSize(b),$.data(a,PROP_NAME,b),b.settings.disabled&&this._disableDatepicker(a))},_attachments:function(a,b){var c=this._get(b,"appendText"),d=this._get(b,"isRTL");b.append&&b.append.remove(),c&&(b.append=$('<span class="'+this._appendClass+'">'+c+"</span>"),a[d?"before":"after"](b.append)),a.unbind("focus",this._showDatepicker),b.trigger&&b.trigger.remove();var e=this._get(b,"showOn");(e=="focus"||e=="both")&&a.focus(this._showDatepicker);if(e=="button"||e=="both"){var f=this._get(b,"buttonText"),g=this._get(b,"buttonImage");b.trigger=$(this._get(b,"buttonImageOnly")?$("<img/>").addClass(this._triggerClass).attr({src:g,alt:f,title:f}):$('<button type="button"></button>').addClass(this._triggerClass).html(g==""?f:$("<img/>").attr({src:g,alt:f,title:f}))),a[d?"before":"after"](b.trigger),b.trigger.click(function(){$.datepicker._datepickerShowing&&$.datepicker._lastInput==a[0]?$.datepicker._hideDatepicker():$.datepicker._datepickerShowing&&$.datepicker._lastInput!=a[0]?($.datepicker._hideDatepicker(),$.datepicker._showDatepicker(a[0])):$.datepicker._showDatepicker(a[0]);return!1})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var d=function(a){var b=0,c=0;for(var d=0;d<a.length;d++)a[d].length>b&&(b=a[d].length,c=d);return c};b.setMonth(d(this._get(a,c.match(/MM/)?"monthNames":"monthNamesShort"))),b.setDate(d(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=$(a);c.hasClass(this.markerClassName)||(c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(a,c,d){b.settings[c]=d}).bind("getData.datepicker",function(a,c){return this._get(b,c)}),$.data(a,PROP_NAME,b),this._setDate(b,this._getDefaultDate(b),!0),this._updateDatepicker(b),this._updateAlternate(b),b.settings.disabled&&this._disableDatepicker(a),b.dpDiv.css("display","block"))},_dialogDatepicker:function(a,b,c,d,e){var f=this._dialogInst;if(!f){this.uuid+=1;var g="dp"+this.uuid;this._dialogInput=$('<input type="text" id="'+g+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>'),this._dialogInput.keydown(this._doKeyDown),$("body").append(this._dialogInput),f=this._dialogInst=this._newInst(this._dialogInput,!1),f.settings={},$.data(this._dialogInput[0],PROP_NAME,f)}extendRemove(f.settings,d||{}),b=b&&b.constructor==Date?this._formatDate(f,b):b,this._dialogInput.val(b),this._pos=e?e.length?e:[e.pageX,e.pageY]:null;if(!this._pos){var h=document.documentElement.clientWidth,i=document.documentElement.clientHeight,j=document.documentElement.scrollLeft||document.body.scrollLeft,k=document.documentElement.scrollTop||document.body.scrollTop;this._pos=[h/2-100+j,i/2-150+k]}this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px"),f.settings.onSelect=c,this._inDialog=!0,this.dpDiv.addClass(this._dialogClass),this._showDatepicker(this._dialogInput[0]),$.blockUI&&$.blockUI(this.dpDiv),$.data(this._dialogInput[0],PROP_NAME,f);return this},_destroyDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();$.removeData(a,PROP_NAME),d=="input"?(c.append.remove(),c.trigger.remove(),b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",this._doKeyUp)):(d=="div"||d=="span")&&b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!1,c.trigger.filter("button").each(function(){this.disabled=!1}).end().filter("img").css({opacity:"1.0",cursor:""});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().removeClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").removeAttr("disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b})}},_disableDatepicker:function(a){var b=$(a),c=$.data(a,PROP_NAME);if(!!b.hasClass(this.markerClassName)){var d=a.nodeName.toLowerCase();if(d=="input")a.disabled=!0,c.trigger.filter("button").each(function(){this.disabled=!0}).end().filter("img").css({opacity:"0.5",cursor:"default"});else if(d=="div"||d=="span"){var e=b.children("."+this._inlineClass);e.children().addClass("ui-state-disabled"),e.find("select.ui-datepicker-month, select.ui-datepicker-year").attr("disabled","disabled")}this._disabledInputs=$.map(this._disabledInputs,function(b){return b==a?null:b}),this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return!1;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return!0;return!1},_getInst:function(a){try{return $.data(a,PROP_NAME)}catch(b){throw"Missing instance data for this datepicker"}},_optionDatepicker:function(a,b,c){var d=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?$.extend({},$.datepicker._defaults):d?b=="all"?$.extend({},d.settings):this._get(d,b):null;var e=b||{};typeof b=="string"&&(e={},e[b]=c);if(d){this._curInst==d&&this._hideDatepicker();var f=this._getDateDatepicker(a,!0),g=this._getMinMaxDate(d,"min"),h=this._getMinMaxDate(d,"max");extendRemove(d.settings,e),g!==null&&e.dateFormat!==undefined&&e.minDate===undefined&&(d.settings.minDate=this._formatDate(d,g)),h!==null&&e.dateFormat!==undefined&&e.maxDate===undefined&&(d.settings.maxDate=this._formatDate(d,h)),this._attachments($(a),d),this._autoSize(d),this._setDate(d,f),this._updateAlternate(d),this._updateDatepicker(d)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){var b=this._getInst(a);b&&this._updateDatepicker(b)},_setDateDatepicker:function(a,b){var c=this._getInst(a);c&&(this._setDate(c,b),this._updateDatepicker(c),this._updateAlternate(c))},_getDateDatepicker:function(a,b){var c=this._getInst(a);c&&!c.inline&&this._setDateFromField(c,b);return c?this._getDate(c):null},_doKeyDown:function(a){var b=$.datepicker._getInst(a.target),c=!0,d=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=!0;if($.datepicker._datepickerShowing)switch(a.keyCode){case 9:$.datepicker._hideDatepicker(),c=!1;break;case 13:var e=$("td."+$.datepicker._dayOverClass+":not(."+$.datepicker._currentClass+")",b.dpDiv);e[0]&&$.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,e[0]);var f=$.datepicker._get(b,"onSelect");if(f){var g=$.datepicker._formatDate(b);f.apply(b.input?b.input[0]:null,[g,b])}else $.datepicker._hideDatepicker();return!1;case 27:$.datepicker._hideDatepicker();break;case 33:$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 34:$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 35:(a.ctrlKey||a.metaKey)&&$.datepicker._clearDate(a.target),c=a.ctrlKey||a.metaKey;break;case 36:(a.ctrlKey||a.metaKey)&&$.datepicker._gotoToday(a.target),c=a.ctrlKey||a.metaKey;break;case 37:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?1:-1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?-$.datepicker._get(b,"stepBigMonths"):-$.datepicker._get(b,"stepMonths"),"M");break;case 38:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,-7,"D"),c=a.ctrlKey||a.metaKey;break;case 39:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,d?-1:1,"D"),c=a.ctrlKey||a.metaKey,a.originalEvent.altKey&&$.datepicker._adjustDate(a.target,a.ctrlKey?+$.datepicker._get(b,"stepBigMonths"):+$.datepicker._get(b,"stepMonths"),"M");break;case 40:(a.ctrlKey||a.metaKey)&&$.datepicker._adjustDate(a.target,7,"D"),c=a.ctrlKey||a.metaKey;break;default:c=!1}else a.keyCode==36&&a.ctrlKey?$.datepicker._showDatepicker(this):c=!1;c&&(a.preventDefault(),a.stopPropagation())},_doKeyPress:function(a){var b=$.datepicker._getInst(a.target);if($.datepicker._get(b,"constrainInput")){var c=$.datepicker._possibleChars($.datepicker._get(b,"dateFormat")),d=String.fromCharCode(a.charCode==undefined?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||d<" "||!c||c.indexOf(d)>-1}},_doKeyUp:function(a){var b=$.datepicker._getInst(a.target);if(b.input.val()!=b.lastVal)try{var c=$.datepicker.parseDate($.datepicker._get(b,"dateFormat"),b.input?b.input.val():null,$.datepicker._getFormatConfig(b));c&&($.datepicker._setDateFromField(b),$.datepicker._updateAlternate(b),$.datepicker._updateDatepicker(b))}catch(a){$.datepicker.log(a)}return!0},_showDatepicker:function(a){a=a.target||a,a.nodeName.toLowerCase()!="input"&&(a=$("input",a.parentNode)[0]);if(!$.datepicker._isDisabledDatepicker(a)&&$.datepicker._lastInput!=a){var b=$.datepicker._getInst(a);$.datepicker._curInst&&$.datepicker._curInst!=b&&($.datepicker._curInst.dpDiv.stop(!0,!0),b&&$.datepicker._datepickerShowing&&$.datepicker._hideDatepicker($.datepicker._curInst.input[0]));var c=$.datepicker._get(b,"beforeShow"),d=c?c.apply(a,[a,b]):{};if(d===!1)return;extendRemove(b.settings,d),b.lastVal=null,$.datepicker._lastInput=a,$.datepicker._setDateFromField(b),$.datepicker._inDialog&&(a.value=""),$.datepicker._pos||($.datepicker._pos=$.datepicker._findPos(a),$.datepicker._pos[1]+=a.offsetHeight);var e=!1;$(a).parents().each(function(){e|=$(this).css("position")=="fixed";return!e}),e&&$.browser.opera&&($.datepicker._pos[0]-=document.documentElement.scrollLeft,$.datepicker._pos[1]-=document.documentElement.scrollTop);var f={left:$.datepicker._pos[0],top:$.datepicker._pos[1]};$.datepicker._pos=null,b.dpDiv.empty(),b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"}),$.datepicker._updateDatepicker(b),f=$.datepicker._checkOffset(b,f,e),b.dpDiv.css({position:$.datepicker._inDialog&&$.blockUI?"static":e?"fixed":"absolute",display:"none",left:f.left+"px",top:f.top+"px"});if(!b.inline){var g=$.datepicker._get(b,"showAnim"),h=$.datepicker._get(b,"duration"),i=function(){var a=b.dpDiv.find("iframe.ui-datepicker-cover");if(!!a.length){var c=$.datepicker._getBorders(b.dpDiv);a.css({left:-c[0],top:-c[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex($(a).zIndex()+1),$.datepicker._datepickerShowing=!0,$.effects&&$.effects[g]?b.dpDiv.show(g,$.datepicker._get(b,"showOptions"),h,i):b.dpDiv[g||"show"](g?h:null,i),(!g||!h)&&i(),b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus(),$.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this;b.maxRows=4;var c=$.datepicker._getBorders(a.dpDiv);instActive=a,a.dpDiv.empty().append(this._generateHTML(a));var d=a.dpDiv.find("iframe.ui-datepicker-cover");!d.length||d.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()}),a.dpDiv.find("."+this._dayOverClass+" a").mouseover();var e=this._getNumberOfMonths(a),f=e[1],g=17;a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width(""),f>1&&a.dpDiv.addClass("ui-datepicker-multi-"+f).css("width",g*f+"em"),a.dpDiv[(e[0]!=1||e[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi"),a.dpDiv[(this._get(a,"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl"),a==$.datepicker._curInst&&$.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input[0]!=document.activeElement&&a.input.focus();if(a.yearshtml){var h=a.yearshtml;setTimeout(function(){h===a.yearshtml&&a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml),h=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(a){return{thin:1,medium:2,thick:3}[a]||a};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},_checkOffset:function(a,b,c){var d=a.dpDiv.outerWidth(),e=a.dpDiv.outerHeight(),f=a.input?a.input.outerWidth():0,g=a.input?a.input.outerHeight():0,h=document.documentElement.clientWidth+$(document).scrollLeft(),i=document.documentElement.clientHeight+$(document).scrollTop();b.left-=this._get(a,"isRTL")?d-f:0,b.left-=c&&b.left==a.input.offset().left?$(document).scrollLeft():0,b.top-=c&&b.top==a.input.offset().top+g?$(document).scrollTop():0,b.left-=Math.min(b.left,b.left+d>h&&h>d?Math.abs(b.left+d-h):0),b.top-=Math.min(b.top,b.top+e>i&&i>e?Math.abs(e+g):0);return b},_findPos:function(a){var b=this._getInst(a),c=this._get(b,"isRTL");while(a&&(a.type=="hidden"||a.nodeType!=1||$.expr.filters.hidden(a)))a=a[c?"previousSibling":"nextSibling"];var d=$(a).offset();return[d.left,d.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=$.data(a,PROP_NAME))&&this._datepickerShowing){var c=this._get(b,"showAnim"),d=this._get(b,"duration"),e=this,f=function(){$.datepicker._tidyDialog(b),e._curInst=null};$.effects&&$.effects[c]?b.dpDiv.hide(c,$.datepicker._get(b,"showOptions"),d,f):b.dpDiv[c=="slideDown"?"slideUp":c=="fadeIn"?"fadeOut":"hide"](c?d:null,f),c||f(),this._datepickerShowing=!1;var g=this._get(b,"onClose");g&&g.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]),this._lastInput=null,this._inDialog&&(this._dialogInput.css({position:"absolute",left:"0",top:"-100px"}),$.blockUI&&($.unblockUI(),$("body").append(this.dpDiv))),this._inDialog=!1}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},_checkExternalClick:function(a){if(!!$.datepicker._curInst){var b=$(a.target),c=$.datepicker._getInst(b[0]);(b[0].id!=$.datepicker._mainDivId&&b.parents("#"+$.datepicker._mainDivId).length==0&&!b.hasClass($.datepicker.markerClassName)&&!b.closest("."+$.datepicker._triggerClass).length&&$.datepicker._datepickerShowing&&(!$.datepicker._inDialog||!$.blockUI)||b.hasClass($.datepicker.markerClassName)&&$.datepicker._curInst!=c)&&$.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){var d=$(a),e=this._getInst(d[0]);this._isDisabledDatepicker(d[0])||(this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):0),c),this._updateDatepicker(e))},_gotoToday:function(a){var b=$(a),c=this._getInst(b[0]);if(this._get(c,"gotoCurrent")&&c.currentDay)c.selectedDay=c.currentDay,c.drawMonth=c.selectedMonth=c.currentMonth,c.drawYear=c.selectedYear=c.currentYear;else{var d=new Date;c.selectedDay=d.getDate(),c.drawMonth=c.selectedMonth=d.getMonth(),c.drawYear=c.selectedYear=d.getFullYear()}this._notifyChange(c),this._adjustDate(b)},_selectMonthYear:function(a,b,c){var d=$(a),e=this._getInst(d[0]);e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10),this._notifyChange(e),this._adjustDate(d)},_selectDay:function(a,b,c,d){var e=$(a);if(!$(d).hasClass(this._unselectableClass)&&!this._isDisabledDatepicker(e[0])){var f=this._getInst(e[0]);f.selectedDay=f.currentDay=$("a",d).html(),f.selectedMonth=f.currentMonth=b,f.selectedYear=f.currentYear=c,this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){var b=$(a),c=this._getInst(b[0]);this._selectDate(b,"")},_selectDate:function(a,b){var c=$(a),d=this._getInst(c[0]);b=b!=null?b:this._formatDate(d),d.input&&d.input.val(b),this._updateAlternate(d);var e=this._get(d,"onSelect");e?e.apply(d.input?d.input[0]:null,[b,d]):d.input&&d.input.trigger("change"),d.inline?this._updateDatepicker(d):(this._hideDatepicker(),this._lastInput=d.input[0],typeof d.input[0]!="object"&&d.input.focus(),this._lastInput=null)},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),d=this._getDate(a),e=this.formatDate(c,d,this._getFormatConfig(a));$(b).each(function(){$(this).val(e)})}},noWeekends:function(a){var b=a.getDay();return[b>0&&b<6,""]},iso8601Week:function(a){var b=new Date(a.getTime());b.setDate(b.getDate()+4-(b.getDay()||7));var c=b.getTime();b.setMonth(0),b.setDate(1);return Math.floor(Math.round((c-b)/864e5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var d=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;d=typeof d!="string"?d:(new Date).getFullYear()%100+parseInt(d,10);var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,g=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,h=(c?c.monthNames:null)||this._defaults.monthNames,i=-1,j=-1,k=-1,l=-1,m=!1,n=function(b){var c=s+1<a.length&&a.charAt(s+1)==b;c&&s++;return c},o=function(a){var c=n(a),d=a=="@"?14:a=="!"?20:a=="y"&&c?4:a=="o"?3:2,e=new RegExp("^\\d{1,"+d+"}"),f=b.substring(r).match(e);if(!f)throw"Missing number at position "+r;r+=f[0].length;return parseInt(f[0],10)},p=function(a,c,d){var e=$.map(n(a)?d:c,function(a,b){return[[b,a]]}).sort(function(a,b){return-(a[1].length-b[1].length)}),f=-1;$.each(e,function(a,c){var d=c[1];if(b.substr(r,d.length).toLowerCase()==d.toLowerCase()){f=c[0],r+=d.length;return!1}});if(f!=-1)return f+1;throw"Unknown name at position "+r},q=function(){if(b.charAt(r)!=a.charAt(s))throw"Unexpected literal at position "+r;r++},r=0;for(var s=0;s<a.length;s++)if(m)a.charAt(s)=="'"&&!n("'")?m=!1:q();else switch(a.charAt(s)){case"d":k=o("d");break;case"D":p("D",e,f);break;case"o":l=o("o");break;case"m":j=o("m");break;case"M":j=p("M",g,h);break;case"y":i=o("y");break;case"@":var t=new Date(o("@"));i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"!":var t=new Date((o("!")-this._ticksTo1970)/1e4);i=t.getFullYear(),j=t.getMonth()+1,k=t.getDate();break;case"'":n("'")?q():m=!0;break;default:q()}if(r<b.length)throw"Extra/unparsed characters found in date: "+b.substring(r);i==-1?i=(new Date).getFullYear():i<100&&(i+=(new Date).getFullYear()-(new Date).getFullYear()%100+(i<=d?0:-100));if(l>-1){j=1,k=l;for(;;){var u=this._getDaysInMonth(i,j-1);if(k<=u)break;j++,k-=u}}var t=this._daylightSavingAdjust(new Date(i,j-1,k));if(t.getFullYear()!=i||t.getMonth()+1!=j||t.getDate()!=k)throw"Invalid date";return t},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1e7,formatDate:function(a,b,c){if(!b)return"";var d=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,e=(c?c.dayNames:null)||this._defaults.dayNames,f=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,g=(c?c.monthNames:null)||this._defaults.monthNames,h=function(b){var c=m+1<a.length&&a.charAt(m+1)==b;c&&m++;return c},i=function(a,b,c){var d=""+b;if(h(a))while(d.length<c)d="0"+d;return d},j=function(a,b,c,d){return h(a)?d[b]:c[b]},k="",l=!1;if(b)for(var m=0;m<a.length;m++)if(l)a.charAt(m)=="'"&&!h("'")?l=!1:k+=a.charAt(m);else switch(a.charAt(m)){case"d":k+=i("d",b.getDate(),2);break;case"D":k+=j("D",b.getDay(),d,e);break;case"o":k+=i("o",Math.round(((new Date(b.getFullYear(),b.getMonth(),b.getDate())).getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864e5),3);break;case"m":k+=i("m",b.getMonth()+1,2);break;case"M":k+=j("M",b.getMonth(),f,g);break;case"y":k+=h("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case"@":k+=b.getTime();break;case"!":k+=b.getTime()*1e4+this._ticksTo1970;break;case"'":h("'")?k+="'":l=!0;break;default:k+=a.charAt(m)}return k},_possibleChars:function(a){var b="",c=!1,d=function(b){var c=e+1<a.length&&a.charAt(e+1)==b;c&&e++;return c};for(var e=0;e<a.length;e++)if(c)a.charAt(e)=="'"&&!d("'")?c=!1:b+=a.charAt(e);else switch(a.charAt(e)){case"d":case"m":case"y":case"@":b+="0123456789";break;case"D":case"M":return null;case"'":d("'")?b+="'":c=!0;break;default:b+=a.charAt(e)}return b},_get:function(a,b){return a.settings[b]!==undefined?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),d=a.lastVal=a.input?a.input.val():null,e,f;e=f=this._getDefaultDate(a);var g=this._getFormatConfig(a);try{e=this.parseDate(c,d,g)||f}catch(h){this.log(h),d=b?"":d}a.selectedDay=e.getDate(),a.drawMonth=a.selectedMonth=e.getMonth(),a.drawYear=a.selectedYear=e.getFullYear(),a.currentDay=d?e.getDate():0,a.currentMonth=d?e.getMonth():0,a.currentYear=d?e.getFullYear():0,this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var d=function(a){var b=new Date;b.setDate(b.getDate()+a);return b},e=function(b){try{return $.datepicker.parseDate($.datepicker._get(a,"dateFormat"),b,$.datepicker._getFormatConfig(a))}catch(c){}var d=(b.toLowerCase().match(/^c/)?$.datepicker._getDate(a):null)||new Date,e=d.getFullYear(),f=d.getMonth(),g=d.getDate(),h=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,i=h.exec(b);while(i){switch(i[2]||"d"){case"d":case"D":g+=parseInt(i[1],10);break;case"w":case"W":g+=parseInt(i[1],10)*7;break;case"m":case"M":f+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f));break;case"y":case"Y":e+=parseInt(i[1],10),g=Math.min(g,$.datepicker._getDaysInMonth(e,f))}i=h.exec(b)}return new Date(e,f,g)},f=b==null||b===""?c:typeof b=="string"?e(b):typeof b=="number"?isNaN(b)?c:d(b):new Date(b.getTime());f=f&&f.toString()=="Invalid Date"?c:f,f&&(f.setHours(0),f.setMinutes(0),f.setSeconds(0),f.setMilliseconds(0));return this._daylightSavingAdjust(f)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var d=!b,e=a.selectedMonth,f=a.selectedYear,g=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=a.currentDay=g.getDate(),a.drawMonth=a.selectedMonth=a.currentMonth=g.getMonth(),a.drawYear=a.selectedYear=a.currentYear=g.getFullYear(),(e!=a.selectedMonth||f!=a.selectedYear)&&!c&&this._notifyChange(a),this._adjustInstDate(a),a.input&&a.input.val(d?"":this._formatDate(a))},_getDate:function(a){var b=!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return b},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),d=this._get(a,"showButtonPanel"),e=this._get(a,"hideIfNoPrevNext"),f=this._get(a,"navigationAsDateFormat"),g=this._getNumberOfMonths(a),h=this._get(a,"showCurrentAtPos"),i=this._get(a,"stepMonths"),j=g[0]!=1||g[1]!=1,k=this._daylightSavingAdjust(a.currentDay?new Date(a.currentYear,a.currentMonth,a.currentDay):new Date(9999,9,9)),l=this._getMinMaxDate(a,"min"),m=this._getMinMaxDate(a,"max"),n=a.drawMonth-h,o=a.drawYear;n<0&&(n+=12,o--);if(m){var p=this._daylightSavingAdjust(new Date(m.getFullYear(),m.getMonth()-g[0]*g[1]+1,m.getDate()));p=l&&p<l?l:p;while(this._daylightSavingAdjust(new Date(o,n,1))>p)n--,n<0&&(n=11,o--)}a.drawMonth=n,a.drawYear=o;var q=this._get(a,"prevText");q=f?this.formatDate(q,this._daylightSavingAdjust(new Date(o,n-i,1)),this._getFormatConfig(a)):q;var r=this._canAdjustMonth(a,-1,o,n)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._adjustDate('#"+a.id+"', -"+i+", 'M');\""+' title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>":e?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+q+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+q+"</span></a>",s=this._get(a,"nextText");s=f?this.formatDate(s,this._daylightSavingAdjust(new Date(o,n+i,1)),this._getFormatConfig(a)):s;var t=this._canAdjustMonth(a,1,o,n)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._adjustDate('#"+a.id+"', +"+i+", 'M');\""+' title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>":e?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+s+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+s+"</span></a>",u=this._get(a,"currentText"),v=this._get(a,"gotoCurrent")&&a.currentDay?k:b;u=f?this.formatDate(u,v,this._getFormatConfig(a)):u;var w=a.inline?"":'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+dpuuid+'.datepicker._hideDatepicker();">'+this._get(a,"closeText")+"</button>",x=d?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?w:"")+(this._isInRange(a,v)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+dpuuid+".datepicker._gotoToday('#"+a.id+"');\""+">"+u+"</button>":"")+(c?"":w)+"</div>":"",y=parseInt(this._get(a,"firstDay"),10);y=isNaN(y)?0:y;var z=this._get(a,"showWeek"),A=this._get(a,"dayNames"),B=this._get(a,"dayNamesShort"),C=this._get(a,"dayNamesMin"),D=this._get(a,"monthNames"),E=this._get(a,"monthNamesShort"),F=this._get(a,"beforeShowDay"),G=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths"),I=this._get(a,"calculateWeek")||this.iso8601Week,J=this._getDefaultDate(a),K="";for(var L=0;L<g[0];L++){var M="";this.maxRows=4;for(var N=0;N<g[1];N++){var O=this._daylightSavingAdjust(new Date(o,n,a.selectedDay)),P=" ui-corner-all",Q="";if(j){Q+='<div class="ui-datepicker-group';if(g[1]>1)switch(N){case 0:Q+=" ui-datepicker-group-first",P=" ui-corner-"+(c?"right":"left");break;case g[1]-1:Q+=" ui-datepicker-group-last",P=" ui-corner-"+(c?"left":"right");break;default:Q+=" ui-datepicker-group-middle",P=""}Q+='">'}Q+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+P+'">'+(/all|left/.test(P)&&L==0?c?t:r:"")+(/all|right/.test(P)&&L==0?c?r:t:"")+this._generateMonthYearHeader(a,n,o,l,m,L>0||N>0,D,E)+'</div><table class="ui-datepicker-calendar"><thead>'+"<tr>";var R=z?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(var S=0;S<7;S++){var T=(S+y)%7;R+="<th"+((S+y+6)%7>=5?' class="ui-datepicker-week-end"':"")+">"+'<span title="'+A[T]+'">'+C[T]+"</span></th>"}Q+=R+"</tr></thead><tbody>";var U=this._getDaysInMonth(o,n);o==a.selectedYear&&n==a.selectedMonth&&(a.selectedDay=Math.min(a.selectedDay,U));var V=(this._getFirstDayOfMonth(o,n)-y+7)%7,W=Math.ceil((V+U)/7),X=j?this.maxRows>W?this.maxRows:W:W;this.maxRows=X;var Y=this._daylightSavingAdjust(new Date(o,n,1-V));for(var Z=0;Z<X;Z++){Q+="<tr>";var _=z?'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(Y)+"</td>":"";for(var S=0;S<7;S++){var ba=F?F.apply(a.input?a.input[0]:null,[Y]):[!0,""],bb=Y.getMonth()!=n,bc=bb&&!H||!ba[0]||l&&Y<l||m&&Y>m;_+='<td class="'+((S+y+6)%7>=5?" ui-datepicker-week-end":"")+(bb?" ui-datepicker-other-month":"")+(Y.getTime()==O.getTime()&&n==a.selectedMonth&&a._keyEvent||J.getTime()==Y.getTime()&&J.getTime()==O.getTime()?" "+this._dayOverClass:"")+(bc?" "+this._unselectableClass+" ui-state-disabled":"")+(bb&&!G?"":" "+ba[1]+(Y.getTime()==k.getTime()?" "+this._currentClass:"")+(Y.getTime()==b.getTime()?" ui-datepicker-today":""))+'"'+((!bb||G)&&ba[2]?' title="'+ba[2]+'"':"")+(bc?"":' onclick="DP_jQuery_'+dpuuid+".datepicker._selectDay('#"+a.id+"',"+Y.getMonth()+","+Y.getFullYear()+', this);return false;"')+">"+(bb&&!G?" ":bc?'<span class="ui-state-default">'+Y.getDate()+"</span>":'<a class="ui-state-default'+(Y.getTime()==b.getTime()?" ui-state-highlight":"")+(Y.getTime()==k.getTime()?" ui-state-active":"")+(bb?" ui-priority-secondary":"")+'" href="#">'+Y.getDate()+"</a>")+"</td>",Y.setDate(Y.getDate()+1),Y=this._daylightSavingAdjust(Y)}Q+=_+"</tr>"}n++,n>11&&(n=0,o++),Q+="</tbody></table>"+(j?"</div>"+(g[0]>0&&N==g[1]-1?'<div class="ui-datepicker-row-break"></div>':""):""),M+=Q}K+=M}K+=x+($.browser.msie&&parseInt($.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':""), +a._keyEvent=!1;return K},_generateMonthYearHeader:function(a,b,c,d,e,f,g,h){var i=this._get(a,"changeMonth"),j=this._get(a,"changeYear"),k=this._get(a,"showMonthAfterYear"),l='<div class="ui-datepicker-title">',m="";if(f||!i)m+='<span class="ui-datepicker-month">'+g[b]+"</span>";else{var n=d&&d.getFullYear()==c,o=e&&e.getFullYear()==c;m+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+dpuuid+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" "+">";for(var p=0;p<12;p++)(!n||p>=d.getMonth())&&(!o||p<=e.getMonth())&&(m+='<option value="'+p+'"'+(p==b?' selected="selected"':"")+">"+h[p]+"</option>");m+="</select>"}k||(l+=m+(f||!i||!j?" ":""));if(!a.yearshtml){a.yearshtml="";if(f||!j)l+='<span class="ui-datepicker-year">'+c+"</span>";else{var q=this._get(a,"yearRange").split(":"),r=(new Date).getFullYear(),s=function(a){var b=a.match(/c[+-].*/)?c+parseInt(a.substring(1),10):a.match(/[+-].*/)?r+parseInt(a,10):parseInt(a,10);return isNaN(b)?r:b},t=s(q[0]),u=Math.max(t,s(q[1]||""));t=d?Math.max(t,d.getFullYear()):t,u=e?Math.min(u,e.getFullYear()):u,a.yearshtml+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+dpuuid+".datepicker._selectMonthYear('#"+a.id+"', this, 'Y');\" "+">";for(;t<=u;t++)a.yearshtml+='<option value="'+t+'"'+(t==c?' selected="selected"':"")+">"+t+"</option>";a.yearshtml+="</select>",l+=a.yearshtml,a.yearshtml=null}}l+=this._get(a,"yearSuffix"),k&&(l+=(f||!i||!j?" ":"")+m),l+="</div>";return l},_adjustInstDate:function(a,b,c){var d=a.drawYear+(c=="Y"?b:0),e=a.drawMonth+(c=="M"?b:0),f=Math.min(a.selectedDay,this._getDaysInMonth(d,e))+(c=="D"?b:0),g=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(d,e,f)));a.selectedDay=g.getDate(),a.drawMonth=a.selectedMonth=g.getMonth(),a.drawYear=a.selectedYear=g.getFullYear(),(c=="M"||c=="Y")&&this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max"),e=c&&b<c?c:b;e=d&&e>d?d:e;return e},_notifyChange:function(a){var b=this._get(a,"onChangeMonthYear");b&&b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){var b=this._get(a,"numberOfMonths");return b==null?[1,1]:typeof b=="number"?[1,b]:b},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-this._daylightSavingAdjust(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,d){var e=this._getNumberOfMonths(a),f=this._daylightSavingAdjust(new Date(c,d+(b<0?b:e[0]*e[1]),1));b<0&&f.setDate(this._getDaysInMonth(f.getFullYear(),f.getMonth()));return this._isInRange(a,f)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min"),d=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!d||b.getTime()<=d.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,d){b||(a.currentDay=a.selectedDay,a.currentMonth=a.selectedMonth,a.currentYear=a.selectedYear);var e=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(d,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),e,this._getFormatConfig(a))}}),$.fn.datepicker=function(a){if(!this.length)return this;$.datepicker.initialized||($(document).mousedown($.datepicker._checkExternalClick).find("body").append($.datepicker.dpDiv),$.datepicker.initialized=!0);var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return $.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this[0]].concat(b));return this.each(function(){typeof a=="string"?$.datepicker["_"+a+"Datepicker"].apply($.datepicker,[this].concat(b)):$.datepicker._attachDatepicker(this,a)})},$.datepicker=new Datepicker,$.datepicker.initialized=!1,$.datepicker.uuid=(new Date).getTime(),$.datepicker.version="1.8.18",window["DP_jQuery_"+dpuuid]=$})(jQuery); \ No newline at end of file diff --git a/login.php b/login.php index 044d74644785f32a0f79bae76e6c4309fd473b2a..48dc9ec4aea9a5ab7c427cacc30b17c8005944b5 100644 --- a/login.php +++ b/login.php @@ -45,7 +45,7 @@ if($_POST && (!empty($_POST['lemail']) && !empty($_POST['lticket']))): //At this point we know the ticket is valid. //TODO: 1) Check how old the ticket is...3 months max?? 2) Must be the latest 5 tickets?? //Check the email given. - if($ticket->getId() && strcasecmp($ticket->getEMail(),$email)==0){ + if($ticket->getId() && strcasecmp($ticket->getEmail(),$email)==0){ //valid match...create session goodies for the client. $user = new ClientSession($email,$ticket->getId()); $_SESSION['_client']=array(); //clear. diff --git a/main.inc.php b/main.inc.php index b098bc175a890478dee7c40f99e7a42031ca37f9..0bfcf903a91866cd9c046f3d90020e3539cd935a 100644 --- a/main.inc.php +++ b/main.inc.php @@ -54,8 +54,8 @@ /*############## 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.7-DPR2'); //Shown on admin panel - define('SCHEMA_SIGNATURE','ssddsdsd'); //MD5 signature of the db schema. (used to trigger upgrades) + define('THIS_VERSION','1.7-DPR3'); //Shown on admin panel + define('SCHEMA_SIGNATURE','c2d2fabfdf15e1632f00850ffb361558'); //MD5 signature of the db schema. (used to trigger upgrades) #load config info $configfile=''; @@ -141,6 +141,7 @@ define('PRIORITY_TABLE',TICKET_PRIORITY_TABLE); define('TICKET_LOCK_TABLE',TABLE_PREFIX.'ticket_lock'); define('TICKET_EVENT_TABLE',TABLE_PREFIX.'ticket_event'); + define('TICKET_EMAIL_INFO_TABLE',TABLE_PREFIX.'ticket_email_info'); define('EMAIL_TABLE',TABLE_PREFIX.'email'); define('EMAIL_TEMPLATE_TABLE',TABLE_PREFIX.'email_template'); diff --git a/scp/admin.inc.php b/scp/admin.inc.php index a580fa6986b87661b039419bcf178e5ae46ad12e..5f6f5e7633422251ca7bbf8960f69461a8afbc35 100644 --- a/scp/admin.inc.php +++ b/scp/admin.inc.php @@ -15,34 +15,29 @@ **********************************************************************/ require('staff.inc.php'); //Make sure config is loaded and the staff is set and of admin type -if(!$cfg or !$thisstaff or !$thisstaff->isadmin()){ +if(!$cfg or !$thisstaff or !$thisstaff->isAdmin()){ header('Location: index.php'); require('index.php'); // just in case! exit; } //Some security related warnings - bitch until fixed!!! :) -if(defined('THIS_VERSION') && strcasecmp($cfg->getVersion(),THIS_VERSION)) { - $sysnotice=sprintf('The script is version %s while the database is version %s.',THIS_VERSION,$cfg->getVersion()); - if(file_exists('../setup/')) - $sysnotice.=' Possibly caused by incomplete <a href="../setup/upgrade.php">upgrade</a>.'; - $errors['err']=$sysnotice; -}elseif(!$cfg->isHelpDeskOffline()) { - if(file_exists('../setup/')){ - $sysnotice='Please take a minute to delete <strong>setup/install</strong> directory for security reasons.'; - }else{ - - if(CONFIG_FILE && file_exists(CONFIG_FILE) && is_writable(CONFIG_FILE)) { +if($cfg->isUpgradePending()) { + $errors['err']=$sysnotice='System upgrade is pending <a href="../setup/upgrade.php">Upgrade Now</a>'; +} elseif(!$cfg->isHelpDeskOffline()) { + + if(file_exists('../setup/')) { + $sysnotice='Please take a minute to delete <strong>setup/install</strong> directory (../setup/) for security reasons.'; + } elseif(CONFIG_FILE && file_exists(CONFIG_FILE) && is_writable(CONFIG_FILE)) { //Confirm for real that the file is writable by group or world. clearstatcache(); //clear the cache! $perms = @fileperms(CONFIG_FILE); if(($perms & 0x0002) || ($perms & 0x0010)) { $sysnotice=sprintf('Please change permission of config file (%s) to remove write access. e.g <i>chmod 644 %s</i>', - basename(CONFIG_FILE),basename(CONFIG_FILE)); + basename(CONFIG_FILE), basename(CONFIG_FILE)); } - } - } + if(!$sysnotice && ini_get('register_globals')) $sysnotice='Please consider turning off register globals if possible'; } diff --git a/scp/ajax.php b/scp/ajax.php index fac8a088f6a5ede0cc29c9488da06d2463b03a8f..c1da3acdaf4a2817c8a07ff3deb8ab7e6c546de5 100644 --- a/scp/ajax.php +++ b/scp/ajax.php @@ -43,7 +43,7 @@ $dispatcher = patterns('', url_get('^ticket_variables', 'ticket_variables') )), url('^/config/', patterns('ajax.config.php:ConfigAjaxAPI', - url_get('^ui', 'ui') + url_get('^ui', 'scp_ui') )), url('^/report/overview/', patterns('ajax.reports.php:OverviewReportAjaxAPI', # Send @@ -52,12 +52,13 @@ $dispatcher = patterns('', url_get('^table$', 'getTabularData') )), url_get('^/users$', array('ajax.users.php:UsersAjaxAPI', 'search')), - url_get('^/tickets$', array('ajax.tickets.php:TicketsAjaxAPI', 'search')), - url('^/ticket/', patterns('ajax.tickets.php:TicketsAjaxAPI', + url('^/tickets/', patterns('ajax.tickets.php:TicketsAjaxAPI', url_get('^(?P<tid>\d+)/preview', 'previewTicket'), url_get('^(?P<tid>\d+)/lock', 'acquireLock'), url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/renew', 'renewLock'), - url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/release', 'releaseLock') + url_post('^(?P<tid>\d+)/lock/(?P<id>\d+)/release', 'releaseLock'), + url_get('^lookup', 'lookup'), + url_get('^search', 'search') )) ); diff --git a/scp/banlist.php b/scp/banlist.php index 1ef580a5746e7666c7aebf4f72e364acb30456ea..b56d05c6d07b28b2536127abe9a5b3be6330cb69 100644 --- a/scp/banlist.php +++ b/scp/banlist.php @@ -68,7 +68,7 @@ if($_POST && !$errors && $filter){ }else{ $count=count($_POST['ids']); if($_POST['enable']){ - $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=1 WHERE filter_id='.db_input($filter->getID()). + $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=1 WHERE filter_id='.db_input($filter->getId()). ' AND id IN ('.implode(',',$_POST['ids']).')'; if(db_query($sql) && ($num=db_affected_rows())){ if($num==$count) @@ -79,7 +79,7 @@ if($_POST && !$errors && $filter){ $errors['err']='Unable to enable selected emails'; } }elseif($_POST['disable']){ - $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=0 WHERE filter_id='.db_input($filter->getID()). + $sql='UPDATE '.EMAIL_FILTER_RULE_TABLE.' SET isactive=0 WHERE filter_id='.db_input($filter->getId()). ' AND id IN ('.implode(',',$_POST['ids']).')'; if(db_query($sql) && ($num=db_affected_rows())) { if($num==$count) diff --git a/scp/css/scp.css b/scp/css/scp.css index 5ccdbe543b0030b0fe910fc2382102bd997a4acc..aa6ca4782492783d221fef0c6b18fe412f3cbcd5 100644 --- a/scp/css/scp.css +++ b/scp/css/scp.css @@ -1,1062 +1,1305 @@ -body { - background:#eee; - font-family:arial, helvetica, sans-serif; - font-size:10pt; - color:#000; - margin:0; - padding:0; -} - -a { - color:#E65524; - text-decoration:none; -} - -.centered { - text-align:center; -} - -.clear { - clear:both; -} - -.faded { - color:#666; -} - -.strike { text-decoration:line-through; color:red; } - -#canned_attachments label { padding:3px; padding-right:10px; } - - -#breadcrumbs { - color: #333; - margin-bottom: 15px; -} - -#breadcrumbs a { - color: #555; -} - -#msg_notice { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #0a0; background: url('../images/icons/ok.png?1300763726') 10px 50% no-repeat #e0ffe0; } - -#msg_warning { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #f26522; background: url('../images/icons/alert.png?1307823786') 10px 50% no-repeat #ffffdd; } - -#msg_error { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #a00; background: url('../images/icons/error.png') 10px 50% no-repeat #fff0f0; } - - -#container { - width:960px; - margin:0 auto 20px auto; -} - -#header { - height:76px; - background:url(../images/header-bg.png) top left repeat-x; - border-left:1px solid #aaa; - border-right:1px solid #aaa; -} - -#logo { - display:block; - float:left; - width:190px; - height:76px; - text-decoration:none; - outline:none; - text-indent:-9999px; - background:url(../images/ost-logo.png) top left no-repeat; -} - -#header p { - display:block; - width:430px; - float:right; - margin:10px; - background:#eee; - border:1px solid #ccc; - padding:8px; - text-align:center; -} - -#nav, #sub_nav { - clear:both; - margin:0; - padding:0 20px; - height:26px; - line-height:26px; - border-left:1px solid #aaa; - border-right:1px solid #aaa; -} - -#nav .active, #sub_nav li { - margin:0; - padding:0; - list-style:none; - display:inline; -} - -#nav { - background:#eee; - padding-top:4px; - z-index:200; - border-top:1px solid #ddd; - border-bottom:1px solid #c5d9ec; -} - -#nav .active a, #nav .inactive { - display:block; - float:left; - width:115px; - height:26px; - color:#555; - text-align:center; - font-weight:bold; - margin-top:1px; - margin-right:5px; - position:relative; -} - -#nav .inactive a { - color:#555; - display:block; -} - -#nav .active a { - background:url(../images/tab-bg.png) top left no-repeat; - color:#004a80; -} - -#nav .inactive ul { - display:none; - width:230px; - background:#fbfbfb; - margin:0; - padding:0; - position:relative; - z-index:500; - border-bottom:1px solid #ccc; - border-left:1px solid #ccc; - border-right:1px solid #ccc; -} - -#nav .inactive li { - display:block; - margin:0; - padding:0 5px; - list-style:none; - text-align:left; -} - -#nav .inactive:hover { - background:url(../images/tab-bg.png) bottom left no-repeat; -} - -#nav .inactive:hover ul { - display:block; - -moz-box-shadow: 3px 3px 3px #ccc; - -webkit-box-shadow: 3px 3px 3px #ccc; - box-shadow: 3px 3px 3px #ccc; -} - -.ieshadow { - width:230px; - background:#000; - filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30); - -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30)"; - zoom: 1; - z-index:300; - position:absolute; - top:24px; - left:0; -} - -#nav .inactive li { - background:#fbfbfb; -} - -#nav .inactive li a { - padding-left:24px; - background-position:0 50%; - background-repeat:no-repeat; - font-weight:normal; - background-color:#fbfbfb; -} - -#nav .inactive li a:hover { - color:#E65524; -} - -#sub_nav { - background:#f7f7f7; - border-bottom:1px solid #bebebe; -} - -#sub_nav a { - display:block; - float:left; - margin-right:10px; - padding:0 10px 0 21px; - background-position:0 50%; - background-repeat:no-repeat; - color:#000; -} - -#sub_nav a:hover { - color:#E65524; -} - -#sub_nav a.active { - font-weight:bold; -} - -#sub_nav .open { background-image:url(../images/icons/open.gif) } -#sub_nav .answered { background-image:url(../images/icons/answered.gif) } -#sub_nav .mine { background-image:url(../images/icons/mine.gif) } -#sub_nav .closed { background-image:url(../images/icons/closed.gif) } -#sub_nav .new { background-image:url(../images/icons/new.gif) } - -a.test { background-image:url(../images/icons/open.gif) } - -a.Ticket { background:url(../images/icons/open_tickets.gif) } -a.assignedTickets { background:url(../images/icons/assigned_tickets.gif) } -a.overdueTickets { background:url(../images/icons/overdue_tickets.gif) } -a.answeredTickets { background:url(../images/icons/answered_tickets.gif) } -a.closedTickets { background:url(../images/icons/closed_tickets.gif) } -a.newTicket { background:url(../images/icons/new_ticket.gif) } - -a.premade { background:url(../images/icons/premade_reply.gif) } -a.newPremade { background:url(../images/icons/new_premade_reply.gif) } - -a.staff { background:url(../images/icons/list_groups.gif) } -a.user { background:url(../images/icons/list_users.gif) } -a.userPref { background:url(../images/icons/user_preferences.gif) } -a.userPasswd { background:url(../images/icons/change_password.gif) } - -a.preferences { background:url(../images/icons/settings.gif) } -a.attachment { background:url(../images/icons/attachment.gif ) } -a.api { background:url(../images/icons/api.png) } -a.newapi { background:url(../images/icons/new_api.png) } - -a.sla { background:url(../images/icons/slas.png) } -a.newsla { background:url(../images/icons/new_sla.png) } - -a.logs { background:url(../images/icons/logs.gif) } - -a.emails { background:url(../images/icons/emails.png) } -a.newEmail { background:url(../images/icons/new_email.png) } - -a.emailTemplates { background:url(../images/icons/email_templates.png) } -a.newEmailTemplate { background:url(../images/icons/new_email_template.png) } - -a.emailFilters { background:url(../images/icons/email_filters.png) } -a.newEmailFilter { background:url(../images/icons/new_email_filter.png) } - -a.emailSettings { background:url(../images/icons/emails.png) } -a.emailDiagnostic { background:url(../images/icons/email_diagnostic.gif) } -a.banList { background:url(../images/icons/ban_list.gif) } - -a.users { background:url(../images/icons/list_users.gif) } -a.newuser { background:url(../images/icons/new_user.gif) } -a.groups { background:url(../images/icons/list_groups.gif) } -a.teams { background:url(../images/icons/teams.gif) } -a.newgroup { background:url(../images/icons/new_group.gif) } - -a.helpTopics { background:url(../images/icons/help_topics.png) } -a.newHelpTopic { background:url(../images/icons/new_help_topic.png) } - -a.departments { background:url(../images/icons/list_departments.gif) } -a.newDepartment { background:url(../images/icons/new_department.gif) } - - -/* Generic CSS based Icons. use=> <tag class="Icon iconname">text</tag> */ - -.Icon { - width: auto; - padding-left:20px; - background-position: left center; - background-repeat: no-repeat; -} - - -a.Icon { background-repeat: no-repeat;} - - -a.Icon:hover { - text-decoration: underline; -} - - -.Icon.newstaff { background:url(../images/icons/new_user.gif) 0 0 no-repeat; } -.Icon.newteam { background:url(../images/icons/new_team.gif) 0 0 no-repeat; } - -.Icon.Ticket { background:url(../images/icons/ticket.gif) 0 2px no-repeat; } -.Icon.webTicket { background:url(../images/icons/ticket_source_web.gif) 0 0 no-repeat; } -.Icon.emailTicket { background:url(../images/icons/ticket_source_email.gif) 0 0 no-repeat; } -.Icon.phoneTicket { background:url(../images/icons/ticket_source_phone.gif) 0 0 no-repeat; } -.Icon.otherTicket { background:url(../images/icons/ticket_source_other.gif) 0 0 no-repeat; } -.Icon.overdueTicket { background:url(../images/icons/overdue_ticket.gif) 0 0 no-repeat; } -.Icon.assignedTicket { background:url(../images/icons/assigned_ticket.gif) 0 0 no-repeat; } -.Icon.lockedTicket { background:url(../images/icons/locked_ticket.gif) 0 0 no-repeat; } -.Icon.editTicket { background-image: url(../images/icons/edit_ticket.png); } - -.Icon.file { background-image: url(../images/icons/file.gif); } -.Icon.refresh { background-image: url(../images/icons/refresh.gif); } -.Icon.note { - font-weight: bold; - font-size: 1em; - background-image: url(../images/icons/note.gif); -} - -.Icon.thread { - font-weight: bold; - font-size: 1em; - background-image: url(../images/icons/thread.gif); -} - - -.Icon.debugLog { background:url(../images/icons/log_debug.gif) 0 2px no-repeat; } -.Icon.alertLog { background:url(../images/icons/log_alert.gif) 0 2px no-repeat; } -.Icon.errorLog { background:url(../images/icons/log_error.gif) 0 2px no-repeat; } - - - -#content { - clear:both; - border:1px solid #aaa; - border-top:none; - border-bottom:3px solid #bbb; - padding:10px 10px 20px 10px; - background:#fff; -} - -#content a { - color:#184E81; -} - -#footer { - clear:both; - padding:10px; - text-align:center; - font-size:9pt; -} - -table { vertical-align:top; } - -table.list { - clear:both; - background:#ccc; - margin: 2px 0; - border-bottom: 1px solid #ccc; - font-family:arial, helvetica, sans-serif; - font-size:10pt; -} - -table.list caption { - text-align:left; - padding:5px; - background:#929292; - color:#fff; - font-weight:bold; -} - -table.list thead th { - background-color:#eee; - color:#000; - text-align:left; - vertical-align:top; -} - -table.list th a { - - text-decoration:none; - color:#000; -} - -table.list thead th a { padding: 3px; display: block; color: #000; background: url('../images/asc_desc.gif') 100% 50% no-repeat; } - -table.list thead th a.asc { background: url('../images/asc.gif') 100% 50% no-repeat #cfe6ff; } -table.list thead th a.desc { background: url('../images/desc.gif') 100% 50% no-repeat #cfe6ff; } -table.list tbody td { - background:#fff; - border:1px solid #fff; - padding:1px; - vertical-align:top; -} - -table.list tbody td { background: #fff; padding: 1px; padding-left:2px; vertical-align: top; } -table.list tbody tr.odd td { background-color: #f0faff; } -table.list tbody tr:hover td { background: #ffe; } -table.list tbody tr.odd:hover td { background: #ffd; } - -table.list tfoot td { - background:#eee; - padding: 2px; -} - -table.list tbody td.webticket, table.list tbody tr.row1 td.webticket { - text-indent:20px; - background:url(../images/icons/ticket_source_web.gif) 0 50% no-repeat #fff; -} - -table.list tbody td.emailticket, table.list tbody tr.row1 td.emailticket { - text-indent:20px; - background:url(../images/icons/ticket_source_email.gif) 0 50% no-repeat; -} - -table.list tbody td.phoneticket, table.list tbody tr.row1 td.phoneticket { - text-indent:20px; - background:url(../images/icons/ticket_source_phone.gif) 0 50% no-repeat; -} - -table.list tbody td.otherticket, table.list tbody tr.row1 td.otherticket { - text-indent:20px; - background:url(../images/icons/ticket_source_other.gif) 0 50% no-repeat; -} - -a.refresh { - display:block; - float:right; - width:auto; - height:16px; - line-height:16px; - padding:2px 5px 2px 2px; - background-position:2px 50%; - background-repeat:no-repeat; - padding-left:24px; - margin-left:10px; - margin-bottom: 2px; - border:1px solid #aaa; - background-image:url(../images/icons/refresh.gif); -} - -a.edit, a.print { - display:block; - float:right; - width:auto; - height:16px; - line-height:16px; - padding:2px 5px 2px 2px; - background-position:2px 50%; - background-repeat:no-repeat; - padding-left:24px; - margin-left:10px; - border:1px solid #aaa; - background-image:url(../images/icons/edit_ticket.png); -} - -a.print { - background-image:url(../images/icons/printer.gif); -} - -.btn { - padding:3px 10px; - background:url(../images/btn_bg.png) top left repeat-x #ccc; - border:1px solid #777; - color:#000; -} - -.button { padding:1px 5px; margin-right:10px; color:#777; font-weight:bold;} - -.btn_sm { - padding:2px 5px; - font-size:9pt; - background:url(../images/btn_sm_bg.png) top left repeat-x #f90; - border:1px solid #777; - color:#fff; - font-weight:bold; -} - -.btn:hover, .btn_sm:hover { - background-position: bottom left; -} - -.search label { - display:block; - line-height:25px; - height:25px; -} - -.search input[type=text] { - height:23px; - line-height:23px; - border:1px solid #aaa; - background:#fff; - padding:2px; -} - -.form_table { - margin-top:3px; - border-left:1px solid #ddd; - border-right:1px solid #ddd; -} - -.form_table td { - border-bottom:1px solid #ddd; -} - - -.form_table td.multi-line { - vertical-align:top; -} - -.form_table input[type=text], .form_table input[type=password], .form_table textarea { - background:#fff; - border:1px solid #aaa; -} - -.form_table input[type=radio], .form_table input[type=checkbox] { - position:relative; - top:3px; - margin-left:0; - padding-left:0; -} - -.form_table .required { - font-weight:bold; -} - -.form_table em { - font-weight:normal; - color:#666; -} - -.error { - color:#f00; -} - -.form_table .error input { - border:1px solid #f00; -} - -.form_table th { - text-align:left; - border:1px solid #ccc; - background:#eee; - padding:0; -} - -.form_table th h4 { - margin:0; - padding:5px; - color:#fff; - background:#929292; -} - -.form_table th em { - display:block; - padding:5px; - color:#000; -} - -.settings_table { - margin-top:2px; - border-left:1px solid #ddd; - border-right:1px solid #ddd; -} - -.settings_table td { - border-bottom:1px solid #ddd; -} - -.settings_table input[type=radio], .settings_table input[type=checkbox] { - margin-left:0; - padding-left:0; -} - -#content .settings_table th h4 a { - display:block; - color:#fff; -} - -.settings_table h4 a span { - font-size:12pt; - line-height:14px; - display:inline-block; - width:14px; - height:14px; - overflow:hidden; - text-align:center; - color:#444; - background:#ccc; - position:relative; - top:2px; -} - -h2 { - margin:0; - padding:0; - font-size:12pt; - color:#0A568E; -} - -h2 span { color:#000; } - -h3 { - margin:10px 0 0 0; - padding:5px 0; - font-size:10pt; - color:#444; -} - -.ticket_info th { - text-align:left; -} - -.ticket_info { - background:#F4FAFF; -} - -.right_align { text-align:right; } - -h2 .reload { - display:inline-block; - width:16px; - height:16px; - background:url(../images/icons/refresh.gif) top left no-repeat; - outline:none; - text-indent:-9999px; -} - -#assigned_message { - margin:10px 0; - padding:5px 5px 5px 30px; - background:url(../images/icons/assigned_ticket.gif) 5px 50% no-repeat #ffd; - border:1px solid #f90; -} - - - - -#ticket_actions { - padding:5px; - background:#eee; - border:1px solid #aaa; - border-bottom:none; - margin:0; -} - -#threads { - margin:0; - padding:5px 10px 0 10px; - border:1px solid #aaa; - background:#F4FAFF; - height:30px; -} - -#threads li { - list-style:none; - margin:0; - padding:0; - display:inline; -} - -#threads li a { - display:block; - width:auto; - float:left; - height:30px; - line-height:30px; - border-top:1px solid #F4FAFF; - padding:0 10px 0 32px; - margin-right:10px; -} - -#threads li a.active { - height:29px; - background-color:#fff; - border:1px solid #aaa; - border-bottom:none; - border-top:2px solid #ed9100; - font-weight:bold; -} - -#toggle_ticket_thread { - background:url(../images/icons/open.gif) 10px 50% no-repeat; -} - -#toggle_notes { - background:url(../images/icons/note.gif) 10px 50% no-repeat; -} - -#latest_notes { - margin:10px 0; - padding:10px; - background:#ffe; - border:1px solid #e7e765; -} - -#latest_notes h3 { - margin:0 0 10px 0; - padding:0; - font-size:11pt; -} - -#latest_notes h3 span, #latest_notes h3 a { - color:#777; - font-weight:normal; - text-decoration:none; - font-size:10pt; -} - -#latest_notes ul { - margin:0 20px; - padding:0; -} - -#latest_notes ul li { - margin:0; - padding:0 0 10px 0; - list-style:none; -} - -#latest_notes em { - color:#777; -} - -#ticket_thread table { - margin-top:10px; - border:1px solid #aaa; - border-bottom:2px solid #aaa; -} - -#ticket_notes table { - margin-top:10px; - border:1px solid #ddd; - border-bottom:2px solid #ddd; -} - -#ticket_thread table th, #ticket_notes table th { - text-align:left; - border-bottom:1px solid #aaa; - font-size:10pt; - padding:5px; -} - -#ticket_notes table th { - text-align:left; - border-bottom:1px solid #ddd; - font-size:10pt; - padding:5px; - background:#F4FAFF; -} - -#ticket_notes table th em { - font-weight:normal; - font-size:10pt; - color:#666; -} - -#ticket_thread .message th { - background:#C3D9FF; -} - -#ticket_notes .date { - font-weight:normal; - font-size:10pt; - color:#888; - text-align:right; -} - -#ticket_thread .response th { - background:#FFE0B3; -} - -#ticket_thread table td, #ticket_notes table td { - padding:5px; -} - -#ticket_notes td { - background:#f9f9f9; -} - -#ticket_thread .info, #ticket_notes .info { - padding:5px; - background:#F4FAFF; - height:16px; - line-height:16px; -} - -#ticket_notes .info { - background:#f9f9f9; -} - -#response_options { - margin-top:30px; -} - -#response_options form { - padding:0 10px; -} - -#response_options ul { - padding:4px 0 0 190px; - margin:0; - text-align:center; - height:29px; - border-bottom:1px solid #aaa; - background:#eef3f8; -} - -#response_options li { - margin:0; - padding:0; - display:inline; - list-style:none; -} - -#response_options li a { - width:130px; - font-weight:bold; - padding:5px; - height:18px; - line-height:20px; - color:#444; - display:block; - float:left; - outline:none; - position:relative; - top:0; - background:#fbfbfb; - border:1px solid #eee; - border-bottom:none; -} - -#response_options .reply_tab.tell { - color:#a00 !important; - background-image:url(../images/reminder.png); - background-position:12px 50%; - background-repeat:no-repeat; -} - -#response_options li a.active { - height:18px; - color:#184E81; - background-color:#f9f9f9; - border:1px solid #aaa; - border-top:2px solid #81a9d7; - border-bottom:none; -} - -#response_options form { - padding:10px 5px; - background:#f9f9f9; - border:1px solid #aaa; - border-top:none; -} - -#response_options table { - width:928px; -} - -#response_options td { - vertical-align:top; -} - -#response_options textarea { - width:760px !important; -} - -#response_options input[type=text], #response_options textarea { - border:1px solid #aaa; - background:#fff; -} - -.attachments .uploads div { - display:inline-block; - padding-right:20px; -} - - - -.file { - display:inline-block; - padding-left:20px; - margin-right:20px; - background:url(../images/icons/file.gif) 0 50% no-repeat; -} - -.expander { - line-height:14px; - display:inline-block; - width:12px; - height:12px; - overflow:hidden; - text-align:center; - color:#aaa; - position:relative; -} - -/** Popup Tool Tips and Content **/ - -.tip_box { - display:block; - height:30px; - position:absolute; - z-index:1000; -} - -.tip_arrow { - display:block; - position:absolute; - top:5px; - left:-11px; - width:12px; - z-index:700; -} - -.tip_content { - height:auto !important; - height:20px; - min-height:20px; - padding:10px 5px 5px 5px; - border:1px solid #666; - background:#fff; - -moz-border-radius:5px; - -webkit-border-radius:5px; - border-radius:5px; - -moz-box-shadow: 3px 3px 3px #666; - -webkit-box-shadow: 3px 3px 3px #666; - box-shadow: 3px 3px 3px #666; - z-index:500; - position:absolute; - top:0; - left:-1px; - width:auto !important; - width:300px; -} - -.tip_content hr { - - color: #ddd; - background-color: #ddd; - height: 1px; - border: 0; - padding: 0; - margin: 0.2em 0; - width: 100%; -} - -.tip_close { - position:absolute; - left:100%; - top:0; - margin-left:-12px; -} - -.tip_shadow { - display:none; - background:#000; - filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60); - -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60)"; - zoom: 1; - position:absolute; - z-index:200; - top:0; - left:0; - width:auto !important; - width:310px; -} - -.tip_menu { - margin:10px 0 0 0; - padding:5px 0; - border-top:1px solid #aaa; - height:16px; - font-size:9pt; -} - -.tip_menu li { - display:inline; - list-style:none; - margin:0; - padding:0; -} - -.tip_menu li a { - display:block; - width:auto; - _width:0; - float:left; - padding:0 10px; - border-right:1px solid #ddd; - color:#666; -} - -.tip_menu li a:hover { - color:#E76C74; -} - -.tip_content form { - display:none; - line-height:24px; -} - -.tip_content select, .tip_content textarea { - width:295px; -} - -.tip_content textarea { - padding:0; - border:1px solid #aaa; - background:#fff; -} - -.tip_content form p { - margin:0; - width:auto !important; - width:295px; - text-align:right; - line-height:24px; -} - -/* Knowledgebase */ -#kb { - margin: 2px 0; - padding: 0; - overflow: hidden; -} - -#kb > li { - margin: 0 0 5px 0; - padding: 0 10px; - width: auto; - float: left; - clear: both; -} - -#kb > li h4 { - padding-bottom:3px; - margin-bottom:3px; -} - -#kb > li h4 span { - color:#666; -} - -#kb > li h4 a { - font-size: 14px; -} - -#faq { - clear: both; - margin: 0; - padding: 5 0 10px 5px; -} -#faq ol { - font-size: 15px; - margin-left: 0; - padding-left: 0; -} -#faq ol li { - list-style: none; - margin: 0 0 10px 0; - color: #999; -} -#faq ol li a { - display: inline; - height: 16px; - line-height: 16px; - padding-left: 24px; - background: url('../images/icons/page.png') 0 50% no-repeat; -} +body { + background:#eee; + font-family:arial, helvetica, sans-serif; + font-size:10pt; + color:#000; + margin:0; + padding:0; +} + +a { + color:#E65524; + text-decoration:none; +} + +.centered { + text-align:center; +} + +.clear { + clear:both; +} + +.faded { + color:#666; +} + +.strike { text-decoration:line-through; color:red; } + +#canned_attachments label { padding:3px; padding-right:10px; } + + +#breadcrumbs { + color: #333; + margin-bottom: 15px; +} + +#breadcrumbs a { + color: #555; +} + +#msg_notice { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #0a0; background: url('../images/icons/ok.png?1300763726') 10px 50% no-repeat #e0ffe0; } + +#msg_warning { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #f26522; background: url('../images/icons/alert.png?1307823786') 10px 50% no-repeat #ffffdd; } + +#msg_error { margin: 0; padding: 5px 10px 5px 36px; height: 16px; line-height: 16px; margin-bottom: 10px; border: 1px solid #a00; background: url('../images/icons/error.png') 10px 50% no-repeat #fff0f0; } + + +#container { + width:960px; + margin:0 auto 20px auto; +} + +#header { + height:76px; + background:url(../images/header-bg.png) top left repeat-x; + border-left:1px solid #aaa; + border-right:1px solid #aaa; +} + +#logo { + display:block; + float:left; + width:190px; + height:76px; + text-decoration:none; + outline:none; + text-indent:-9999px; + background:url(../images/ost-logo.png) top left no-repeat; +} + +#header p { + display:block; + width:430px; + float:right; + margin:10px; + background:#eee; + border:1px solid #ccc; + padding:8px; + text-align:center; +} + +#nav, #sub_nav { + clear:both; + margin:0; + padding:0 20px; + height:26px; + line-height:26px; + border-left:1px solid #aaa; + border-right:1px solid #aaa; +} + +#nav .active, #sub_nav li { + margin:0; + padding:0; + list-style:none; + display:inline; +} + +#nav { + background:#eee; + padding-top:4px; + z-index:200; + border-top:1px solid #ddd; + border-bottom:1px solid #c5d9ec; +} + +#nav .active a, #nav .inactive { + display:block; + float:left; + width:115px; + height:26px; + color:#555; + text-align:center; + font-weight:bold; + margin-top:1px; + margin-right:5px; + position:relative; +} + +#nav .inactive a { + color:#555; + display:block; +} + +#nav .active a { + background:url(../images/tab-bg.png) top left no-repeat; + color:#004a80; +} + +#nav .inactive ul { + display:none; + width:230px; + background:#fbfbfb; + margin:0; + padding:0; + position:relative; + z-index:500; + border-bottom:1px solid #ccc; + border-left:1px solid #ccc; + border-right:1px solid #ccc; +} + +#nav .inactive li { + display:block; + margin:0; + padding:0 5px; + list-style:none; + text-align:left; +} + +#nav .inactive:hover { + background:url(../images/tab-bg.png) bottom left no-repeat; +} + +#nav .inactive:hover ul { + display:block; + -moz-box-shadow: 3px 3px 3px #ccc; + -webkit-box-shadow: 3px 3px 3px #ccc; + box-shadow: 3px 3px 3px #ccc; +} + +.ieshadow { + width:230px; + background:#000; + filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30); + -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.30)"; + zoom: 1; + z-index:300; + position:absolute; + top:24px; + left:0; +} + +#nav .inactive li { + background:#fbfbfb; +} + +#nav .inactive li a { + padding-left:24px; + background-position:0 50%; + background-repeat:no-repeat; + font-weight:normal; + background-color:#fbfbfb; +} + +#nav .inactive li a:hover { + color:#E65524; +} + +#sub_nav { + background:#f7f7f7; + border-bottom:1px solid #bebebe; +} + +#sub_nav a { + display:block; + float:left; + margin-right:10px; + padding:0 10px 0 21px; + background-position:0 50%; + background-repeat:no-repeat; + color:#000; +} + +#sub_nav a:hover { + color:#E65524; +} + +#sub_nav a.active { + font-weight:bold; +} + +#sub_nav .open { background-image:url(../images/icons/open.gif) } +#sub_nav .answered { background-image:url(../images/icons/answered.gif) } +#sub_nav .mine { background-image:url(../images/icons/mine.gif) } +#sub_nav .closed { background-image:url(../images/icons/closed.gif) } +#sub_nav .new { background-image:url(../images/icons/new.gif) } + +a.test { background-image:url(../images/icons/open.gif) } + +a.Ticket { background:url(../images/icons/open_tickets.gif) } +a.assignedTickets { background:url(../images/icons/assigned_tickets.gif) } +a.overdueTickets { background:url(../images/icons/overdue_tickets.gif) } +a.answeredTickets { background:url(../images/icons/answered_tickets.gif) } +a.closedTickets { background:url(../images/icons/closed_tickets.gif) } +a.newTicket { background:url(../images/icons/new_ticket.gif) } + +a.premade { background:url(../images/icons/premade_reply.gif) } +a.newPremade { background:url(../images/icons/new_premade_reply.gif) } + +a.kb { background:url(../images/icons/kb.gif) } +a.kb-categories { background:url(../images/icons/kb-categories.gif) } +a.canned { background:url(../images/icons/canned.gif) } + +a.staff { background:url(../images/icons/list_groups.gif) } +a.user { background:url(../images/icons/list_users.gif) } +a.userPref { background:url(../images/icons/user_preferences.gif) } +a.userPasswd { background:url(../images/icons/change_password.gif) } + +a.preferences { background:url(../images/icons/settings.gif) } +a.attachment { background:url(../images/icons/attachment.gif ) } +a.api { background:url(../images/icons/api.png) } +a.newapi { background:url(../images/icons/new_api.png) } + +a.sla { background:url(../images/icons/slas.png) } +a.newsla { background:url(../images/icons/new_sla.png) } + +a.logs { background:url(../images/icons/logs.gif) } + +a.emails { background:url(../images/icons/emails.png) } +a.newEmail { background:url(../images/icons/new_email.png) } + +a.emailTemplates { background:url(../images/icons/email_templates.png) } +a.newEmailTemplate { background:url(../images/icons/new_email_template.png) } + +a.emailFilters { background:url(../images/icons/email_filters.png) } +a.newEmailFilter { background:url(../images/icons/new_email_filter.png) } + +a.emailSettings { background:url(../images/icons/emails.png) } +a.emailDiagnostic { background:url(../images/icons/email_diagnostic.gif) } +a.banList { background:url(../images/icons/ban_list.gif) } + +a.users { background:url(../images/icons/list_users.gif) } +a.newuser { background:url(../images/icons/new_user.gif) } +a.groups { background:url(../images/icons/list_groups.gif) } +a.teams { background:url(../images/icons/teams.gif) } +a.newgroup { background:url(../images/icons/new_group.gif) } + +a.helpTopics { background:url(../images/icons/help_topics.png) } +a.newHelpTopic { background:url(../images/icons/new_help_topic.png) } + +a.departments { background:url(../images/icons/list_departments.gif) } +a.newDepartment { background:url(../images/icons/new_department.gif) } + + +/* Generic CSS based Icons. use=> <tag class="Icon iconname">text</tag> */ + +.Icon { + width: auto; + padding-left:20px; + background-position: left center; + background-repeat: no-repeat; +} + + +a.Icon { background-repeat: no-repeat;} + + +a.Icon:hover { + text-decoration: underline; +} + + +.Icon.newstaff { background:url(../images/icons/new_user.gif) 0 0 no-repeat; } +.Icon.newteam { background:url(../images/icons/new_team.gif) 0 0 no-repeat; } + +.Icon.Ticket { background:url(../images/icons/ticket.gif) 0 2px no-repeat; } +.Icon.webTicket { background:url(../images/icons/ticket_source_web.gif) 0 0 no-repeat; } +.Icon.emailTicket { background:url(../images/icons/ticket_source_email.gif) 0 0 no-repeat; } +.Icon.phoneTicket { background:url(../images/icons/ticket_source_phone.gif) 0 0 no-repeat; } +.Icon.otherTicket { background:url(../images/icons/ticket_source_other.gif) 0 0 no-repeat; } +.Icon.overdueTicket { background:url(../images/icons/overdue_ticket.gif) 0 0 no-repeat; } +.Icon.assignedTicket { background:url(../images/icons/assigned_ticket.gif) 0 0 no-repeat; } +.Icon.lockedTicket { background:url(../images/icons/locked_ticket.gif) 0 0 no-repeat; } +.Icon.editTicket { background-image: url(../images/icons/edit_ticket.png); } + +.Icon.newCategory { background-image: url(../images/icons/new_category.png); } +.Icon.editCategory { background-image: url(../images/icons/edit_category.png); } +.Icon.deleteCategory { background-image: url(../images/icons/delete_category.png); } +.Icon.newFAQ { background-image: url(../images/icons/new_faq.png); } +.Icon.newReply { background-image: url(../images/icons/new_reply.png); } + +.Icon.file { background-image: url(../images/icons/file.gif); } +.Icon.refresh { background-image: url(../images/icons/refresh.gif); } +.Icon.note { + font-weight: bold; + font-size: 1em; + background-image: url(../images/icons/note.gif); +} + +.Icon.thread { + font-weight: bold; + font-size: 1em; + background-image: url(../images/icons/thread.gif); +} + + +.Icon.debugLog { background:url(../images/icons/log_debug.gif) 0 2px no-repeat; } +.Icon.alertLog { background:url(../images/icons/log_alert.gif) 0 2px no-repeat; } +.Icon.errorLog { background:url(../images/icons/log_error.gif) 0 2px no-repeat; } + + + +#content { + clear:both; + border:1px solid #aaa; + border-top:none; + border-bottom:3px solid #bbb; + padding:10px 10px 20px 10px; + background:#fff; +} + +#content a { + color:#184E81; +} + +#footer { + clear:both; + padding:10px; + text-align:center; + font-size:9pt; +} + +table { vertical-align:top; } + +table.list { + clear:both; + background:#ccc; + margin: 2px 0; + border-bottom: 1px solid #ccc; + font-family:arial, helvetica, sans-serif; + font-size:10pt; +} + +table.list caption { + text-align:left; + padding:5px; + background:#929292; + color:#fff; + font-weight:bold; +} + +table.list thead th { + background-color:#eee; + color:#000; + text-align:left; + vertical-align:top; +} + +table.list th a { + + text-decoration:none; + color:#000; +} + +table.list thead th a { padding: 3px; display: block; color: #000; background: url('../images/asc_desc.gif') 100% 50% no-repeat; } + +table.list thead th a.asc { background: url('../images/asc.gif') 100% 50% no-repeat #cfe6ff; } +table.list thead th a.desc { background: url('../images/desc.gif') 100% 50% no-repeat #cfe6ff; } +table.list tbody td { + background:#fff; + border:1px solid #fff; + padding:1px; + vertical-align:top; +} + +table.list tbody td { background: #fff; padding: 1px; padding-left:2px; vertical-align: top; } +table.list tbody tr.odd td { background-color: #f0faff; } +table.list tbody tr:hover td { background: #ffe; } +table.list tbody tr.odd:hover td { background: #ffd; } + +table.list tfoot td { + background:#eee; + padding: 2px; +} + +table.list tbody td.webticket, table.list tbody tr.row1 td.webticket { + text-indent:20px; + background:url(../images/icons/ticket_source_web.gif) 0 50% no-repeat #fff; +} + +table.list tbody td.emailticket, table.list tbody tr.row1 td.emailticket { + text-indent:20px; + background:url(../images/icons/ticket_source_email.gif) 0 50% no-repeat; +} + +table.list tbody td.phoneticket, table.list tbody tr.row1 td.phoneticket { + text-indent:20px; + background:url(../images/icons/ticket_source_phone.gif) 0 50% no-repeat; +} + +table.list tbody td.otherticket, table.list tbody tr.row1 td.otherticket { + text-indent:20px; + background:url(../images/icons/ticket_source_other.gif) 0 50% no-repeat; +} + +a.refresh { + display:block; + float:right; + width:auto; + height:16px; + line-height:16px; + padding:2px 5px 2px 2px; + background-position:2px 50%; + background-repeat:no-repeat; + padding-left:24px; + margin-left:10px; + margin-bottom: 2px; + border:1px solid #aaa; + background-image:url(../images/icons/refresh.gif); +} + +a.edit, a.print { + display:block; + float:right; + width:auto; + height:16px; + line-height:16px; + padding:2px 5px 2px 2px; + background-position:2px 50%; + background-repeat:no-repeat; + padding-left:24px; + margin-left:10px; + border:1px solid #aaa; + background-image:url(../images/icons/edit_ticket.png); +} + +a.print { + background-image:url(../images/icons/printer.gif); +} + +.btn { + padding:3px 10px; + background:url(../images/btn_bg.png) top left repeat-x #ccc; + border:1px solid #777; + color:#000; +} + +.button { padding:1px 5px; margin-right:10px; color:#777; font-weight:bold;} + +.btn_sm { + padding:2px 5px; + font-size:9pt; + background:url(../images/btn_sm_bg.png) top left repeat-x #f90; + border:1px solid #777; + color:#fff; + font-weight:bold; +} + +.btn:hover, .btn_sm:hover { + background-position: bottom left; +} + +.search label { + display:block; + line-height:25px; + height:25px; +} + +.search input[type=text] { + height:23px; + line-height:23px; + border:1px solid #aaa; + background:#fff; + padding:2px; +} + +.form_table { + margin-top:3px; + border-left:1px solid #ddd; + border-right:1px solid #ddd; +} + +.form_table td { + border-bottom:1px solid #ddd; +} + + +.form_table td.multi-line { + vertical-align:top; +} + +.form_table input[type=text], .form_table input[type=password], .form_table textarea { + background:#fff; + border:1px solid #aaa; +} + +.form_table input[type=radio], .form_table input[type=checkbox] { + position:relative; + top:3px; + margin-left:0; + padding-left:0; +} + +.form_table .required { + font-weight:bold; +} + +.form_table em { + font-weight:normal; + color:#666; +} + +.error { + color:#f00; +} + +.form_table .error input { + border:1px solid #f00; +} + +.form_table th { + text-align:left; + border:1px solid #ccc; + background:#eee; + padding:0; +} + +.form_table th h4 { + margin:0; + padding:5px; + color:#fff; + background:#929292; +} + +.form_table th em { + display:block; + padding:5px; + color:#000; +} + +.settings_table { + margin-top:2px; + border-left:1px solid #ddd; + border-right:1px solid #ddd; +} + +.settings_table td { + border-bottom:1px solid #ddd; +} + +.settings_table input[type=radio], .settings_table input[type=checkbox] { + margin-left:0; + padding-left:0; +} + +#content .settings_table th h4 a { + display:block; + color:#fff; +} + +.settings_table h4 a span { + font-size:12pt; + line-height:14px; + display:inline-block; + width:14px; + height:14px; + overflow:hidden; + text-align:center; + color:#444; + background:#ccc; + position:relative; + top:2px; +} + +h2 { + margin:0; + padding:0; + font-size:12pt; + color:#0A568E; +} + +h2 span { color:#000; } + +h3 { + margin:10px 0 0 0; + padding:5px 0; + font-size:10pt; + color:#444; +} + +.ticket_info th { + text-align:left; +} + +.ticket_info { + background:#F4FAFF; +} + +.right_align { text-align:right; } + +h2 .reload { + display:inline-block; + width:16px; + height:16px; + background:url(../images/icons/refresh.gif) top left no-repeat; + outline:none; + text-indent:-9999px; +} + +#assigned_message { + margin:10px 0; + padding:5px 5px 5px 30px; + background:url(../images/icons/assigned_ticket.gif) 5px 50% no-repeat #ffd; + border:1px solid #f90; +} + + + + +#ticket_actions { + padding:5px; + background:#eee; + border:1px solid #aaa; + border-bottom:none; + margin:0; +} + +#threads { + margin:0; + padding:5px 10px 0 10px; + border:1px solid #aaa; + background:#F4FAFF; + height:30px; +} + +#threads li { + list-style:none; + margin:0; + padding:0; + display:inline; +} + +#threads li a { + display:block; + width:auto; + float:left; + height:30px; + line-height:30px; + border-top:1px solid #F4FAFF; + padding:0 10px 0 32px; + margin-right:10px; +} + +#threads li a.active { + height:29px; + background-color:#fff; + border:1px solid #aaa; + border-bottom:none; + border-top:2px solid #ed9100; + font-weight:bold; +} + +#toggle_ticket_thread { + background:url(../images/icons/open.gif) 10px 50% no-repeat; +} + +#toggle_notes { + background:url(../images/icons/note.gif) 10px 50% no-repeat; +} + +#ticket_thread table { + margin-top:10px; + border:1px solid #aaa; + border-bottom:2px solid #aaa; +} + +#ticket_notes table { + margin-top:10px; + border:1px solid #ddd; + border-bottom:2px solid #ddd; +} + +#ticket_thread table th, #ticket_notes table th { + text-align:left; + border-bottom:1px solid #aaa; + font-size:10pt; + padding:5px; +} + +#ticket_notes table th { + text-align:left; + border-bottom:1px solid #ddd; + font-size:10pt; + padding:5px; + background:#F4FAFF; +} + +#ticket_notes table th em { + font-weight:normal; + font-size:10pt; + color:#666; +} + +#ticket_notes .date { + font-weight:normal; + font-size:10pt; + color:#888; + text-align:right; +} + +#ticket_thread table th.tmeta { + font-weight:bold; + font-size:10pt; + color:#888; + text-align:right; + padding-right:15px; +} + +#ticket_thread table th span { + font-weight:normal; + font-size:10pt; + color:#888; + padding-left:5px; +} + +#ticket_thread .message th { + background:#C3D9FF; +} + +#ticket_thread .response th { + background:#FFE0B3; +} + +#ticket_thread .note th { + background:#FFE; +} + +#ticket_thread table td, #ticket_notes table td { + padding:5px; +} + +#ticket_notes td { + background:#f9f9f9; +} + +#ticket_thread .info, #ticket_notes .info { + padding:5px; + background:#F4FAFF; + height:16px; + line-height:16px; +} + +#ticket_notes .info { + background:#f9f9f9; +} + +#response_options { + margin-top:30px; +} + +#response_options form { + padding:0 10px; +} + +#response_options ul { + padding:4px 0 0 190px; + margin:0; + text-align:center; + height:29px; + border-bottom:1px solid #aaa; + background:#eef3f8; +} + +#response_options li { + margin:0; + padding:0; + display:inline; + list-style:none; +} + +#response_options li a { + width:130px; + font-weight:bold; + padding:5px; + height:18px; + line-height:20px; + color:#444; + display:block; + float:left; + outline:none; + position:relative; + top:0; + background:#fbfbfb; + border:1px solid #eee; + border-bottom:none; +} + +#response_options .reply_tab.tell { + color:#a00 !important; + background-image:url(../images/reminder.png); + background-position:12px 50%; + background-repeat:no-repeat; +} + +#response_options li a.active { + height:18px; + color:#184E81; + background-color:#f9f9f9; + border:1px solid #aaa; + border-top:2px solid #81a9d7; + border-bottom:none; +} + +#response_options form { + padding:10px 5px; + background:#f9f9f9; + border:1px solid #aaa; + border-top:none; +} + +#response_options table { + width:928px; +} + +#response_options td { + vertical-align:top; +} + +#response_options textarea { + width:760px !important; +} + +#response_options input[type=text], #response_options textarea { + border:1px solid #aaa; + background:#fff; +} + +.attachments .uploads div { + display:inline-block; + padding-right:20px; +} + + + +.file { + display:inline-block; + padding-left:20px; + margin-right:20px; + background:url(../images/icons/file.gif) 0 50% no-repeat; +} + +.expander { + line-height:14px; + display:inline-block; + width:12px; + height:12px; + overflow:hidden; + text-align:center; + color:#aaa; + position:relative; +} + +/** Popup Tool Tips and Content **/ + +.tip_box { + display:block; + height:30px; + position:absolute; + z-index:1000; +} + +.tip_arrow { + display:block; + position:absolute; + top:5px; + left:-11px; + width:12px; + z-index:700; +} + +.tip_content { + height:auto !important; + height:20px; + min-height:20px; + padding:10px 5px 5px 5px; + border:1px solid #666; + background:#fff; + -moz-border-radius:5px; + -webkit-border-radius:5px; + border-radius:5px; + -moz-box-shadow: 3px 3px 3px #666; + -webkit-box-shadow: 3px 3px 3px #666; + box-shadow: 3px 3px 3px #666; + z-index:500; + position:absolute; + top:0; + left:-1px; + width:auto !important; + width:300px; +} + +.tip_content hr { + + color: #ddd; + background-color: #ddd; + height: 1px; + border: 0; + padding: 0; + margin: 0.2em 0; + width: 100%; +} + +.tip_close { + position:absolute; + left:100%; + top:0; + margin-left:-12px; +} + +.tip_shadow { + display:none; + background:#000; + filter: progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60); + -ms-filter: "progid:DXImageTransform.Microsoft.Blur(PixelRadius=3,MakeShadow=true,ShadowOpacity=0.60)"; + zoom: 1; + position:absolute; + z-index:200; + top:0; + left:0; + width:auto !important; + width:310px; +} + +.tip_menu { + margin:10px 0 0 0; + padding:5px 0; + border-top:1px solid #aaa; + height:16px; + font-size:9pt; +} + +.tip_menu li { + display:inline; + list-style:none; + margin:0; + padding:0; +} + +.tip_menu li a { + display:block; + width:auto; + _width:0; + float:left; + padding:0 10px; + border-right:1px solid #ddd; + color:#666; +} + +.tip_menu li a:hover { + color:#E76C74; +} + +.tip_content form { + display:none; + line-height:24px; +} + +.tip_content select, .tip_content textarea { + width:295px; +} + +.tip_content textarea { + padding:0; + border:1px solid #aaa; + background:#fff; +} + +.tip_content form p { + margin:0; + width:auto !important; + width:295px; + text-align:right; + line-height:24px; +} + +/* Knowledgebase */ +/* Knowledgebase */ +#kb { + margin: 2px 0; + padding: 5px; + overflow: hidden; +} + +#kb li { + padding:10px 10px 10px 46px; + height:auto !important; + overflow:hidden; + margin:0; + background-image:url(../images/kb_large_folder.png), url(../images/kb_category_bg.png); + background-position:0 50%, bottom left; + background-repeat:no-repeat, repeat-x; + border-bottom:1px solid #ddd; +} + + +#kb li h4 { + padding-bottom:3px; + margin:0 0 3px 0; +} + +#kb li h4 span { + color:#666; + font-weight:normal; +} + +#kb li h4 a { + font-size: 14px; +} + +#kbSearch { + padding:10px 0; + overflow:hidden; +} + +#kbSearch div { + clear:both; + overflow:hidden; + padding-top:5px; +} + +#kbSearch #query { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; +} + +#kbSearch #cid { + margin:0; + display:inline-block; + float:left; + width:200px; + margin-right:5px; + position:relative; + top:2px; +} + +#kbSearch #topic-id { + margin:0; + display:inline-block; + float:left; + width:410px; +} + +#kbSearch #searchSubmit { + margin:0; + display:inline-block; + float:left; + position:relative; + top:2px; +} + +#faq { + clear: both; + margin: 0; + padding: 5 0 10px 5px; +} +#faq ol { + font-size: 15px; + margin-left: 0; + padding-left: 0; +} +#faq ol li { + list-style: none; + margin: 0; + padding:5px 0; + color: #999; + border-bottom:1px solid #ddd; +} + +#faq ol li a { + display: inline; + height: 16px; + font-size:13px; + line-height: 16px; + padding-left: 24px; + background: url('../images/icons/page.png') 0 50% no-repeat; +} + +#faq ol li a span { + font-weight:normal; + color:#777; +} + +#faq ol li:hover { + background-color:#e9f5ff; +} + +time { + display:inline-block; + float:right; + color:#777; +} + +.cat-desc { + padding-top:5px; + padding-bottom:25px; +} + +.cat-manage-bar { + background:#e3f5ff; + padding:5px; + border-bottom:1px solid #777; +} + +.cat-manage-bar a { + display:inline-block; + margin-right:20px; +} + +/* Advanced Ticket Search */ + +#overlay { + background:#000; + position:absolute; + display:none; + z-index:1000; +} + +#advanced-search, #advanced-search * { + box-sizing: border-box; + -moz-box-sizing: border-box; + -webkit-box-sizing: border-box; +} + +#advanced-search { + position:absolute; + padding:1em; + width:640px; + height:360px; + background:#fff; + border:1px solid #2a67ac; + display:none; + z-index:1200; +} + +#advanced-search h3 { + color:#2a67ac; + font-size:20px; + margin:0; + padding:0; + display:inline-block; +} + +#advanced-search a.close { + display:inline-block; + float:right; + font-size:16px; + color:#777; +} + +#advanced-search form { + clear:both; + padding:2em 0 1em 0; + width:100%; +} + +#advanced-search div.closed_by, #advanced-search span.spinner { + display:none; +} + +#advanced-search fieldset { + margin:0; + padding:0.25em 0; + border:none; + overflow:hidden; +} + +#advanced-search label { + width:100px; + display:inline-block; + text-align:right; + padding:10px; +} + +#advanced-search fieldset input { + border:1px solid #ccc; + background:#fff; +} + +#advanced-search fieldset select { + width:170px; + display:inline-block; +} + +#advanced-search fieldset span { + width:50px; + display:inline-block; + text-align:center; + color:#777; + font-size:0.75em; +} + +#advanced-search .query input { + width:350px; +} + +#advanced-search .date_range input { + width:175px; +} + +#advanced-search .date_range i { + display:inline-block; + margin-left:3px; + position:relative; + top:5px; + width:16px; + height:16px; + background:url(../images/cal.png) bottom left no-repeat; +} + +#advanced-search fieldset.sorting select { + width:130px; +} + +#advanced-search p { + text-align:center; +} + +#advanced-search input[type="submit"], +#advanced-search input[type="reset"], +#advanced-search input[type="button"] +{ + display:inline-block; + margin:0; + height:24px; + line-height:24px; + font-weight:bold; + border:1px solid #666666; + padding:0 10px; + background: url('../images/grey_btn_bg.png?1312910883') top left repeat-x; + color: #333; +} + +#advanced-search input[type="reset"], #advanced-search input[type="button"] { + opacity:0.7; +} + +#advanced-search input[type=submit]:hover, #advanced-search input[type=submit]:active, +#advanced-search input[type=reset]:hover, #advanced-search input[type=reset]:active { + background-position:bottom left; +} + +#result-count div { + padding:5px 10px; + text-align:left; + font-weight:bold; + width:100%; + margin:0 auto; +} + +#result-count .success { + background:#e3ffd8; + border:1px solid #0a0; +} + +#result-count .fail { + background:#ffd8d8; + border:1px solid #a00; +} + +/* Custom css for datepicker */ +.ui-datepicker-trigger { + display:inline-block; + border:0; + padding:0; + margin-left:2px; + position:relative; + top:5px; + width:16px; + height:16px; + background:inherit; +} diff --git a/scp/images/ajax-loader.gif b/scp/images/ajax-loader.gif new file mode 100644 index 0000000000000000000000000000000000000000..d42f72c723644bbf8cf8d6e1b7ff0bea7ddd305a Binary files /dev/null and b/scp/images/ajax-loader.gif differ diff --git a/scp/images/icons/canned.gif b/scp/images/icons/canned.gif new file mode 100644 index 0000000000000000000000000000000000000000..8539a783ddfb80608aad5107785e3e67aa791c57 Binary files /dev/null and b/scp/images/icons/canned.gif differ diff --git a/scp/images/icons/delete_category.png b/scp/images/icons/delete_category.png new file mode 100644 index 0000000000000000000000000000000000000000..7afa4a1a80afe76791fad19ecdb62b7dcb8fb47f Binary files /dev/null and b/scp/images/icons/delete_category.png differ diff --git a/scp/images/icons/edit_category.png b/scp/images/icons/edit_category.png new file mode 100644 index 0000000000000000000000000000000000000000..cce44c7ff6efee4891f7cb6a99936b1a8447eeb3 Binary files /dev/null and b/scp/images/icons/edit_category.png differ diff --git a/scp/images/icons/kb-categories.gif b/scp/images/icons/kb-categories.gif new file mode 100644 index 0000000000000000000000000000000000000000..4a0293cfd78eb8795a05301ad88ec87e56c5da61 Binary files /dev/null and b/scp/images/icons/kb-categories.gif differ diff --git a/scp/images/icons/kb-categories.png b/scp/images/icons/kb-categories.png new file mode 100644 index 0000000000000000000000000000000000000000..2a175ed4eea1dc8fa682a46254db4bfb7992f535 Binary files /dev/null and b/scp/images/icons/kb-categories.png differ diff --git a/scp/images/icons/kb.gif b/scp/images/icons/kb.gif new file mode 100644 index 0000000000000000000000000000000000000000..fe969df4e22a5dfe437757e096b4b251d5684360 Binary files /dev/null and b/scp/images/icons/kb.gif differ diff --git a/scp/images/icons/new_category.png b/scp/images/icons/new_category.png new file mode 100644 index 0000000000000000000000000000000000000000..ef036c2565f43c132824f9fb8d89128d70918290 Binary files /dev/null and b/scp/images/icons/new_category.png differ diff --git a/scp/images/icons/new_faq.png b/scp/images/icons/new_faq.png new file mode 100644 index 0000000000000000000000000000000000000000..49bb3baecc76753b9b76e50190844ef6223dd861 Binary files /dev/null and b/scp/images/icons/new_faq.png differ diff --git a/scp/images/icons/new_reply.png b/scp/images/icons/new_reply.png new file mode 100644 index 0000000000000000000000000000000000000000..b09dc40666dab28f988f1a261c696c8a006211b2 Binary files /dev/null and b/scp/images/icons/new_reply.png differ diff --git a/scp/images/kb_category_bg.png b/scp/images/kb_category_bg.png new file mode 100644 index 0000000000000000000000000000000000000000..174d675f4c491060a413232bdef7e0e9298df60e Binary files /dev/null and b/scp/images/kb_category_bg.png differ diff --git a/scp/images/kb_large_folder.png b/scp/images/kb_large_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..144fa828a3fc83613dd7a5b29368b6da290fd09d Binary files /dev/null and b/scp/images/kb_large_folder.png differ diff --git a/scp/js/calendar.js b/scp/js/calendar.js deleted file mode 100644 index 3a9c87601147e6e97b6990cdf5f23be16ee1e8c1..0000000000000000000000000000000000000000 --- a/scp/js/calendar.js +++ /dev/null @@ -1,254 +0,0 @@ -/* - Tiny DHTML Calendar - - Stolen somewhere online....add credit. - - */ - -function getObj(objID) -{ - if (document.getElementById) {return document.getElementById(objID);} - else if (document.all) {return document.all[objID];} - else if (document.layers) {return document.layers[objID];} -} - -function checkClick(e) { - e?evt=e:evt=event; - CSE=evt.target?evt.target:evt.srcElement; - if (getObj('fc')) - if (!isChild(CSE,getObj('fc'))) - getObj('fc').style.display='none'; -} - -function isChild(s,d) { - while(s) { - if (s==d) - return true; - s=s.parentNode; - } - return false; -} - -function Left(obj) -{ - var curleft = 0; - if (obj.offsetParent) - { - while (obj.offsetParent) - { - curleft += obj.offsetLeft - obj = obj.offsetParent; - } - } - else if (obj.x) - curleft += obj.x; - - - return curleft; -} - -function Top(obj) -{ - var curtop = 0; - if (obj.offsetParent) - { - while (obj.offsetParent) - { - curtop += obj.offsetTop - obj = obj.offsetParent; - } - } - else if (obj.y) - curtop += obj.y; - return curtop; -} - -document.write('<table id="fc" style="position:absolute;border-collapse:collapse;background:#FFFFFF;border:1px solid #ABABAB;display:none" cellpadding=2>'); -document.write('<tr><td style="cursor:pointer" onclick="csubm()"><img src="images/arrowleftmonth.gif"></td><td colspan=5 id="mns" align="center" style="font:bold 13px Arial;text-align:center"></td><td align="right" style="cursor:pointer" onclick="caddm()"><img src="images/arrowrightmonth.gif"></td></tr>'); -document.write('<tr><td align=center style="background:#ABABAB;font:12px Arial">S</td><td align=center style="background:#ABABAB;font:12px Arial">M</td><td align=center style="background:#ABABAB;font:12px Arial">T</td><td align=center style="background:#ABABAB;font:12px Arial">W</td><td align=center style="background:#ABABAB;font:12px Arial">T</td><td align=center style="background:#ABABAB;font:12px Arial">F</td><td align=center style="background:#ABABAB;font:12px Arial">S</td></tr>'); -for(var kk=1;kk<=6;kk++) { - document.write('<tr>'); - for(var tt=1;tt<=7;tt++) { - num=7 * (kk-1) - (-tt); - document.write('<td id="v' + num + '" style="width:18px;height:18px"> </td>'); - } - document.write('</tr>'); -} -document.write('</table>'); - -document.all?document.attachEvent('onclick',checkClick):document.addEventListener('click',checkClick,false); - - -// Calendar script -var now = new Date; -var sccm=now.getMonth(); -var sccy=now.getFullYear(); -var ccm=now.getMonth(); -var ccy=now.getFullYear(); - -var updobj; - -function calendar(ielem) { - - if(ielem) { - ielem.select(); - lcs(ielem); - } -} - - -function lcs(ielem) { - updobj=ielem; - getObj('fc').style.left=Left(ielem)+'px'; - getObj('fc').style.top=Top(ielem)+ielem.offsetHeight+'px'; - getObj('fc').style.display=''; - - // First check date is valid - curdt=ielem.value; - curdtarr=curdt.split('/'); - isdt=true; - for(var k=0;k<curdtarr.length;k++) { - if (isNaN(curdtarr[k])) - isdt=false; - } - if (isdt&(curdtarr.length==3)) { - ccm=curdtarr[0]-1; - ccy=curdtarr[2]; - prepcalendar(curdtarr[1],curdtarr[0]-1,curdtarr[2]); - } - -} - -function evtTgt(e) -{ - var el; - if(e.target)el=e.target; - else if(e.srcElement)el=e.srcElement; - if(el.nodeType==3)el=el.parentNode; // defeat Safari bug - return el; -} -function EvtObj(e){if(!e)e=window.event;return e;} -function cs_over(e) { - evtTgt(EvtObj(e)).style.background='#FFCC66'; -} -function cs_out(e) { - evtTgt(EvtObj(e)).style.background='#C4D3EA'; -} -function cs_click(e) { - updobj.value=calvalarr[evtTgt(EvtObj(e)).id.substring(1,evtTgt(EvtObj(e)).id.length)]; - getObj('fc').style.display='none'; - -} - -var mn=new Array('JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP','OCT','NOV','DEC'); -var mnn=new Array('31','28','31','30','31','30','31','31','30','31','30','31'); -var mnl=new Array('31','29','31','30','31','30','31','31','30','31','30','31'); -var calvalarr=new Array(42); - -function f_cps(obj) { - obj.style.background='#C4D3EA'; - obj.style.font='10px Arial'; - obj.style.color='#333333'; - obj.style.textAlign='center'; - obj.style.textDecoration='none'; - obj.style.border='1px solid #6487AE'; - obj.style.cursor='pointer'; -} - -function f_cpps(obj) { - obj.style.background='#C4D3EA'; - obj.style.font='10px Arial'; - obj.style.color='#ABABAB'; - obj.style.textAlign='center'; - obj.style.textDecoration='line-through'; - obj.style.border='1px solid #6487AE'; - obj.style.cursor='default'; -} - -function f_hds(obj) { - obj.style.background='#FFF799'; - obj.style.font='bold 10px Arial'; - obj.style.color='#333333'; - obj.style.textAlign='center'; - obj.style.border='1px solid #6487AE'; - obj.style.cursor='pointer'; -} - -// day selected -function prepcalendar(hd,cm,cy) { - now=new Date(); - sd=now.getDate(); - td=new Date(); - td.setDate(1); - td.setFullYear(cy); - td.setMonth(cm); - cd=td.getDay(); - getObj('mns').innerHTML=mn[cm]+ ' ' + cy; - marr=((cy%4)==0)?mnl:mnn; - for(var d=1;d<=42;d++) { - f_cps(getObj('v'+parseInt(d))); - if ((d >= (cd -(-1))) && (d<=cd-(-marr[cm]))) { - dip=((d-cd < sd)&&(cm==sccm)&&(cy==sccy)); - htd=((hd!='')&&(d-cd==hd)); - if (0 && dip) - f_cpps(getObj('v'+parseInt(d))); - else if (htd) - f_hds(getObj('v'+parseInt(d))); - else - f_cps(getObj('v'+parseInt(d))); - - getObj('v'+parseInt(d)).onmouseover=cs_over; - getObj('v'+parseInt(d)).onmouseout=cs_out; - getObj('v'+parseInt(d)).onclick=cs_click; - - getObj('v'+parseInt(d)).innerHTML=d-cd; - calvalarr[d]=''+(cm-(-1))+'/'+(d-cd)+'/'+cy; - } - else { - getObj('v'+d).innerHTML=' '; - getObj('v'+parseInt(d)).onmouseover=null; - getObj('v'+parseInt(d)).onmouseout=null; - getObj('v'+parseInt(d)).style.cursor='default'; - } - } -} - -prepcalendar('',ccm,ccy); -//getObj('fc'+cc).style.visibility='hidden'; - -function caddm() { - marr=((ccy%4)==0)?mnl:mnn; - - ccm+=1; - if (ccm>=12) { - ccm=0; - ccy++; - } - cdayf(); - prepcalendar('',ccm,ccy); -} - -function csubm() { - marr=((ccy%4)==0)?mnl:mnn; - - ccm-=1; - if (ccm<0) { - ccm=11; - ccy--; - } - cdayf(); - prepcalendar('',ccm,ccy); -} - -function cdayf() { - - return; - - if ((ccy>sccy)|((ccy==sccy)&&(ccm>=sccm))) - return; - else { - ccy=sccy; - ccm=sccm; - cfd=scfd; - } -} diff --git a/scp/js/scp.js b/scp/js/scp.js index 7a9e0e218d1da97b3ec4b2860f307dd1c1769d1f..b31f673f0d9f7119768846bae078d11770ed18fc 100644 --- a/scp/js/scp.js +++ b/scp/js/scp.js @@ -185,6 +185,14 @@ $(document).ready(function(){ }, 'json') .error( function() {}); + /* Datepicker */ + + $('.dp').datepicker({ + numberOfMonths: 2, + showButtonPanel: true, + buttonImage: './images/cal.png', + showOn:'both' + }); /* NicEdit richtext init */ var rtes = $('.richtext'); @@ -198,11 +206,11 @@ $(document).ready(function(){ } } - /* Typeahead init */ + /* Typeahead tickets lookup */ $('#basic-ticket-search').typeahead({ source: function (typeahead, query) { $.ajax({ - url: "ajax.php/tickets?q="+query, + url: "ajax.php/tickets/lookup?q="+query, dataType: 'json', success: function (data) { typeahead.process(data); @@ -215,6 +223,7 @@ $(document).ready(function(){ property: "value" }); + /* Typeahead user lookup */ $('#email.typeahead').typeahead({ source: function (typeahead, query) { if(query.length > 2) { @@ -235,5 +244,84 @@ $(document).ready(function(){ property: "email" }); + /* advanced search */ + $("#overlay").css({ + opacity : 0.3, + top : 0, + left : 0, + width : $(window).width(), + height : $(window).height() + }); + + $("#advanced-search").css({ + top : ($(window).height() / 6), + left : ($(window).width() / 2 - 300) + }); + + $('#go-advanced').click(function(e) { + e.preventDefault(); + $('#result-count').html(''); + $('#overlay').show(); + $('#advanced-search').show(); + }); + + $('#advanced-search').delegate('a.close, input.close', 'click', function(e) { + e.preventDefault(); + $('#advanced-search').hide() + $('#overlay').hide(); + }).delegate('#status', 'change', function() { + switch($(this).val()) { + case 'closed': + $('select#assignee').find('option:first').attr('selected', 'selected').parent('select'); + $('select#assignee').attr('disabled','disabled'); + $('select#staffId').removeAttr('disabled'); + break; + case 'open': + case 'overdue': + $('select#staffId').find('option:first').attr('selected', 'selected').parent('select'); + $('select#staffId').attr('disabled','disabled'); + $('select#assignee').removeAttr('disabled'); + break; + default: + $('select#staffId').removeAttr('disabled'); + $('select#assignee').removeAttr('disabled'); + } + }); + + $('#advanced-search form#search').submit(function(e) { + e.preventDefault(); + var fObj = $(this); + var elem = $('#advanced-search'); + $('#result-count').html(''); + $.ajax({ + url: "ajax.php/tickets/search", + data: fObj.serialize(), + dataType: 'json', + beforeSend: function ( xhr ) { + $('.buttons', elem).hide(); + $('.spinner', elem).show(); + return true; + }, + success: function (resp) { + + if(resp.success) { + $('#result-count').html('<div class="success">' + resp.success +'</div>'); + } else if (resp.fail) { + $('#result-count').html('<div class="fail">' + resp.fail +'</div>'); + } else { + $('#result-count').html('<div class="fail">Unknown error</div>'); + } + } + }) + .done( function () { + }) + .fail( function () { + $('#result-count').html('<div class="fail">Advanced search failed - try again!</div>'); + }) + .always( function () { + $('.spinner', elem).hide(); + $('.buttons', elem).show(); + }); + }); }); diff --git a/scp/js/ticket.js b/scp/js/ticket.js index 902298ce43f64240a819282967a45f984ce2a424..22a97d623bd34d0ef664b012c1cd040e9f55c15e 100644 --- a/scp/js/ticket.js +++ b/scp/js/ticket.js @@ -153,7 +153,7 @@ var autoLock = { } else { $.ajax({ type: "GET", - url: 'ajax.php/ticket/'+autoLock.tid+'/lock', + url: 'ajax.php/tickets/'+autoLock.tid+'/lock', dataType: 'json', cache: false, success: function(lock){ @@ -176,7 +176,7 @@ var autoLock = { if(!autoLock.lastcheckTime || (now-autoLock.lastcheckTime)>=(autoLock.renewFreq*1000)){ $.ajax({ type: 'POST', - url: 'ajax.php/ticket/'+autoLock.tid+'/lock/'+autoLock.lockId+'/renew', + url: 'ajax.php/tickets/'+autoLock.tid+'/lock/'+autoLock.lockId+'/renew', dataType: 'json', cache: false, success: function(lock){ @@ -193,7 +193,7 @@ var autoLock = { $.ajax({ type: 'POST', - url: 'ajax.php/ticket/'+autoLock.tid+'/lock/'+autoLock.lockId+'/release', + url: 'ajax.php/tickets/'+autoLock.tid+'/lock/'+autoLock.lockId+'/release', data: 'delete', cache: false, success: function(){ @@ -264,7 +264,7 @@ jQuery(function($) { if(location.hash != "" && $('#response_options '+location.hash).length) { $('#response_options '+location.hash+'_tab').addClass('active'); $('#response_options '+location.hash).show(); - } else if(location.hash == "#notes") { + } else if(location.hash == "#notes" && $('#ticket_notes').length) { $('#response_options #note_tab').addClass('active'); $('#response_options form').hide(); $('#response_options #note').show(); diff --git a/scp/js/tips.js b/scp/js/tips.js index ec0f1875d55f31e5b8e9afcf283d7700183ea6e8..c560b8d913e635047e98e7a8198262a9db2809fc 100644 --- a/scp/js/tips.js +++ b/scp/js/tips.js @@ -80,7 +80,7 @@ jQuery(function($) { var elem = $(this); var vars = elem.attr('href').split('='); - var url = 'ajax.php/ticket/'+vars[1]+'/preview'; + var url = 'ajax.php/tickets/'+vars[1]+'/preview'; var id='t'+vars[1]; var xoffset = 80; diff --git a/scp/staff.inc.php b/scp/staff.inc.php index b3ee30a4ec3a555c2fd8c3c86ed6e72b2c6517ca..7a4dfb9e3a596fcc480894c60ecf2bede2304181 100644 --- a/scp/staff.inc.php +++ b/scp/staff.inc.php @@ -63,19 +63,19 @@ if(!$thisstaff || !is_object($thisstaff) || !$thisstaff->getId() || !$thisstaff- exit; } //2) if not super admin..check system status and group status -if(!$thisstaff->isadmin()){ - //Staff are not allowed to login in offline mode!! - if($cfg->isHelpDeskOffline()){ - staffLoginPage('System Offline'); - exit; - } +if(!$thisstaff->isAdmin()) { //Check for disabled staff or group! if(!$thisstaff->isactive() || !$thisstaff->isGroupActive()) { staffLoginPage('Access Denied. Contact Admin'); exit; } -} + //Staff are not allowed to login in offline mode!! + if($cfg->isHelpDeskOffline() || $cfg->isUpgradePending()) { + staffLoginPage('System Offline'); + exit; + } +} //Keep the session activity alive $thisstaff->refreshSession(); @@ -93,10 +93,9 @@ $errors=array(); $msg=$warn=$sysnotice=''; $tabs=array(); $submenu=array(); - -if(defined('THIS_VERSION') && strcasecmp($cfg->getVersion(),THIS_VERSION)) { - $errors['err']=$sysnotice=sprintf('The script is version %s while the database is version %s',THIS_VERSION,$cfg->getVersion()); -}elseif($cfg->isHelpDeskOffline()){ +if($cfg->isUpgradePending()) { + $errors['err']=$sysnotice='System upgrade is pending <a href="../setup/upgrade.php">Upgrade Now</a>'; +} elseif($cfg->isHelpDeskOffline()) { $sysnotice='<strong>System is set to offline mode</strong> - Client interface is disabled and ONLY admins can access staff control panel.'; $sysnotice.=' <a href="settings.php">Enable</a>.'; } diff --git a/scp/tickets.php b/scp/tickets.php index c881381e0d9ff9613b1e26e1df6c410157df664b..567c3f69755525aca1146ce8433a44e2485c6fc3 100644 --- a/scp/tickets.php +++ b/scp/tickets.php @@ -55,7 +55,7 @@ if($_POST && !$errors): if(!$errors['err'] && EmailFilter::isBanned($ticket->getEmail())) $errors['err']='Email is in banlist. Must be removed to reply.'; - $wasOpen =($ticket->isopen()); + $wasOpen =($ticket->isOpen()); //If no error...do the do. if(!$errors && ($respId=$ticket->postReply($_POST,$_FILES['attachments'],$errors))) { $msg='Reply posted successfully'; @@ -189,7 +189,7 @@ if($_POST && !$errors): } break; case 'close': - if(!$thisstaff->isadmin() && !$thisstaff->canCloseTickets()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canCloseTickets()){ $errors['err']='Perm. Denied. You are not allowed to close tickets.'; }else{ if($ticket->close()){ @@ -204,7 +204,7 @@ if($_POST && !$errors): break; case 'reopen': //if they can close...then assume they can reopen. - if(!$thisstaff->isadmin() && !$thisstaff->canCloseTickets()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canCloseTickets()){ $errors['err']='Perm. Denied. You are not allowed to reopen tickets.'; }else{ if($ticket->reopen()){ @@ -233,7 +233,7 @@ if($_POST && !$errors): break; case 'overdue': //Mark the ticket as overdue - if(!$thisstaff->isadmin() && !$thisstaff->isManager()){ + if(!$thisstaff->isAdmin() && !$thisstaff->isManager()){ $errors['err']='Perm. Denied. You are not allowed to flag tickets overdue'; }else{ if($ticket->markOverdue()){ @@ -252,7 +252,7 @@ if($_POST && !$errors): } break; case 'banemail': - if(!$thisstaff->isadmin() && !$thisstaff->canManageBanList()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canBanEmails()){ $errors['err']='Perm. Denied. You are not allowed to ban emails'; }elseif(Banlist::add($ticket->getEmail(),$thisstaff->getName())){ $msg='Email ('.$ticket->getEmail().') added to banlist'; @@ -266,7 +266,7 @@ if($_POST && !$errors): } break; case 'unbanemail': - if(!$thisstaff->isadmin() && !$thisstaff->canManageBanList()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canBanEmails()){ $errors['err']='Perm. Denied. You are not allowed to remove emails from banlist.'; }elseif(Banlist::remove($ticket->getEmail())){ $msg='Email removed from banlist'; @@ -275,7 +275,7 @@ if($_POST && !$errors): } break; case 'delete': // Dude what are you trying to hide? bad customer support?? - if(!$thisstaff->isadmin() && !$thisstaff->canDeleteTickets()){ + if(!$thisstaff->isAdmin() && !$thisstaff->canDeleteTickets()){ $errors['err']='Perm. Denied. You are not allowed to DELETE tickets!!'; }else{ if($ticket->delete()){ @@ -339,7 +339,7 @@ if($_POST && !$errors): $note='Ticket flagged as overdue by '.$thisstaff->getName(); foreach($_POST['tids'] as $k=>$v) { $t = new Ticket($v); - if($t && !$t->isoverdue()) + if($t && !$t->isOverdue()) if($t->markOverdue()) { $i++; $t->logActivity('Ticket Marked Overdue',$note,false,'System'); diff --git a/setup/cleanup.php b/setup/cleanup.php deleted file mode 100644 index 1309228eb6c64eaaee6f16926ec98b06d91d0221..0000000000000000000000000000000000000000 --- a/setup/cleanup.php +++ /dev/null @@ -1,24 +0,0 @@ -<?php -/********************************************************************* - cleanup.php - - Cleanup script called via ajax to migrate attachments. - - Peter Rotich <peter@osticket.com> - Copyright (c) 2006-2012 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: -**********************************************************************/ -session_start(); -if($_GET['c']>10) { //When Done send 304 - nothing else to do. - $_SESSION['s']='done'; - session_write_close(); - header("HTTP/1.1 304 Not Modified"); - exit; -} -echo "Cleaning up...".time(); -?> diff --git a/setup/css/wizard.css b/setup/css/wizard.css index 6fd18e17854f65a30a2947460a955ca4c403541c..c92b05447a6acb9992ea21be3ce13581840784a9 100644 --- a/setup/css/wizard.css +++ b/setup/css/wizard.css @@ -70,7 +70,7 @@ form .row span { width: 600px; color: #666666; } #overlay { display: none; position: fixed; background: #000; z-index: 2000; } -#loading { padding: 10px 10px 10px 60px; width: 300px; height: 100px; background: url('../images/ajax-loader.gif?1312925608') 10px 50% no-repeat white; position: fixed; display: none; z-index: 3000; } +#loading { padding: 10px 10px 10px 60px; width: 400px; height: 150px; background: url('../images/ajax-loader.gif?1312925608') 10px 50% no-repeat white; position: fixed; display: none; z-index: 3000; } #loading h4 { margin: 3px 0 0 0; padding: 0; color: #d80; } .tip { display: inline-block; width: 16px; height: 16px; outline: none; text-decoration: none; color: #d80; } diff --git a/setup/inc/class.installer.php b/setup/inc/class.installer.php new file mode 100644 index 0000000000000000000000000000000000000000..7b3dbe534eb0af30f13f27223f555849d30a6bb1 --- /dev/null +++ b/setup/inc/class.installer.php @@ -0,0 +1,204 @@ +<?php +/********************************************************************* + class.installer.php + + osTicket Intaller - installs the latest version. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 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: +**********************************************************************/ +require_once INC_DIR.'class.setup.php'; + +class Installer extends SetupWizard { + + var $config; + + function Installer($configfile) { + $this->config =$configfile; + $this->errors=array(); + } + + function getConfigFile() { + return $this->config; + } + + function config_exists() { + return ($this->getConfigFile() && file_exists($this->getConfigFile())); + } + + function config_writable() { + return ($this->getConfigFile() && is_writable($this->getConfigFile())); + } + + function check_config() { + return ($this->config_exists() && $this->config_writable()); + } + + //XXX: Latest version insall logic...no carry over. + function install($vars) { + + $this->errors=$f=array(); + + $f['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required'); + $f['email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); + $f['fname'] = array('type'=>'string', 'required'=>1, 'error'=>'First name required'); + $f['lname'] = array('type'=>'string', 'required'=>1, 'error'=>'Last name required'); + $f['admin_email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); + $f['username'] = array('type'=>'username', 'required'=>1, 'error'=>'Username required'); + $f['passwd'] = array('type'=>'password', 'required'=>1, 'error'=>'Password required'); + $f['passwd2'] = array('type'=>'string', 'required'=>1, 'error'=>'Confirm password'); + $f['prefix'] = array('type'=>'string', 'required'=>1, 'error'=>'Table prefix required'); + $f['dbhost'] = array('type'=>'string', 'required'=>1, 'error'=>'Hostname required'); + $f['dbname'] = array('type'=>'string', 'required'=>1, 'error'=>'Database name required'); + $f['dbuser'] = array('type'=>'string', 'required'=>1, 'error'=>'Username required'); + $f['dbpass'] = array('type'=>'string', 'required'=>1, 'error'=>'password required'); + + + if(!Validator::process($f,$vars,$this->errors) && !$this->errors['err']) + $this->errors['err']='Missing or invalid data - correct the errors and try again.'; + + + //Staff's email can't be same as system emails. + if($vars['admin_email'] && $vars['email'] && !strcasecmp($vars['admin_email'],$vars['email'])) + $this->errors['admin_email']='Conflicts with system email above'; + //Admin's pass confirmation. + if(!$this->errors && strcasecmp($vars['passwd'],$vars['passwd2'])) + $this->errors['passwd2']='passwords to not match!'; + //Check table prefix underscore required at the end! + if($vars['prefix'] && substr($vars['prefix'], -1)!='_') + $this->errors['prefix']='Bad prefix. Must have underscore (_) at the end. e.g \'ost_\''; + + //Make sure admin username is not very predictable. XXX: feels dirty but necessary + if(!$this->errors['username'] && in_array(strtolower($vars['username']),array('admin','admins','username','osticket'))) + $this->errors['username']='Bad username'; + + //MYSQL: Connect to the DB and check the version & database (create database if it doesn't exist!) + if(!$this->errors) { + if(!db_connect($vars['dbhost'],$vars['dbuser'],$vars['dbpass'])) + $this->errors['db']='Unable to connect to MySQL server. Possibly invalid login info.'; + elseif(db_version()< $this->getMySQLVersion()) + $this->errors['db']=sprintf('osTicket requires MySQL %s or better!',$this->getMySQLVersion()); + elseif(!db_select_database($vars['dbname']) && !db_create_database($vars['dbname'])) { + $this->errors['dbname']='Database doesn\'t exist'; + $this->errors['db']='Unable to create the database.'; + } elseif(!db_select_database($vars['dbname'])) { + $this->errors['dbname']='Unable to select the database'; + } + } + + //bailout on errors. + if($this->errors) return false; + + /*************** We're ready to install ************************/ + define('ADMIN_EMAIL',$vars['admin_email']); //Needed to report SQL errors during install. + define('PREFIX',$vars['prefix']); //Table prefix + + $schemaFile =INC_DIR.'sql/osticket-v1.7-mysql.sql'; //DB dump. + $debug = true; //XXX:Change it to true to show SQL errors. + + //Last minute checks. + if(!file_exists($schemaFile)) + $this->errors['err']='Internal Error - please make sure your download is the latest (#1)'; + elseif(!($signature=trim(file_get_contents("$schemaFile.md5"))) || strcasecmp($signature, md5_file($schemaFile))) + $this->errors['err']='Unknown or invalid schema signature ('.$signature.' .. '.md5_file($schemaFile).')'; + elseif(!file_exists($this->getConfigFile()) || !($configFile=file_get_contents($this->getConfigFile()))) + $this->errors['err']='Unable to read config file. Permission denied! (#2)'; + elseif(!($fp = @fopen($this->getConfigFile(),'r+'))) + $this->errors['err']='Unable to open config file for writing. Permission denied! (#3)'; + elseif(!$this->load_sql_file($schemaFile,$vars['prefix'], true, $debug)) + $this->errors['err']='Error parsing SQL schema! Get help from developers (#4)'; + + if(!$this->errors) { + //Create admin user. + $sql='INSERT INTO '.PREFIX.'staff SET created=NOW() ' + .', isactive=1, isadmin=1, group_id=1, dept_id=1, timezone_id=8, max_page_size=25 ' + .', email='.db_input($_POST['admin_email']) + .', firstname='.db_input($vars['fname']) + .', lastname='.db_input($vars['lname']) + .', username='.db_input($vars['username']) + .', passwd='.db_input(Passwd::hash($vars['passwd'])); + if(!mysql_query($sql) || !($uid=mysql_insert_id())) + $this->errors['err']='Unable to create admin user (#6)'; + } + + if(!$this->errors) { + //Create config settings---default settings! + //XXX: rename ostversion helpdesk_* ?? + $sql='INSERT INTO '.PREFIX.'config SET updated=NOW(), isonline=0 ' + .', default_email_id=1, alert_email_id=2, default_dept_id=1 ' + .', default_sla_id=1, default_timezone_id=8, default_template_id=1 ' + .', admin_email='.db_input($vars['admin_email']) + .', schema_signature='.db_input($signature) + .', helpdesk_url='.db_input(URL) + .', helpdesk_title='.db_input($vars['name']); + if(!mysql_query($sql) || !($cid=mysql_insert_id())) + $this->errors['err']='Unable to create config settings (#7)'; + } + + if($this->errors) return false; //Abort on internal errors. + + + //Rewrite the config file - MUST be done last to allow for installer recovery. + $configFile= str_replace("define('OSTINSTALLED',FALSE);","define('OSTINSTALLED',TRUE);",$configFile); + $configFile= str_replace('%ADMIN-EMAIL',$vars['admin_email'],$configFile); + $configFile= str_replace('%CONFIG-DBHOST',$vars['dbhost'],$configFile); + $configFile= str_replace('%CONFIG-DBNAME',$vars['dbname'],$configFile); + $configFile= str_replace('%CONFIG-DBUSER',$vars['dbuser'],$configFile); + $configFile= str_replace('%CONFIG-DBPASS',$vars['dbpass'],$configFile); + $configFile= str_replace('%CONFIG-PREFIX',$vars['prefix'],$configFile); + $configFile= str_replace('%CONFIG-SIRI',Misc::randcode(32),$configFile); + if(!$fp || !ftruncate($fp,0) || !fwrite($fp,$configFile)) { + $this->errors['err']='Unable to write to config file. Permission denied! (#5)'; + return false; + } + @fclose($fp); + + /************* Make the system happy ***********************/ + //Create default emails! + $email = $vars['email']; + list(,$domain)=explode('@',$vars['email']); + $sql='INSERT INTO '.PREFIX.'email (`email_id`, `dept_id`, `name`,`email`,`created`,`updated`) VALUES ' + ." (1,1,'Support','$email',NOW(),NOW())" + .",(2,1,'osTicket Alerts','alerts@$domain',NOW(),NOW())" + .",(3,1,'','noreply@$domain',NOW(),NOW())"; + @mysql_query($sql); + + //Create a ticket to make the system warm and happy. + $sql='INSERT INTO '.PREFIX.'ticket SET created=NOW(), status="open", source="Web" ' + .' ,priority_id=2, dept_id=1, topic_id=1 ' + .' ,ticketID='.db_input(Misc::randNumber(6)) + .' ,email="support@osticket.com" ' + .' ,name="osTicket Support" ' + .' ,subject="osTicket Installed!"'; + if(mysql_query($sql) && ($tid=mysql_insert_id())) { + if(!($msg=file_get_contents(INC_DIR.'msg/installed.txt'))) + $msg='Congratulations and Thank you for choosing osTicket!'; + + $sql='INSERT INTO '.PREFIX.'ticket_thread SET created=NOW()' + .', source="Web" ' + .', thread_type="M" ' + .', ticket_id='.db_input($tid) + .', title='.db_input('osTicket Installed') + .', body='.db_input($msg); + @mysql_query($sql); + } + //TODO: create another personalized ticket and assign to admin?? + + //Log a message. + $msg="Congratulations osTicket basic installation completed!\n\nThank you for choosing osTicket!"; + $sql='INSERT INTO '.PREFIX.'syslog SET created=NOW(), updated=NOW(), log_type="Debug" ' + .', title="osTicket installed!"' + .', log='.db_input($msg) + .', ip_address='.db_input($_SERVER['REMOTE_ADDR']); + @mysql_query($sql); + + return true; + } +} +?> diff --git a/setup/inc/class.migrater.php b/setup/inc/class.migrater.php new file mode 100644 index 0000000000000000000000000000000000000000..de8a3d9590e97b9d78ecb905528bcbc1bc2c03a5 --- /dev/null +++ b/setup/inc/class.migrater.php @@ -0,0 +1,67 @@ +<?php +/********************************************************************* + class.migrater.php + + SQL database migrater. This provides the engine capable of rolling the + database for an osTicket installation forward (and perhaps even + backward) in time using a set of included migration scripts. Each script + will roll the database between two database checkpoints. Where possible, + the migrater will roll several checkpoint scripts into one to be applied + together. + + Jared Hancock <jared@osticket.com> + Copyright (c) 2006-2012 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: +**********************************************************************/ + +class DatabaseMigrater { + + var $start; + var $end; + var $sqldir; + + function DatabaseMigrater($start, $end, $sqldir) { + + $this->start = $start; + $this->end = $end; + $this->sqldir = $sqldir; + + } + + function getPatches($stop=null) { + + $start= $this->start; + $stop = $stop?$stop:$this->end; + + $patches = array(); + while (true) { + $next = glob($this->sqldir . substr($start, 0, 8) + . '-*.patch.sql'); + if (count($next) == 1) { + $patches[] = $next[0]; + $start = substr(basename($next[0]), 9, 8); + } elseif (count($next) == 0) { + # There are no patches leaving the current signature. We + # have to assume that we've applied all the available + # patches. + break; + } else { + # Problem -- more than one patch exists from this snapshot. + # We probably need a graph approach to solve this. + break; + } + + # Break if we've reached our target stop. + if(!$start || !strncasecmp($start, $stop, 8)) + break; + } + + return $patches; + } +} +?> diff --git a/setup/inc/class.setup.php b/setup/inc/class.setup.php index c6bf7b6751c9e80236d3cbfe143a37c6d52cf6c5..438eca54505302a30d6da9575067c90b296369dc 100644 --- a/setup/inc/class.setup.php +++ b/setup/inc/class.setup.php @@ -21,8 +21,8 @@ Class SetupWizard { 'mysql' => '4.4'); //Version info - same as the latest version. - var $version ='1.7-rc1'; - var $version_verbose='1.7 RC 1'; + var $version ='1.7-dpr3'; + var $version_verbose='1.7 DPR 3'; //Errors var $errors=array(); @@ -31,34 +31,34 @@ Class SetupWizard { $this->errors=array(); } - function load_sql_file($file, $prefix, $debug=false) { + function load_sql_file($file, $prefix, $abort=true, $debug=false) { if(!file_exists($file) || !($schema=file_get_contents($file))) - return $this->abort('Error accessing SQL file'); + return $this->abort('Error accessing SQL file '.basename($file), $debug); - return $this->load_sql($schema, $prefix, $debug); + return $this->load_sql($schema, $prefix, $abort, $debug); } /* load SQL schema - assumes MySQL && existing connection */ - function load_sql($schema, $prefix, $debug=false) { + function load_sql($schema, $prefix, $abort=true, $debug=false) { # Strip comments and remarks - $schema=preg_replace('%^\s*(#|--).*$%m','',$schema); + $schema=preg_replace('%^\s*(#|--).*$%m', '', $schema); # Replace table prefis - $schema = str_replace('%TABLE_PREFIX%',$prefix, $schema); + $schema = str_replace('%TABLE_PREFIX%', $prefix, $schema); # Split by semicolons - and cleanup if(!($statements = array_filter(array_map('trim', @explode(';', $schema))))) - return $this->abort('Error parsing SQL schema'); + return $this->abort('Error parsing SQL schema', $debug); @mysql_query('SET SESSION SQL_MODE =""'); foreach($statements as $k=>$sql) { - if(!mysql_query($sql)) { - if($debug) echo "[$sql]=>".mysql_error(); - return $this->abort("[$sql] - ".mysql_error()); - } + if(mysql_query($sql)) continue; + $error = "[$sql] ".mysql_error(); + if($abort) + return $this->abort($error, $debug); } return true; @@ -81,7 +81,7 @@ Class SetupWizard { } function check_php() { - return (version_compare(PHP_VERSION,$this->getPHPVersion())>=0); + return (version_compare(PHP_VERSION, $this->getPHPVersion())>=0); } function check_mysql() { @@ -95,293 +95,28 @@ Class SetupWizard { /* @error is a mixed var. */ - function abort($error) { - + function abort($error, $debug=false) { + + if($debug) echo $error; + $this->onError($error); + return false; // Always false... It's an abort. + } + + function setError($error) { + if($error && is_array($error)) - $this->errors = array_merge($this->errors,$error); + $this->errors = array_merge($this->errors, $error); elseif($error) $this->errors[] = $error; - - //Always returns FALSE. - return false; } function getErrors(){ - return $this->errors; } - /* Access and user validation*/ - - function getThisUser() { - - - } -} - -class Upgrader extends SetupWizard { - - var $prefix; - - function Upgrader($prefix) { - $this->prefix = $prefix; - $this->errors = array(); - } - - function getTablePrefix() { - return $this->prefix; - } - - /* upgrade magic related to the given version */ - function upgradeTo($version) { - - $errors = array(); - switch($version) { - case '1.7-RC1': - //TODO: latest upgrade logic. - break; - case '1.6 ST': - //TODO: refactor code from 1.6 ST. - break; - case '1.6 RC5': - //TODO: refactor code from 1.6 ST. - break; - default: - //XXX: escape version - return $this->abort('Trying to upgrade unknown version '.$version); - } - - if($errors) - return $this->abort($errors); - - return true; - } - - /* - Do base upgrade - Does fall-through upgrade until we reach the current version. - We're assumming the user - is upgrading upgradable version of osTicket! - @version - version number to upgrade from! - */ - function upgradeFrom($version) { - - if(!$version || $this->getErrors()) - return false; - - if(!strcasecmp($version,$this->getVersion())) - return true; - - //XXX: Note FALLTHROUGH (we only break on error) and uppercase cases. - switch(strtoupper($version)) { - case 'OLD': //Upgrade old versions to 1.6 ST. - if(!$this->upgradeTo('1.6 RC5')) break; - /* FALLTHROUGH */ - case '1.6 RC5': //Upgrade 1.6 RC5 to 1.6 ST - if(!$this->upgradeTo('1.6 ST')) break; - /* FALLTHROUGH */ - case '1.6 ST': //Upgrade 1.6 ST to to 1.7 RC1 - if(!$this->upgradeTo('1.7-RC1')) break; - /* LAST CASE IS NOT FALLTHROUGH */ - break; - default: //Catch all - Upgrading older versions 1.3+ - return $this->upgradeFrom('OLD'); - } - //XXX: Set errors??? - - return (!$this->getErrors()); - } - - function cleanup() { - //FIXME: cleanup logic here. - sleep(2); - - return true; - } -} - -/* - Installer class - latest version. - */ -class Installer extends SetupWizard { - - var $config; - - function Installer($configfile) { - $this->config =$configfile; - $this->errors=array(); - } - - function getConfigFile() { - return $this->config; - } - - function config_exists() { - return ($this->getConfigFile() && file_exists($this->getConfigFile())); - } - - function config_writable() { - return ($this->getConfigFile() && is_writable($this->getConfigFile())); - } - - function check_config() { - return ($this->config_exists() && $this->config_writable()); - } - - //XXX: Latest version insall logic...no carry over. - function install($vars) { - - $this->errors=$f=array(); - - $f['name'] = array('type'=>'string', 'required'=>1, 'error'=>'Name required'); - $f['email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); - $f['fname'] = array('type'=>'string', 'required'=>1, 'error'=>'First name required'); - $f['lname'] = array('type'=>'string', 'required'=>1, 'error'=>'Last name required'); - $f['admin_email'] = array('type'=>'email', 'required'=>1, 'error'=>'Valid email required'); - $f['username'] = array('type'=>'username', 'required'=>1, 'error'=>'Username required'); - $f['passwd'] = array('type'=>'password', 'required'=>1, 'error'=>'Password required'); - $f['passwd2'] = array('type'=>'string', 'required'=>1, 'error'=>'Confirm password'); - $f['prefix'] = array('type'=>'string', 'required'=>1, 'error'=>'Table prefix required'); - $f['dbhost'] = array('type'=>'string', 'required'=>1, 'error'=>'Hostname required'); - $f['dbname'] = array('type'=>'string', 'required'=>1, 'error'=>'Database name required'); - $f['dbuser'] = array('type'=>'string', 'required'=>1, 'error'=>'Username required'); - $f['dbpass'] = array('type'=>'string', 'required'=>1, 'error'=>'password required'); - - - if(!Validator::process($f,$vars,$this->errors) && !$this->errors['err']) - $this->errors['err']='Missing or invalid data - correct the errors and try again.'; - - - //Staff's email can't be same as system emails. - if($vars['admin_email'] && $vars['email'] && !strcasecmp($vars['admin_email'],$vars['email'])) - $this->errors['admin_email']='Conflicts with system email above'; - //Admin's pass confirmation. - if(!$this->errors && strcasecmp($vars['passwd'],$vars['passwd2'])) - $this->errors['passwd2']='passwords to not match!'; - //Check table prefix underscore required at the end! - if($vars['prefix'] && substr($vars['prefix'], -1)!='_') - $this->errors['prefix']='Bad prefix. Must have underscore (_) at the end. e.g \'ost_\''; - - //Make sure admin username is not very predictable. XXX: feels dirty but necessary - if(!$this->errors['username'] && in_array(strtolower($vars['username']),array('admin','admins','username','osticket'))) - $this->errors['username']='Bad username'; - - //MYSQL: Connect to the DB and check the version & database (create database if it doesn't exist!) - if(!$this->errors) { - if(!db_connect($vars['dbhost'],$vars['dbuser'],$vars['dbpass'])) - $this->errors['db']='Unable to connect to MySQL server. Possibly invalid login info.'; - elseif(db_version()< $this->getMySQLVersion()) - $this->errors['db']=sprintf('osTicket requires MySQL %s or better!',$this->getMySQLVersion()); - elseif(!db_select_database($vars['dbname']) && !db_create_database($vars['dbname'])) { - $this->errors['dbname']='Database doesn\'t exist'; - $this->errors['db']='Unable to create the database.'; - } elseif(!db_select_database($vars['dbname'])) { - $this->errors['dbname']='Unable to select the database'; - } - } - - //bailout on errors. - if($this->errors) return false; - - /*************** We're ready to install ************************/ - define('ADMIN_EMAIL',$vars['admin_email']); //Needed to report SQL errors during install. - define('PREFIX',$vars['prefix']); //Table prefix - - $schemaFile =INC_DIR.'sql/osticket-v1.7-mysql.sql'; //DB dump. - $debug = true; //XXX:Change it to true to show SQL errors. - - //Last minute checks. - if(!file_exists($schemaFile)) - $this->errors['err']='Internal Error - please make sure your download is the latest (#1)'; - elseif(!file_exists($this->getConfigFile()) || !($configFile=file_get_contents($this->getConfigFile()))) - $this->errors['err']='Unable to read config file. Permission denied! (#2)'; - elseif(!($fp = @fopen($this->getConfigFile(),'r+'))) - $this->errors['err']='Unable to open config file for writing. Permission denied! (#3)'; - elseif(!$this->load_sql_file($schemaFile,$vars['prefix'],$debug)) - $this->errors['err']='Error parsing SQL schema! Get help from developers (#4)'; - - if(!$this->errors) { - //Create admin user. - $sql='INSERT INTO '.PREFIX.'staff SET created=NOW() ' - .', isactive=1, isadmin=1, group_id=1, dept_id=1, timezone_id=8, max_page_size=25 ' - .', email='.db_input($_POST['admin_email']) - .', firstname='.db_input($vars['fname']) - .', lastname='.db_input($vars['lname']) - .', username='.db_input($vars['username']) - .', passwd='.db_input(Passwd::hash($vars['passwd'])); - if(!mysql_query($sql) || !($uid=mysql_insert_id())) - $this->errors['err']='Unable to create admin user (#6)'; - } - - if(!$this->errors) { - //Create config settings---default settings! - //XXX: rename ostversion helpdesk_* ?? - $sql='INSERT INTO '.PREFIX.'config SET updated=NOW(), isonline=0 ' - .', default_email_id=1, alert_email_id=2, default_dept_id=1 ' - .', default_sla_id=1, default_timezone_id=8, default_template_id=1 ' - .', admin_email='.db_input($vars['admin_email']) - .', schema_signature='.db_input(md5_file($schemaFile)) - .', helpdesk_url='.db_input(URL) - .', helpdesk_title='.db_input($vars['name']); - if(!mysql_query($sql) || !($cid=mysql_insert_id())) - $this->errors['err']='Unable to create config settings (#7)'; - } - - if($this->errors) return false; //Abort on internal errors. - - - //Rewrite the config file - MUST be done last to allow for installer recovery. - $configFile= str_replace("define('OSTINSTALLED',FALSE);","define('OSTINSTALLED',TRUE);",$configFile); - $configFile= str_replace('%ADMIN-EMAIL',$vars['admin_email'],$configFile); - $configFile= str_replace('%CONFIG-DBHOST',$vars['dbhost'],$configFile); - $configFile= str_replace('%CONFIG-DBNAME',$vars['dbname'],$configFile); - $configFile= str_replace('%CONFIG-DBUSER',$vars['dbuser'],$configFile); - $configFile= str_replace('%CONFIG-DBPASS',$vars['dbpass'],$configFile); - $configFile= str_replace('%CONFIG-PREFIX',$vars['prefix'],$configFile); - $configFile= str_replace('%CONFIG-SIRI',Misc::randcode(32),$configFile); - if(!$fp || !ftruncate($fp,0) || !fwrite($fp,$configFile)) { - $this->errors['err']='Unable to write to config file. Permission denied! (#5)'; - return false; - } - @fclose($fp); - - /************* Make the system happy ***********************/ - //Create default emails! - $email = $vars['email']; - list(,$domain)=explode('@',$vars['email']); - $sql='INSERT INTO '.PREFIX.'email (`email_id`, `dept_id`, `name`,`email`,`created`,`updated`) VALUES ' - ." (1,1,'Support','$email',NOW(),NOW())" - .",(2,1,'osTicket Alerts','alerts@$domain',NOW(),NOW())" - .",(3,1,'','noreply@$domain',NOW(),NOW())"; - @mysql_query($sql); - - //Create a ticket to make the system warm and happy. - $sql='INSERT INTO '.PREFIX.'ticket SET created=NOW(), status="open", source="Web" ' - .' ,priority_id=2, dept_id=1, topic_id=1 ' - .' ,ticketID='.db_input(Misc::randNumber(6)) - .' ,email="support@osticket.com" ' - .' ,name="osTicket Support" ' - .' ,subject="osTicket Installed!"'; - if(mysql_query($sql) && ($tid=mysql_insert_id())) { - if(!($msg=file_get_contents(INC_DIR.'msg/installed.txt'))) - $msg='Congratulations and Thank you for choosing osTicket!'; - - $sql='INSERT INTO '.PREFIX.'ticket_message SET created=NOW(),source="Web" ' - .', ticket_id='.db_input($tid) - .', message='.db_input($msg); - @mysql_query($sql); - } - //TODO: create another personalized ticket and assign to admin?? - - //Log a message. - $msg="Congratulations osTicket basic installation completed!\n\nThank you for choosing osTicket!"; - $sql='INSERT INTO '.PREFIX.'syslog SET created=NOW(),updated=NOW(),log_type="Debug" ' - .', title="osTicket installed!"' - .', log='.db_input($msg) - .', ip_address='.db_input($_SERVER['REMOTE_ADDR']); - @mysql_query($sql); - - return true; + function onError($error) { + return $this->setError($error); } } ?> diff --git a/setup/inc/class.upgrader.php b/setup/inc/class.upgrader.php new file mode 100644 index 0000000000000000000000000000000000000000..73af7e6066cddf41140d7bd6f2c2618431dfe83f --- /dev/null +++ b/setup/inc/class.upgrader.php @@ -0,0 +1,273 @@ +<?php +/********************************************************************* + class.upgrader.php + + osTicket Upgrader + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 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: +**********************************************************************/ + +require_once INC_DIR.'class.setup.php'; +require_once INC_DIR.'class.migrater.php'; + +class Upgrader extends SetupWizard { + + var $prefix; + var $sqldir; + var $signature; + + function Upgrader($signature, $prefix, $sqldir) { + + $this->signature = $signature; + $this->shash = substr($signature, 0, 8); + $this->prefix = $prefix; + $this->sqldir = $sqldir; + $this->errors = array(); + + //Init persistent state of upgrade. + $this->state = &$_SESSION['ost_upgrader'][$this->getShash()]['state']; + + //Init the task Manager. + if(!isset($_SESSION['ost_upgrader'][$this->getShash()])) + $_SESSION['ost_upgrader'][$this->getShash()]['tasks']=array(); + + //Tasks to perform - saved on the session. + $this->tasks = &$_SESSION['ost_upgrader'][$this->getShash()]['tasks']; + + //Database migrater + $this->migrater = new DatabaseMigrater($this->signature, SCHEMA_SIGNATURE, $this->sqldir); + } + + function getStops() { + return array('7be60a84' => 'migrateAttachments2DB'); + } + + function onError($error) { + + Sys::log(LOG_ERR, 'Upgrader Error', $error); + $this->setError($error); + $this->setState('aborted'); + } + + function isUpgradable() { + return (!$this->isAborted() && $this->getNextPatch()); + } + + function isAborted() { + return !strcasecmp($this->getState(), 'aborted'); + } + + function getSchemaSignature() { + return $this->signature; + } + + function getShash() { + return $this->shash; + } + + function getTablePrefix() { + return $this->prefix; + } + + function getSQLDir() { + return $this->sqldir; + } + + function getState() { + return $this->state; + } + + function setState($state) { + $this->state = $state; + } + + function getPatches() { + return $this->migrater->getPatches(); + } + + function getNextPatch() { + $p = $this->getPatches(); + return (count($p)) ? $p[0] : false; + } + + function getNextVersion() { + if(!$patch=$this->getNextPatch()) + return '(Latest)'; + + $info = $this->readPatchInfo($patch); + return $info['version']; + } + + function readPatchInfo($patch) { + $info = array(); + if (preg_match('/\*(.*)\*/', file_get_contents($patch), $matches)) { + if (preg_match('/@([\w\d_-]+)\s+(.*)$/', $matches[0], $matches2)) + foreach ($matches2 as $match) + $info[$match[0]] = $match[1]; + } + if (!isset($info['version'])) + $info['version'] = substr(basename($patch), 9, 8); + return $info; + } + + function getNextAction() { + + $action='Upgrade osTicket to '.$this->getVersion(); + if($this->getNumPendingTasks() && ($task=$this->getNextTask())) { + $action = $task['desc']; + if($task['status']) //Progress report... + $action.=' ('.$task['status'].')'; + } elseif($this->isUpgradable() && ($nextversion = $this->getNextVersion())) { + $action = "Upgrade to $nextversion"; + } + + return $action; + } + + function getNumPendingTasks() { + + return count($this->getPendingTasks()); + } + + function getPendingTasks() { + + $pending=array(); + if(($tasks=$this->getTasks())) { + foreach($tasks as $k => $task) { + if(!$task['done']) + $pending[$k] = $task; + } + } + + return $pending; + } + + function getTasks() { + return $this->tasks; + } + + function getNextTask() { + + if(!($tasks=$this->getPendingTasks())) + return null; + + return current($tasks); + } + + function removeTask($tId) { + + if(isset($this->tasks[$tId])) + unset($this->tasks[$tId]); + + return (!$this->tasks[$tId]); + } + + function setTaskStatus($tId, $status) { + if(isset($this->tasks[$tId])) + $this->tasks[$tId]['status'] = $status; + } + + function doTasks() { + + if(!($tasks=$this->getPendingTasks())) + return true; //Nothing to do. + + foreach($tasks as $k => $task) { + if(call_user_func(array($this, $task['func']), $k)===0) { + $this->tasks[$k]['done'] = true; + } else { //Task has pending items to process. + break; + } + } + + return (!$this->getPendingTasks()); + } + + function upgrade() { + + if($this->getPendingTasks() || !($patches=$this->getPatches())) + return false; + + foreach ($patches as $patch) { + if (!$this->load_sql_file($patch, $this->getTablePrefix())) + return false; + + //clear previous patch info - + unset($_SESSION['ost_upgrader'][$this->getShash()]); + + $phash = substr(basename($patch), 0, 17); + + //Log the patch info + $logMsg = "Patch $phash applied "; + if(($info = $this->readPatchInfo($patch)) && $info['version']) + $logMsg.= ' ('.$info['version'].') '; + + Sys::log(LOG_DEBUG, 'Upgrader - Patch applied', $logMsg); + + //Check if the said patch has scripted tasks + if(!($tasks=$this->getTasksForPatch($phash))) + continue; + + //We have work to do... set the tasks and break. + $shash = substr($phash, 9, 8); + $_SESSION['ost_upgrader'][$shash]['tasks'] = $tasks; + $_SESSION['ost_upgrader'][$shash]['state'] = 'upgrade'; + break; + } + + return true; + + } + + function getTasksForPatch($phash) { + + $tasks=array(); + switch($phash) { //Add patch specific scripted tasks. + case 'd4fe13b1-7be60a84': //V1.6 ST- 1.7 * + $tasks[] = array('func' => 'migrateAttachments2DB', + 'desc' => 'Migrating attachments to database, it might take a while depending on the number of files.'); + break; + } + + //Check if cleanup p + $file=$this->getSQLDir().$phash.'.cleanup.sql'; + if(file_exists($file)) + $tasks[] = array('func' => 'cleanup', 'desc' => 'Post-upgrade cleanup!'); + + + return $tasks; + } + + /************* TASKS **********************/ + function cleanup($tId=0) { + + $file=$this->getSQLDir().$this->getShash().'-cleanup.sql'; + if(!file_exists($file)) //No cleanup script. + return 0; + + //We have a cleanup script ::XXX: Don't abort on error? + if($this->load_sql_file($file, $this->getTablePrefix(), false, true)) + return 0; + + //XXX: ??? + return false; + } + + + function migrateAttachments2DB($tId=0) { + echo "Process attachments here - $tId"; + $att_migrater = new AttachmentMigrater(); + $att_migrater->start_migration(); + # XXX: Loop here (with help of task manager) + $att_migrater->do_batch(); + return 0; + } +} +?> diff --git a/setup/inc/sql/02decaa2-60fcbee1.patch.sql b/setup/inc/sql/02decaa2-60fcbee1.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..40dc644b3df64b0e103a3a7c16ed3c835a4bfae3 --- /dev/null +++ b/setup/inc/sql/02decaa2-60fcbee1.patch.sql @@ -0,0 +1,6 @@ +-- Update all temlates with the new wording. +UPDATE `%TABLE_PREFIX%email_template` + SET `ticket_overlimit_body` = '%name\r\n\r\nYou have reached the maximum number of open tickets allowed.\r\n\r\nTo be able to open another ticket, one of your pending tickets must be closed. To update or add comments to an open ticket simply login using the link below.\r\n\r\n%url/view.php?e=%email\r\n\r\nThank you.\r\n\r\nSupport Ticket System'; + +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='60fcbee1da3180d1b690187aa5006c88'; diff --git a/setup/inc/sql/49478749-c2d2fabf.patch.sql b/setup/inc/sql/49478749-c2d2fabf.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..506d85572be1438a2734627f447e04f8616d6285 --- /dev/null +++ b/setup/inc/sql/49478749-c2d2fabf.patch.sql @@ -0,0 +1,2 @@ +ALTER TABLE `%TABLE_PREFIX%config` CHANGE `show_answered_tickets` `show_answered_tickets` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '0'; +ALTER TABLE `%TABLE_PREFIX%config` ADD `show_notes_inline` TINYINT( 1 ) UNSIGNED NOT NULL DEFAULT '1' AFTER `show_answered_tickets`; diff --git a/setup/inc/sql/patches/522e5b78-02decaa2.patch.sql b/setup/inc/sql/522e5b78-02decaa2.patch.sql similarity index 85% rename from setup/inc/sql/patches/522e5b78-02decaa2.patch.sql rename to setup/inc/sql/522e5b78-02decaa2.patch.sql index 6dc1f3a8afdb8fe83f75a7f10e9852284432725e..78c951d69cc10f255ffb3e4ba85fcf93dae6db58 100644 --- a/setup/inc/sql/patches/522e5b78-02decaa2.patch.sql +++ b/setup/inc/sql/522e5b78-02decaa2.patch.sql @@ -1,3 +1,6 @@ +/** + * @version v1.7-DPR2-P2 + */ UPDATE `%TABLE_PREFIX%sla` SET `created` = NOW(), `updated` = NOW() diff --git a/setup/inc/sql/60fcbee1-f8856d56.patch.sql b/setup/inc/sql/60fcbee1-f8856d56.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..2b7e48599816e88702f709f50557189b160a727e --- /dev/null +++ b/setup/inc/sql/60fcbee1-f8856d56.patch.sql @@ -0,0 +1,19 @@ +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`; +CREATE TABLE `%TABLE_PREFIX%ticket_event` ( + `ticket_id` int(11) unsigned NOT NULL default '0', + `staff_id` int(11) unsigned NOT NULL, + `team_id` int(11) unsigned NOT NULL, + `dept_id` int(11) unsigned NOT NULL, + `topic_id` int(11) unsigned NOT NULL, + `state` enum('created','closed','reopened','assigned','transferred','overdue') NOT NULL, + `staff` varchar(255) NOT NULL default 'SYSTEM', + `timestamp` datetime NOT NULL, + KEY `ticket_state` (`ticket_id`, `state`, `timestamp`), + KEY `ticket_stats` (`timestamp`, `state`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_history`; +DROP TABLE IF EXISTS `%TABLE_PREFIX%history`; + +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='f8856d56e51c5cc3416389de78b54515'; diff --git a/setup/inc/sql/patches/7be60a84-522e5b78.patch.sql b/setup/inc/sql/7be60a84-522e5b78.patch.sql similarity index 86% rename from setup/inc/sql/patches/7be60a84-522e5b78.patch.sql rename to setup/inc/sql/7be60a84-522e5b78.patch.sql index 17ab3e07bd82c42df9b5cf7b2a73107afffbb499..acdaf7d0d3c1f8baaedd40bd68e33b01b97e72c9 100644 --- a/setup/inc/sql/patches/7be60a84-522e5b78.patch.sql +++ b/setup/inc/sql/7be60a84-522e5b78.patch.sql @@ -1,3 +1,6 @@ +/** + * @version v1.7-DPR1 (P1) + */ UPDATE `%TABLE_PREFIX%email_template` SET `ticket_overlimit_subj` = 'Open Tickets Limit Reached' WHERE `tpl_id` = 1 AND `cfg_id` = 1; diff --git a/setup/inc/sql/abe9c0cb-bbb021fb.patch.sql b/setup/inc/sql/abe9c0cb-bbb021fb.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..0a3248db4569aebd2ce75eed39cfff3da68d559c --- /dev/null +++ b/setup/inc/sql/abe9c0cb-bbb021fb.patch.sql @@ -0,0 +1,14 @@ +/** + * Add an 'annulled' column to the %ticket_event table to assist in tracking + * real statistics for reopened and closed tickets -- the events should not + * count more than one time. + * + * @version 1.7-dpr3 ticket-event-annul + */ + +ALTER TABLE `%TABLE_PREFIX%ticket_event` + ADD `annulled` tinyint(1) NOT NULL DEFAULT '0' AFTER `staff`; + +-- Finished with patch +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='bbb021fbeb377ca66b6997b77e0167cc'; diff --git a/setup/inc/sql/bbb021fb-49478749.patch.sql b/setup/inc/sql/bbb021fb-49478749.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..8bd81f32016f936848f790ef325e1613317cc3fc --- /dev/null +++ b/setup/inc/sql/bbb021fb-49478749.patch.sql @@ -0,0 +1,9 @@ +/** + * Transitional patch - FIX on the INSTALLER schema + * + * @version 1.7-dpr3 installerfix + */ + +-- Finished with patch +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='49478749dc680eef08b7954bd568cfd1'; diff --git a/setup/inc/sql/f8856d56-abe9c0cb.patch.sql b/setup/inc/sql/f8856d56-abe9c0cb.patch.sql new file mode 100644 index 0000000000000000000000000000000000000000..a5f54aa8516aaaaf268e363b8ae58674725b61af --- /dev/null +++ b/setup/inc/sql/f8856d56-abe9c0cb.patch.sql @@ -0,0 +1,109 @@ +/** + * Merge ticket thread tables into one + * + * Replace the ticket_{message,response,note} tables with a single + * ticket_thread table that will contain data for all three current message + * types. This simplifies much of the ticket thread code and paves the way + * for other types of messages in the future. + * + * This patch automagically moves the data from the three federated tables + * into the one combined table. + */ +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_thread`; +CREATE TABLE `%TABLE_PREFIX%ticket_thread` ( + `id` int(11) unsigned NOT NULL auto_increment, + `pid` int(11) unsigned NOT NULL default '0', + `ticket_id` int(11) unsigned NOT NULL default '0', + `staff_id` int(11) unsigned NOT NULL default '0', + `thread_type` enum('M','R','N') NOT NULL, + `poster` varchar(128) NOT NULL default '', + `source` varchar(32) NOT NULL default '', + `title` varchar(255), + `body` text NOT NULL, + `ip_address` varchar(64) NOT NULL default '', + `created` datetime NOT NULL, + `updated` datetime NOT NULL, + -- Temporary columns for conversion + `old_pk` int(11) unsigned NOT NULL, + `old_pid` int(11) unsigned, + PRIMARY KEY (`id`), + KEY `ticket_id` (`ticket_id`), + KEY `staff_id` (`staff_id`), + FULLTEXT KEY `body` (`body`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_email_info`; +CREATE TABLE `%TABLE_PREFIX%ticket_email_info` ( + `message_id` int(11) unsigned NOT NULL, + `email_mid` varchar(255) NOT NULL, + `headers` text, + KEY `message_id` (`email_mid`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + +-- Transfer messages +INSERT INTO `%TABLE_PREFIX%ticket_thread` + (`ticket_id`, `thread_type`, `body`, `ip_address`, + `created`, `updated`, `old_pk`) + SELECT `ticket_id`, 'M', `message`, `ip_address`, + `created`, COALESCE(`updated`, NOW()), `msg_id` + FROM `%TABLE_PREFIX%ticket_message`; + +-- Transfer responses +INSERT INTO `%TABLE_PREFIX%ticket_thread` + (`ticket_id`, `staff_id`, `thread_type`, `poster`, `body`, `ip_address`, + `created`, `updated`, `old_pk`, `old_pid`) + SELECT `ticket_id`, `staff_id`, 'R', `staff_name`, `response`, `ip_address`, + `created`, COALESCE(`updated`, NOW()), `response_id`, `msg_id` + FROM `%TABLE_PREFIX%ticket_response`; + +-- Connect responses to (new) messages +CREATE TABLE `%TABLE_PREFIX%T_resp_links` + SELECT `id`, `old_pk`, `old_pid` FROM `%TABLE_PREFIX%ticket_thread`; + +UPDATE `%TABLE_PREFIX%ticket_thread` + SET `pid` = ( SELECT T2.`id` FROM `%TABLE_PREFIX%T_resp_links` T2 + WHERE `old_pid` = T2.`old_pk` ) + WHERE `thread_type` = 'R' + AND `old_pid` IS NOT NULL; + +DROP TABLE `%TABLE_PREFIX%T_resp_links`; + +-- Transfer notes +INSERT INTO `%TABLE_PREFIX%ticket_thread` + (`ticket_id`, `staff_id`, `thread_type`, `body`, `title`, + `source`, `poster`, `created`, `updated`, `old_pk`) + SELECT `ticket_id`, `staff_id`, 'N', `note`, `title`, + `source`, ( SELECT CONCAT_WS(' ', T2.`firstname`, T2.`lastname`) + FROM `%TABLE_PREFIX%staff` T2 + WHERE T2.`staff_id` = `staff_id` ), + `created`, NOW(), `note_id` + FROM `%TABLE_PREFIX%ticket_note`; + +-- Transfer email information from messages +INSERT INTO `%TABLE_PREFIX%ticket_email_info` + (`message_id`, `email_mid`, `headers`) + SELECT ( SELECT T2.`id` FROM `%TABLE_PREFIX%ticket_thread` T2 + WHERE `msg_id` = T2.`old_pk` + AND `thread_type` = 'M' ), + `messageId`, `headers` + FROM `%TABLE_PREFIX%ticket_message` + WHERE `messageId` IS NOT NULL; + +-- Update attachment table +UPDATE `%TABLE_PREFIX%ticket_attachment` + SET `ref_id` = ( SELECT T2.`id` FROM `%TABLE_PREFIX%ticket_thread` T2 + WHERE `ref_id` = T2.`old_pk` + AND `ref_type` = T2.`thread_type` ); + +-- Drop temporary columns +ALTER TABLE `%TABLE_PREFIX%ticket_thread` DROP COLUMN `old_pk`; +ALTER TABLE `%TABLE_PREFIX%ticket_thread` DROP COLUMN `old_pid`; + +-- Drop old tables +DROP TABLE `%TABLE_PREFIX%ticket_message`; +DROP TABLE `%TABLE_PREFIX%ticket_response`; +DROP TABLE `%TABLE_PREFIX%ticket_note`; + +-- Finished with patch +UPDATE `%TABLE_PREFIX%config` + SET `schema_signature`='abe9c0cb845be52c10fcd7b3e626a589'; diff --git a/setup/inc/sql/osticket-v1.7-mysql.sql b/setup/inc/sql/osticket-v1.7-mysql.sql index 7a31d814e1ad8544066830ad2d5d782aaf2da426..a3d03dd7218066d54ee3b900fba1fad9129add9a 100644 --- a/setup/inc/sql/osticket-v1.7-mysql.sql +++ b/setup/inc/sql/osticket-v1.7-mysql.sql @@ -134,7 +134,8 @@ CREATE TABLE `%TABLE_PREFIX%config` ( `auto_assign_reopened_tickets` tinyint(1) unsigned NOT NULL default '1', `show_related_tickets` tinyint(1) unsigned NOT NULL default '1', `show_assigned_tickets` tinyint(1) unsigned NOT NULL default '0', - `show_answered_tickets` tinyint(1) NOT NULL default '0', + `show_answered_tickets` tinyint(1) unsigned NOT NULL default '0', + `show_notes_inline` tinyint(1) unsigned NOT NULL default '1', `hide_staff_name` tinyint(1) unsigned NOT NULL default '0', `overlimit_notice_active` tinyint(1) unsigned NOT NULL default '0', `email_attachments` tinyint(1) unsigned NOT NULL default '1', @@ -598,6 +599,14 @@ CREATE TABLE `%TABLE_PREFIX%ticket_lock` ( KEY `staff_id` (`staff_id`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_email_info`; +CREATE TABLE `%TABLE_PREFIX%ticket_email_info` ( + `message_id` int(11) unsigned NOT NULL, + `email_mid` varchar(255) NOT NULL, + `headers` text, + KEY `message_id` (`email_mid`) +) ENGINE=MyISAM DEFAULT CHARSET=utf8; + DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_event`; CREATE TABLE `%TABLE_PREFIX%ticket_event` ( `ticket_id` int(11) unsigned NOT NULL default '0', @@ -607,43 +616,12 @@ CREATE TABLE `%TABLE_PREFIX%ticket_event` ( `topic_id` int(11) unsigned NOT NULL, `state` enum('created','closed','reopened','assigned','transferred','overdue') NOT NULL, `staff` varchar(255) NOT NULL default 'SYSTEM', + `annulled` tinyint(1) unsigned NOT NULL default '0', `timestamp` datetime NOT NULL, KEY `ticket_state` (`ticket_id`, `state`, `timestamp`), KEY `ticket_stats` (`timestamp`, `state`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_message`; -CREATE TABLE `%TABLE_PREFIX%ticket_message` ( - `msg_id` int(11) unsigned NOT NULL auto_increment, - `ticket_id` int(11) unsigned NOT NULL default '0', - `messageId` varchar(255) default NULL, - `message` text NOT NULL, - `headers` text, - `source` varchar(16) default NULL, - `ip_address` varchar(16) default NULL, - `created` datetime NOT NULL, - `updated` datetime default NULL, - PRIMARY KEY (`msg_id`), - KEY `ticket_id` (`ticket_id`), - KEY `msgId` (`messageId`), - FULLTEXT KEY `message` (`message`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_note`; -CREATE TABLE `%TABLE_PREFIX%ticket_note` ( - `note_id` int(11) unsigned NOT NULL auto_increment, - `ticket_id` int(11) unsigned NOT NULL default '0', - `staff_id` int(10) unsigned NOT NULL default '0', - `source` varchar(32) NOT NULL default '', - `title` varchar(255) NOT NULL default 'Generic Intermal Notes', - `note` text NOT NULL, - `created` datetime NOT NULL, - PRIMARY KEY (`note_id`), - KEY `ticket_id` (`ticket_id`), - KEY `staff_id` (`staff_id`), - FULLTEXT KEY `note` (`note`) -) ENGINE=MyISAM DEFAULT CHARSET=utf8; - DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_priority`; CREATE TABLE `%TABLE_PREFIX%ticket_priority` ( `priority_id` tinyint(4) NOT NULL auto_increment, @@ -664,22 +642,24 @@ INSERT INTO `%TABLE_PREFIX%ticket_priority` (`priority_id`, `priority`, `priorit (3, 'high', 'High', '#FEE7E7', 2, 1), (4, 'emergency', 'Emergency', '#FEE7E7', 1, 0); -DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_response`; -CREATE TABLE `%TABLE_PREFIX%ticket_response` ( - `response_id` int(11) unsigned NOT NULL auto_increment, - `msg_id` int(11) unsigned NOT NULL default '0', +DROP TABLE IF EXISTS `%TABLE_PREFIX%ticket_thread`; +CREATE TABLE `%TABLE_PREFIX%ticket_thread` ( + `id` int(11) unsigned NOT NULL auto_increment, + `pid` int(11) unsigned NOT NULL default '0', `ticket_id` int(11) unsigned NOT NULL default '0', `staff_id` int(11) unsigned NOT NULL default '0', - `staff_name` varchar(32) NOT NULL default '', - `response` text NOT NULL, - `ip_address` varchar(16) NOT NULL default '', + `thread_type` enum('M','R','N') NOT NULL, + `poster` varchar(128) NOT NULL default '', + `source` varchar(32) NOT NULL default '', + `title` varchar(255), + `body` text NOT NULL, + `ip_address` varchar(64) NOT NULL default '', `created` datetime NOT NULL, `updated` datetime NOT NULL, - PRIMARY KEY (`response_id`), + PRIMARY KEY (`id`), KEY `ticket_id` (`ticket_id`), - KEY `msg_id` (`msg_id`), KEY `staff_id` (`staff_id`), - FULLTEXT KEY `response` (`response`) + FULLTEXT KEY `body` (`body`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS `%TABLE_PREFIX%timezone`; diff --git a/setup/inc/sql/osticket-v1.7-mysql.sql.md5 b/setup/inc/sql/osticket-v1.7-mysql.sql.md5 index 73090636d948f041c1a368ef416674c6269a309a..798a76acc57bcf65d56d7c11af8cda14317aefea 100644 --- a/setup/inc/sql/osticket-v1.7-mysql.sql.md5 +++ b/setup/inc/sql/osticket-v1.7-mysql.sql.md5 @@ -1 +1 @@ -f8856d56e51c5cc3416389de78b54515 +c2d2fabfdf15e1632f00850ffb361558 diff --git a/setup/inc/sql/patches/02decaa2-60fcbee1.patch.sql b/setup/inc/sql/patches/02decaa2-60fcbee1.patch.sql deleted file mode 100644 index 351bea5821c9fc9a84743f780e5b8f3752b2a8e6..0000000000000000000000000000000000000000 --- a/setup/inc/sql/patches/02decaa2-60fcbee1.patch.sql +++ /dev/null @@ -1,6 +0,0 @@ -UPDATE `%TABLE_PREFIX%email_template` - SET `overlimit_body` = '%name\r\n\r\nYou have reached the maximum number of open tickets allowed.\r\n\r\nTo be able to open another ticket, one of your pending tickets must be closed. To update or add comments to an open ticket simply login using the link below.\r\n\r\n%url/view.php?e=%email\r\n\r\nThank you.\r\n\r\nSupport Ticket System' - WHERE `tpl_id` = 1 AND `cfg_id` = 1; - -UPDATE `%TABLE_PREFIX%config` - SET `schema_signature`='60fcbee1da3180d1b690187aa5006c88'; diff --git a/setup/inc/sql/patches/60fcbee1-f8856d56.patch.sql b/setup/inc/sql/patches/60fcbee1-f8856d56.patch.sql deleted file mode 100644 index dcdb1850237b475327cd2b74c0e7fc00d68a5e62..0000000000000000000000000000000000000000 --- a/setup/inc/sql/patches/60fcbee1-f8856d56.patch.sql +++ /dev/null @@ -1,10 +0,0 @@ -ALTER TABLE `%TABLE_PREFIX%history` - ADD `staff_id` int(11) unsigned NOT NULL AFTER `ticket_id`, - ADD `team_id` int(11) unsigned NOT NULL AFTER `staff_id`, - ADD `dept_id` int(11) unsigned NOT NULL AFTER `team_id`, - ADD `topic_id` int(11) unsigned NOT NULL AFTER `dept_id`; - -RENAME TABLE `%TABLE_PREFIX%history` TO `%TABLE_PREFIX%event`; - -UPDATE `%TABLE_PREFIX%config` - SET `schema_signature`='f8856d56e51c5cc3416389de78b54515'; diff --git a/setup/inc/upgrade-aborted.inc.php b/setup/inc/upgrade-aborted.inc.php index 8d8f64aa831841dd9431f017c7289760ba18448e..8624590d35710a42906952afab82b2688f028315 100644 --- a/setup/inc/upgrade-aborted.inc.php +++ b/setup/inc/upgrade-aborted.inc.php @@ -6,17 +6,18 @@ if(!defined('SETUPINC')) die('Kwaheri!'); <div id="intro"> <p>Upgrade aborted due to errors. Any errors at this stage are fatal. Please note the error(s), if any, when contacting us.<p> <?php - if($_SESSION['upgrader']['errors']) { - $errors=$_SESSION['upgrader']['errors']; + if($upgrader && ($errors=$upgrader->getErrors())) { if($errors['err']) echo sprintf('<b><font color="red">%s</font></b>',$errors['err']); - echo '<ul class="error">'; unset($errors['err']); - foreach($errors as $k=>$error) + foreach($errors as $k => $error) echo sprintf('<li>%s</li>',$error); echo '</ul>'; - } ?> + } else { + echo '<b><font color="red">Internal error occurred - get technical help.</font></b>'; + } + ?> <p>Please, refer to the <a target="_blank" href="http://osticket.com/wiki/Upgrade_and_Migration">Upgrade Guide</a> on the wiki for more information.</p> </div> <p><strong>Need Help?</strong> We provide <a target="_blank" href="http://osticket.com/support/professional_services.php"><u>professional upgrade services</u></a> and commercial support. <a target="_blank" href="http://osticket.com/support/">Contact us</a> today for expedited help.</p> diff --git a/setup/inc/upgrade-attachments.inc.php b/setup/inc/upgrade-attachments.inc.php deleted file mode 100644 index c8155d32c672e358cb068d79720a076327a88706..0000000000000000000000000000000000000000 --- a/setup/inc/upgrade-attachments.inc.php +++ /dev/null @@ -1,32 +0,0 @@ -<?php -if(!defined('SETUPINC')) die('Kwaheri!'); -$msg = $_SESSION['ost_upgrader']['msg']; -?> -<div id="main"> - <h1>Attachments Migration</h1> - <p>We're almost done! We're now migrating attachments to the database, it might take a while dending on the number of files in your database.<p> - <p style="color:#FF7700;font-weight:bold;">We have to migrate files in batches for technical reasons.</p> - <p>Please don't cancel or close the browser.</p> - - <div id="bar"> - <form method="post" action="upgrade.php" id="attachments"> - <input type="hidden" name="s" value="cleanup"> - <input class="btn" type="submit" name="submit" value="Next Batch"> - </form> - - </div> -</div> -<div id="sidebar"> - <h3>Upgrade Tips</h3> - <p>1. Be patient the process will take a few minutes.</p> - <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> -</div> -<div id="overlay"></div> - <div id="loading"> - <h4>Moving attachments</h4> - <br> - Please wait... while we migrate attachments! - <br><br> - <div id="msg" style="font-weight: bold;"><?php echo Format::htmlchars($msg); ?></div> - </div> diff --git a/setup/inc/upgrade-cleanup.inc.php b/setup/inc/upgrade-cleanup.inc.php deleted file mode 100644 index f8406ae533a9efbce73e864239d749b586e8f66e..0000000000000000000000000000000000000000 --- a/setup/inc/upgrade-cleanup.inc.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php -if(!defined('SETUPINC')) die('Kwaheri!'); - -?> - <div id="main"> - <h1>osTicket Upgrade</h1> - <div id="intro"> - <p>We're almost done! Please don't cancel or close the browser, any errors at this stage will be fatal.</p> - </div> - <h2>Cleanup: Step 2 of 2</h2> - <p>The upgrade wizard will now attempt to do post upgrade cleanup. It might take a while dending on the size of your database. </p> - <ul> - <li>Setting Changes</li> - <li>Attachment Migration</li> - <li>Database Optimization</li> - </ul> - <div id="bar"> - <form method="post" action="upgrade.php" id="cleanup"> - <input type="hidden" name="s" value="cleanup"> - <input class="btn" type="submit" name="submit" value="Do It Now!"> - </form> - </div> - </div> - <div id="sidebar"> - <h3>Upgrade Tips</h3> - <p>1. Be patient the process will take a couple of seconds.</p> - <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> - </div> - - <div id="overlay"></div> - <div id="loading"> - <h4>Doing serious stuff!</h4> - <br> - Please wait... while we do post-upgrade cleanup! - <br><br> - <div id="msg" style="font-weight: bold;"></div> - </div> diff --git a/setup/inc/upgrade-core.inc.php b/setup/inc/upgrade-core.inc.php deleted file mode 100644 index ec42e50437537ea01931484a18e86c902ba909b1..0000000000000000000000000000000000000000 --- a/setup/inc/upgrade-core.inc.php +++ /dev/null @@ -1,38 +0,0 @@ -<?php -if(!defined('SETUPINC')) die('Kwaheri!'); - -?> - <div id="main"> - <h1>osTicket Upgrade</h1> - <div id="intro"> - <p>Thank you for taking the time to upgrade your osTicket intallation!</p> - <p>Please don't cancel or close the browser, any errors at this - stage will be fatal.</p> - </div> - <h2>Base upgrade: Step 1 of 2</h2> - <p>The upgrade wizard will now attempt to upgrade your database and core settings!</p> - <ul> - <li>Database enhancements</li> - <li>New and updated features</li> - <li>Enhance settings and security</li> - </ul> - <div id="bar"> - <form method="post" action="upgrade.php" id="upgrade"> - <input type="hidden" name="s" value="upgrade"> - <input class="btn" type="submit" name="submit" value="Do It Now!"> - </form> - </div> - </div> - <div id="sidebar"> - <h3>Upgrade Tips</h3> - <p>1. Be patient the process will take a couple of seconds.</p> - <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> - </div> - - <div id="overlay"></div> - <div id="loading"> - <h4>Doing serious stuff!</h4> - Please wait... while we upgrade your osTicket installation! - <div id="udb"><br><b>Smile!</b></div> - </div> diff --git a/setup/inc/upgrade-prereq.inc.php b/setup/inc/upgrade-prereq.inc.php new file mode 100644 index 0000000000000000000000000000000000000000..5f60cece25500679de83b01981ea05ac634949e9 --- /dev/null +++ b/setup/inc/upgrade-prereq.inc.php @@ -0,0 +1,50 @@ +<?php +if(!defined('SETUPINC')) die('Kwaheri!'); + +?> + <div id="main"> + <h1>osTicket Upgrade!</h1> + <font color="red"><b><?php echo $errors['err']; ?></b></font> + <div id="intro"> + <p>Thank you for being a loyal osTicket user!</p> + <p>The upgrade wizard will guide you every step of the way in the upgrade process. While we try to ensure that the upgrade process is straightforward and painless, we can't guarantee it will be the case for every user.</p> + </div> + <h2>Getting ready!</h2> + <p>Before we begin, we'll check your server configuration to make sure you meet the minimum requirements to run the latest version of osTicket.</p> + <h3>Prerequisites: <font color="red"><?php echo $errors['prereq']; ?></font></h3> + These items are necessary in order to use osTicket the latest version of osTicket. + <ul class="progress"> + <li class="<? echo $upgrader->check_php()?'yes':'no'; ?>"> + PHP v4.3 or greater - (<small><b><?php echo PHP_VERSION; ?></b></small>)</li> + <li class="<? echo $upgrader->check_mysql()?'yes':'no'; ?>"> + MySQL v4.4 or greater - (<small><b><?php echo extension_loaded('mysql')?'module loaded':'missing!'; ?></b></small>)</li> + </ul> + <h3>Higly Recommended:</h3> + We hightly recommend that you follow the steps below. + <ul> + <li>Take osTicket offline momentarily during upgrade.</li> + <li>Backup the current database, if you haven't done so already.</li> + <li>Be patient the upgrade process will take a couple of seconds.</li> + </ul> + <div id="bar"> + <form method="post" action="upgrade.php" id="prereq"> + <input type="hidden" name="s" value="prereq"> + <input class="btn" type="submit" name="submit" value="Start Upgrade Now »"> + </form> + </div> + </div> + <div id="sidebar"> + <h3>Upgrade Tips</h3> + <p>1. Remember to backup your osTicket database</p> + <p>2. Take osTicket offline momentarily</p> + <p>3. If you experience any problems, you can always restore your files/dabase backup.</p> + <p>4. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> + + </div> + + <div id="overlay"></div> + <div id="loading"> + <h4>Doing stuff!</h4> + Please wait... while we upgrade your osTicket installation! + <div id="udb"></div> + </div> diff --git a/setup/inc/upgrade.inc.php b/setup/inc/upgrade.inc.php index e5b8ba77bef7da18c547820031d1ca294b2b4dea..6f05cd169c66d49163908d8a6c6bef9d5b9a1a18 100644 --- a/setup/inc/upgrade.inc.php +++ b/setup/inc/upgrade.inc.php @@ -1,50 +1,40 @@ <?php -if(!defined('SETUPINC')) die('Kwaheri!'); +if(!defined('SETUPINC') || !$upgrader) die('Kwaheri!'); +$action=$upgrader->getNextAction(); ?> <div id="main"> - <h1>osTicket Upgrade!</h1> - <font color="red"><b><?php echo $errors['err']; ?></b></font> + <h1>osTicket Upgrade</h1> <div id="intro"> - <p>Thank you for being a loyal osTicket user!</p> - <p>The upgrade wizard will guide you every step of the way in the upgrade process. While we try to ensure that the upgrade process is straightforward and painless, we can't guarantee it will be the case for every user.</p> + <p>Thank you for taking the time to upgrade your osTicket intallation!</p> + <p>Please don't cancel or close the browser, any errors at this + stage will be fatal.</p> </div> - <h2>Getting ready!</h2> - <p>Before we begin, we'll check your server configuration to make sure you meet the minimum requirements to run the latest version of osTicket.</p> - <h3>Prerequisites: <font color="red"><?php echo $errors['prereq']; ?></font></h3> - These items are necessary in order to use osTicket the latest version of osTicket. - <ul class="progress"> - <li class="<? echo $upgrader->check_php()?'yes':'no'; ?>"> - PHP v4.3 or greater - (<small><b><?php echo PHP_VERSION; ?></b></small>)</li> - <li class="<? echo $upgrader->check_mysql()?'yes':'no'; ?>"> - MySQL v4.4 or greater - (<small><b><?php echo extension_loaded('mysql')?'module loaded':'missing!'; ?></b></small>)</li> - </ul> - <h3>Higly Recommended:</h3> - We hightly recommend that you follow the steps below. + <h2><?php echo $action ?></h2> + <p>The upgrade wizard will now attempt to upgrade your database and core settings!</p> <ul> - <li>Take osTicket offline momentarily during upgrade.</li> - <li>Backup the current database, if you haven't done so already.</li> - <li>Be patient the upgrade process will take a couple of seconds.</li> + <li>Database enhancements</li> + <li>New and updated features</li> + <li>Enhance settings and security</li> </ul> <div id="bar"> <form method="post" action="upgrade.php" id="upgrade"> - <input type="hidden" name="s" value="prereq"> - <input class="btn" type="submit" name="submit" value="Start Upgrade Now »"> + <input type="hidden" name="s" value="upgrade"> + <input type="hidden" name="sh" value="<?php echo $upgrader->getSchemaSignature(); ?>"> + <input class="btn" type="submit" name="submit" value="Do It Now!"> </form> </div> </div> <div id="sidebar"> <h3>Upgrade Tips</h3> - <p>1. Remember to backup your osTicket database</p> - <p>2. Take osTicket offline momentarily</p> - <p>3. If you experience any problems, you can always restore your files/dabase backup.</p> - <p>4. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> - + <p>1. Be patient the process will take a couple of seconds.</p> + <p>2. If you experience any problems, you can always restore your files/dabase backup.</p> + <p>3. We can help, feel free to <a href="http://osticket.com/support/" target="_blank">contact us </a> for professional help.</p> </div> <div id="overlay"></div> <div id="loading"> - <h4>Doing stuff!</h4> + <h4><?php echo $action; ?></h4> Please wait... while we upgrade your osTicket installation! - <div id="udb"></div> + <div id="msg" style="font-weight: bold;padding-top:10px;">Smile!</div> </div> diff --git a/setup/install.php b/setup/install.php index 27b1388933d03ef9c0db5690dd147213848d750f..d019598e55de7099c9dbb517b4a9aa1663886ad0 100644 --- a/setup/install.php +++ b/setup/install.php @@ -15,6 +15,9 @@ **********************************************************************/ require('setup.inc.php'); +require_once INC_DIR.'class.installer.php'; + + //define('OSTICKET_CONFIGFILE','../include/ost-config.php'); //osTicket config file full path. define('OSTICKET_CONFIGFILE','../include/ost-config.php'); //XXX: Make sure the path is corrent b4 releasing. diff --git a/setup/js/setup.js b/setup/js/setup.js index 5d274ea3198bbec310c20abef16ac68df51ee270..b1f8e08c3aa48397206c43ad854fc3bf4815473c 100644 --- a/setup/js/setup.js +++ b/setup/js/setup.js @@ -13,30 +13,30 @@ jQuery(function($) { left : ($(window).width() / 2 - 160) }); - $('form#install, form#upgrade, form#attachments').submit(function(e) { + $('form#install').submit(function(e) { $('input[type=submit]', this).attr('disabled', 'disabled'); $('#overlay, #loading').show(); return true; }); - $('form#cleanup').submit(function(e) { + $('form#upgrade').submit(function(e) { e.preventDefault(); var form = $(this); $('input[type=submit]', this).attr('disabled', 'disabled'); $('#overlay, #loading').show(); - doCleanup('upgrade',form.attr('action')); + doTasks('upgrade.php',form.serialize()); + return false; }); - - function doCleanup(type,url) { + function doTasks(url, data) { function _lp(count) { $.ajax({ type: 'GET', - url: 'cleanup.php', + url: 'p.php', async: true, cache: false, - data: {c:count,type:type}, + data: data, dataType: 'text', success: function(res) { if (res) { @@ -45,16 +45,17 @@ jQuery(function($) { }, statusCode: { 200: function() { - setTimeout(function() { _lp(count+1); },2); + setTimeout(function() { _lp(count+1); }, 2); }, 304: function() { - $('#loading #msg').html("We're done... "); - setTimeout(function() { location.href =url;},1000); + $('#loading #msg').html("We're done... cleaning up!"); + setTimeout(function() { location.href =url;}, 3000); } }, - error: function(){ - alert("Something went wrong"); + error: function() { + $('#loading #msg').html("Something went wrong"); + setTimeout(function() { location.href =url;}, 1000); } }); }; diff --git a/setup/p.php b/setup/p.php new file mode 100644 index 0000000000000000000000000000000000000000..babeebb866f198e7fc78516a34133164d72a9b47 --- /dev/null +++ b/setup/p.php @@ -0,0 +1,69 @@ +<?php +/********************************************************************* + upgrader.php + + osTicket Upgrader Helper - called via ajax. + + Peter Rotich <peter@osticket.com> + Copyright (c) 2006-2012 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: +**********************************************************************/ +function staffLoginPage($msg) { + Http::response(403, $msg?$msg:'Access Denied'); + exit; +} + +require '../scp/staff.inc.php'; +if(!$thisstaff or !$thisstaff->isAdmin()) { + staffLoginPage('Admin Access Required!'); + exit; +} + +define('SETUPINC', true); +define('INC_DIR', './inc/'); +define('SQL_DIR', INC_DIR.'sql/'); + +require_once INC_DIR.'class.upgrader.php'; + + +$upgrader = new Upgrader($cfg->getSchemaSignature(), TABLE_PREFIX, SQL_DIR); + +//Just report the next action on the first call. +if(!$_SESSION['ost_upgrader'][$upgrader->getShash()]['progress']) { + $_SESSION['ost_upgrader'][$upgrader->getShash()]['progress'] = $upgrader->getNextAction(); + Http::response(200, $upgrader->getNextAction()); + exit; +} + +if($upgrader->getNumPendingTasks()) { + if($upgrader->doTasks() && !$upgrader->getNumPendingTasks() && $cfg->isUpgradePending()) { + //Just reporting done...with tasks - break in between patches! + header("HTTP/1.1 304 Not Modified"); + exit; + } +} elseif($cfg->isUpgradePending() && $upgrader->isUpgradable()) { + $version = $upgrader->getNextVersion(); + if($upgrader->upgrade()) { + //We're simply reporting progress here - call back will report next action' + Http::response(200, "Upgraded to $version ... post-upgrade checks!"); + exit; + } +} elseif(!$cfg->isUpgradePending()) { + $upgrader->setState('done'); + session_write_close(); + header("HTTP/1.1 304 Not Modified"); + exit; +} + +if($upgrader->isAborted() || $upgrader->getErrors()) { + Http::response(416, "We have a problem ... wait a sec."); + exit; +} + +Http::response(200, $upgrader->getNextAction()); +?> diff --git a/setup/setup.inc.php b/setup/setup.inc.php index f2af40af61e1b7e94b9ae915eb1e81e103560594..44b2ad4d593f5521b66ad170c9e801a817cf74f1 100644 --- a/setup/setup.inc.php +++ b/setup/setup.inc.php @@ -52,10 +52,8 @@ ini_set('include_path', './'.PATH_SEPARATOR.INC_DIR.PATH_SEPARATOR.INCLUDE_DIR.P endif; #required files -require_once(INC_DIR.'class.setup.php'); require_once(INCLUDE_DIR.'class.validator.php'); require_once(INCLUDE_DIR.'class.format.php'); require_once(INCLUDE_DIR.'class.misc.php'); require_once(INCLUDE_DIR.'mysql.php'); - ?> diff --git a/setup/test/lib/phplint.tcl b/setup/test/lib/phplint.tcl new file mode 100755 index 0000000000000000000000000000000000000000..6b857c75048a26fcd136d9213ece4c5b784bbfbc --- /dev/null +++ b/setup/test/lib/phplint.tcl @@ -0,0 +1,208 @@ +#!/usr/bin/tclsh + +# Copyright (C) 2007 Salvatore Sanfilippo <antirez at gmail dot com> +# This software is released under the GPL license version 2 + +proc scan file { + set fd [open $file] + set infunc 0 + set linenr 0 + set fnre {(^\s*)((public|private|protected|static)\s*)*function\s+([^(]+)\s*\((.*)\).*} + while {[gets $fd line] != -1} { + incr linenr + if {[regexp $fnre $line - ind - - - fa]} { + # If $infunc is true we miss the end of the last function + # so we analyze it now. + if {$infunc} { + analyze $file $arglist $body + } + set body {} + set arglist {} + foreach arg [split $fa ,] { + # remove default value + regsub {=.*} $arg {} arg + # remove optional type spec + regsub {^.*\s+} [string trim $arg] {} arg + set arg [string trim $arg " $&"] + lappend arglist $arg + } + set infunc 1 + } elseif {$infunc && [regexp "^$ind\}" $line]} { + set infunc 0 + analyze $file $arglist $body + } elseif {$infunc} { + lappend body $linenr [string trim $line] + } + } +} + +proc analyze {file arglist body} { + set initialized(this) 1 + set linton 1 + foreach arg $arglist { + set initialized($arg) 1 + } + # Superglobals + set superglobals { + "GLOBALS" + "_SESSION" + "_SESSION" + "_GET" + "_POST" + "_REQUEST" + "_ENV" + "_SERVER" + "_FILES" + "php_errormsg" + } + foreach sg $superglobals { + set initialized($sg) 1 + } + # analyze body + foreach {linenr line} $body { + # Handle annotations + if {[string first {nolint} [string tolower $line]] != -1} continue + if {[string first {linton} [string tolower $line]] != -1} { + if {$linton == 1} { + puts "! Warning 'linton' annotation with lint already ON" + continue + } + set linton 1 + puts ". $skipped lines skipped in $file from line $skipstart" + } + if {[string first {lintoff} [string tolower $line]] != -1} { + if {$linton == 0} { + puts "! Warning 'lintoff' annotation with lint already OFF" + continue + } + set linton 0 + set skipped 0 + set skipstart [expr {$linenr+1}] + continue + } + if {$linton == 0} { + incr skipped + continue + } + # Skip comments + if {[string index $line 0] eq {#}} continue + if {[string index $line 0] eq {/} && [string index $line 1] eq {/}} continue + # PHP variable regexp + set varre {\$[_A-Za-z]+[_A-Za-z0-9]*(\[[^\]]*\])*} + # Check for globals + set re {\s*(global|static)\s+((?:\$[^;,]+[ ,]*)+)(;|$)} + if {[regexp $re $line -> - g]} { + set g [split [string trim $g ";"] ,] + foreach v $g { + set v [string trim $v "$ "] + set initialized($v) 1 + } + } + # Check for assignment via foreach ... as &$varname + set re {} + append re {foreach\s*\(.*\s+as\s+&?(} $varre {)\s*\)} + set l [regexp -all -inline -nocase $re $line] + foreach {- a -} $l { + set initialized([string trim $a "$ "]) 1 + } + # Check for assignment via foreach ... as $key => &$val + set re {} + append re {foreach\s*\(.*\s+as\s+(} $varre {)\s*=>\s*&?(} $varre {)\s*\)} + set l [regexp -all -inline -nocase $re $line] + foreach {- a1 - a2 -} $l { + set initialized([string trim $a1 "$ "]) 1 + set initialized([string trim $a2 "$ "]) 1 + } + # Check for assigments in the form list($a,$b,$c) = ... + set re {list\s*\(([^=]*)\)\s*=} + set l [regexp -all -inline $re $line] + foreach {- vars} $l { + foreach v [split $vars ,] { + set v [string trim $v "$ "] + set initialized($v) 1 + } + } + # Check for assigments via = operator + set re $varre + append re {\s*=} + set l [regexp -all -inline $re $line] + foreach {a -} $l { + set a [string trim $a "=$ "] + regsub -all {\[.*\]} $a {[]} a + #puts "assigmnent of $a" + set initialized($a) 1 + regsub -all {\[\]} $a {} a + set initialized($a) 1 + } + # Check for assignments via catch(Exception $e) + set re {} + append re {catch\s*\(.*\s+(} $varre {)} + set l [regexp -all -inline -nocase $re $line] + foreach {- a} $l { + set initialized([string trim $a "$ "]) 1 + } + # Check for assignments by reference + # + # funclist format is {type funcname spos epos} where spos is the + # zero-based index of the first argument that can be considered + # an assignment, while epos is the last. + # + # name is the function name to match, and type is what + # to do with the args. "assignment" to consider them assigned + # or "ingore" to ingore them for the current line. + # + # The "ignore" is used for isset() and other functions that can + # deal with not initialized vars. + unset -nocomplain -- ignore + array set ignore {} + set funclist { + assignment scanf 2 100 + assignment preg_match 2 100 + assignment preg_match_all 2 100 + assignment ereg 2 100 + ignore isset 0 0 + } + set cline $line + regsub -all {'[^']+'} $cline {''} cline + foreach {type name spos epos} $funclist { + set re {} + append re $name {\s*\(([^()]*)\)} + foreach {- fargs} [regexp -all -inline $re $cline] { + set argidx 0 + foreach a [split $fargs ,] { + set a [string trim $a ", $"] + regsub -all {\[.*\]} $a {} a + if {$argidx >= $spos && $argidx <= $epos} { + if {$type eq {assignment}} { + set initialized($a) 1 + } elseif {$type eq {ignore}} { + set ignore($a) 1 + } + } + incr argidx + } + } + } + + # Check for var accesses + set varsimplere {\$[_A-Za-z]+[_A-Za-z0-9]*} + set l [regexp -all -inline $varsimplere $line] + foreach a $l { + set a [string trim $a "=$ "] + regsub -all {\[.*\]} $a {} a + #puts "access of $a" + if {![info exists initialized($a)] && + ![info exists ignore($a)]} { + puts "* In $file line $linenr: access to uninitialized var '$a'" + } + } + } +} + +proc main argv { + foreach file $argv { + scan $file + } +} + +main $argv diff --git a/setup/test/lint.php b/setup/test/lint.php new file mode 100644 index 0000000000000000000000000000000000000000..4566c495a247874f538fc043cd777185e17d509c --- /dev/null +++ b/setup/test/lint.php @@ -0,0 +1,107 @@ +#!/usr/bin/env php +<?php +if (php_sapi_name() != 'cli') exit(); + +function get_osticket_root_path() { + # Hop up to the root folder + $start = dirname(__file__); + for (;;) { + if (file_exists($start . '/main.inc.php')) break; + $start .= '/..'; + } + return realpath($start); +} + +$root = get_osticket_root_path(); + +# Check PHP syntax across all php files +function glob_recursive($pattern, $flags = 0) { + $files = glob($pattern, $flags); + foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) { + $files = array_merge($files, + glob_recursive($dir.'/'.basename($pattern), $flags)); + } + return $files; +} +echo "PHP Syntax Errors: "; +ob_start(); +$scripts=glob_recursive("$root/*.php"); +$exit=0; +$syntax_errors=""; +foreach ($scripts as $s) { + system("php -l $s", $exit); + $line = ob_get_contents(); + ob_clean(); + if ($exit !== 0) + $syntax_errors .= $line; +} +ob_end_clean(); + +if (strlen($syntax_errors)) { + $syntax_errors=str_replace("$root/", '', $syntax_errors); + echo "FAIL\n"; + echo "-------------------------------------------------------\n"; + echo "$syntax_errors"; + exit(); +} else { + echo "\n"; +} + +# Run phplint across all php files +echo "Access to unitialized variables: "; +ob_start(); +# XXX: This won't run well on Windoze +system("$root/setup/test/lib/phplint.tcl ".implode(" ", $scripts)); +$lint_errors = ob_get_clean(); + +if (strlen($lint_errors)) { + $lint_errors=str_replace("$root/", '', $lint_errors); + echo "FAIL\n"; + echo "-------------------------------------------------------\n"; + echo "$lint_errors"; +} else { + echo "\n"; +} + +function find_function_calls($scripts) { + $calls=array(); + foreach ($scripts as $s) { + $lines = explode("\n", file_get_contents($s)); + $lineno=0; + foreach (explode("\n", file_get_contents($s)) as $line) { + $lineno++; $matches=array(); + preg_match_all('/-[>]([a-zA-Z0-9]*)\(/', $line, $matches, + PREG_SET_ORDER); + foreach ($matches as $m) { + $calls[] = array($s, $lineno, $line, $m[1]); + } + } + } + return $calls; +} + +$php_script_content=''; +foreach ($scripts as $s) { + $php_script_content .= file_get_contents($s); +} +echo "Access to undefined object methods: "; +ob_start(); +foreach (find_function_calls($scripts) as $call) { + list($file, $no, $line, $func) = $call; + if (!preg_match('/^\s*(\/\*[^*]*\*\/)?'."\s*function\s+&?\s*$func\\(/m", + $php_script_content)) { + print "$func: Definitely undefined, from $file:$no\n"; + } +} +$undef_func_errors = ob_get_clean(); + +if (strlen($undef_func_errors)) { + $undef_func_errors=str_replace("$root/", '', $undef_func_errors); + echo "FAIL\n"; + echo "-------------------------------------------------------\n"; + echo "$undef_func_errors"; + exit(); +} else { + echo "\n"; +} +?> diff --git a/setup/upgrade.php b/setup/upgrade.php index 6fc34cfd307cfcc9df319deb25101ec159f52d75..0406383707cfe245fd11aae9323ee1422d6d679e 100644 --- a/setup/upgrade.php +++ b/setup/upgrade.php @@ -13,5 +13,89 @@ vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ -die('Upgrade NOT supported for v1.7 DPR.'); +function staffLoginPage($msg) { + + $_SESSION['_staff']['auth']['dest']=THISPAGE; + $_SESSION['_staff']['auth']['msg']=$msg; + header('Location: ../scp/login.php'); + exit; +} + +require '../scp/staff.inc.php'; +if(!$thisstaff or !$thisstaff->isAdmin()) { + staffLoginPage('Admin Access Required!'); + exit; +} + +define('SETUPINC', true); +define('INC_DIR', './inc/'); +define('SQL_DIR', INC_DIR.'sql/'); + +require_once INC_DIR.'class.upgrader.php'; + +//$_SESSION['ost_upgrader']=null; +$upgrader = new Upgrader($cfg->getSchemaSignature(), TABLE_PREFIX, SQL_DIR); + + +$wizard=array(); +$wizard['title']='osTicket Upgrade Wizard'; +$wizard['tagline']='Upgrading osTicket to v'.$upgrader->getVersionVerbose(); +$wizard['logo']='logo-upgrade.png'; +$wizard['menu']=array('Upgrade Guide'=>'http://osticket.com/wiki/Upgrade_and_Migration', + 'Get Professional Help'=>'http://osticket.com/support'); +$errors=array(); +if($_POST && $_POST['s'] && !$upgrader->isAborted()) { + switch(strtolower($_POST['s'])) { + case 'prereq': + //XXX: check if it's upgradable version?? + if(!$cfg->isUpgradePending()) + $errors['err']=' Nothing to do! System already upgraded to the current version'; + elseif(!$upgrader->isUpgradable()) + $errors['err']='The upgrader does NOT support upgrading from the current vesion!'; + elseif($upgrader->check_prereq()) + $upgrader->setState('upgrade'); + else + $errors['prereq']='Minimum requirements not met!'; + break; + case 'upgrade': //Manual upgrade.... when JS (ajax) is not supported. + if($upgrader->getNumPendingTasks()) { + $upgrader->doTasks(); + } elseif($cfg->isUpgradePending() && $upgrader->isUpgradable()) { + $upgrader->upgrade(); + } elseif(!$cfg->isUpgradePending()) { + $upgrader->setState('done'); + } + + if(($errors=$upgrader->getErrors())) { + $upgrader->setState('aborted'); + } + break; + default: + $errors['err']='Unknown action!'; + } +} + +switch(strtolower($upgrader->getState())) { + case 'aborted': + $inc='upgrade-aborted.inc.php'; + break; + case 'upgrade': + $inc='upgrade.inc.php'; + break; + case 'done': + $inc='upgrade-done.inc.php'; + break; + default: + $inc='upgrade-prereq.inc.php'; + if($upgrader->isAborted()) + $inc='upgrade-aborted.inc.php'; + elseif(!$cfg->isUpgradePending()) + $errors['err']='Nothing to do! System already upgraded to the latest version'; + elseif(!$upgrader->isUpgradable()) + $errors['err']='The upgrader does NOT support upgrading from the current vesion!'; +} + +require(INC_DIR.'header.inc.php'); +require(INC_DIR.$inc); +require(INC_DIR.'footer.inc.php'); ?> diff --git a/tickets.php b/tickets.php index d4759ba522e328911d2e9a494254ce338ea7f905..81b8ed68f153b551c4b063d2fa6860ea84070ac1 100644 --- a/tickets.php +++ b/tickets.php @@ -52,7 +52,7 @@ if($_POST && is_object($ticket) && $ticket->getId()): } } - if(!$errors){ + if(!$errors) { //Everything checked out...do the magic. if(($msgid=$ticket->postMessage($_POST['message'],'Web'))) { if($files && $cfg->allowOnlineAttachments()) @@ -64,9 +64,7 @@ if($_POST && is_object($ticket) && $ticket->getId()): } } elseif(!$errors['err']) { - print_r($errors); $errors['err']='Error(s) occurred. Please try again'; - } break; default: