package.xml 0000664 0001750 0001750 00000163034 12160315154 011304 0 ustar jan jan
whupspear.horde.orgTicket-tracking applicationWhups is a Horde ticket-tracking application. It is very flexible in design, and can be used for help-desk requests, tracking software development, and anything else that needs to track a set of requests and their status.Chuck Hagenbuchchuckchuck@horde.orgyesJan Schneiderjanjan@horde.orgyes2013-06-193.0.0beta13.0.0betabetaBSD-2-Clause
* [jan] Fix deleting attributes.
* [jan] Add configuration option to include raw processed message.
* [jan] Add due date to ticket columns (Request #10986).
* [jan] Make columns of portal block configurable (Request #10986).
5.3.01.7.0hordepear.horde.org5.0.06.0.0alpha16.0.0alpha1Horde_Authpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Autoloaderpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Compresspear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Corepear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Datepear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Dbpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Exceptionpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Formpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Grouppear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Mailpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Mimepear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Mime_Viewerpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Notificationpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Permspear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Prefspear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Schedulerpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Sharepear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Supportpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Text_Filterpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Utilpear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Vfspear.horde.org2.0.03.0.0alpha13.0.0alpha1Horde_Viewpear.horde.org2.0.03.0.0alpha13.0.0alpha1gettextjson2.0.0alpha12.0.0alpha1alphaalpha2011-09-27BSD-2-Clause
* First alpha release for Horde 4.
2.0.0RC12.0.0RC1betabeta2011-10-11BSD-2-Clause
* [jan] Don't create stray update and assign permission (Bug #10624).
* [jan] Add script to convert backends to UTF-8.
* [jan] Fix executing queries on non-UTF-8 backends.
* [jan] Add index to whups_attributes table.
* [jan] Fix using custom SQL configurations.
* [jan] Fix fatal error when updating address book preferences (Bug #10567).
* [jan] Don't access protected properties in the addTicket/updateTicket API methods (Bug #10566).
* [jan] Fix adding comments as a guest (Bug #10559).
2.0.0RC22.0.0RC2betabeta2011-10-18BSD-2-Clause
* [jan] Support more complex attributes types (Bug #9947).
* [jan] Fix displaying form errors from updating tickets.
* [jan] Allow to create private comments during ticket creation (Request #8312).
* [jan] Fix addTicket API method.
* [jan] Add missing default value for whups_priorities.priority_default column (Bug #10631).
2.0.02.0.0stablestable2011-10-27BSD-2-Clause
* [jan] Fix rendering of attributes if a ticket's type has changed.
2.0.12.0.0stablestable2011-12-13BSD-2-Clause
* [jan] Fix some CLI scripts if run from a PEAR installation (Bug #10839).
* [jan] Automatically create parent permissions when adding the first restricted comment.
* [jan] Ignore messages from postmaster too when processing mails.
* [jan] Add setting to use different addresses for Return-Path: and From: headers.
* [jan] Fix whups-reminders script (Bug #10783).
* [jan] Add Latvian translation (Jānis Eisaks).
2.0.22.0.0stablestable2011-12-13BSD-2-Clause
* [jan] Fix saving portal blocks.
* [jan] Fix deleting queries (Bug #10985).
* [jan] Fix encoding of auto-completion results (Bug #10945).
2.0.32.0.0stablestable2012-02-28BSD-2-Clause
* [jan] Fix converting searches in individual queues to queries (Bug #11819).
* [jan] Fix editing single attribute and text criteria in query editor.
* [jan] Fix setting active tabs in query editor.
* [jan] Group active and inactive versions in queue adminstration.
* [jan] Fix auto-submitting of tickets if using groups (Bug #10654).
* [jan] Improve error reporting in whups-mail-filter.
2013-06-193.0.0beta13.0.0betabetaBSD-2-Clause
* [jan] Fix deleting attributes.
* [jan] Add configuration option to include raw processed message.
* [jan] Add due date to ticket columns (Request #10986).
* [jan] Make columns of portal block configurable (Request #10986).
whups-3.0.0beta1/admin/index.php 0000664 0001750 0001750 00000123550 12160315153 014614 0 ustar jan jan
*/
require_once __DIR__ . '/../lib/Application.php';
Horde_Registry::appInit('whups', array(
'permission' => array('whups:admin', Horde_Perms::EDIT)
));
Whups::addTopbarSearch();
// Set up the page config vars.
$showExtraForm = null;
// Setup vars with all relevant info.
$vars = Horde_Variables::getDefaultVariables();
if (!$vars->exists('action')) {
$vars->set('action', 'queue');
}
// Admin actions.
$adminurl = Horde::selfUrl(false, false);
$tabs = new Horde_Core_Ui_Tabs('action', $vars);
$tabs->addTab(_("_Edit Queues"), $adminurl, 'queue');
$tabs->addTab(_("Edit _Types"), $adminurl, 'type');
$tabs->addTab(_("Queue/Type Matri_x"), $adminurl, 'mtmatrix');
$tabs->addTab(_("Sen_d Reminders"), $adminurl, 'reminders');
$renderer = new Horde_Form_Renderer();
// start the page
function _open($isopened = false)
{
global $notification, $vars;
static $opened;
if ($isopened) {
return $opened;
}
if (is_null($opened)) {
global $registry, $prefs, $browser, $conf, $notification, $title, $tabs;
$opened = true;
$title = _("Administration");
$GLOBALS['page_output']->header(array(
'title' => $title
));
$notification->notify(array('listeners' => 'status'));
echo $tabs->render($vars->get('action'));
}
}
function _editStateForms()
{
global $vars, $renderer, $adminurl;
_open();
$form1 = new Whups_Form_Admin_EditStateStepOne($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$form2 = new Whups_Form_Admin_DefaultState($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$form3 = new Whups_Form_Admin_AddState($vars);
$form3->renderActive($renderer, $vars, $adminurl, 'post');
}
function _editPriorityForms()
{
global $vars, $renderer, $adminurl;
_open();
$form1 = new Whups_Form_Admin_EditPriorityStepOne($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$form2 = new Whups_Form_Admin_DefaultPriority($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$form3 = new Whups_Form_Admin_AddPriority($vars);
$form3->renderActive($renderer, $vars, $adminurl, 'post');
}
switch ($vars->get('formname')) {
case 'whups_form_admin_addtype':
$form1 = new Whups_Form_Admin_AddType($vars);
if ($form1->validate($vars)) {
// First, add the type
$tid = $whups_driver->addType($vars->get('name'),
$vars->get('description'));
_open();
$vars->add('type', $tid);
$form2 = new Whups_Form_Admin_EditTypeStepTwo($vars);
$form2->open($renderer, $vars, $adminurl, 'post');
// render the stage 1 form readonly
$form1->preserve($vars);
$renderer->beginInactive(sprintf(_("Add Type %s"), _("- Stage 1")));
$renderer->renderFormInactive($form1, $vars);
$renderer->end();
// render the second stage form
$renderer->beginActive(sprintf(_("Add Type %s"), _("- Stage 2")));
$renderer->renderFormActive($form2, $vars);
$renderer->submit();
$renderer->end();
$form2->close($renderer);
} else {
_open();
$form1->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_edittypestepone':
$form1 = new Whups_Form_Admin_EditTypeStepOne($vars);
$vars->set('action', 'type');
if ($form1->validate($vars)) {
switch ($vars->get('submitbutton')) {
case _("Edit Type"):
_open();
$form2 = new Whups_Form_Admin_EditTypeStepTwo($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
case _("Delete Type"):
_open();
$form2 = new Whups_Form_Admin_DeleteType($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
case _("Clone Type"):
_open();
$form2 = new Whups_Form_Admin_CloneType($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
}
} else {
_open();
$form1->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_clonetype':
$form = new Whups_Form_Admin_CloneType($vars);
if ($form->validate($vars)) {
// Create a new type and copy all attributes of the clone master to
// the new type.
$tid = $vars->get('type');
$type = $whups_driver->getType($tid);
$states = $whups_driver->getAllStateInfo($tid);
$priorities = $whups_driver->getAllPriorityInfo($tid);
$attributes = $whups_driver->getAttributeInfoForType($tid);
// Create the new type.
$nid = $ntype = $whups_driver->addType(
$vars->get('name'), $vars->get('description'));
// Add the states.
foreach ($states as $s) {
$whups_driver->addState(
$nid, $s['state_name'], $s['state_description'], $s['state_category']);
}
// Add the priorities.
foreach ($priorities as $p) {
$whups_driver->addPriority(
$nid, $p['priority_name'], $p['priority_description']);
}
// Add attributes.
foreach ($attributes as $attribute) {
$a = $whups_driver->getAttributeDesc($attribute['attribute_id']);
$whups_driver->addAttributeDesc(
$nid, $a['name'], $a['description'], $a['type'], $a['params'], $a['required']);
}
$notification->push(
sprintf(_("Successfully Cloned %s to %s."), $type['name'], $vars->get('name')),
'horde.success');
Horde::url('admin/?action=type', true)->redirect();
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_edittypesteptwo':
$form = new Whups_Form_Admin_EditTypeStepTwo($vars);
if ($form->validate($vars)) {
try {
$whups_driver->updateType(
$vars->get('type'),
$vars->get('name'),
$vars->get('description'));
$notification->push(sprintf(_("The type \"%s\" has been modified."),
$vars->get('name')),
'horde.success');
Horde::url('admin/?action=type', true)->redirect();
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error modifying the type:") . ' ' . $e->getMessage(),
'horde.error');
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_createdefaultstates':
$type = $vars->get('type');
foreach ($conf['states'] as $state) {
if ($state['active'] == 'active') {
$whups_driver->addState($type, $state['name'],
$state['desc'], $state['category']);
}
}
_open();
$form = new Whups_Form_Admin_EditTypeStepTwo($vars);
$form->renderActive($renderer, $vars, $adminurl, 'post');
break;
case 'whups_form_admin_createdefaultpriorities':
$type = $vars->get('type');
foreach ($conf['priorities'] as $priority) {
if ($priority['active'] == 'active') {
$whups_driver->addPriority($type, $priority['name'],
$priority['desc']);
}
}
_open();
$form = new Whups_Form_Admin_EditTypeStepTwo($vars);
$form->renderActive($renderer, $vars, $adminurl, 'post');
break;
case 'whups_form_admin_deletetype':
$form = new Whups_Form_Admin_DeleteType($vars);
if ($form->validate($vars)) {
if ($vars->get('yesno') == 1) {
try {
$whups_driver->deleteType($vars->get('type'));
$notification->push(
_("The type has been deleted."), 'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error deleting the type:") . ' ' . $e->getMessage(),
'horde.error');
}
} else {
$notification->push(_("The type was not deleted."),
'horde.message');
}
$vars->set('action', 'type');
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_addqueue':
$form = new Whups_Form_Admin_AddQueue($vars);
if ($form->validate($vars)) {
try {
$result = $whups_driver->addQueue(
$vars->get('name'),
$vars->get('description'),
$vars->get('slug'),
$vars->get('email'));
$notification->push(
sprintf(_("The queue \"%s\" has been created."),
$vars->get('name')),
'horde.success');
_open();
$vars->set('queue', $result);
$form2 = new Whups_Form_Admin_EditQueueStepTwo($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error creating the queue:") . ' ' . $e->getMessage(),
'horde.error');
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_editqueuestepone':
$form1 = new Whups_Form_Admin_EditQueueStepOne($vars);
if ($form1->validate($vars)) {
switch ($vars->get('submitbutton')) {
case _("Edit Queue"):
_open();
$form2 = new Whups_Form_Admin_EditQueueStepTwo($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
case _("Delete Queue"):
_open();
$form2 = new Whups_Form_Admin_DeleteQueue($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
}
} else {
_open();
$form1->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_editqueuestepone':
case 'whups_form_admin_editqueuesteptwo':
$form = new Whups_Form_Admin_EditQueueStepTwo($vars);
if ($vars->get('formname') == 'whups_form_admin_editqueuesteptwo' &&
$form->validate($vars)) {
try {
$whups_driver->updateQueue(
$vars->get('queue'),
$vars->get('name'),
$vars->get('description'),
$vars->get('types'),
$vars->get('versioned'),
$vars->get('slug'),
$vars->get('email'),
$vars->get('default'));
$notification->push(
_("The queue has been modified."), 'horde.success');
_open();
$form->renderInactive($renderer, $vars);
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error editing the queue:") . ' ' . $e->getMessage(),
'horde.error');
}
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_deletequeue':
$form = new Whups_Form_Admin_DeleteQueue($vars);
if ($form->validate($vars)) {
if ($vars->get('yesno') == 1) {
try {
$whups_driver->deleteQueue($vars->get('queue'));
$notification->push(
_("The queue has been deleted."),
'horde.success');
} catch (Horde_Exception $e) {
$notification->push(
_("There was an error deleting the queue:") . ' ' . $e->getMessage(),
'horde.error');
}
} else {
$notification->push(
_("The queue was not deleted."),
'horde.message');
}
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_addstate':
$vars->set('action', 'type');
$form = new Whups_Form_Admin_AddState($vars);
if ($form->validate($vars)) {
try {
$whups_driver->addState(
$vars->get('type'),
$vars->get('name'),
$vars->get('description'),
$vars->get('category'));
$typename = $whups_driver->getType($vars->get('type'));
$typename = $typename['name'];
$notification->push(
sprintf(_("The state \"%s\" has been added to %s."),
$vars->get('name'), $typename),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error creating the state:") . ' ' . $e->getMessage(),
'horde.error');
}
$vars = new Horde_Variables(array('type' => $vars->get('type')));
_editStateForms();
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_editstatestepone':
$vars->set('action', 'type');
if (!$vars->get('submitbutton')) {
_editStateForms();
} else {
_open();
$form1 = new Whups_Form_Admin_EditStateStepOne($vars);
if ($form1->validate($vars)) {
switch ($vars->get('submitbutton')) {
case _("Edit State"):
$form2 = new Whups_Form_Admin_EditStateStepTwo($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
case _("Delete State"):
$form2 = new Whups_Form_Admin_DeleteState($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
}
} else {
$form1->renderActive($renderer, $vars, $adminurl, 'post');
}
}
break;
case 'whups_form_admin_editstatesteptwo':
$vars->set('action', 'type');
$form = new Whups_Form_Admin_EditStateStepTwo($vars);
if ($form->validate($vars)) {
try {
$whups_driver->updateState(
$vars->get('state'),
$vars->get('name'),
$vars->get('description'),
$vars->get('category'));
$notification->push(
_("The state has been modified."),
'horde.success');
_open();
$form->renderInactive($renderer, $vars);
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error editing the state:") . ' ' . $e->getMessage(),
'horde.error');
}
$vars = new Horde_Variables(array('type' => $vars->get('type')));
_editStateForms();
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_defaultstate':
$vars->set('action', 'type');
$form = new Whups_Form_Admin_DefaultState($vars);
if ($form->validate($vars)) {
try {
$whups_driver->setDefaultState(
$vars->get('type'), $vars->get('state'));
$notification->push(
_("The default state has been set."),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error setting the default state:") . ' ' . $e->getMessage(),
'horde.error');
}
_editStateForms();
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_deletestate':
$vars->set('action', 'type');
$form = new Whups_Form_Admin_DeleteState($vars);
if ($form->validate($vars)) {
if ($vars->get('yesno') == 1) {
try {
$whups_driver->deleteState($vars->get('state'));
$notification->push(
_("The state has been deleted."),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error deleting the state:") . ' ' . $e->getMessage(),
'horde.error');
}
} else {
$notification->push(_("The state was not deleted."),
'horde.message');
}
_editStateForms();
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_addpriority':
$vars->set('action', 'type');
$form = new Whups_Form_Admin_AddPriority($vars);
if ($form->validate($vars)) {
try {
$whups_driver->addPriority(
$vars->get('type'),
$vars->get('name'),
$vars->get('description'));
$typename = $whups_driver->getType($vars->get('type'));
$typename = $typename['name'];
$notification->push(
sprintf(_("The priority \"%s\" has been added to %s."),
$vars->get('name'), $typename),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error creating the priority:") . ' ' . $e->getMessage(),
'horde.error');
}
$vars = new Horde_Variables(array('type' => $vars->get('type')));
_editPriorityForms();
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_editprioritystepone':
$vars->set('action', 'type');
if (!$vars->get('submitbutton')) {
_editPriorityForms();
} else {
_open();
$form1 = new Whups_Form_Admin_EditPriorityStepOne($vars);
if ($form1->validate($vars)) {
switch ($vars->get('submitbutton')) {
case _("Edit Priority"):
$form2 = new Whups_Form_Admin_EditPriorityStepTwo($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
case _("Delete Priority"):
$form2 = new Whups_Form_Admin_DeletePriority($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
}
} else {
$form1->renderActive($renderer, $vars, $adminurl, 'post');
}
}
break;
case 'whups_form_admin_editprioritysteptwo':
$vars->set('action', 'type');
$form = new Whups_Form_Admin_EditPriorityStepTwo($vars);
if ($form->validate($vars)) {
try {
$whups_driver->updatePriority(
$vars->get('priority'),
$vars->get('name'),
$vars->get('description'));
$notification->push(
_("The priority has been modified."),
'horde.success');
_open();
$form->renderInactive($renderer, $vars);
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error editing the priority:") . ' ' . $e->getMessage(),
'horde.error');
}
$vars = new Horde_Variables(array('type' => $vars->get('type')));
_editPriorityForms();
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_defaultpriority':
$vars->set('action', 'type');
$form = new Whups_Form_Admin_DefaultPriority($vars);
if ($form->validate($vars)) {
try {
$whups_driver->setDefaultPriority(
$vars->get('type'), $vars->get('priority'));
$notification->push(
_("The default priority has been set."),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error setting the default priority:") . ' ' . $e->getMessage(),
'horde.error');
}
_editPriorityForms();
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_deletepriority':
$vars->set('action', 'type');
$form = new Whups_Form_Admin_DeletePriority($vars);
if ($form->validate($vars)) {
if ($vars->get('yesno') == 1) {
try {
$whups_driver->deletePriority($vars->get('priority'));
$notification->push(
_("The priority has been deleted."),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error deleting the priority:") . ' '
. $e->getMessage(),
'horde.error');
}
} else {
$notification->push(
_("The priority was not deleted."),
'horde.message');
}
_editPriorityForms();
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_adduser':
$form = new Whups_Form_Admin_AddUser($vars);
if ($form->validate($vars)) {
$info = $whups_driver->getQueue($vars->get('queue'));
try {
$whups_driver->addQueueUser(
$vars->get('queue'), $vars->get('user'));
$user = $vars->get('user');
if (is_array($user)) {
$userinfo = array();
foreach ($user as $userID) {
$userinfo[] = Whups::formatUser($userID);
}
$userinfo = implode(', ', $userinfo);
} else {
$userinfo = Whups::formatUser($user);
}
$notification->push(
sprintf(_("%s added to those responsible for \"%s\""),
$userinfo, $info['name']),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
sprintf(_("There was an error adding \"%s\" to the responsible list for \"%s\":"),
Whups::formatUser($vars->get('user')),
$info['name'])
. ' ' . $e->getMessage(),
'horde.error');
}
}
_open();
$form1 = new Whups_Form_Admin_EditUser($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$vars = new Horde_Variables(array('queue' => $vars->get('queue')));
$form->renderActive($renderer, $vars, $adminurl, 'post');
break;
case 'edituserform':
$form1 = new Whups_Form_Admin_EditUser($vars);
$form2 = new Whups_Form_Admin_AddUser($vars);
_open();
$form1->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$vars = new Horde_Variables(array('queue' => $vars->get('queue')));
$form2 = new Whups_Form_Admin_AddUser($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
case 'whups_form_admin_edituser':
$form = new Whups_Form_Admin_EditUser($vars);
if ($form->validate($vars)) {
$info = $whups_driver->getQueue($vars->get('queue'));
try {
$whups_driver->removeQueueUser($vars->get('queue'), $vars->get('user'));
$notification->push(
sprintf(_("\"%s\" is no longer among those responsible for \"%s\""),
Whups::formatUser($vars->get('user')), $info['name']),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
sprintf(_("There was an error removing \"%s\" from the responsible list for \"%s\":"),
Whups::formatUser($vars->get('user')), $info['name'])
. ' ' . $e->getMessage(),
'horde.error');
}
}
_open();
$vars = new Horde_Variables(array('queue' => $vars->get('queue')));
$form = new Whups_Form_Admin_EditUser($vars);
$form->renderActive($renderer, $vars, $adminurl, 'get');
$form1 = new Whups_Form_Admin_AddUser($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'get');
break;
case 'whups_form_admin_addversion':
$form = new Whups_Form_Admin_AddVersion($vars);
if ($form->validate($vars)) {
try {
$whups_driver->addVersion(
$vars->get('queue'),
$vars->get('name'),
$vars->get('description'),
$vars->get('active') == 'on');
$queuename = $whups_driver->getQueue($vars->get('queue'));
$queuename = $queuename['name'];
$notification->push(
sprintf(_("The version \"%s\" has been added to %s."),
$vars->get('name'), $queuename),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error creating the version:") . ' ' . $e->getMessage(),
'horde.error');
}
_open();
$vars = new Horde_Variables(array('queue' => $vars->get('queue')));
$form1 = new Whups_Form_Admin_EditVersionStepOne($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'post');
$form2 = new Whups_Form_Admin_AddVersion($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_editversionstepone':
$form1 = new Whups_Form_Admin_EditVersionStepOne($vars);
_open();
if (!$vars->get('submitbutton')) {
$form1->renderActive($renderer, $vars, $adminurl, 'post');
$form2 = new Whups_Form_Admin_AddVersion($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} else {
if ($form1->validate($vars)) {
switch ($vars->get('submitbutton')) {
case _("Edit Version"):
$form2 = new Whups_Form_Admin_EditVersionStepTwo($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
case _("Delete Version"):
$form2 = new Whups_Form_Admin_DeleteVersion($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
}
} else {
$form1->renderActive($renderer, $vars, $adminurl, 'post');
}
}
break;
case 'whups_form_admin_editversionsteptwo':
$form = new Whups_Form_Admin_EditVersionStepTwo($vars);
if ($form->validate($vars)) {
try {
$whups_driver->updateVersion(
$vars->get('version'),
$vars->get('name'),
$vars->get('description'),
$vars->get('active') == 'on');
$notification->push(
_("The version has been modified."),
'horde.success');
_open();
$form->renderInactive($renderer, $vars);
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error editing the version:") . ' ' . $e->getMessage(),
'horde.error');
}
_open();
$vars = new Horde_Variables(array('queue' => $vars->get('queue')));
$form1 = new Whups_Form_Admin_EditVersionStepOne($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'post');
$form2 = new Whups_Form_Admin_AddVersion($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_deleteversion':
$form = new Whups_Form_Admin_DeleteVersion($vars);
if ($form->validate($vars)) {
if ($vars->get('yesno') == 1) {
try {
$whups_driver->deleteVersion($vars->get('version'));
$notification->push(
_("The version has been deleted."),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error deleting the version:") . ' ' . $e->getMessage(),
'horde.error');
}
} else {
$notification->push(_("The version was not deleted."),
'horde.message');
}
_open();
$form1 = new Whups_Form_Admin_EditVersionStepOne($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'post');
$form2 = new Whups_Form_Admin_AddVersion($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_addattribute':
case 'whups_form_admin_addattribute_reload':
$form = new Whups_Form_Admin_AddAttribute($vars);
$vars->set('action', 'type');
if ($vars->get('formname') == 'whups_form_admin_addattribute' &&
$form->validate($vars)) {
try {
$whups_driver->addAttributeDesc(
$vars->get('type'),
$vars->get('attribute_name'),
$vars->get('attribute_description'),
$vars->get('attribute_type'),
$vars->get('attribute_params', array()),
$vars->get('attribute_required'));
$typename = $whups_driver->getType($vars->get('type'));
$typename = $typename['name'];
$notification->push(
sprintf(_("The attribute \"%s\" has been added to %s."),
$vars->get('attribute_name'), $typename),
'horde.success');
$vars = new Horde_Variables(array('type' => $vars->get('type')));
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error creating the attribute:") . ' ' . $e->getMessage(),
'horde.error');
}
_open();
$form1 = new Whups_Form_Admin_EditAttributeStepOne($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$form2 = new Whups_Form_Admin_AddAttribute($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_editattributestepone':
$form1 = new Whups_Form_Admin_EditAttributeStepOne($vars);
$vars->set('action', 'type');
_open();
if (!$vars->get('submitbutton')) {
$form1->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$form2 = new Whups_Form_Admin_AddAttribute($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} else {
if ($form1->validate($vars)) {
switch ($vars->get('submitbutton')) {
case _("Edit Attribute"):
$form2 = new Whups_Form_Admin_EditAttributeStepTwo($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
case _("Delete Attribute"):
$form2 = new Whups_Form_Admin_DeleteAttribute($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
}
} else {
$form1->renderActive($renderer, $vars, $adminurl, 'post');
}
}
break;
case 'whups_form_admin_editattributesteptwo':
case 'whups_form_admin_editattributesteptwo_reload':
$form = new Whups_Form_Admin_EditAttributeStepTwo($vars);
$vars->set('action', 'type');
if ($vars->get('formname') == 'whups_form_admin_editattributesteptwo' &&
$form->validate($vars)) {
$form->getInfo($vars, $info);
try {
$whups_driver->updateAttributeDesc(
$info['attribute'],
$info['attribute_name'],
$info['attribute_description'],
$info['attribute_type'],
!empty($info['attribute_params']) ? $info['attribute_params'] : array(),
$info['attribute_required']);
$notification->push(
_("The attribute has been modified."),
'horde.success');
_open();
$form->renderInactive($renderer, $vars);
echo ' ';
$vars = new Horde_Variables(array('type' => $vars->get('type')));
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error editing the attribute:") . ' ' . $e->getMessage(),
'horde.error');
}
_open();
$form1 = new Whups_Form_Admin_EditAttributeStepOne($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$form2 = new Whups_Form_Admin_AddAttribute($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_deleteattribute':
$form = new DeleteAttributeDescForm($vars);
if ($form->validate($vars)) {
if ($vars->get('yesno') == 1) {
try {
$whups_driver->deleteAttributeDesc($vars->get('attribute'));
$notification->push(
_("The attribute has been deleted."),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error deleting the attribute:")
. ' ' . $e->getMessage(),
'horde.error');
}
} else {
$notification->push(
_("The attribute was not deleted."),
'horde.message');
}
_open();
$form1 = new Whups_Form_Admin_EditAttributeStepOne($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'post');
$form2 = new Whups_From_Admin_AddAttribute($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_addreply':
$form = new Whups_Form_Admin_AddReply($vars);
$vars->set('action', 'type');
if ($form->validate($vars)) {
try {
$result = $whups_driver->addReply(
$vars->get('type'),
$vars->get('reply_name'),
$vars->get('reply_text'));
$typename = $whups_driver->getType($vars->get('type'));
$typename = $typename['name'];
$notification->push(
sprintf(_("The form reply \"%s\" has been added to %s."),
$vars->get('reply_name'), $typename),
'horde.success');
_open();
$vars->set('reply', $result);
$form = new Whups_Form_Admin_EditReplyStepTwo($vars);
$form->renderInactive($renderer, $vars);
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error creating the form reply:") . ' ' . $e->getMessage(),
'horde.error');
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_editreplystepone':
$form1 = new Whups_Form_Admin_EditReplyStepOne($vars);
$vars->set('action', 'type');
_open();
if (!$vars->get('submitbutton')) {
$form1->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$form2 = new Whups_Form_Admin_AddReply($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} else {
if ($form1->validate($vars)) {
switch ($vars->get('submitbutton')) {
case _("Edit Form Reply"):
$form2 = new Whups_Form_Admin_EditReplyStepTwo($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
case _("Delete Form Reply"):
$form2 = new Whups_Form_Admin_DeleteReply($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
break;
}
} else {
$form1->renderActive($renderer, $vars, $adminurl, 'post');
}
}
break;
case 'whups_form_admin_editreplysteptwo':
$form = new Whups_Form_Admin_EditReplyStepTwo($vars);
$vars->set('action', 'type');
if ($vars->get('formname') == 'whups_form_admin_editreplysteptwo' &&
$form->validate($vars)) {
try {
$whups_driver->updateReply(
$vars->get('reply'),
$vars->get('reply_name'),
$vars->get('reply_text'));
$notification->push(
_("The form reply has been modified."),
'horde.success');
_open();
$form->renderInactive($renderer, $vars);
echo ' ';
$vars = new Horde_Variables(array('type' => $vars->get('type')));
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error editing the form reply:") . ' ' . $e->getMessage(),
'horde.error');
}
_open();
$form1 = new Whups_Form_Admin_EditReplyStepOne($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$form2 = new Whups_Form_Admin_AddReply($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_admin_deletereply':
$form = new Whups_Form_Admin_DeleteReply($vars);
if ($form->validate($vars)) {
if ($vars->get('yesno') == 1) {
try {
$whups_driver->deleteReply($vars->get('reply'));
$notification->push(
_("The form reply has been deleted."),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push(
_("There was an error deleting the form reply:") . ' ' . $e->getMessage(),
'horde.error');
}
} else {
$notification->push(
_("The form reply was not deleted."),
'horde.message');
}
_open();
$form1 = new Whups_Form_Admin_EditReplyStepOne($vars);
$form1->renderActive($renderer, $vars, $adminurl, 'post');
echo ' ';
$form2 = new Whups_Form_Admin_AddReply($vars);
$form2->renderActive($renderer, $vars, $adminurl, 'post');
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'whups_form_sendreminder':
$form = new Whups_Form_SendReminder($vars);
if ($form->validate($vars)) {
try {
Whups::sendReminders($vars);
$notification->push(_("Reminders were sent."), 'horde.success');
} catch (Whups_Exception $e) {
$notification->push($e, 'horde.error');
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
} else {
_open();
$form->renderActive($renderer, $vars, $adminurl, 'post');
}
break;
case 'mtmatrix':
$vars->set('action', 'mtmatrix');
$queues = $whups_driver->getQueues();
$types = $whups_driver->getAllTypes();
$matrix = $vars->get('matrix');
// Validate data.
$pairs = array();
if (!empty($matrix)) {
foreach ($matrix as $mid => $mtypes) {
if (isset($queues[$mid])) {
foreach ($mtypes as $tid => $on) {
if (isset($types[$tid])) {
$pairs[] = array($mid, $tid);
}
}
}
}
}
try {
$whups_driver->updateTypesQueues($pairs);
$notification->push(
_("Associations updated successfully."),
'horde.success');
} catch (Whups_Exception $e) {
$notification->push($e, 'horde.error');
}
break;
}
if (!_open(true)) {
// Check for actions.
switch ($vars->get('action')) {
case 'type':
if (count($whups_driver->getAllTypes())) {
$main1 = new Whups_Form_Admin_EditTypeStepOne($vars);
}
$main2 = new Whups_Form_Admin_AddType($vars);
break;
case 'reminders':
$main1 = new Whups_Form_SendReminder($vars);
break;
case 'mtmatrix':
_open();
$queues = $whups_driver->getQueues();
$types = $whups_driver->getAllTypes();
$tlink = Horde::url('admin/?formname=whups_form_admin_edittypestepone');
$mlink = Horde::url('admin/?formname=whups_form_admin_editqueuestepone');
require WHUPS_TEMPLATES . '/admin/mtmatrix.inc';
break;
case 'queue':
if (count($whups_driver->getQueues())) {
$main1 = new Whups_Form_Admin_EditQueueStepOne($vars);
}
if ($registry->hasMethod('tickets/listQueues') == $registry->getApp()) {
$main2 = new Whups_Form_Admin_AddQueue($vars);
}
break;
}
_open();
if (isset($main1)) {
$main1->renderActive($renderer, $vars, $adminurl, 'get');
}
if (isset($main1) && isset($main2)) {
echo ' ';
}
if (isset($main2)) {
$main2->renderActive($renderer, $vars, $adminurl, 'get');
}
}
_open();
$page_output->footer();
whups-3.0.0beta1/bin/whups-bugzilla-import 0000775 0001750 0001750 00000014275 12160315153 016672 0 ustar jan jan #!/usr/bin/env php
*/
/* CONFIGURATION */
$BUGZILLA_DSN = array('adapter' => 'mysql',
'user' => 'root',
'password' => 'password',
'host' => 'localhost',
'database' => 'bugzilla');
$BUGZILLA_STATES = array('NEW', 'ASSIGNED', 'RESOLVED', 'REOPENED', 'CLOSED');
$BUGZILLA_BUG_TYPE = array('Bug', 'Imported Bugzilla Bug');
$BUGZILLA_PRIORITIES = array('P1', 'P2', 'P3', 'P4', 'P5');
/* END CONFIGURATION */
if (file_exists(__DIR__ . '/../../whups/lib/Application.php')) {
$baseDir = __DIR__ . '/../';
} else {
require_once 'PEAR/Config.php';
$baseDir = PEAR_Config::singleton()
->get('horde_dir', null, 'pear.horde.org') . '/whups/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('whups', array('cli' => true));
function sectionHeader($text)
{
global $cli;
$cli->writeln($cli->bold($text));
}
function error($text, $error = null)
{
global $cli;
$cli->message($text, 'cli.error');
}
function success($text)
{
global $cli;
$cli->message($text, 'cli.success');
}
function info($text)
{
global $cli;
$cli->message($text, 'cli.message');
}
/* Connect to the Bugzilla database. */
$bugzilla = $injector->getInstance('Horde_Db')->createDb($BUGZILLA_DSN);
sectionHeader('Creating Types');
try {
$type = $whups_driver->addType($BUGZILLA_BUG_TYPE[0], $BUGZILLA_BUG_TYPE[1]);
} catch (Whups_Exception $e) {
error("Failed to add '" . $BUGZILLA_BUG_TYPE[0] . "' type", $e->getMessage());
exit;
}
info("Created '" . $BUGZILLA_BUG_TYPE[0] . "' type");
$cli->writeln();
sectionHeader('Creating States');
$states = array();
foreach ($BUGZILLA_STATES as $state) {
try {
$result = $whups_driver->addState($type, $state, "Bugzilla - $state", $state);
} catch (Whups_Exception $e) {
error("Failed to add '$state' state", $e->getMessage());
continue;
}
$states[$state] = $result;
info("Created '$state' state");
}
$cli->writeln();
sectionHeader('Creating Priorities');
$priorities = array();
foreach ($BUGZILLA_PRIORITIES as $priority) {
try {
$result = $whups_driver->addPriority($type, $priority, "Bugzilla - $priority");
} catch (Whups_Exception $e) {
error("Failed to add '$priority' priority", $e->getMessage());
continue;
}
$priorities[$priority] = $result;
info("Created '$priority' priority");
}
$cli->writeln();
/* Create a mapping of products and components. */
$components = array();
sectionHeader('Importing Components');
$res = $bugzilla->select('SELECT value, program, description FROM components');
foreach ($res as $row) {
try {
$result = $whups_driver->addQueue($row['value'], $row['description']);
} catch (Whups_Exception $e) {
error('Failed to add queue: ' . $row['value'], $e->getMessage());
continue;
}
/* Set the queue's parameters. */
$whups_driver->updateQueue(
$result,
$row['value'],
$row['description'],
array($type),
false);
/* Add this component to the map. */
$components[($row['program'])][] = $row['value'];
success('Created queue: ' . $row['value']);
}
$cli->writeln();
/* Get a mapping of queue IDs to queue names. */
$queues = $whups_driver->getQueues();
/* Maintain a mapping of version names. */
$versions = array();
sectionHeader('Importing Versions');
$res = $bugzilla->select('SELECT value, program FROM versions');
foreach ($res as $row) {
/* Bugzilla manages versions on a per-product basis. Whups manages
* versions on a per-queue (i.e., per-component) basis. Add this
* product's versions to each each of its components. */
foreach ($components[($row['program'])] as $component) {
$queueID = array_search($component, $queues);
if ($queueID === false) {
error('Unknown queue: ' . $component);
continue;
}
try {
$result = $whups_driver->addVersion($queueID, $row['value'], '', true, 0);
} catch (Whups_Exception $e) {
error('Failed to add version: ' . $row['value'], $e->getMessage());
continue;
}
$versions[$queueID][($row['value'])] = $result;
success('Added version: ' . $row['value'] . " ($component)");
}
}
$cli->writeln();
/* Maintain a mapping of Bugzilla userid's to email addresses. */
$profiles = array();
sectionHeader('Loading Profiles');
$res = $bugzilla->select('SELECT userid, login_name FROM profiles');
foreach ($res as $row) {
$profiles[($row['userid'])] = $row['login_name'];
}
info('Loaded ' . count($profiles) . ' profiles');
$cli->writeln();
sectionHeader('Importing Bugs');
$res = $bugzilla->select('SELECT * FROM bugs');
foreach ($res as $row) {
$info = array();
$info['queue'] = array_search($row['component'], $queues);
if ($info['queue'] === false) {
error('Unknown queue: ' . $row['component']);
continue;
}
$info['version'] = null;
if (isset($versions[($info['queue'])][($row['version'])])) {
$info['version'] = $versions[($info['queue'])][($row['version'])];
}
$info['type'] = $type;
if (!isset($priorities[($row['priority'])])) {
error('Unknown priority: ' . $row['priority']);
continue;
}
$info['priority'] = $priorities[($row['priority'])];
if (!isset($states[($row['bug_status'])])) {
error('Unknown state: ' . $row['bug_status']);
continue;
}
$info['state'] = $states[($row['bug_status'])];
if (isset($profiles[($row['reporter'])])) {
$info['user_email'] = $profiles[($row['reporter'])];
}
$info['summary'] = htmlspecialchars($row['short_desc']);
$info['comment'] = $row['long_desc'];
try {
$result = $whups_driver->addTicket($info);
} catch (Whups_Exception $e) {
error('Failed to add ticket', $e->getMessage());
continue;
}
success('Added new ticket ' . $result . ' to ' . $row['component']);
}
$cli->writeln();
whups-3.0.0beta1/bin/whups-convert-datatree-shares-to-sql 0000775 0001750 0001750 00000013000 12160315153 021501 0 ustar jan jan #!/usr/bin/env php
get('horde_dir', null, 'pear.horde.org') . '/whups/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('whups', array('cli' => true));
$db = $injector->getInstance('Horde_Db_Adapter');
$error_cnt = 0;
$delete_dt_data = false;
$answer = $cli->prompt('Do you want to keep your old datatree data or delete it?', array('Keep', 'Delete'));
if ($answer == 1) {
$delete_dt_data = true;
}
$answer = $cli->prompt(sprintf("Data will be copied into the new tables, and %s be deleted from the datatree.\n Is this what you want?", (($delete_dt_data) ? 'WILL' : 'WILL NOT')), array('y' => 'Yes', 'n' => 'No'));
if ($answer != 'y') {
exit;
}
/* Get the share entries */
try {
$shares_result = $db->selectAssoc('SELECT datatree_id, datatree_name FROM horde_datatree WHERE group_uid = ' . $db->quoteString('horde.shares.whups'));
} catch (Horde_Db_Exception $e) {
die($e->getMessage());
}
$query = 'SELECT attribute_name, attribute_key, attribute_value FROM horde_datatree_attributes WHERE datatree_id = ?';
foreach ($shares_result as $share_id => $share_name) {
$data = array('share_name' => $share_name);
$rows = $db->selectAll($query, array($share_id));
$users = array();
$groups = array();
foreach ($rows as $row) {
if ($row['attribute_name'] == 'perm_groups') {
/* Group table entry */
$groups[] = array('group_uid' => $row['attribute_key'],
'perm' => $row['attribute_value']);
} elseif ($row['attribute_name'] == 'perm_users') {
/* User table entry */
$users[] = array('user_uid' => $row['attribute_key'],
'perm' => $row['attribute_value']);
} else {
/* Everything else goes in the main share table */
switch ($row['attribute_name']) {
case 'perm_creator':
case 'perm_default':
case 'perm_guest':
$data[$row['attribute_name']] = $row['attribute_value'];
break;
case 'owner':
$data['share_owner'] = $row['attribute_value'];
break;
case 'name':
// Note the key to the $data array is not related to
// the attribute_name field in the dt_attributes table.
$data['attribute_name'] = $row['attribute_value'];
break;
case 'slug':
// Note the key to the $data array is not related to
// the attribute_name field in the dt_attributes table.
$data['attribute_slug'] = $row['attribute_value'];
break;
}
}
}
/* Set flags */
$data['share_flags'] = 0;
if (count($users)) {
$data['share_flags'] |= 1;
}
if (count($groups)) {
$data['share_flags'] |= 2;
}
/* Insert the new data */
$cli->message('Migrating share data for share_id: ' . $share_id, 'cli.message');
$error = false;
$db->beginDbTransaction();
try {
$nextId = insertData('whups_shares', $data, $db);
} catch (Horde_Db_Exception $e) {
$cli->message($e->getMessage(), 'cli.error');
$error = true;
}
if (count($groups)) {
foreach ($groups as $group) {
$group['share_id'] = $nextId;
try {
insertData('whups_shares_groups', $group, $db);
} catch (Horde_Db_Exception $e) {
$cli->message($e->getMessage(), 'cli.error');
$error = true;
}
}
}
if (count($users)) {
foreach ($users as $user) {
$user['share_id'] = $nextId;
try {
insertData('whups_shares_users', $user, $db);
} catch (Horde_Db_Exception $e) {
$cli->message($e->getMessage(), 'cli.error');
$error = true;
}
}
}
/* Delete the datatree data, but ONLY if it was requested */
if ($delete_dt_data && !$error) {
$cli->message('DELETING datatree data for share_id: ' . $share_id, 'cli.message');
try {
$db->delete('DELETE FROM horde_datatree_attributes WHERE datatree_id = ?', array($share_id));
$db->delete('DELETE FROM horde_datatree WHERE datatree_id = ?', array($share_id));
} catch (Horde_Db_Exception $e) {
$cli->message($e->getMessage(), 'cli.error');
$error = true;
}
}
/* Cleanup */
unset($row, $rows, $data, $groups, $users);
if ($error) {
$db->rollbackDbTransaction();
$cli->message('Rollback for share data for share_id: ' . $share_id, 'cli.message');
++$error_cnt;
} else {
$db->commitDbTransaction();
$cli->message('Commit for share data for share_id: ' . $share_id, 'cli.message');
}
}
if ($error_cnt) {
$cli->message(sprintf("Encountered %u errors.", $error_cnt));
}
echo "\nDone.\n";
/**
* Helper function
*/
function insertData($table, $data, $db)
{
$fields = array_keys($data);
$values = array_values($data);
$sql = 'INSERT INTO ' . $table . ' (' . implode(', ', $fields) . ') VALUES (' . str_repeat('?, ', count($values) - 1) . '?)';
return $db->insert($sql, $values);
}
whups-3.0.0beta1/bin/whups-convert-sql-shares-to-sqlng 0000775 0001750 0001750 00000002663 12160315153 021051 0 ustar jan jan #!/usr/bin/env php
get('horde_dir', null, 'pear.horde.org') . '/whups/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('whups', array('cli' => true));
require_once __DIR__ . '/../../migration/3_whups_upgrade_sqlng.php';
$db = $injector->getInstance('Horde_Db_Adapter');
$migration = new WhupsUpgradeSqlng($db);
$delete = $cli->prompt('Delete existing shares from the NEW backend before migrating the OLD backend? This should be done to avoid duplicate entries or primary key collisions in the storage backend from earlier migrations.', array('y' => 'Yes', 'n' => 'No'), 'n');
if ($delete == 'y' || $delete == 'Y') {
$db->delete('DELETE FROM whups_sharesng');
$db->delete('DELETE FROM whups_sharesng_users');
$db->delete('DELETE FROM whups_sharesng_groups');
}
$migration->dataUp();
whups-3.0.0beta1/bin/whups-convert-to-utf8 0000775 0001750 0001750 00000021654 12160315153 016534 0 ustar jan jan #!/usr/bin/env php
*/
if (file_exists(__DIR__ . '/../../whups/lib/Application.php')) {
$baseDir = __DIR__ . '/../';
} else {
require_once 'PEAR/Config.php';
$baseDir = PEAR_Config::singleton()
->get('horde_dir', null, 'pear.horde.org') . '/whups/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('whups', array('cli' => true));
if ($conf['tickets']['driver'] != 'Sql') {
exit("You must have an SQL backend configured.\n");
}
// Get current charset.
$charset = $cli->prompt('Please specify the current charset of the data',
null, 'ISO-8859-1');
$dbFactory = $injector->getInstance('Horde_Core_Factory_Db');
$config = $dbFactory->getConfig('tickets');
$config['charset'] = $charset;
$dbin = $dbFactory->create('whups', $config);
$config['charset'] = 'UTF-8';
$dbout = $dbFactory->create('whups', $config);
$mysql = stristr($dbout->adapterName(), 'mysql');
// Convert queues.
try {
$results = $dbin->select('SELECT queue_id, queue_name, queue_description FROM whups_queues');
$sth = 'UPDATE whups_queues SET queue_name = ?, queue_description = ?'
. ' WHERE queue_id = ?';
echo 'Converting queues';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['queue_name'], $row['queue_description']),
$charset, 'UTF-8');
$values[] = $row['queue_id'];
$dbout->update($sth, $values);
echo '.';
}
$cli->writeln($cli->green('Done'));
} catch (Horde_Db_Exception $e) {
$cli->fatal($e->getMessage());
}
// Convert types.
try {
$results = $dbin->select('SELECT type_id, type_name, type_description FROM whups_types');
$sth = 'UPDATE whups_types SET type_name = ?, type_description = ?'
. ' WHERE type_id = ?';
echo 'Converting types';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['type_name'], $row['type_description']),
$charset, 'UTF-8');
$values[] = $row['type_id'];
$dbout->update($sth, $values);
echo '.';
}
$cli->writeln($cli->green('Done'));
} catch (Horde_Db_Exception $e) {
$cli->fatal($e->getMessage());
}
// Convert states.
try {
$results = $dbin->select('SELECT state_id, state_name, state_description, state_category FROM whups_states');
$sth = 'UPDATE whups_states SET state_name = ?, state_description = ?, state_category = ?'
. ' WHERE state_id = ?';
echo 'Converting states';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['state_name'], $row['state_description'], $row['state_category']),
$charset, 'UTF-8');
$values[] = $row['state_id'];
$dbout->update($sth, $values);
echo '.';
}
$cli->writeln($cli->green('Done'));
} catch (Horde_Db_Exception $e) {
$cli->fatal($e->getMessage());
}
// Convert priorities.
try {
$results = $dbin->select('SELECT priority_id, priority_name, priority_description FROM whups_priorities');
$sth = 'UPDATE whups_priorities SET priority_name = ?, priority_description = ?'
. ' WHERE priority_id = ?';
echo 'Converting priorities';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['priority_name'], $row['priority_description']),
$charset, 'UTF-8');
$values[] = $row['priority_id'];
$dbout->update($sth, $values);
echo '.';
}
$cli->writeln($cli->green('Done'));
} catch (Horde_Db_Exception $e) {
$cli->fatal($e->getMessage());
}
// Convert versions.
try {
$results = $dbin->select('SELECT version_id, version_name, version_description FROM whups_versions');
$sth = 'UPDATE whups_versions SET version_name = ?, version_description = ?'
. ' WHERE version_id = ?';
echo 'Converting versions';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['version_name'], $row['version_description']),
$charset, 'UTF-8');
$values[] = $row['version_id'];
$dbout->update($sth, $values);
echo '.';
}
$cli->writeln($cli->green('Done'));
} catch (Horde_Db_Exception $e) {
$cli->fatal($e->getMessage());
}
// Convert replies.
try {
$results = $dbin->select('SELECT reply_id, reply_name, reply_text FROM whups_replies');
$sth = 'UPDATE whups_replies SET reply_name = ?, reply_text = ?'
. ' WHERE reply_id = ?';
echo 'Converting replies';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['reply_name'], $row['reply_text']),
$charset, 'UTF-8');
$values[] = $row['reply_id'];
$dbout->update($sth, $values);
echo '.';
}
$cli->writeln($cli->green('Done'));
} catch (Horde_Db_Exception $e) {
$cli->fatal($e->getMessage());
}
// Convert tickets.
try {
$results = $dbin->select('SELECT ticket_id, ticket_summary FROM whups_tickets');
$sth = 'UPDATE whups_tickets SET ticket_summary = ?'
. ' WHERE ticket_id = ?';
echo 'Converting tickets';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['ticket_summary']),
$charset, 'UTF-8');
$values[] = $row['ticket_id'];
$dbout->update($sth, $values);
echo '.';
}
$cli->writeln($cli->green('Done'));
} catch (Horde_Db_Exception $e) {
$cli->fatal($e->getMessage());
}
// Convert comments.
try {
$results = $dbin->select('SELECT comment_id, comment_text FROM whups_comments');
$sth = 'UPDATE whups_comments SET comment_text = ?'
. ' WHERE comment_id = ?';
echo 'Converting comments';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['comment_text']),
$charset, 'UTF-8');
$values[] = $row['comment_id'];
$dbout->update($sth, $values);
echo '.';
}
$cli->writeln($cli->green('Done'));
} catch (Horde_Db_Exception $e) {
$cli->fatal($e->getMessage());
}
// Convert queries.
try {
$results = $dbin->select('SELECT query_id, query_parameters, query_object FROM whups_queries');
$sth = 'UPDATE whups_queries SET query_parameters = ?, query_object = ?'
. ' WHERE query_id = ?';
echo 'Converting queries';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['query_parameters'], $row['query_object']),
$charset, 'UTF-8');
$values[] = $row['query_id'];
$dbout->update($sth, $values);
echo '.';
}
$cli->writeln($cli->green('Done'));
} catch (Horde_Db_Exception $e) {
$cli->fatal($e->getMessage());
}
// Convert attributes.
try {
echo 'Converting attributes';
$results = $dbin->select('SELECT attribute_id, attribute_name, attribute_description, attribute_params FROM whups_attributes_desc');
$sth = 'UPDATE whups_attributes_desc SET attribute_name = ?, attribute_description = ?, attribute_params = ?'
. ' WHERE attribute_id = ?';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['attribute_name'], $row['attribute_description']),
$charset, 'UTF-8');
$values[] = serialize(Horde_String::convertCharset(unserialize($row['attribute_params']), $charset, 'UTF-8'));
$values[] = $row['attribute_id'];
$dbout->update($sth, $values);
echo '.';
}
$results = $dbin->select('SELECT ticket_id, attribute_id, attribute_value FROM whups_attributes');
$sth = 'UPDATE whups_attributes SET attribute_value = ?'
. ' WHERE ticket_id = ? AND attribute_id = ?';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['attribute_value']),
$charset, 'UTF-8');
$values[] = $row['ticket_id'];
$values[] = $row['attribute_id'];
$dbout->update($sth, $values);
echo '.';
}
$cli->writeln($cli->green('Done'));
} catch (Horde_Db_Exception $e) {
$cli->fatal($e->getMessage());
}
// Convert logs.
try {
$results = $dbin->select('SELECT log_id, log_value FROM whups_logs');
$sth = 'UPDATE whups_logs SET log_value = ?'
. ' WHERE log_id = ?';
echo 'Converting logs';
foreach ($results as $row) {
$values = Horde_String::convertCharset(
array($row['log_value']),
$charset, 'UTF-8');
$values[] = $row['log_id'];
$dbout->update($sth, $values);
echo '.';
}
$cli->writeln($cli->green('Done'));
} catch (Horde_Db_Exception $e) {
$cli->fatal($e->getMessage());
}
whups-3.0.0beta1/bin/whups-git-hook 0000775 0001750 0001750 00000006067 12160315153 015272 0 ustar jan jan #!/usr/bin/env php
getMessage());
}
return true;
}
whups-3.0.0beta1/bin/whups-git-hook-conf.php.dist 0000644 0001750 0001750 00000000544 12160315153 017732 0 ustar jan jan '',
'pass' => '');
whups-3.0.0beta1/bin/whups-mail-filter 0000775 0001750 0001750 00000015412 12160315153 015750 0 ustar jan jan #!/usr/bin/env php
$value) {
$dump .= sprintf("\n%${idlen}d: %s", $id, $value);
}
return $dump;
}
if (file_exists(__DIR__ . '/../../whups/lib/Application.php')) {
$baseDir = __DIR__ . '/../';
} else {
require_once 'PEAR/Config.php';
$baseDir = PEAR_Config::singleton()
->get('horde_dir', null, 'pear.horde.org') . '/whups/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('whups', array('cli' => true));
// Set server name.
$conf['server']['name'] = $conf['mail']['server_name'];
$conf['server']['port'] = $conf['mail']['server_port'];
// Read command-line parameters.
$info = array();
$mail = array('host' => 'localhost',
'pass' => '',
'port' => 143,
'protocol' => 'imap/notls',
'folder' => 'INBOX');
$from_mail = false;
// @TODO: Horde_Argv
$options = Console_Getopt::getopt(Console_Getopt::readPHPArgv(),
'ha:q:Q:gk:',
array('help',
'default-auth=',
'queue-name=', 'queue-id=',
'guess-queue',
'ticket=',
'mail-host=', 'mail-user=',
'mail-pass=', 'mail-port=',
'mail-protocol=', 'mail-folder='));
if (is_a($options, 'PEAR_Error')) {
usage();
$cli->fatal($options->getMessage());
}
// Convert options into a hash. This is possible because all options are only
// allowed once.
$opts_hash = array();
list($opts, $args) = $options;
foreach ($opts as $opt) {
list($optName, $optValue) = $opt;
switch ($optName) {
case 'h': $optName = '--help'; break;
case 'a': $optName = '--default-auth'; break;
case 'k': $optName = '--ticket'; break;
case 'q': $optName = '--queue-name'; break;
case 'Q': $optName = '--queue-id'; break;
case 'g': $optName = '--guess-queue'; break;
}
$opts_hash[$optName] = is_null($optValue) ? true : $optValue;
}
// Process options in this order because some depend on others.
if (isset($opts_hash['--help'])) {
usage();
exit;
}
if (isset($opts_hash['--default-auth'])) {
$info['default_auth'] = $opts_hash['--default-auth'];
$registry->setAuth($info['default_auth'], array());
}
if (isset($opts_hash['--ticket'])) {
$info['ticket'] = (int)$opts_hash['--ticket'];
}
if (isset($opts_hash['--guess-queue'])) {
$info['guess-queue'] = true;
}
if (isset($opts_hash['--queue-name'])) {
$queues = $whups_driver->getQueues();
foreach ($queues as $queueId => $queueName) {
if (strcasecmp($queueName, $opts_hash['--queue-name']) == 0) {
$info['queue'] = $queueId;
break;
}
}
}
if (isset($opts_hash['--queue-id'])) {
$queues = $whups_driver->getQueues();
foreach ($queues as $queueId => $queueName) {
if (strcasecmp($queueId, $opts_hash['--queue-id']) == 0) {
$info['queue'] = $queueId;
break;
}
}
}
foreach (array('host', 'user', 'pass', 'port', 'protocol', 'folder') as $opt) {
if (isset($opts_hash['--mail-' . $opt])) {
$mail[$opt] = $opts_hash['--mail-' . $opt];
}
}
// Sanity check options.
if (empty($info['ticket'])) {
if (empty($info['queue'])) {
usage();
$msg = _("--queue-name or --queue-id must specify a valid and public queue.");
if (isset($queues)) {
$msg .= ' ' . _("Available queues:") . _dump($queues);
}
$cli->fatal($msg);
}
}
// Read and parse the message.
if (empty($mail['user'])) {
try {
Whups_Mail::processMail($cli->readStdin(), $info);
} catch (Whups_Exception $e) {
$cli->fatal($e);
}
} else {
$messages = array();
$imap = imap_open(sprintf('{%s:%d/%s}%s',
$mail['host'],
$mail['port'],
$mail['protocol'],
$mail['folder']),
$mail['user'], $mail['pass']);
if (!$imap) {
$cli->fatal(_("Cannot authenticate at mail server:") . ' ' . implode('; ', imap_errors()));
}
_error();
$mailbox = imap_search($imap, 'ALL', SE_UID);
_error();
if ($mailbox) {
foreach ($mailbox as $uid) {
$message = imap_fetchheader($imap, $uid, FT_UID)
. imap_body($imap, $uid, FT_UID);
try {
Whups_Mail::processMail($message, $info);
imap_delete($imap, $uid, FT_UID);
} catch (Whups_Exception $e) {
$cli->message(_("Error processing message:") . ' ' . $e->getMessage(), 'cli.error');
}
}
}
imap_expunge($imap);
imap_close($imap);
}
exit(0);
whups-3.0.0beta1/bin/whups-obliterate 0000775 0001750 0001750 00000003446 12160315153 015701 0 ustar jan jan #!/usr/bin/env php
*/
if (file_exists(__DIR__ . '/../../whups/lib/Application.php')) {
$baseDir = __DIR__ . '/../';
} else {
require_once 'PEAR/Config.php';
$baseDir = PEAR_Config::singleton()
->get('horde_dir', null, 'pear.horde.org') . '/whups/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('whups', array('cli' => true, 'user_admin' => true));
$confirm = $cli->prompt(
'Are you sure you want to obliterate all Whups data?',
array(
'n' => 'No',
'y' => 'Yes'));
$cli->writeln();
if ($confirm !== 'y') {
exit;
}
$GLOBALS['whups_driver'] = $injector->getInstance('Whups_Factory_Driver')->create();
$cli->writeln($cli->bold('Obliterating queues'));
$queues = $whups_driver->getQueues();
foreach ($queues as $queue_id => $queue_name) {
$cli->message("Deleting queue: $queue_name");
$whups_driver->deleteQueue($queue_id);
}
$cli->writeln();
$cli->writeln($cli->bold('Obliterating types'));
$types = $whups_driver->getAllTypes();
foreach ($types as $type_id => $type_name) {
$cli->message("Deleting type: $type_name");
$whups_driver->deleteType($type_id);
}
$cli->writeln();
$queues = $registry->tickets->listQueues();
$cli->writeln($cli->bold('Obliterating tickets'));
$cli->writeln();
foreach (array_keys($queues) as $queue) {
$info['queue_id'] = $queue;
$tickets = $whups_driver->getTicketsByProperties($info);
foreach ($tickets as $info) {
$cli->message('Deleting ticket: ' . $info['id']);
$ticket = Whups_Ticket::makeTicket($info['id']);
$ticket->delete();
}
}
whups-3.0.0beta1/bin/whups-reminders 0000775 0001750 0001750 00000001451 12160315153 015531 0 ustar jan jan #!/usr/bin/env php
*/
if (file_exists(__DIR__ . '/../../whups/lib/Application.php')) {
$baseDir = __DIR__ . '/../';
} else {
require_once 'PEAR/Config.php';
$baseDir = PEAR_Config::singleton()
->get('horde_dir', null, 'pear.horde.org') . '/whups/';
}
require_once $baseDir . 'lib/Application.php';
Horde_Registry::appInit('whups', array('authentication' => 'none'));
// Get an instance of the Whups scheduler.
$reminder = Horde_Scheduler::unserialize('Whups_Scheduler');
// Check for and send reminders.
$reminder->run();
whups-3.0.0beta1/bin/whups-svn-hook 0000775 0001750 0001750 00000005035 12160315153 015307 0 ustar jan jan #!/usr/bin/env php
getMessage());
}
return true;
}
whups-3.0.0beta1/bin/whups-svn-hook-conf.php.dist 0000644 0001750 0001750 00000000563 12160315153 017756 0 ustar jan jan '',
'pass' => '');
whups-3.0.0beta1/config/.htaccess 0000644 0001750 0001750 00000000016 12160315153 014734 0 ustar jan jan Deny from all
whups-3.0.0beta1/config/conf.xml 0000664 0001750 0001750 00000033104 12160315153 014613 0 ustar jan jan
Sql
false
/usr/share/games/figlet/fonts/big.flffalsefalsefalsenew
newchronologicalrevchronologicalfalsetrue127.0.0.180User Preference Attributesbug|ticket|issuefalseactive
UnconfirmedA ticket has been reported but not yet analyzedunconfirmed
unconfirmednewassignedresolvedactive
AcceptedThe ticket has been analyzed and accepted as valid.new
unconfirmednewassignedresolvedactive
AssignedSomeone has accepted responsibility for the ticket.assigned
unconfirmednewassignedresolvedactive
ResolvedThe ticket has been resolved.resolved
unconfirmednewassignedresolvedactive
CanceledThe ticket is no longer valid for one reason or another.resolved
unconfirmednewassignedresolvedinactive
unconfirmednewassignedresolvedinactive
unconfirmednewassignedresolvedinactive
unconfirmednewassignedresolvedactive
1. LowThis is a very low priority ticketactive
2. MediumThis is an important task, but not urgent.active
3. HighThis ticket is very urgentinactive
inactive
inactive
whups-3.0.0beta1/config/create_email.plain.php 0000644 0001750 0001750 00000002622 12160315153 017370 0 ustar jan jan ticket_url: The link to the ticket page.
* $this->table: The ticket summary table.
* $this->comment: The user comment(s) to include if any.
* $this->dont_reply: Whether telling users to not reply is enabled in
* the configuration.
* $this->date: The current date.
* $this->full_name: The full name of the notification recipient.
* $this->auth_name: The full name of the user that updated the ticket.
* $this->role: The recipient role, one of 'always', 'listener',
* 'requester', 'queue', 'owner' in ascending importance
* order.
*/
?>
dont_reply): ?>
ticket_url ?>
table ?>
comment ?>
whups-3.0.0beta1/config/delete_email.plain.php 0000644 0001750 0001750 00000001377 12160315153 017375 0 ustar jan jan date: The current date.
* $this->full_name: The full name of the notification recipient.
* $this->auth_name: The full name of the user that updated the ticket.
* $this->role: The recipient role, one of 'always', 'listener',
* 'requester', 'queue', 'owner' in ascending importance
* order.
*/
?>
auth_name) ?> whups-3.0.0beta1/config/hooks.php.dist 0000644 0001750 0001750 00000004601 12160315153 015740 0 ustar jan jan $common_fields,
// 'Attributes' => $attributes);
// }
/**
* This is an example hook that intercepts ticket changes.
*
* If a comment has been added to a closed ticket, it will re-open the
* ticket, setting the state to "assigned". You might want to use numeric
* ids for the 'to' item in a real life hook.
*/
// public function ticket_update($ticket, $changes)
// {
// /* We only want to change the ticket state if it is closed, a comment
// * has been added, and the state hasn't been changed already. */
// if (!empty($changes['comment']) &&
// empty($changes['state']) &&
// $ticket->get('state_category') == 'resolved') {
// /* Pick the first state from the state category 'assigned'. */
// $states = $GLOBALS['whups_driver']->getStates($ticket->get('type'),
// 'assigned');
// /* These three item have to exist in a change set. */
// $changes['state'] = array(
// 'to' => key($states),
// 'from' => $ticket->get('state'),
// 'from_name' => $ticket->get('state_name'));
// }
//
// return $changes;
// }
}
whups-3.0.0beta1/config/menu.php.dist 0000644 0001750 0001750 00000002335 12160315153 015563 0 ustar jan jan 'http://www.example.com/',
* 'text' => 'Example, Inc.',
* 'icon' => 'example.gif',
* 'icon_path' => 'http://www.example.com/images/',
* 'target' => '_blank',
* 'onclick' => ''
* );
*
* You can also add a "separator" (a spacer) between menu items. To add a
* separator, simply add a new string to the $_menu array set to the text
* 'separator'. It should look like this:
*
* $_menu[] = 'separator';
*/
$_menu = array();
/* Add your custom entries below this line. */
whups-3.0.0beta1/config/mime_drivers.php 0000644 0001750 0001750 00000001476 12160315153 016347 0 ustar jan jan array(
'handles' => array(
'application/x-compressed',
'application/x-zip-compressed',
'application/zip',
'x-extension/zip',
),
'icons' => array(
'default' => 'compressed.png'
)
)
);
whups-3.0.0beta1/config/notify_email.plain.php 0000644 0001750 0001750 00000002625 12160315153 017440 0 ustar jan jan ticket_url: The link to the ticket page.
* $this->table: The ticket summary table.
* $this->comment: The user comment(s) to include if any.
* $this->dont_reply: Whether telling users to not reply is enabled in
* the configuration.
* $this->date: The current date.
* $this->full_name: The full name of the notification recipient.
* $this->auth_name: The full name of the user that updated the ticket.
* $this->role: The recipient role, one of 'always', 'listener',
* 'requester', 'queue', 'owner' in ascending importance
* order.
*/
?>
dont_reply): ?>
ticket_url ?>
table ?>
comment ?>
whups-3.0.0beta1/config/prefs.php 0000664 0001750 0001750 00000012501 12160315153 014772 0 ustar jan jan _("General Preferences"),
'label' => _("Display Preferences"),
'desc' => _("Change display preferences such as how search results are sorted."),
'members' => array(
'sortby', 'sortdir', 'comment_sort_dir', 'whups_default_view',
'summary_show_requested', 'summary_show_ticket_numbers',
'report_time_format', 'autolink_tickets'
)
);
$prefGroups['notification'] = array(
'column' => _("General Preferences"),
'label' => _("Notification Preferences"),
'desc' => _("Change preferences for email notifications of ticket activity."),
'members' => array('email_others_only', 'email_comments_only'));
$prefGroups['addressbooks'] = array(
'column' => _("General Preferences"),
'label' => _("Address Books"),
'desc' => _("Select address book sources for adding and searching for addresses."),
'members' => array('sourceselect'),
'suppress' => function() {
return !$GLOBALS['registry']->hasMethod('contacts/sources');
}
);
// the layout of the bugs portal.
$_prefs['mybugs_layout'] = array(
'value' => 'a:0:{}'
);
// user preferred sorting column
$_prefs['sortby'] = array(
'value' => 'id',
'type' => 'enum',
'enum' => array(
'id' => _("Id"),
'summary' => _("Summary"),
'state_name' => _("State"),
'type_name' => _("Type"),
'priority_name' => _("Priority"),
'queue_name' => _("Queue"),
'version_name' => _("Version"),
'timestamp' => _("Created"),
'date_assigned' => _("Assigned"),
'date_resolved' => _("Resolved")
),
'desc' => _("Default sorting criteria:")
);
// user preferred sorting direction
$_prefs['sortdir'] = array(
'value' => 0,
'type' => 'enum',
'enum' => array(
0 => _("Ascending"),
1 => _("Descending")
),
'desc' => _("Default sorting direction:")
);
// default view
$_prefs['whups_default_view'] = array(
'value' => 'mybugs',
'type' => 'enum',
'enum' => array(
'mybugs' => _("My Tickets"),
'search' => _("Search Tickets"),
'ticket/create' => _("Create Ticket")
),
'desc' => _("Select the view to display after login:")
);
// show requested tickets in the horde summary?
$_prefs['summary_show_requested'] = array(
'value' => 1,
'type' => 'checkbox',
'desc' => _("Show tickets you have requested in the summary view?"),
);
// show ticket ids in the horde summary?
$_prefs['summary_show_ticket_numbers'] = array(
'value' => 1,
'type' => 'checkbox',
'desc' => _("Show ticket IDs in the summary view?"),
);
// Allow custom time/date formats in reports
$_prefs['report_time_format'] = array(
'value' => '%m/%d/%y',
'type' => 'enum',
'enum' => array(
'%a %d %B' => _("Weekday Day Month"),
'%c' => _("Weekday Day Month HH:MM:SS TZ"),
'%m/%d/%y' => _("MM/DD/YY"),
'%m/%d/%y %H:%M:%S' => _("MM/DD/YY HH:MM:SS"),
'%d/%m/%y' => _("DD/MM/YY"),
'%d/%m/%y %H:%M:%S' => _("DD/MM/YY HH:MM:SS"),
'%y/%m/%d' => _("YY/MM/DD"),
'%y/%m/%d %H:%M:%S' => _("YY/MM/DD HH:MM:SS"),
),
'desc' => _("Date/Time format for search results"),
);
// Skip notification of changes you added?
$_prefs['email_others_only'] = array(
'value' => 1,
'type' => 'checkbox',
'desc' => _("Only notify me of ticket changes from other users?"),
);
// Skip notification without comments?
$_prefs['email_comments_only'] = array(
'value' => 0,
'type' => 'checkbox',
'desc' => _("Only notify me of ticket changes with comments?")
);
// AutoLink to tickets references in comments
$_prefs['autolink_tickets'] = array(
'value' => 1,
'type' => 'checkbox',
'desc' => _("Autolink to other tickets in comments?")
);
// Show ticket comments in ascending or descending order?
$_prefs['comment_sort_dir'] = array(
'value' => 1,
'type' => 'enum',
'enum' => array(
0 => _("Chronological (oldest first)"),
1 => _("Most recent first")
),
'desc' => _("Show comments in chronological order, or most recent first?")
);
// address book selection widget
$_prefs['sourceselect'] = array(
'type' => 'special',
'requires_nolock' => array('search_sources')
);
// Address book(s) to use when expanding addresses
// Refer to turba/config/sources.php for possible source values
//
// You can provide default values this way:
// 'value' => json_encode(array('source_one', 'source_two'))
$_prefs['search_sources'] = array(
'value' => ''
);
// Field(s) to use when expanding addresses
// Refer to turba/config/sources.php for possible source and field values
//
// If you want to provide a default value, this field depends on the
// search_sources preference. For example:
// 'value' => json_encode(array(
// 'source_one' => array('field_one', 'field_two'),
// 'source_two' => array('field_three')
// ))
// will search the fields 'field_one' and 'field_two' in source_one and
// 'field_three' in source_two.
$_prefs['search_fields'] = array(
'value' => ''
);
whups-3.0.0beta1/config/reminders.php 0000664 0001750 0001750 00000004223 12160315153 015645 0 ustar jan jan A cron-style date specification defining how often
* the rule will be triggered. For example,
* '* 30 11 1-31&Mon *' would run any second, at half
* past the hour of 11, every Monday in the month, every
* month.
*
* 'server_name' => The hostname that reminder emails will be sent
* from. Necessary since $_SERVER['SERVER_NAME'] is
* not present when running from cron. You can ignore
* this if you've set an explicit server name in
* horde's conf.php in $conf['server']['name'].
*
* 'queue' => Which Whups queue are we looking at?
*
* 'unassigned' => What email address should we send notification of
* unassigned tickets to? Can be set to false or any
* empty value if no email is necessary.
*
* 'category' => An array of states to send reminders for. Any of
* 'unconfirmed', 'new', 'assigned', and 'resolved',
* though I doubt you'll want to send reminders for
* resolved tickets.
*/
$reminders = array();
// Here's an example entry that will send reminders for queue number 1
// every Monday at 5am, for everything but resolved tickets.
$reminders[] = array('frequency' => '* 0 5 1-31&Mon *',
'server_name' => 'www.example.com',
'queue' => 1,
'unassigned' => false,
'category' => array('unconfirmed', 'new', 'assigned'));
whups-3.0.0beta1/config/reminder_email.plain.php 0000644 0001750 0001750 00000001752 12160315153 017735 0 ustar jan jan date: The current date.
* $this->full_name: The full name of the notification recipient.
* $this->role: The recipient role, always 'owner'.
*/
?>
tickets as $ticket): ?>
:
whups-3.0.0beta1/config/templates.php 0000644 0001750 0001750 00000003551 12160315153 015654 0 ustar jan jan 'searchresults',
'filename' => 'report.html',
'name' => _("Simple HTML Report"),
'sortby' => array('type_name', 'timestamp'),
'sortdir' => array(0, 1),
'template' => '
#
Type
Owners
Open Date
Description
'
);
$_templates['csv'] = array(
'type' => 'searchresults',
'name' => _("Comma Separated Values (CSV file)"),
'filename' => 'report.csv',
'callback' => '_csvQuote',
'template' => 'ID,Summary,State,Type,Priority,Queue,Version,Owners,Created,Assigned,Resolved,,,,,,,,,,
'
);
if (!function_exists('_csvQuote')) {
function _csvQuote(&$data, $key)
{
if (strpos($data, ',') !== false) {
$data = '"' . str_replace('"', '\"', $data) . '"';
}
}
}
whups-3.0.0beta1/docs/CHANGES 0000600 0001750 0001750 00000052013 12160315153 013610 0 ustar jan jan -----------
v3.0.0beta1
-----------
[jan] Fix deleting attributes.
[jan] Add configuration option to include raw processed message.
[jan] Add due date to ticket columns (Request #10986).
[jan] Make columns of portal block configurable (Request #10986).
----------
v2.0.3-git
----------
[jan] Fix converting searches in individual queues to queries (Bug #11819).
[jan] Fix editing single attribute and text criteria in query editor.
[jan] Fix setting active tabs in query editor.
[jan] Group active and inactive versions in queue adminstration.
[jan] Fix auto-submitting of tickets if using groups (Bug #10654).
[jan] Improve error reporting in whups-mail-filter.
------
v2.0.2
------
[jan] Fix saving portal blocks.
[jan] Fix deleting queries (Bug #10985).
[jan] Fix encoding of auto-completion results (Bug #10945).
------
v2.0.1
------
[jan] Fix some CLI scripts if run from a PEAR installation (Bug #10839).
[jan] Automatically create parent permissions when adding the first restricted
comment.
[jan] Ignore messages from postmaster too when processing mails.
[jan] Add setting to use different addresses for Return-Path: and From:
headers.
[jan] Fix whups-reminders script (Bug #10783).
[jan] Add Latvian translation (Jānis Eisaks).
----
v2.0
----
[jan] Fix rendering of attributes if a ticket's type has changed.
--------
v2.0-RC2
--------
[jan] Support more complex attributes types (Bug #9947).
[jan] Fix displaying form errors from updating tickets.
[jan] Allow to create private comments during ticket creation (Request #8312).
[jan] Fix addTicket API method.
[jan] Add missing default value for whups_priorities.priority_default column
(Bug #10631).
--------
v2.0-RC1
--------
[jan] Don't create stray update and assign permission (Bug #10624).
[jan] Add script to convert backends to UTF-8.
[jan] Fix executing queries on non-UTF-8 backends.
[jan] Add index to whups_attributes table.
[jan] Fix using custom SQL configurations.
[jan] Fix fatal error when updating address book preferences (Bug #10567).
[jan] Don't access protected properties in the addTicket/updateTicket API
methods (Bug #10566).
[jan] Fix adding comments as a guest (Bug #10559).
-----------
v2.0-ALPHA1
-----------
[jan] Fix automatic linking of bug numbers inside URLs (Bug #7081).
[jan] Don't search for all states if no states have been selected.
[jan] Add templates for delete and reminder notifications.
[jan] Add message template variable for recipient role.
[jan] Convert notification message templates to Horde_View.
[jan] Send notification when deleting tickets.
[jan] Fix determining whether to send updates without comments.
[jan] Send uploaded attachments with notification messages (Request #7615).
[mjr] Correctly set ticket version when changing queues (Bug #9645).
[jan] Add listSlugs API method.
[jan] Convert HTML messages to plain text when processing mail messages.
[jan] Fix creating temporary files with open_basedir restrictions.
[jan] Provide default configuration files instead of .dist versions.
------
v1.0.1
------
[jan] Fix Oracle SQL scripts.
[jan] Render private comments for everyone, but hide the comment text.
[jan] Add flag to disable old versions.
[jan] Apply simple markup highlighting on comments.
[jan] Save queue email addresses when editing queues (horde@hatzidakis.org,
Bug #7905).
[jan] Fix charset conversion of comments added with mail-filter.php
(thomas@gelf.net, Bug #7730).
[cjh] Show version changes in the ticket history.
[jan] Use all credentials and mailer settings when sending mails.
[cjh] Allow changing the queue version from the Update screen.
[cjh] Add more date formats to the report_time_format preference
(b5b5b5b5@centrum.sk, Request #7793).
[jan] Escape SQL wildcards in string queries.
[cjh] Enforce queue permissions in ticket-listing blocks (Bug #7614).
[cjh] Ensure the DB library is explicitly loaded (Bug #7647).
[jan] Add Turkish translation (Akif Dinc ).
[jan] Fix linking to queries if URL rewriting is turned off.
----
v1.0
----
[jan] Change group field in shares table to work with LDAP groups (Bug #6883).
[jan] Fix rendering attribute criteria in the query tree.
[jan] Generate a valid Message-ID.
[mjr] Fix an issue with searching on installations with a single queue that
was causing all existing tickets in the queue to be displayed on entering
the search page.
--------
v1.0-RC2
--------
[jan] Add date search criteria (Duck , Request #7274).
[cjh] Add an RSS feed of search results (Duck , Request #7259).
[jan] Group statistics by ticket type.
[jan] Add Precedence and Auto-Submitted headers to notification messages
(Request #7082).
[jan] Add In-Reply-To header to notification messages (Request #7103).
[jan] Add button to save searches as queries (Request #5921).
[jan] Add query slugs and RSS feeds (Request #5924).
[jan] Implement editing of query elements.
[mjr] Fix saving of queries.
--------
v1.0-RC1
--------
[jan] Remove attributes hooks.
[jan] Add form replies.
[jan] Add support for queue-specific notification messages.
[jan] Add email address per queue for ticket notifications.
[jan] Use highlightquotes filter for quoted comments.
[jan] Send notification messages in flowed text format (requires Horde 3.2.1).
[jan] Allow to specify field types and parameters for attributes.
[jan] Add a hook that is called if a ticket is being updated, for automatic
ticket changes.
[jan] Add auto-completion to retrieve requesters from the address book.
[jan] Add per-queue permission to manually set the ticket requester.
[jan] Deal with queue vs. admin permissions more consistently.
[jan] Add configuration option whether to include email headers in comments.
[cjh] Improve resource usage in datatree_to_sql share migration script
(Bug #6740).
[cjh] Add an upgrade script for the new SQL share driver (Request #6109).
[jan] Add preference to only receive notifications if a comment has been added.
[jan] Send personalized ticket notification messages.
[jan] Add addAttachment API method.
[jan] Add message templates for email notifications.
[jan] Sequentially number comments (Request #4895).
[jan] Unset resolved date when un-resolving tickets (Bug #6310).
[jan] Add mail sender as requester when using the --default-auth argument with
scripts/mail-filter.php.
[jan] Notify watchers that have just been added by email.
[jan] Add attributes search to query builder.
[jan] Rename API methods get_assigned_ticket_ids, get_requested_ticket_ids,
get_schema, add_tickets, and set_ticket_attributes.
[jan] Add --guess-queue argument to mail-filter.php.
[cjh] Use pretty URLs if Horde is configured for them (Request #5922).
[jan] Add configuration for default types, states, and priorities.
[mjr] Attribute values now show correctly in initial ticket notifications.
[jan] Add a hook to customize field grouping in the ticket views.
[cjh] Combine Type and Category selects in search form (php@ideacode.com,
Request #4928).
[jan] Show attribute changes in ticket history.
[jan] Allow scripts/mail-filter.php to process attachments.
[jan] Add ability to read messages from a mailbox to scripts/mail-filter.php.
[cjh] Don't re-use old attachment names even if the attachment has since been
deleted (Bug #4472).
[cjh] Store the guest user associated with transactions that only add an
attachment, with no comment text (Bug #2890).
[cjh] Include attribute values in ticket emails, including "diffs" for changes
(Bug #1083).
[cjh] When creating a ticket, preserve attachments uploaded in step 3 when
step 4 is used to assign the ticket (Bug #2514).
[cjh] When replying to a restricted comment, default to the same restriction
(Request #4902).
[cjh] Support split read and write databases (, Request #5926).
[jan] Add Lithuanian translation (Vilius Sumskas ).
[cjh] Add an addComment API method.
[jan] Add OpenSearch interface for direct ticket access through browser bars.
[jan] Move all Whups-specific hook examples from Horde's config/ directory.
[cjh] Rename whups_tickets_listeners to whups_ticket_listeners for consistency.
[cjh] Add a tree menu block (Jakob Schroeter ).
[cjh] On the search screen, only show types that are associated with queues
that are available/active (tinu@humbapa.ch, Request #4107).
[jan] Add Polish translation (Tadeusz Lesiecki , Piotr
Tarnowski ).
[jan] Add Ukrainian translation (Andriy Kopystyansky ).
[cjh] Ensure that a due date in a prior year doesn't make the EditTicketForm
invalid (Bug #4763).
[cjh] Remove saved searches (Request #4897).
[cjh] Calculate ticket date attributes when they change instead of on every
access (php@ideacode.com, Request #4893).
[cjh] Queries are now managed as shares, but the serialized bits are stored
and managed by Whups in their own dedicated table.
[jan] Allow guest access to query page.
[cjh] Smarter word wrapping in string representations of tickets
(Request #4510).
[cjh] Add a Queue Summary block showing queues with the number of open
tickets in each (Request #4628).
[cjh] Combine the People tab with the Update tab.
[cjh] Allow changing ticket queues as long as the user has DELETE permissions
on the current queue and EDIT permissions on the new queue
(tmerritt@email.arizona.edu, Request #4268).
[cjh] Add hours and minutes to due dates.
[cjh] Always use Summary for the ticket summary field label.
[jan] Add Slovenian translation (Duck ).
[cjh] Show the requester in search results (rodion (at) nezna (dot) com,
Bug #2820).
[cjh] Show either the Comment or Update tabs depending on permissions,
but not both.
[cjh] Report the last-updated date for tickets (Bug #2396).
[cjh] Tickets now have an optional due date field.
[cjh] New updateTicket API call (Ben Klang , Bug #4101).
[cjh] Check permissions when setting ticket attributes through an API call
(Ben Klang , Bug #4098).
[cjh] If guests can add tickets but not view them, don't tell them adding
failed (Bug #3630).
[cjh] Add Unassigned Tickets Horde_Block (Request #766).
[mas] Fix sorting in summary page to better handle dates. (Bug #2930)
[cjh] Add CAPTCHA support to the Add Comment and Create Ticket forms.
[cjh] Deliver RSS feeds in a way that supports USM
(http://www.kbcafe.com/rss/usm.html, Request #2593).
[cjh] processMail() now ignores emails that were generated by Whups
(Bug #3398).
[ben] Better support for MS-SQL.
[jan] Add Norwegian (Bokmal) translation (Torbjorn Grindhaug
).
[cjh] "My Bugs" page is now a Horde_Block layout (Request #3202).
[cjh] Fix permissions checking for ticket comments when an admin user is the
one making the comment (Bug #2673).
[cjh] Delete searches by getvars string, not by name (Bug #3197).
[jan] Allow to assign tickets to foreign groups
(ronny.adsetts@amazinginternet.com, Request #2477).
[cjh] Add support for dynamic re-sorting of search results, including saving
the sort preferences on any changes.
[mas] Protect against HTML tags in the search results summary.
[jan] Allow other applications to provide versions.
[jan] Simplify UI for query editor and allow to search for versions.
[jan] Allow to send notification mails to queue-specific addresses (Marcus
Boerger ).
[jan] Allow other applications to provide queues.
[cjh] Add *-id arguments for type, priority, state, and queue to
mail-filter.php (Bug #2347).
[cjh] Add a link to return to the list of search results, along with the
previous/next links (Bug #1751).
[cjh] Fix the Quicksearch links.
[cjh] mail-filter.php now handles replies as well (Bug #280).
[cjh] Use the date_format preference for displaying TicketDetailsForm
as well (Bug #2151).
[jan] Add Russian translation (Illya Belov ).
[mas] Add ability to search by ticket requester.
[mas] Change any output of and tags to and for better
accessibility support.
[cjh] Add links to Update/Comment from individual transactions, which quote
that transaction's comment text (Bug #823).
[cjh] Add explicit permissions for assigning and updating tickets
(tmerritt@email.arizona.edu, Bug #1955).
[jan] Strike-through links to resolved tickets.
[jan] Make server name and port in mail-filter.php configurable (Bug #2004).
[cjh] Honor creator permissions on tickets (tmerritt@email.arizona.edu,
Bug #1945).
[cjh] Implement ticket watchers (tmerritt@email.arizona.edu, Bug #867).
[cjh] Enforce permissions on queues in reports, let guests see reports
if they have permissions (Bug #1812).
[cjh] Allow export templates to define a callback function for filtering
data. Includes an example for properly quoting CSV data (Bug #1774).
[jan] Use bind variables in the SQL driver (Bug #1701).
[cjh] Queries are stored as Horde_Share objects with full permissions.
(Bug #1481).
[cjh] Delete queue permissions when deleting a queue (Bug #1462).
[jan] Add MIME viewer for ZIP files.
[cjh] Queries can now be deleted (Bug #1193).
[cjh] Preserve the current search criteria when re-sorting results (Bug #1024).
[cjh] Link to ticket RSS feeds on all ticket display pages.
[cjh] Allow administrators to delete attachments (Bug #1252).
[cjh] Allow uploading an attachment when initially creating a ticket.
[cjh] Fix group-restricted comments (Bug #1225).
[jan] Add Brazilian Portuguese translation (Daniel V. Hoisel
).
[cjh] Whups_Mail::processMail needs to use Whups_Ticket for ticket creation
to trigger email notifications, etc (Bug #1134).
[cjh] Allow inserting explicit Type filters into Query Builder queries
(Bug #434).
[cjh] Force users to choose a queue when creating tickets with the goal
of cutting down on misfiled tickets (Bug #588).
[cjh] Remove the Attachment tab, as it currently serves no purpose beyond
the Comment tab (Bug #868).
[cjh] Add a numeric log_value_num field for faster logs table comparisons
and for compatibility with databases that can't cast strings into
integer comparisons (Oracle, etc) (rvs (at) angara (dot) ru).
[jan] Add Finnish translation (Leena Heino ).
[jan] Add Spanish translation (Manuel Perez Ayala ).
[cjh] The way ticket histories are stored and retrieved has been completely
revamped to be quicker, more robust, and more complete.
[cjh] Add a 'summary' search option in the basic search form (Bug #269).
[cjh] Queue is now a valid query builder criterion.
[cjh] Add previous/next navigation when there's a current list of search
results to navigate through.
[cjh] Changing a ticket's queue now also allows setting a queue version.
[cjh] Group ticket histories by transaction, not by individual change.
[cjh] Show users their saved queries as well as saved searches.
[jan] Add Simplified Chinese translation (Liaobin ).
[cjh] Add a basic "Update" screen for changing summary, state, priority,
and adding attachments/comments, all at once.
[cjh] Finish renaming "module" to "queue" throughout the data and SQL.
[cjh] Add $conf['mail']['always_copy'] to allow Whups to always copy
a specific email address on ticket mail.
[cjh] Mail can be configured to come from a single email address now,
making it easier to allow Whups to post ticket email to a
mailing list, etc.
[cjh] Add a "DO NOT REPLY" note to generated emails if Whups isn't
configured to handle replies to ticket mail.
[cjh] Advertise permissions through the API.
[jan] Add Dutch translation (Stefan de Konink ).
[cjh] Make ticket owners available in search results again.
[jan] Allow uploading of attachments.
[cjh] Allow assigning tickets to groups.
[cjh] Add Set Type action to the details page (Bo Daley ).
[cjh] Allow clearing of all or individual searches (Bo Daley ).
[cjh] Start of a reminder-sending daemon.
[cjh] Allow assignment of a ticket to multiple users.
[cjh] Queue/Type matrix is now functional and allows very quick editing
of which ticket types are associated with each module.
[jan] Add Romanian translation (Eugen Hoanca ).
[cjh] Allow much more flexible configuration of who gets email on
various actions (Bo Daley ).
[cjh] Whups can now send out simple reminders.
[cjh] By giving users the 'whups:admin' permission, people can administer
individual queues in Whups, or just Whups as opposed to all of Horde.
[cjh] Allow multiple levels of sorting (first by date, then type, etc).
[cjh] Phrases in ticket comments can now be linked to the ticket in question
automatically (Mike Baptiste ).
[cjh] Use Horde_Template to generate configurable reports from
search result sets.
[cjh] Add a New Ticket link in the summary screen
(Brian Keifer ).
[cjh] Add a preference for not showing requested tickets in the summary
screen (Brian Keifer ).
[cjh] Prevent guest users from assigning tickets and make them enter
the ticket password to change state/priority.
[cjh] Guest users can now add tickets and add comments to tickets when
they have permissions to do so.
[cjh] We can now retrieve much more flexible datasets, such as the
average time it takes to resolve a ticket by developer,
requester, module, etc.
[cjh] Add a flexible set of stats, such as the average time a ticket
is unresolved.
[cjh] Add a much more flexible set of graphs, and a "My Bugs"
section for ticket summaries.
[cjh] Search results can now specify the results title header.
[cjh] Reports currently lacks pretty graphs, but now shows more useful
information - all assigned and requested tickets.
[cjh] Fix usage of Variables:: class.
[jan] Add Traditional Chinese translation (David Chang ).
[jan] Add Bulgarian translation (Miroslav Pendev ).
[cjh] Better enforcement of permissions on modules, especially
during searches.
[cjh] Add options for how many comments are sent in bug emails,
and in what order.
[cjh] Make sure that comments mailed to users don't include private
comments they aren't authorized to see.
[cjh] Clean up the format of generated emails to be much clearer.
[cjh] All email notification triggers now work.
[cjh] Add a standard Horde menu.
[cjh] Add an Options screen.
[cjh] Fix the Query Builder.
[cjh] Whups now uses the Horde FormSprocket:: API for all form handling.
[cjh] Ticket search results are now fully sortable, and a user preference.
[jan] Add French translation (Thierry Thomas).
[cjh] Use users' identities for showing names of requester, owner, etc.
[cjh] Include assigned and resolved dates in the search results view.
[cjh] Include date created, assigned, and resolved in the details view.
[cjh] Don't show resolved tickets in the summary.
[cjh] Require permission (whups:hiddenComments, at level Edit) to make
comments specific to a group.
[cjh] Display comments which are restricted differently.
[cjh] Add the ability to restrict viewing of a comment to a Group.
[cjh] Improve the reporting data that gets saved by a lot.
[jan] Add Czech translation.
[cjh] Fix some non-portable SQL.
[cjh] Add the option to keep track of different versions for a module.
[cjh] Fix problems when there are no types associated with a module.
[cjh] Default select lists which have only one value to that value. In
some cases this allows for auto-filling of forms (creating tickets).
[cjh] Include session ID in forms/links.
[cjh] Only show users queues which they have permissions for.
[cjh] Add a link from the edit queue section to edit the permissions on
that module.
[cjh] Add managing of which users can have tickets assigned to them, on a
per-module basis.
[cjh] Remove the sample data, as it poses sequence problems and isn't needed
now that the administration interface works.
[cjh] Don't create the sequence tables in whups.sql; PEAR needs to create
them itself to get implementation-specific details right.
[cjh] Administration interface - adding, deleting, and editing of modules,
types, states, and priorities all work now.
[jon] Adapt to the new Horde::img() syntax.
[cjh] Types can now map to multiple modules, instead of either one or global.
This is a much more flexible setup, and actually allows re-use of types.
[cjh] Added a SetType for collections of on/off values (a checkbox set).
[cjh] Use $registry->get() in place of other $registry->get
functions.
[cjh] Use WHUPS_TEMPLATES for template paths.
[jon] Enable the "portability" option in the SQL driver.
[jan] Remove the standard value for the language preference. The language to
fall back to should be set Horde wide in lang.php instead.
[cjh] Add API method and implementation for adding modules.
[rec] Add query builder, many UI improvements, more horde-style design.
[cjh] Apply patches from Alex L. for assignment, users, etc.
[avsm] Replace $conf['paths'] with the $registry equivalents.
[cjh] Convert short tags () to
- Initial codebase
- Query builder
Chuck Hagenbuch
- Horde cleanup
- Reports generation
- Administration GUI
Jan Schneider
- Attachments
- E-mail support
- Form replies
- Stuff
Localization
============
====================== ===============================================
Brazilian Portuguese Daniel V. Hoisel
Bulgarian Miroslav Pendev
Chinese (Simplified) Liaobin
Chinese (Traditional) David Chang
Czech Pavel Chytil
Václav Hůla
Dutch Stefan de Konink
Han Spruyt
Finnish Leena Heino
French Thierry Thomas
German Jan Schneider
Hungarian Andras Galos
Italian Fabio Pedretti
Latvian Jānis Eisaks
Lithuanian Vilius Šumskas
Norwegian (Bokmal) Torbjorn Grindhaug
Polish Tadeusz Lesiecki
Piotr Tarnowski
Romanian Eugen Hoanca
Russian Illya Belov
Alexey Zakharov
Slovenian Duck
Spanish Manuel Perez Ayala
Juan C. Blanco
Turkish Akif Dinc
Ukrainian Andriy Kopystyansky
====================== ===============================================
whups-3.0.0beta1/docs/INSTALL 0000664 0001750 0001750 00000024341 12160315153 013663 0 ustar jan jan =====================
Installing Whups H5
=====================
:Contact: dev@lists.horde.org
.. contents:: Contents
.. section-numbering::
This document contains instructions for installing the Whups web-based
ticket-tracking application on your system.
For information on the capabilities and features of Whups, see the file
README_ in the top-level directory of the Whups distribution.
Prerequisites
=============
To function properly, Whups **requires** the following:
1. A working Horde installation.
Whups runs within the `Horde Application Framework`_, a set of common tools
for web applications written in PHP. You must install Horde before
installing Whups.
.. Important:: Whups H5 requires version 5.0+ of the Horde Framework -
earlier versions of Horde will **not** work.
.. Important:: Be sure to have completed all of the steps in the
`horde/docs/INSTALL`_ file for the Horde Framework before
installing Whups. Many of Whups's prerequisites are also
Horde prerequisites. Additionally, many of Whups's optional
features are configured via the Horde install.
.. _`Horde Application Framework`: http://www.horde.org/apps/horde
2. The following PHP capabilities:
a. SQL support
Whups stores its data in an SQL database. Build PHP with whichever SQL
driver you require; see the`horde/docs/INSTALL`_ file for details.
Installing Whups
================
The **RECOMMENDED** way to install Whups is using the PEAR installer.
Alternatively, if you want to run the latest development code or get the
latest not yet released fixes, you can install Whups from Git.
Installing with PEAR
~~~~~~~~~~~~~~~~~~~~
First follow the instructions in `horde/docs/INSTALL`_ to prepare a PEAR
environment for Horde and install the Horde Framework.
When installing Whups through PEAR now, the installer will automatically
install any dependencies of Whups too. If you want to install Whups with all
optional dependencies, but without the binary PECL packages that need to be
compiled, specify both the ``-a`` and the ``-B`` flag::
pear install -a -B horde/whups
By default, only the required dependencies will be installed::
pear install horde/whups
If you want to install Whups even with all binary dependencies, you need to
remove the ``-B`` flag. Please note that this might also try to install PHP
extensions through PECL that might need further configuration or activation in
your PHP configuration::
pear install -a horde/whups
Installing from Git
~~~~~~~~~~~~~~~~~~~
See http://www.horde.org/source/git.php
Configuring Whups
=================
1. Configuring Whups
You must login to Horde as a Horde Administrator to finish the
configuration of Whups. Use the Horde ``Administration`` menu item to get
to the administration page, and then click on the ``Configuration`` icon to
get the configuration page. Select ``Tickets`` from the selection list of
applications. Fill in or change any configuration values as needed. When
done click on ``Generate Tickets Configuration`` to generate the
``conf.php`` file. If your web server doesn't have write permissions to the
Whups configuration directory or file, it will not be able to write the
file. In this case, go back to ``Configuration`` and choose one of the
other methods to create the configuration file ``whups/config/conf.php``.
Documentation on the format and purpose of the other configuration files and
templates in the ``config/`` directory can be found in each file. You may
create ``*.local.php`` versions of these files if you wish to customize
Whups' appearance and behavior. See the header of the configuration files
for details and examples. With one exception (``reminders.php``, in case you
want to automatically sent out reminders about open tickets) the defaults
will be correct for most sites.
The ``*_email.plain.php`` files define how outgoing email notifications
about ticket changes look like. See the comments in these files for details.
If you would like the ability to create and update tickets via email, you
will need to set up ``whups-mail-filter`` to receive email from the
appropriate addresses. This script takes a number of arguments; see the
script for more details. A typical setup might be::
bugs |/usr/bin/whups-mail-filter --queue-name=Bugs
This will take in mail to the ``bugs`` address at your domain, and create
new tickets in the ``Bugs`` queue, with the default type, state and priority
of this queue. If an email references an existing ticket (ticket numbers are
recognized in the subject line) it will be updated instead.
If not installing Whups through PEAR of if PEAR's ``bin_dir`` configuration
doesn't point to ``/usr/bin/``, replace ``/usr/bin/whups-mail-filter`` with
the path to the ``whups-mail-filter`` script in your Horde installation.
See also `Creating tickets from email messages`_ below.
2. Creating the database table
Once you finished the configuration in the previous step, you can create all
database tables by clicking the ``DB schema is out of date.`` link in the
Whups row of the configuration screen.
Alternatively creating the Whups database tables can be accomplished with
horde's ``horde-db-migrate`` utility. If your database is properly setup in
the Horde configuration, just run the following::
horde-db-migrate whups
3. Testing Whups
Use Whups to create your base data, create tickets, and modify tickets. Test
at least the following:
- Creating a new project (queue)
- Creating ticket types, states, priorities for a project
- Adding a ticket
- Assigning a ticket
- Closing a ticket
4. _`Creating tickets from email messages`
Whups provides functionality that can be used to create and update tickets
from email messages. One part of this functionality is the
``whups-mail-filter`` script. It can either be installed inside the mail
chain, or run as a standalone script against an IMAP or POP3 server. It
provides a list of all available command line arguments if called with the
``--help`` argument: ``whups-mail-filter --help``.
If you use the arguments starting with ``--mail``, the script will login to
the provided IMAP or POP3 server and process all messages in the specified
folder. Any successfully processed messages will be deleted. An error
message will be displayed for any failed messages. Using the script in this
mode makes most sense when run regularly, e.g. by a cron job or the Windows
task planner.
You can also install the script inside the mail chain. In this mode, the
script expects a single email message from standard input. A common
scenario would be to pipe all messages to a certain email address through
this script, e.g. through the forwarding or alias mechanism. An example
entry in ``/etc/alias`` could look like this::
bugs:"|/usr/bin/whups-mail-filter -q 'Test Queue'"
Even though this example uses a queue "name" for the argument, it's
preferred to use IDs, because those doesn't cause any problems with spaces,
or non-ascii characters.
The script tries to determine the ticket number from the message, if a
ticket number hasn't been specified with the ``--ticket`` argument.
Currently it searches for strings looking like "[Bug #1]" in the message
subject. If a ticket number cannot be determined by any means, or if a
ticket with that number doesn't exist, a new ticket is created.
The (Horde) user that will be used to create or update the ticket, will
also be determined by investigating the message. The email address used in
the ``From:`` header of the message will be looked up by searching all
identities of all users in the authentication backend. This only works if
the authentication backend is capable of listing users. If a user cannot be
determined this way, the user provided by the ``--default--auth`` argument,
if any, is used. Finally, if none has been provided, the user specified in
Whups' configuration (``$conf[mail][username]``) will be used. If there
still hasn't been a user determined at this point, the ticket will be
updated or created by the "guest" user, using the email address of the
``From:`` header. This only works if guest access has been granted to both
Whups, and the queue specified with the ``--queue-name`` or ``--queue-id``
parameters.
Finally, you might want to to enable the setting in Whups' configuration,
below the "Email Settings" tab, that allows users to reply to ticket
emails. This setting removes the warning from the generated ticket emails to
*not* reply to those emails. And you should of course make sure that you
specify the correct email address here for the generated messages. It should
be the address that you use for the mail pipe, or the IMAP/POP3 account when
calling ``whups-mail-filter``.
Any attachments that have been sent with the message will be added to the
ticket as attachments too. This is done via the virtual file system (VFS) of
Horde. If you use the local file system as the VFS backend, you need to take
care of permissions and umasks, i.e. both the user running the
``whups-mail-filter`` script and the user running the web server need to
have read-write permissions to the VFS storage directory.
Obtaining Support
=================
If you encounter problems with Whups, help is available!
The Horde Frequently Asked Questions List (FAQ), available on the Web at
http://wiki.horde.org/FAQ
The Horde Project runs a number of mailing lists, for individual applications
and for issues relating to the project as a whole. Information, archives, and
subscription information can be found at
http://www.horde.org/community/mail
Lastly, Horde developers, contributors and users may also be found on IRC,
on the channel #horde on the Freenode Network (irc.freenode.net).
Please keep in mind that Whups is free software written by volunteers.
For information on reasonable support expectations, please read
http://www.horde.org/community/support
Thanks for using Whups!
The Whups team
.. _README: README
.. _`horde/docs/INSTALL`: ../../horde/docs/INSTALL
.. _`horde/docs/TRANSLATIONS`: ../../horde/docs/TRANSLATIONS
whups-3.0.0beta1/docs/lighttpd-whups.conf 0000644 0001750 0001750 00000002230 12160315153 016453 0 ustar jan jan ## This file should be reviewed prior to inclusion in your lighttpd
## configuration. Specifically, if you have whups somewhere other than
## /horde/whups you will need to edit the following rules to match your server
## configuration.
## This file should be included in your lighttpd.conf file with the "include"
## directive. Example:
## include "path/to/lighttpd-whups.conf"
## The exact path you use will of course depend on your specific configuration.
url.rewrite-once += (
"^/horde/whups/queue/([0-9]+)/?(?:\?(.*))?$" => "/horde/whups/queue/index.php?id=$1&$2",
"^/horde/whups/queue/([0-9]+)/rss/?(?:\?(.*))?$" => "/horde/whups/queue/rss.php?id=$1&$2",
"^/horde/whups/queue/([a-zA-Z0-9_]+)/?(?:\?(.*))?$" => "/horde/whups/queue/index.php?slug=$1&$2",
"^/horde/whups/queue/([a-zA-Z0-9_]+)/rss/?(?:\?(.*))?$" => "/horde/whups/queue/rss.php?id=$1&2",
"^/horde/whups/ticket/([0-9]+)/?(?:\?(.*))?$" => "/horde/whups/ticket/index.php?id=$1&$2",
"^/horde/whups/ticket/([0-9]+)/rss/?(?:\?(.*))?$" => "/horde/whups/ticket/rss.php?id=$1&$2",
"^/horde/whups/ticket/([0-9]+)/([a-z]+)(\.php)?(?:\?(.*))?$" => "/horde/whups/ticket/$2.php?id=$1&$3"
)
whups-3.0.0beta1/docs/RELEASE_NOTES 0000664 0001750 0001750 00000003647 12160315153 014613 0 ustar jan jan notes['fm']['focus'] = array(Horde_Release::FOCUS_MAJORFEATURE, Horde_Release::FOCUS_MINORBUG);
/* Mailing list release notes. */
$this->notes['ml']['changes'] = <<notes['fm']['changes'] = <<notes['name'] = 'Whups';
$this->notes['list'] = 'horde';
$this->notes['fm']['project'] = 'whups';
$this->notes['fm']['branch'] = 'Horde 5';
whups-3.0.0beta1/docs/TODO 0000644 0001750 0001750 00000004114 12160315153 013314 0 ustar jan jan =============================
Whups Development TODO List
=============================
:Contact: dev@lists.horde.org
- Ability to take/steal tickets from other users in the list UI.
- Ability to merge a ticket with another ticket (instead of marking as
duplicate). Histories of two tickets should be merged.
- Better permissions integration.
- Possible integration with other Horde queues (nag/turba/hermes), including
api support between them.
- docs and help files...
- Additional "work flow" support.
- Handle attachments in Whups_Mail
- States/Priorities (or whole types?) cloning:
| > What if we had a "clone" feature? When editing states/priorities, just
| > being able to clone the states/priorities from another type into this
| > type?
|
| I now think that this would be a good idea. It's almost the same as
| Gary's template patch, but it should work in a slightly different way
| to better fit the workflow direction.
|
| When we have state transitions, it's more important that a type
| doesn't change as tickets flow through it because that could cause
| tickets to become inconsistent. However, it's very likely that as the
| type is being used, people see some way of making it fit the model
| more accurately. In that case, probably the best way to fix it is to
| copy the existing type into a new one. You can then modify the new
| type however you see fit then 'publish' the type and start creating
| tickets in it. Published types can't be altered.
|
| With the type templates, you could only copy particular types into new
| ones, instead of any type that you need to.
|
| However, with the templates, type were created as 'just a template',
| ie. one that shouldn't have tickets created. This can be quite
| useful, but instead of using an underscore prefix to identify it, I'd
| prefer to have a 'published' field in the table to represent types
| that can have tickets in it. A template could then be a normal,
| unpublished, type.
- For project scheduling:
http://www.joelonsoftware.com/articles/fog0000000245.html
whups-3.0.0beta1/docs/UPGRADING 0000664 0001750 0001750 00000002663 12160315153 014100 0 ustar jan jan =================
Upgrading Whups
=================
:Contact: horde@lists.horde.org
.. contents:: Contents
.. section-numbering::
General instructions
====================
These are instructions to upgrade from earlier Whups versions. Please backup
your existing data before running any of the steps described below. You can't
use the updated data with your old Whups version anymore.
Upgrading Whups is as easy as running::
pear upgrade -a -B horde/whups
If you want to upgrade from a Whups version prior to 2.0, please
follow the instructions in INSTALL_ to install the most recent Whups
version using the PEAR installer.
After updating to a newer Whups version, you **always** need to update
configurations and database schemes. Log in as an administrator, go to
Administration => Configuration and update anything that's highlighted as
outdated.
Upgrading Whups from 1.0.x to 2.0.x
===================================
All command line scripts have been renamed, the new versions all have whups-
prefixes.
- Email template changes.
Upgrading Whups from 1.0 to 1.0.1
=================================
SQL Backends
------------
A field to store whether a version is still active has been added to the
default SQL table layout.
Execute the provided SQL script to update your data to the new Whups version,
e.g.::
mysql --user=root --password= < scripts/upgrades/1.0_to_1.0.1.sql
.. _INSTALL: INSTALL
whups-3.0.0beta1/lib/Ajax/Imple/ContactAutoCompleter.php 0000664 0001750 0001750 00000001431 12160315153 021204 0 ustar jan jan
* @category Horde
* @license http://www.horde.org/licenses/bsdl.php BSD
* @package Whups
*/
class Whups_Ajax_Imple_ContactAutoCompleter extends Horde_Core_Ajax_Imple_ContactAutoCompleter
{
/**
*/
protected function _getAddressbookSearchParams()
{
$params = Whups::getAddressbookSearchParams();
$ob = new stdClass;
$ob->fields = $params['fields'];
$ob->sources = $params['sources'];
return $ob;
}
}
whups-3.0.0beta1/lib/Block/Myqueries.php 0000664 0001750 0001750 00000001464 12160315153 016177 0 ustar jan jan _name = _("Saved Queries");
}
/**
*/
protected function _content()
{
$qManager = new Whups_Query_Manager();
$queries = $qManager->listQueries($GLOBALS['registry']->getAuth(), true);
$myqueries = new Whups_View_SavedQueries(
array('results' => $queries));
Horde::startBuffer();
$myqueries->html(false);
$html = Horde::endBuffer();
if ($html) {
return $html;
}
return '
_tokens[] = $matches[0];
return chr(0);
}
/**
* Replaces tokens with links stored earlier during _writeTokens() calls.
*
* @param array $matches Match from preg_replace_callback().
*
* @return string The first available link.
*/
protected function _readTokens($matches)
{
return array_shift($this->_tokens);
}
protected function _autolink($matches)
{
$url = Whups::urlFor('ticket', $matches[2]);
$link = '' . Horde::link($url, 'View ' . $matches[0])
. $matches[0] . '';
$state = $GLOBALS['whups_driver']->getTicketState($matches[2]);
if ($state['state_category'] == 'resolved') {
$link = '' . $link . '';
}
return $link;
}
public function end()
{
echo '
';
}
}
whups-3.0.0beta1/lib/Form/Renderer/Query.php 0000664 0001750 0001750 00000021233 12160315153 016734 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*
* @package Whups
*/
/*class Horde_Form_Renderer_QuerySetCurrentType extends Horde_Form_Renderer {
function _renderForm(&$form, &$vars, $isActive)
{
global $whups_driver;
$droptext = Horde_Core_Ui_VarRenderer_html::selectOptions($whups_driver->getAllTypes());
include WHUPS_TEMPLATES . '/renderer/querysetcurrenttype.inc';
}
function submit()
{
// noop
}
}*/
class Whups_Form_Renderer_Query extends Horde_Form_Renderer
{
public $ticketTypes = null;
public $attributes = null;
function __construct()
{
$this->ticketTypes = $GLOBALS['whups_driver']->getAllTypes();
$this->attributes = $GLOBALS['whups_driver']->getAllAttributes();
}
protected function _renderBegin()
{
echo '
';
}
/**
* @TODO: this is public because the parent:: method is public
*/
public function _renderForm(&$query, &$vars, $active)
{
$this->currentRow = 1;
$this->isActive = $active;
$this->currentPath = $vars->get('path');
$this->_renderBegin();
$query->walk($this, '_renderRow');
$this->_renderEnd();
}
public function edit(&$operations, $formname, $id)
{
include WHUPS_TEMPLATES . '/renderer/query/edit.inc';
}
/**
* @TODO: This must be public, but method name has underscore.
*/
public function _renderRow(&$more, &$path, $type, $criterion, $cvalue, $operator, $value)
{
global $whups_driver, $registry;
$this->currentRow++;
$pathstring = Whups_Query::pathToString($path);
$depth = count($path);
$class = "item" . ($this->currentRow % 2);
switch ($type) {
case Whups_Query::TYPE_AND: $text = _("And"); break;
case Whups_Query::TYPE_OR: $text = _("Or"); break;
case Whups_Query::TYPE_NOT: $text = _("Not"); break;
case Whups_Query::TYPE_CRITERION:
switch ($criterion) {
case Whups_Query::CRITERION_ID: $text = _("Id"); break;
case Whups_Query::CRITERION_OWNERS: $text = _("Owners"); break;
case Whups_Query::CRITERION_GROUPS: $text = _("Groups"); break;
case Whups_Query::CRITERION_REQUESTER: $text = _("Requester"); break;
case Whups_Query::CRITERION_ADDED_COMMENT: $text = _("Commentor"); break;
case Whups_Query::CRITERION_COMMENT: $text = _("Comment"); break;
case Whups_Query::CRITERION_SUMMARY: $text = _("Summary"); break;
case Whups_Query::CRITERION_QUEUE:
$queue = $whups_driver->getQueue($value);
if ($queue) {
$text = _("Queue");
$value = $queue['name'];
}
break;
case Whups_Query::CRITERION_VERSION:
$version = $whups_driver->getVersion($value);
if ($version) {
$text = _("Version");
$value = $version['name'];
}
break;
case Whups_Query::CRITERION_TYPE:
$text = _("Type");
$value = $whups_driver->getTypeName($value);
break;
case Whups_Query::CRITERION_STATE:
// The value of the following depends on the type.
$state = $whups_driver->getState($value);
if ($state && isset($this->ticketTypes[$state['type']])) {
$text = '[' . $this->ticketTypes[$state['type']] . '] ' .
_("State");
$value = $state['name'];
}
break;
case Whups_Query::CRITERION_PRIORITY:
$state = $whups_driver->getPriority($value);
$text = '[' . $this->ticketTypes[$state['type']] . '] ' .
_("Priority");
$value = $state['name'];
break;
case Whups_Query::CRITERION_ATTRIBUTE:
// The value of the following depends on the type.
$aname = $whups_driver->getAttributeName($cvalue);
foreach ($this->attributes as $attribute) {
if ($attribute['attribute_id'] == $cvalue) {
$type = $attribute['type_id'];
break;
}
}
if (isset($this->ticketTypes[$type])) {
$aname .= ' (' . $this->ticketTypes[$type] . ')';
}
$text = sprintf("Attribute \"%s\"", $aname);
break;
case Whups_Query::CRITERION_TIMESTAMP:
$text = _("Created");
$value = strftime($GLOBALS['prefs']->getValue('report_time_format'), $value);
break;
case Whups_Query::CRITERION_UPDATED:
$text = _("Updated");
$value = strftime($GLOBALS['prefs']->getValue('report_time_format'), $value);
break;
case Whups_Query::CRITERION_RESOLVED:
$text = _("Resolved");
$value = strftime($GLOBALS['prefs']->getValue('report_time_format'), $value);
break;
case Whups_Query::CRITERION_ASSIGNED:
$text = _("Assigned");
$value = strftime($GLOBALS['prefs']->getValue('report_time_format'), $value);
break;
case Whups_Query::CRITERION_DUE:
$text = _("Due");
$value = strftime($GLOBALS['prefs']->getValue('report_time_format'), $value);
break;
}
if (!isset($text)) {
$text = sprintf(_("Unknown node type %s"), $type);
break;
}
$text .= ' ';
switch ($operator) {
case Whups_Query::OPERATOR_GREATER:
$text .= _("is greater than");
break;
case Whups_Query::OPERATOR_LESS:
$text .= _("is less than");
break;
case Whups_Query::OPERATOR_EQUAL:
$text .= _("is");
break;
case Whups_Query::OPERATOR_CI_SUBSTRING:
$text .= _("contains (case insensitive) substring");
break;
case Whups_Query::OPERATOR_CS_SUBSTRING:
$text .= _("contains (case sensitive) substring");
break;
case Whups_Query::OPERATOR_WORD:
$text .= _("contains the word");
break;
case Whups_Query::OPERATOR_PATTERN:
$text .= _("matches the pattern");
break;
}
$text .= " $value";
break;
default:
$text = sprintf(_("Unknown node type %s"), $type);
break;
}
// Stick vertical-align: middle; on everything to make it look a
// little nicer.
$fimgattrs = 'height="20" width="0" style="vertical-align: middle;"';
$imgattrs = 'height="20" width="20" style="vertical-align: middle;"';
$space = '';
$count = count($more);
if ($count == 0) {
// Always have at least one image to make sure all rows are the
// same height.
$space = Horde::img('tree/blank.png', '', $fimgattrs) . "\n";
} else {
for ($i = 0; $i < $count - 1; $i++) {
if ($more[$i] == 1) {
$space .= Horde::img('tree/line.png', '|', $imgattrs) . "\n";
} else {
$space .= Horde::img('tree/blank.png', '', $imgattrs) . "\n";
}
}
}
if ($count > 0) {
if ($more[$count - 1] == 1) {
$space .= Horde::img('tree/join.png', '+', $imgattrs) . "\n";
} else {
$space .= Horde::img('tree/joinbottom.png', '-', $imgattrs) . "\n";
}
}
$extra = ($this->isActive ? '' : ' disabled="disabled"');
$extra .= ($pathstring == $this->currentPath ? ' checked="checked"' : '');
include WHUPS_TEMPLATES . '/renderer/query/render.inc';
}
/**
* @TODO: This needs to stay public for now since Horde_Form_Renderer::
* has it as public.
*/
public function _renderEnd()
{
echo '
';
}
}
whups-3.0.0beta1/lib/Form/Ticket/CreateStepFour.php 0000664 0001750 0001750 00000004500 12160315153 020175 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*
* @author Robert E. Coyle
* @package Whups
*/
/**
* @package Whups
*/
class Whups_Form_Ticket_CreateStepFour extends Horde_Form
{
public function __construct(&$vars)
{
global $whups_driver, $conf;
parent::__construct($vars, _("Create Ticket - Step 4"));
/* Preserve previously uploaded attachments. */
$this->addHidden('', 'deferred_attachment', 'text', false);
/* Groups. */
$mygroups = $GLOBALS['injector']
->getInstance('Horde_Group')
->listAll($conf['prefs']['assign_all_groups']
? null
: $GLOBALS['registry']->getAuth());
asort($mygroups);
$users = $whups_driver->getQueueUsers($vars->get('queue'));
$f_users = array();
foreach ($users as $user) {
$f_users['user:' . $user] = Whups::formatUser($user);
}
$f_groups = array();
if (count($mygroups)) {
foreach ($mygroups as $id => $group) {
$f_groups['group:' . $id] = $group;
}
}
if (count($f_users)) {
asort($f_users);
$owners = &$this->addVariable(_("Owners"), 'owners', 'multienum',
false, false, null, array($f_users));
}
if (count($f_groups)) {
asort($f_groups);
$group_owners = &$this->addVariable(_("Group Owners"),
'group_owners', 'multienum',
false, false, null,
array($f_groups));
}
if (!count($f_users) && !count($f_groups)) {
$owner_params = array(
_("There are no users to which this ticket can be assigned."));
$this->addVariable(_("Owners"), 'owners', 'invalid', false, false,
null, $owner_params);
}
}
} whups-3.0.0beta1/lib/Form/Ticket/CreateStepOne.php 0000664 0001750 0001750 00000003303 12160315153 020003 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*
* @author Robert E. Coyle
* @package Whups
*/
/**
* @package Whups
*/
class Whups_Form_Ticket_CreateStepOne extends Horde_Form
{
protected $_useFormToken = false;
public function __construct($vars)
{
global $whups_driver;
parent::__construct($vars, _("Create Ticket - Step 1"));
$queues = Whups::permissionsFilter(
$whups_driver->getQueues(), 'queue', Horde_Perms::EDIT);
if (!$queues) {
$this->addVariable(
_("Queue Name"), 'queue', 'invalid', true, false, null,
array(_("There are no queues which you can create tickets in.")));
} else {
foreach (array_keys($queues) as $queue_id) {
$info = $whups_driver->getQueue($queue_id);
if (!empty($info['description'])) {
$queues[$queue_id] .= ' [' . $info['description'] . ']';
}
}
// Auto-select the only queue if only one option is available
if (count($queues) == 1) {
$vars->set('queue', array_pop(array_keys($queues)));
}
$queues = $this->addVariable(
_("Queue Name"), 'queue', 'enum', true, false, null,
array($queues, _("Choose:")));
$queues->setAction(Horde_Form_Action::factory('submit'));
}
}
} whups-3.0.0beta1/lib/Form/Ticket/CreateStepThree.php 0000664 0001750 0001750 00000011113 12160315153 020327 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*
* @author Robert E. Coyle
* @package Whups
*/
/**
* @package Whups
*/
class Whups_Form_Ticket_CreateStepThree extends Horde_Form
{
public function __construct(&$vars)
{
global $whups_driver, $conf;
parent::__construct($vars, _("Create Ticket - Step 3"));
$states = $whups_driver->getStates($vars->get('type'), 'unconfirmed');
$attributes = $whups_driver->getAttributesForType($vars->get('type'));
$queue = $vars->get('queue');
$info = $whups_driver->getQueue($queue);
if ($GLOBALS['registry']->getAuth()) {
$states2 = $whups_driver->getStates(
$vars->get('type'), array('new', 'assigned'));
if (is_array($states2)) {
$states = $states + $states2;
}
}
if (Whups::hasPermission($queue, 'queue', 'requester')) {
$test = $this->addVariable(
_("The Requester's Email Address"), 'user_email',
'whups:whupsemail', false);
} elseif (!$GLOBALS['registry']->getAuth()) {
$this->addVariable(
_("Your Email Address"), 'user_email', 'email', true);
if (!empty($conf['guests']['captcha'])) {
$this->addVariable(
_("Spam protection"), 'captcha', 'figlet', true, null, null,
array(
Whups::getCAPTCHA(!$this->isSubmitted()),
$conf['guests']['figlet_font']));
}
}
// Silently default the state if there is only one choice
if (count($states) == 1) {
$vars->set('state', reset(array_keys($states)));
$f_state = &$this->addHidden(
_("Ticket State"), 'state', 'enum', true, false, null, array($states));
} else {
$f_state = &$this->addVariable(
_("Ticket State"), 'state', 'enum', true, false, null, array($states));
$f_state->setDefault(
$whups_driver->getDefaultState($vars->get('type')));
}
$f_priority = &$this->addVariable(
_("Priority"), 'priority', 'enum', true, false, null,
array($whups_driver->getPriorities($vars->get('type'))));
$f_priority->setDefault(
$whups_driver->getDefaultPriority($vars->get('type')));
$this->addVariable(_("Due Date"), 'due', 'datetime', false, false);
$this->addVariable(_("Summary"), 'summary', 'text', true, false);
$this->addVariable(_("Attachment"), 'newattachment', 'file', false);
$this->addVariable(_("Description"), 'comment', 'longtext', true);
foreach ($attributes as $attribute_id => $attribute_value) {
$this->addVariable(
$attribute_value['human_name'],
'attributes[' . $attribute_id . ']',
$attribute_value['type'],
$attribute_value['required'],
$attribute_value['readonly'],
$attribute_value['desc'],
$attribute_value['params']);
}
/* Comment permissions. */
$groups = $GLOBALS['injector']->getInstance('Horde_Group');
$mygroups = $groups->listGroups($GLOBALS['registry']->getAuth());
if ($mygroups) {
$mygroups = array(0 => _("This comment is visible to everyone")) + $mygroups;
$v = $this->addVariable(
_("Make this comment visible only to members of a group?"), 'group',
'enum', false, false, null, array($mygroups));
$v->setDefault(0);
}
}
public function validate(&$vars, $canAutoFill = false)
{
global $conf;
if (!parent::validate($vars, $canAutoFill)) {
if (!$GLOBALS['registry']->getAuth() && !empty($conf['guests']['captcha'])) {
$vars->remove('captcha');
$this->removeVariable($varname = 'captcha');
$this->insertVariableBefore(
'state', _("Spam protection"), 'captcha', 'figlet', true,
null, null,
array(Whups::getCAPTCHA(true),
$conf['guests']['figlet_font']));
}
return false;
}
return true;
}
} whups-3.0.0beta1/lib/Form/Ticket/CreateStepTwo.php 0000664 0001750 0001750 00000004324 12160315153 020037 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*
* @author Robert E. Coyle
* @package Whups
*/
/**
* @package Whups
*/
class Whups_Form_Ticket_CreateStepTwo extends Horde_Form
{
protected $_useFormToken = false;
public function __construct(&$vars)
{
global $whups_driver;
parent::__construct($vars, _("Create Ticket - Step 2"));
$types = $whups_driver->getTypes($vars->get('queue'));
$info = $whups_driver->getQueue($vars->get('queue'));
$type = $whups_driver->getDefaultType($vars->get('queue'));
if (count($types) == 0) {
$typetype = 'invalid';
$type_params = array(
_("There are no ticket types associated with this queue; until there are, you cannot create any tickets in this queue."));
} else {
$typetype = 'enum';
$type_params = array($types);
if (empty($type) || !isset($types[$type])) {
$type_params[] = _("Choose:");
}
}
$types = &$this->addVariable(
_("Ticket Type"), 'type', $typetype, true, false, null, $type_params);
$types->setDefault($type);
if (!empty($info['versioned'])) {
$versions = $whups_driver->getVersions($vars->get('queue'));
if (count($versions) == 0) {
$vtype = 'invalid';
$v_params = array(_("This queue requires that you specify a version, but there are no versions associated with it. Until versions are created for this queue, you will not be able to create tickets."));
} else {
$vtype = 'enum';
$v_params = array($versions);
}
$this->addVariable(
_("Queue Version"), 'version', $vtype, true, false, null, $v_params);
} else {
$types->setAction(Horde_Form_Action::factory('submit'));
}
}
}
whups-3.0.0beta1/lib/Form/Ticket/Delete.php 0000664 0001750 0001750 00000002401 12160315153 016502 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*/
class Whups_Form_Ticket_Delete extends Horde_Form
{
protected $_queue;
public function __construct(&$vars, $title = '')
{
parent::__construct($vars, $title);
$info = $GLOBALS['whups_driver']->getTicketDetails($vars->get('id'));
$this->_queue = $info['queue'];
$this->addHidden('', 'id', 'int', true, true);
$summary = &$this->addVariable(_("Summary"), 'summary', 'text', false,
true);
$summary->setDefault($info['summary']);
$yesno = array(0 => _("No"), 1 => _("Yes"));
$this->addVariable(_("Really delete this ticket? It will NOT be archived, and will be gone forever."), 'yesno', 'enum', true, false, null, array($yesno));
}
public function validate(&$vars)
{
if (!Whups::hasPermission($this->_queue, 'queue', Horde_Perms::DELETE)) {
$this->setError('yesno', _("Permission Denied."));
}
return parent::validate($vars);
}
} whups-3.0.0beta1/lib/Form/Ticket/Edit.php 0000664 0001750 0001750 00000021236 12160315153 016174 0 ustar jan jan
* @package Whups
*/
class Whups_Form_Ticket_Edit extends Horde_Form
{
public function __construct(&$vars, &$ticket, $title = '')
{
global $whups_driver;
parent::__construct($vars, $title);
$type = $vars->get('type');
$start_year = date('Y');
if (is_numeric($d = $vars->get('due'))) {
$start_year = min($start_year, date('Y', $d));
}
$fields = array('summary');
$qinfo = $whups_driver->getQueue($vars->get('queue'));
if (!empty($qinfo['versioned'])) {
$fields[] = 'version';
}
$fields = array_merge($fields, array('state', 'priority', 'due'));
try {
$attributes = $ticket->addAttributes();
} catch (Whups_Exception $e) {
$attributes = array();
}
foreach ($attributes as $attribute) {
$fields[] = 'attribute_' . $attribute['id'];
}
$fields = array_merge($fields, array('owner', 'attachments', 'comment'));
$grouped_fields = array($fields);
$grouped_hook = false;
try {
$grouped_fields = Horde::callHook(
'group_fields',
array($ticket->get('type'), $fields),
'whups');
$grouped_hook = true;
} catch (Horde_Exception_HookNotSet $e) {
} catch (Horde_Exception $e) {
Horde::logMessage($e, 'ERR');
}
$this->addHidden('', 'id', 'int', true, true);
$this->addHidden('', 'type', 'int', true, true);
foreach ($grouped_fields as $header => $fields) {
if ($grouped_hook) {
$this->addVariable($header, null, 'header', false);
}
foreach ($fields as $field) {
switch ($field) {
case 'summary':
$this->addVariable(_("Summary"), 'summary', 'text', true);
break;
case 'version':
$versions = $whups_driver->getVersions($vars->get('queue'));
if (count($versions) == 0) {
$vtype = 'invalid';
$v_params = array(_("This queue requires that you specify a version, but there are no versions associated with it. Until versions are created for this queue, you will not be able to create tickets."));
} else {
$vtype = 'enum';
$v_params = array($versions);
}
$this->addVariable(_("Queue Version"), 'version', $vtype, true, false, null, $v_params);
break;
case 'state':
$this->addVariable(
_("State"), 'state', 'enum', true, false, null,
array($whups_driver->getStates($type)));
break;
case 'priority':
$this->addVariable(
_("Priority"), 'priority', 'enum', true, false, null,
array($whups_driver->getPriorities($type)));
break;
case 'due':
$this->addVariable(
_("Due Date"), 'due', 'datetime', false, false, null,
array($start_year));
break;
case 'owner':
if (Whups::hasPermission($vars->get('queue'), 'queue', 'assign')) {
$groups = $GLOBALS['injector']->getInstance('Horde_Group');
$mygroups = $groups->listAll($GLOBALS['conf']['prefs']['assign_all_groups'] ? null : $GLOBALS['registry']->getAuth());
asort($mygroups);
$f_users = array();
$users = $whups_driver->getQueueUsers($vars->get('queue'));
foreach ($users as $user) {
$f_users['user:' . $user] = Whups::formatUser($user);
}
$f_groups = array();
if ($mygroups) {
foreach (array_keys($mygroups) as $id) {
$f_groups['group:' . $id] = $groups->getName($id);
}
}
if (count($f_users)) {
asort($f_users);
$this->addVariable(
_("Owners"),
'owners',
'multienum',
false, false, null,
array($f_users));
}
if (count($f_groups)) {
asort($f_groups);
$this->addVariable(
_("Group Owners"),
'group_owners',
'multienum',
false, false,
null,
array($f_groups));
}
}
break;
case 'attachments':
$this->addVariable(
_("Attachment"), 'newattachment', 'file', false);
break;
case 'comment':
$cvar = &$this->addVariable(
_("Comment"), 'newcomment', 'longtext', false);
/* Form replies. */
try {
$replies = Whups::permissionsFilter(
$whups_driver->getReplies($type), 'reply');
} catch (Whups_Exception $e) {
$replies = array();
}
if (count($replies)) {
$params = array();
foreach ($replies as $key => $reply) {
$params[$key] = $reply['reply_name'];
}
$rvar = &$this->addVariable(
_("Form Reply:"), 'reply', 'enum', false, false,
null, array($params, true));
$rvar->setAction(Horde_Form_Action::factory('reload'));
if ($vars->get('reply')) {
$reply = $vars->get('newcomment');
if (strlen($reply)) {
$reply .= "\n\n";
}
$reply .= $replies[$vars->get('reply')]['reply_text'];
$vars->set('newcomment', $reply);
$vars->remove('reply');
}
}
/* Comment permissions. */
$groups = $GLOBALS['injector']->getInstance('Horde_Group');
$mygroups = $groups->listGroups($GLOBALS['registry']->getAuth());
if ($mygroups) {
foreach (array_keys($mygroups) as $gid) {
$grouplist[$gid] = $groups->getName($gid, true);
}
asort($grouplist);
$grouplist = array(0 => _("This comment is visible to everyone")) + $grouplist;
$this->addVariable(
_("Make this comment visible only to members of a group?"), 'group',
'enum', false, false, null, array($grouplist));
}
break;
default:
/* Ticket attributes. */
if ($ticket &&
substr($field, 0, 10) == 'attribute_' &&
isset($attributes[substr($field, 10)])) {
$attribute = $attributes[substr($field, 10)];
$var = $this->addVariable(
$attribute['human_name'],
'attribute_' . $attribute['id'],
$attribute['type'],
$attribute['required'],
$attribute['readonly'],
$attribute['desc'],
$attribute['params']);
$var->setDefault($attribute['value']);
}
}
}
}
}
public function validate(&$vars)
{
if (!$GLOBALS['registry']->getAuth()) {
$this->setError('_auth', _("Permission Denied."));
}
return parent::validate($vars);
}
}
whups-3.0.0beta1/lib/Form/Type/whupsemail.php 0000644 0001750 0001750 00000000146 12160315153 017156 0 ustar jan jan addHidden('', 'id', 'int', true, true);
if (!$GLOBALS['registry']->getAuth()) {
$this->addVariable(_("Your Email Address"), 'user_email', 'email', true);
if (!empty($conf['guests']['captcha'])) {
$this->addVariable(
_("Spam protection"),
'captcha',
'figlet',
true,
null,
null,
array(Whups::getCAPTCHA(!$this->isSubmitted()),
$conf['guests']['figlet_font']));
}
}
$this->addVariable(_("Comment"), 'newcomment', 'longtext', false);
$this->addVariable(_("Attachment"), 'newattachment', 'file', false);
$this->addVariable(_("Watch this ticket"), 'add_watch', 'boolean', false);
/* Group restrictions. */
if ($GLOBALS['registry']->isAdmin(array('permission' => 'whups:admin')) ||
$GLOBALS['injector']->getInstance('Horde_Perms')->hasPermission('whups:hiddenComments', $GLOBALS['registry']->getAuth(), Horde_Perms::EDIT)) {
$groups = $GLOBALS['injector']->getInstance('Horde_Group');
$mygroups = $groups->listGroups($GLOBALS['registry']->getAuth());
if ($mygroups) {
foreach (array_keys($mygroups) as $gid) {
$grouplist[$gid] = $groups->getName($gid, true);
}
asort($grouplist);
$grouplist = array_merge(array(0 => _("This comment is visible to everyone")), $grouplist);
$this->addVariable(_("Make this comment visible only to members of a group?"), 'group', 'enum', true, false, null, array($grouplist));
}
}
}
public function validate(&$vars, $canAutoFill = false)
{
global $conf;
if (!parent::validate($vars, $canAutoFill)) {
if (!$GLOBALS['registry']->getAuth() && !empty($conf['guests']['captcha'])) {
$vars->remove('captcha');
$this->removeVariable($varname = 'captcha');
$this->insertVariableBefore('newcomment', _("Spam protection"), 'captcha', 'figlet', true, null, null, array(Whups::getCAPTCHA(true), $conf['guests']['figlet_font']));
}
return false;
}
return true;
}
}
whups-3.0.0beta1/lib/Form/AddListener.php 0000664 0001750 0001750 00000001121 12160315153 016251 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*/
class Whups_Form_AddListener extends Horde_Form
{
public function __construct(&$vars, $title = '')
{
parent::__construct($vars, $title);
$this->addHidden('', 'id', 'int', true, true);
$this->addVariable(_("Email address to notify"), 'add_listener', 'email', true);
}
}
whups-3.0.0beta1/lib/Form/DeleteListener.php 0000664 0001750 0001750 00000001123 12160315153 016765 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*/
class Whups_Form_DeleteListener extends Horde_Form
{
public function __construct(&$vars, $title = '')
{
parent::__construct($vars, $title);
$this->addHidden('', 'id', 'int', true, true);
$this->addVariable(_("Email address to remove"), 'del_listener', 'email', true);
}
}
whups-3.0.0beta1/lib/Form/InsertBranch.php 0000664 0001750 0001750 00000001673 12160315153 016451 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*
* @author Robert E. Coyle
* @author Jan Schneider
* @package Whups
*/
class Whups_Form_InsertBranch extends Horde_Form
{
public function __construct(&$vars)
{
parent::__construct($vars, _("Insert Branch"));
$branchtypes = array(
Whups_Query::TYPE_AND => _("And"),
Whups_Query::TYPE_OR => _("Or"),
Whups_Query::TYPE_NOT => _("Not"));
$this->addHidden(null, 'path', 'text', false, true);
$this->addVariable(
_("Branch Type"), 'type', 'enum', true, false, null, array($branchtypes));
}
}
whups-3.0.0beta1/lib/Form/Search.php 0000664 0001750 0001750 00000013335 12160315153 015272 0 ustar jan jan
* @package Whups
*/
class Whups_Form_Search extends Horde_Form
{
protected $_useFormToken = false;
public function __construct(&$vars)
{
parent::__construct($vars);
$this->setButtons(true);
$this->appendButtons(array(array('class' => 'horde-create', 'value' => _("Save as Query"))));
$this->setSection('attributes', _("Attributes"));
$queues = Whups::permissionsFilter(
$GLOBALS['whups_driver']->getQueues(), 'queue', Horde_Perms::READ);
$queue_count = count($queues);
$types = array();
if ($queue_count == 1) {
$types = $GLOBALS['whups_driver']->getTypes(key($queues));
$this->addHidden('', 'queue', 'int', false, true);
$vars->set('queue', key($queues));
} else {
if ($queue_count > 0) {
$modtype = 'enum';
$queue_params = array(array('0' => _("Any")) + $queues);
foreach ($queues as $queueID => $name) {
$types = $types + $GLOBALS['whups_driver']->getTypes($queueID);
}
} else {
$modtype = 'invalid';
$queue_params = array(_("There are no queues which you can search."));
}
$this->addVariable(
_("Queue"), 'queue', $modtype, false, false, null, $queue_params);
}
$this->addVariable(_("Summary like"), 'summary', 'text', false);
$states = array();
foreach ($types as $typeID => $typeName) {
$states = $GLOBALS['whups_driver']->getAllStateInfo($typeID);
$list = $default = array();
foreach ($states as $state) {
$list[$state['state_id']] = $state['state_name'];
if ($state['state_category'] != 'resolved') {
$default[] = $state['state_id'];
}
}
$v = $this->addVariable(
$typeName, "states[$typeID]", 'multienum', false, false, null,
array ($list, 4));
if (!$this->isSubmitted()) {
$v->setDefault($default);
}
}
$this->setSection('dates', _("Dates"));
$this->addVariable(
_("Created from"), 'ticket_timestamp[from]', 'monthdayyear', false,
false, null, array(date('Y') - 10));
$this->addVariable(
_("to"), 'ticket_timestamp[to]', 'monthdayyear', false, false, null,
array(date('Y') - 10));
$this->addVariable(
_("Updated from"), 'date_updated[from]', 'monthdayyear', false,
false, null, array(date('Y') - 10));
$this->addVariable(
_("to"), 'date_updated[to]', 'monthdayyear', false, false, null,
array(date('Y') - 10));
$this->addVariable(
_("Resolved from"), 'date_resolved[from]', 'monthdayyear', false,
false, null, array(date('Y') - 10));
$this->addVariable(
_("to"), 'date_resolved[to]', 'monthdayyear', false, false, null,
array(date('Y') - 10));
$this->addVariable(
_("Assigned from"), 'date_assigned[from]', 'monthdayyear', false,
false, null, array(date('Y') - 10));
$this->addVariable(
_("to"), 'date_assigned[to]', 'monthdayyear', false, false, null,
array(date('Y') - 10));
$this->addVariable(
_("Due from"), 'ticket_due[from]', 'monthdayyear', false, false,
null, array(date('Y') - 10));
$this->addVariable(
_("to"), 'ticket_due[to]', 'monthdayyear', false, false, null,
array(date('Y') - 10));
}
/**
* Fetch the field values of the submitted form.
*
* @param Horde_Variables $vars A Horde_Variables instance, optional since Horde 3.2.
* @param array $info Array to be filled with the submitted field
* values.
*/
public function getInfo($vars, &$info)
{
parent::getInfo($vars, $info);
if (empty($info['queue'])) {
$info['queue'] = array_keys(
Whups::permissionsFilter(
$GLOBALS['whups_driver']->getQueues(),
'queue',
Horde_Perms::READ,
$GLOBALS['registry']->getAuth(),
$GLOBALS['registry']->getAuth()));
} else {
$info['queue'] = array($info['queue']);
}
if (empty($info['states'])) {
unset($info['states']);
}
// ... if we were given a set of states
if (isset($info['states'])) {
// collect them into a list of state_id
$info['state_id'] = array();
foreach ($info['states'] as $states) {
if (isset($states)) {
// because null === array_merge(array, null)
$info['state_id'] = array_merge($info['state_id'], $states);
}
}
unset($info['states']);
}
// Remove any queues that don't have a state selected.
$types = array();
foreach ($info['queue'] as $queue) {
foreach ($GLOBALS['whups_driver']->getTypeIds($queue) as $type) {
$types[$type][$queue] = true;
}
}
$queues = array();
foreach ($info['state_id'] as $stateId) {
$state = $GLOBALS['whups_driver']->getState($stateId);
if (isset($types[$state['type']])) {
$queues = array_merge($queues, array_keys($types[$state['type']]));
}
}
$info['queue'] = array_intersect($info['queue'], $queues);
}
}
whups-3.0.0beta1/lib/Form/SendReminder.php 0000664 0001750 0001750 00000003443 12160315153 016443 0 ustar jan jan
* @package Whups
*/
class Whups_Form_SendReminder extends Horde_Form
{
public function __construct(&$vars)
{
global $whups_driver;
parent::__construct($vars, _("Send Reminders"));
$queues = Whups::permissionsFilter(
$whups_driver->getQueues(), 'queue', Horde_Perms::EDIT);
if (count($queues)) {
$modtype = 'enum';
$type_params = array($queues);
} else {
$modtype = 'invalid';
$type_params = array(_("There are no queues available."));
}
$this->addVariable(
_("Send only for this list of ticket ids"), 'id', 'intlist', false);
$this->addVariable(
_("For tickets from these queues"),
'queue',
$modtype,
false,
false,
null,
$type_params);
$cats = $whups_driver->getCategories();
unset($cats['resolved']);
$categories = &$this->addVariable(
_("For tickets which are"), 'category', 'multienum', false, false, null, array($cats, 3));
$categories->setDefault(array('assigned'));
$this->addVariable(
_("Unassigned tickets"),
'unassigned',
'email',
false,
false,
_("If you select any tickets that do not have an owner, who should we send email to?"));
}
}
whups-3.0.0beta1/lib/Form/SetTypeStepOne.php 0000664 0001750 0001750 00000002623 12160315153 016756 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*/
class Whups_Form_SetTypeStepOne extends Horde_Form
{
public function __construct(&$vars, $title = '')
{
global $whups_driver;
parent::__construct($vars, $title);
$this->addHidden('', 'id', 'int', true, true);
/* Types */
$queue = $vars->get('queue');
$this->addVariable(_("New Type"), 'type', 'enum', true, false, null, array($whups_driver->getTypes($queue)));
$this->addVariable(_("Comment"), 'newcomment', 'longtext', false);
/* Group restrictions. */
$groups = $GLOBALS['injector']->getInstance('Horde_Group');
$mygroups = $groups->listGroups($GLOBALS['registry']->getAuth());
if ($mygroups) {
foreach (array_keys($mygroups) as $gid) {
$grouplist[$gid] = $groups->getName($gid, true);
}
asort($grouplist);
$grouplist = array_merge(array(0 => _("Any Group")), $grouplist);
$this->addVariable(_("Viewable only by members of"), 'group', 'enum', true, false, null, array($grouplist));
}
}
} whups-3.0.0beta1/lib/Form/SetTypeStepTwo.php 0000664 0001750 0001750 00000002124 12160315153 017002 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*/
class Whups_Form_SetTypeStepTwo extends Horde_Form
{
public function __construct(&$vars, $title = '')
{
global $whups_driver;
parent::__construct($vars, $title);
$this->addHidden('', 'id', 'int', true, false);
$this->addHidden('', 'group', 'int', false, false);
$this->addHidden('', 'type', 'int', true, false);
$this->addHidden('', 'newcomment', 'longtext', false, false);
/* Give user an opportunity to check that state and priority
* are still valid. */
$type = $vars->get('type');
$this->addVariable(_("State"), 'state', 'enum', true, false, null, array($whups_driver->getStates($type)));
$this->addVariable(_("Priority"), 'priority', 'enum', true, false, null, array($whups_driver->getPriorities($type)));
}
} whups-3.0.0beta1/lib/Form/TicketDetails.php 0000664 0001750 0001750 00000014074 12160315153 016617 0 ustar jan jan getValue('date_format'));
$fields = array('summary', 'queue', 'version', 'type', 'state',
'priority', 'owner', 'requester', 'created', 'due',
'updated', 'assigned', 'resolved', 'attachments');
try {
$attributes = $ticket->addAttributes();
} catch (Whups_Exception $e) {
$attributes = array();
}
foreach ($attributes as $attribute) {
$fields[] = 'attribute_' . $attribute['id'];
}
$grouped_fields = array($fields);
$grouped_hook = false;
try {
$grouped_fields = Horde::callHook(
'group_fields', array($ticket->get('type'), $fields), 'whups');
$grouped_hook = true;
} catch (Horde_Exception_HookNotSet $e) {
} catch (Horde_Exception $e) {
Horde::logMessage($e, 'ERR');
}
foreach ($grouped_fields as $header => $fields) {
if ($grouped_hook) {
$this->addVariable($header, null, 'header', false);
}
foreach ($fields as $field) {
switch ($field) {
case 'summary':
$this->addVariable(_("Summary"), 'summary', 'text', true);
break;
case 'queue':
if ($vars->get('queue_link')) {
$this->addVariable(
_("Queue"), 'queue_link', 'link', true, false, null,
array(
array(
'url' => $vars->get('queue_link'),
'text' => $vars->get('queue_name'))));
} else {
$this->addVariable(
_("Queue"), 'queue_name', 'text', true);
}
break;
case 'version':
if ($vars->get('version_name')) {
if ($vars->get('version_link')) {
$this->addVariable(
_("Queue Version"), 'version_name', 'link',
true, false, null,
array(
array(
'url' => $vars->get('version_link'),
'text' => $vars->get('version_name'))));
} else {
$this->addVariable(
_("Queue Version"), 'version_name', 'text', true);
}
}
break;
case 'type':
$this->addVariable(_("Type"), 'type_name', 'text', true);
break;
case 'state':
$this->addVariable(_("State"), 'state_name', 'text', true);
break;
case 'priority':
$this->addVariable(
_("Priority"), 'priority_name', 'text', true);
break;
case 'owner':
$owner = $this->addVariable(
_("Owners"), 'user_id_owner', 'email', false, false,
null, array(false, true));
$owner->setDefault(_("Unassigned"));
break;
case 'requester':
$this->addVariable(
_("Requester"), 'user_id_requester', 'email', false,
false, null, array(false, true));
break;
case 'created':
$this->addVariable(
_("Created"), 'timestamp', 'date', false, false, null,
$date_params);
break;
case 'due':
$this->addVariable(
_("Due"), 'due', 'datetime', false, false, null,
$date_params);
break;
case 'updated':
$this->addVariable(
_("Updated"), 'date_updated', 'date', false, false,
null, $date_params);
break;
case 'assigned':
$this->addVariable(
_("Assigned"), 'date_assigned', 'date', false, false,
null, $date_params);
break;
case 'resolved':
$this->addVariable(
_("Resolved"), 'date_resolved', 'date', false, false,
null, $date_params);
break;
case 'attachments':
$this->addVariable(
_("Attachments"), 'attachments', 'html', false);
break;
default:
if (substr($field, 0, 10) == 'attribute_' &&
isset($attributes[substr($field, 10)])) {
$attribute = $attributes[substr($field, 10)];
if (!$attribute['params']) {
$attribute['params'] = array();
}
$this->attributes[$attribute['id']] = $this->addVariable(
$attribute['human_name'],
'attribute_' . $attribute['id'],
$attribute['type'], $attribute['required'],
$attribute['readonly'], $attribute['desc'],
$attribute['params']);
$this->attributes[$attribute['id']]->setDefault($attribute['value']);
}
break;
}
}
}
}
}
whups-3.0.0beta1/lib/LoginTasks/SystemTask/Upgrade.php 0000664 0001750 0001750 00000004201 12160315153 020726 0 ustar jan jan
* @category Horde
* @license http://www.horde.org/licenses/bsdl.php BSDL
* @package Whups
*/
class Whups_LoginTasks_SystemTask_Upgrade extends Horde_Core_LoginTasks_SystemTask_Upgrade
{
/**
*/
protected $_app = 'whups';
/**
*/
protected $_versions = array(
'2.0'
);
/**
*/
protected function _upgrade($version)
{
switch ($version) {
case '2.0':
$this->_upgradeAbookPrefs();
$this->_upgradeLayout();
break;
}
}
/**
* Upgrade to the new addressbook preferences.
*/
protected function _upgradeAbookPrefs()
{
global $prefs;
if (!$prefs->isDefault('search_sources')) {
$src = $prefs->getValue('search_sources');
if (!is_array(json_decode($src))) {
$prefs->setValue('search_sources', json_encode(explode("\t", $src)));
}
}
if (!$prefs->isDefault('search_fields')) {
$val = $prefs->getValue('search_fields');
if (!is_array(json_decode($val, true))) {
$fields = array();
foreach (explode("\n", $val) as $field) {
$field = trim($field);
if (!empty($field)) {
$tmp = explode("\t", $field);
if (count($tmp) > 1) {
$source = array_splice($tmp, 0, 1);
$fields[$source[0]] = $tmp;
}
}
}
$prefs->setValue('search_fields', $fields);
}
}
}
/**
* Upgrade mybugs_layout preference.
*/
protected function _upgradeLayout()
{
$bu = new Horde_Core_Block_Upgrade();
$bu->upgrade('mybugs_layout');
}
}
whups-3.0.0beta1/lib/Mime/Viewer/Zip.php 0000664 0001750 0001750 00000007130 12160315153 016050 0 ustar jan jan
* @author Michael Slusarz
* @author Jan Schneider
* @package Horde_MIME_Viewer
*/
class Whups_Mime_Viewer_zip extends Horde_Mime_Viewer_Zip
{
/**
* Return the full rendered version of the Horde_Mime_Part object.
*
* URL parameters used by this function:
*
* 'zip_attachment' - (integer) The ZIP attachment to download.
*
*
* @return array See parent::render().
*/
protected function _render()
{
if (!($zip_atc = Horde_Util::getFormData('zip_attachment'))) {
$this->_callback = array($this, '_whupsCallback');
return parent::_render();
}
/* Send the requested file. Its position in the zip archive is located
* in 'zip_attachment'. */
$data = $this->_mimepart->getContents();
if (!($zip = $this->getConfigParam('zip'))) {
$zip = Horde_Compress::factory('zip');
$this->setConfigParam('zip', $zip);
}
$fileKey = $zip_atc - 1;
$zipInfo = $zip->decompress($data, array(
'action' => Horde_Compress_Zip::ZIP_LIST
));
/* Verify that the requested file exists. */
if (isset($zipInfo[$fileKey])) {
$text = $zip->decompress($data, array(
'action' => Horde_Compress_Zip::ZIP_DATA,
'info' => &$zipInfo,
'key' => $fileKey
));
if (!empty($text)) {
return array(
$this->_mimepart->getMimeId() => array(
'data' => $text,
'name' => basename($zipInfo[$fileKey]['name']),
'status' => array(),
'type' => 'application/octet-stream'
)
);
}
}
// TODO: Error reporting
return array();
}
/**
* Return the rendered inline version of the Horde_Mime_Part object.
*
* @return array See parent::render().
*/
protected function _renderInfo()
{
$this->_callback = array($this, '_whupsCallback');
return parent::_renderInfo();
}
/**
* The function to use as a callback to _toHTML().
*
* @param integer $key The position of the file in the zip archive.
* @param array $val The information array for the archived file.
*
* @return string The content-type of the output.
*/
protected function _whupsCallback($key, $val)
{
$name = preg_replace('/( )+$/', '', $val['name']);
if (!empty($val['size']) && (strstr($val['attr'], 'D') === false) &&
((($val['method'] == 0x8) && Horde_Util::extensionExists('zlib')) ||
($val['method'] == 0x0))) {
$mime_part = $this->_mimepart;
$mime_part->setName(basename($name));
$val['name'] = str_replace($name, Horde::url('view.php')->add(array('actionID' => 'view_file', 'type' => Horde_Util::getFormData('type'), 'file' => Horde_Util::getFormData('file'), 'ticket' => Horde_Util::getFormData('ticket'), 'zip_attachment' => $key + 1))->link() . $name . '', $val['name']);
}
return $val;
}
}
whups-3.0.0beta1/lib/Prefs/Special/Sourceselect.php 0000664 0001750 0001750 00000002657 12160315153 020266 0 ustar jan jan
* @category Horde
* @license http://www.horde.org/licenses/gpl GPL
* @package Kronolith
*/
class Whups_Prefs_Special_Sourceselect implements Horde_Core_Prefs_Ui_Special
{
/**
*/
public function init(Horde_Core_Prefs_Ui $ui)
{
Horde_Core_Prefs_Ui_Widgets::addressbooksInit();
}
/**
*/
public function display(Horde_Core_Prefs_Ui $ui)
{
$search = Whups::getAddressbookSearchParams();
return Horde_Core_Prefs_Ui_Widgets::addressbooks(array(
'fields' => $search['fields'],
'sources' => $search['sources']
));
}
/**
*/
public function update(Horde_Core_Prefs_Ui $ui)
{
global $prefs;
$data = Horde_Core_Prefs_Ui_Widgets::addressbooksUpdate($ui);
$updated = false;
if (isset($data['sources'])) {
$prefs->setValue('search_sources', $data['sources']);
$updated = true;
}
if (isset($data['fields'])) {
$prefs->setValue('search_fields', $data['fields']);
$updated = true;
}
return $updated;
}
}
whups-3.0.0beta1/lib/Query/Manager.php 0000664 0001750 0001750 00000013767 12160315153 015652 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*
* @author Robert E. Coyle
* @author Jan Schneider
* @package Whups
*/
class Whups_Query_Manager
{
/**
* Horde_Share instance for managing shares.
*
* @var Horde_Share
*/
protected $_shareManager;
/**
* Constructor.
*
* @TODO: inject the share driver
*/
public function __construct()
{
$this->_shareManager =
$GLOBALS['injector']->getInstance('Horde_Core_Factory_Share')->create();
}
/**
* Returns a specific query identified by its id.
*
* @param integer $queryId A query id.
*
* @return Whups_Query The matching query or null if not found.
* @throws Whups_Exception
*/
public function getQuery($queryId)
{
try {
$share = $this->_shareManager->getShareById($queryId);
} catch (Horde_Exception_NotFound $e) {
throw new Whups_Exception($e);
}
return $this->_getQuery($share);
}
/**
* Returns a specific query identified by its slug name.
*
* @param string $slug A query slug.
*
* @return Whups_Query The matching query or null if not found.
* @throws Whups_Exception
*/
public function getQueryBySlug($slug)
{
try {
$shares = $this->_shareManager->listShares(
$GLOBALS['registry']->getAuth(),
array('perm' => Horde_Perms::READ,
'attributes' => array('slug' => $slug)));
} catch (Horde_Share_Exception $e) {
throw new Whups_Exception($e);
}
if (!count($shares)) {
return;
}
return $this->_getQuery(reset($shares));
}
/**
* Builds a query object from a share object.
*
* @param Horde_Share_Object $share A share object representing a query.
*
* @return Whups_Query The query object built from the share.
*/
protected function _getQuery(Horde_Share_Object $share)
{
$queryDetails = $GLOBALS['whups_driver']->getQuery($share->getId());
$queryDetails['query_id'] = $share->getId();
$queryDetails['query_name'] = $share->get('name');
$queryDetails['query_slug'] = $share->get('slug');
return new Whups_Query($this, $queryDetails);
}
/**
* Checks to see if a user has a given permission to $queryId.
*
* @param integer $queryId The query to check.
* @param string $userid The userid of the user.
* @param integer $permission A Horde_Perms::* constant to test for.
* @param string $creator The creator of the event.
*
* @return boolean Whether or not $userid has $permission.
*/
public function hasPermission($queryId, $userid, $permission, $creator = null)
{
try {
$share = $this->_shareManager->getShareById($queryId);
} catch (Horde_Exception_NotFound $e) {
// If the share doesn't exist yet, then it has open perms.
return true;
}
return $share->hasPermission($userid, $permission, $creator);
}
/**
* List queries.
*/
public function listQueries($user, $return_slugs = false)
{
try {
$shares = $this->_shareManager->listShares($user);
} catch (Horde_Share_Exception $e) {
throw new Whups_Exception($e);
}
$queries = array();
foreach ($shares as $share) {
$queries[$share->getId()] = $return_slugs
? array('name' => $share->get('name'),
'slug' => $share->get('slug'))
: $share->get('name');
}
return $queries;
}
/**
*/
public function newQuery()
{
return new Whups_Query($this);
}
/**
* @param Whups_Query $query The query to save.
* @throws Whups_Exception
*/
public function save(Whups_Query $query)
{
if ($query->id) {
// Query already exists; get its share and update the name
// if necessary.
try {
$share = $this->_shareManager->getShareById($query->id);
} catch (Horde_Exception_NotFound $e) {
// Share has an id but doesn't exist; just throw an
// error.
throw new Whups_Exception($e);
}
if ($share->get('name') != $query->name ||
$share->get('slug') != $query->slug) {
$share->set('name', $query->name);
$share->set('slug', $query->slug);
$share->save();
}
} else {
// Create a new share for the query.
$share = $this->_shareManager->newShare($GLOBALS['registry']->getAuth(), (string)new Horde_Support_Uuid(), $query->name);
$share->set('slug', $query->slug);
try {
$this->_shareManager->addShare($share);
} catch (Horde_Share_Exception $e) {
throw new Whups_Exception($e);
}
$query->id = $share->getId();
}
// Update the queries table.
$GLOBALS['whups_driver']->saveQuery($query);
}
/**
* @param Whups_Query $query The query to delete.
*/
public function delete(Whups_Query $query)
{
if (!$query->id) {
// Queries that aren't saved yet shouldn't be able to be deleted.
return;
}
try {
$share = $this->_shareManager->getShareById($query->id);
$this->_shareManager->removeShare($share);
} catch (Exception $e) {
throw new Whups_Exception($e);
}
$GLOBALS['whups_driver']->deleteQuery($query->id);
}
} whups-3.0.0beta1/lib/tests/ApiTest.php 0000664 0001750 0001750 00000001264 12160315153 015673 0 ustar jan jan
* @package Whups
* @subpackage UnitTests
*/
class Whups_ApiTest Extends Whups_TestBase {
function setUp()
{
parent::setUp();
require_once WHUPS_BASE . '/lib/api.php';
}
function test_listQueues_returns_hash()
{
$GLOBALS['perms'] = new Whups_Test_Perms();
$result = _whups_listQueues();
// Validate the results
$this->assertEquals('queue one', $result[1]);
$this->assertEquals('queue three', $result[3]);
}
}
whups-3.0.0beta1/lib/tests/TestBase.php 0000664 0001750 0001750 00000004154 12160315153 016035 0 ustar jan jan
* @package Whups
* @subpackage UnitTests
*/
class Whups_TestBase Extends PHPUnit_Framework_TestCase {
function setUp()
{
require_once __DIR__ . '/../Application.php';
Horde_Registry::appInit('whups', array('cli' => true));
}
/**
* Asserts that the supplied result is not a PEAR_Error
*
* Fails with a descriptive message if so
* @param mixed $result The value to check
* @return boolean Whether the assertion was successful
*/
function assertOk($result)
{
if (is_a($result, 'DB_Error')) {
$this->fail($result->getDebugInfo());
return false;
} elseif (is_a($result, 'PEAR_Error')) {
$this->fail($result->getMessage());
return false;
}
return true;
}
}
class Whups_Driver_sql {
var $_queues = array(
array('queue_id' => 1,
'queue_name' => 'queue one',
'queue_description' => 'queue one description',
'queue_versioned' => 1),
array('queue_id' => 3,
'queue_name' => 'queue three',
'queue_description' => 'queue three description',
'queue_versioned' => 0));
function initialise()
{
return true;
}
function getQueuesInternal()
{
foreach ($this->_queues as $queue) {
$q[$queue['queue_id']] = $queue['queue_name'];
}
return $q;
}
}
/**
* Permissions class to use when we need to pretend we are checking permissions
*
* Must instantiate it, then overwrite the global $perms object before calling
* any method that needs to check permissions.
*/
class Whups_Test_Perms {
function getPermissions($permission, $user = null, $creator = null)
{
return true;
}
function exists($permission)
{
return true;
}
function hasPermission($permission, $user, $perm, $creator = null)
{
return true;
}
}
whups-3.0.0beta1/lib/Ui/VarRenderer/Whups.php 0000664 0001750 0001750 00000002575 12160315153 017070 0 ustar jan jan
* @package Whups
*/
/**
* The Horde_Core_Ui_VarRenderer_whups class provides additional methods for
* rendering Whups_Form_Type_whupsemail fields.
*
* @author Jan Schneider
* @package Whups
*/
class Horde_Core_Ui_VarRenderer_whups extends Horde_Core_Ui_VarRenderer_Html {
function _renderVarInput_whups_form_type_whupsemail($form, &$var, &$vars)
{
$name = $var->getVarName();
$GLOBALS['injector']->getInstance('Horde_Core_Factory_Imple')->create('Whups_Ajax_Imple_ContactAutoCompleter', array(
'triggerId' => $name
));
return sprintf('',
$name,
$name,
@htmlspecialchars($var->getValue($vars)),
$this->_getActionScripts($form, $var))
. ''
. Horde::img('loading.gif', _("Loading..."))
. '';
}
}
whups-3.0.0beta1/lib/View/Base.php 0000664 0001750 0001750 00000000655 12160315153 014747 0 ustar jan jan
* @package Whups
*/
abstract class Whups_View_Base
{
protected $_params;
public function __construct($params)
{
$this->_params = $params;
if (!isset($this->_params['title'])) {
$this->_params['title'] = '';
}
}
abstract public function html();
}
whups-3.0.0beta1/lib/View/Results.php 0000775 0001750 0001750 00000002043 12160315153 015532 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* @author Robert E. Coyle
* @author Michael J. Rubinsky
* @package Whups
*/
class Whups_View_Results extends Whups_View_Base
{
protected $_id;
public function __construct($params)
{
parent::__construct($params);
$this->_id = uniqid(mt_rand());
}
public function html()
{
$GLOBALS['page_output']->addScriptFile('tables.js', 'horde');
global $prefs, $registry, $session;
$sortby = $prefs->getValue('sortby');
$sortdir = $prefs->getValue('sortdir');
$sortdirclass = $sortdir ? 'sortup' : 'sortdown';
$ids = array();
foreach ($this->_params['results'] as $info) {
$ids[] = $info['id'];
}
$session->set('whups', 'tickets', $ids);
include WHUPS_TEMPLATES . '/view/results.inc';
}
}
whups-3.0.0beta1/lib/View/SavedQueries.php 0000775 0001750 0001750 00000001266 12160315153 016477 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*
* @author Chuck Hagenbuch
* @author Michael J. Rubinsky
* @package Whups
*/
class Whups_View_SavedQueries extends Whups_View_Base
{
// Need title, results in params.
public function html($header = true)
{
if (!count($this->_params['results'])) {
return;
}
include WHUPS_TEMPLATES . '/view/savedqueries.inc';
}
}
whups-3.0.0beta1/lib/.htaccess 0000644 0001750 0001750 00000000016 12160315153 014235 0 ustar jan jan Deny from all
whups-3.0.0beta1/lib/Api.php 0000664 0001750 0001750 00000060436 12160315153 013677 0 ustar jan jan array(
'name' => _("Queues"),
'icon' => Horde_Themes::img('whups.png'),
'browseable' => count(
Whups::permissionsFilter($whups_driver->getQueues(),
'queue', Horde_Perms::READ))));
} else {
$path = explode('/', $path);
Horde::logMessage(var_export($path, true), 'INFO');
$results = array();
switch ($path[0]) {
case 'queue':
$queues = Whups::permissionsFilter($whups_driver->getQueues(),
'queue', Horde_Perms::SHOW);
if (count($path) == 1) {
foreach ($queues as $queue => $name) {
$results['whups/queue/' . $queue] = array(
'name' => sprintf(_("Tickets from %s"), $name),
'browseable' => true);
}
} else {
if (!Whups::hasPermission($queues[$path[1]], 'queue',
Horde_Perms::READ)) {
throw new Horde_Exception_PermissionDenied();
}
$tickets = $whups_driver->getTicketsByProperties(
array('queue' => $path[1]));
foreach ($tickets as $ticket) {
$results['whups/queue/' . $path[1] . '/' . $ticket['id']] = array(
'name' => $ticket['summary'],
'browseable' => false);
}
}
break;
}
}
return $results;
}
/**
* Create a new queue.
*
* @param string $name The queue's name.
*
* @return integer The new queue id.
*/
public function addQueue($name)
{
if ($GLOBALS['registry']->isAdmin(array('permission' => 'whups:admin'))) {
return $GLOBALS['whups_driver']->addQueue($name, '');
}
throw new Horde_Exception_PermissionDenied('You must be an administrator to perform this action.');
}
/**
* Return the ids of all open tickets assigned to the current user.
*
* @return array Array of ticket ids.
*/
public function getAssignedTicketIds()
{
global $whups_driver;
$info = array('owner' => 'user:' . $GLOBALS['registry']->getAuth(), 'nores' => true);
$tickets = $whups_driver->getTicketsByProperties($info);
$result = array();
foreach ($tickets as $ticket) {
$result[] = $ticket['id'];
}
return $result;
}
/**
* Return the ids of all open tickets that the current user created.
*
* @return array Array of ticket ids.
*/
public function getRequestedTicketIds()
{
global $whups_driver;
$info = array('requester' => $GLOBALS['registry']->getAuth(), 'nores' => true);
$tickets = $whups_driver->getTicketsByProperties($info);
$result = array();
foreach ($tickets as $ticket) {
$result[] = (int) $ticket['id'];
}
return $result;
}
/**
* Create a new ticket.
*
* @param array $ticket_info An array of form variables representing all of the
* data collected by CreateStep1Form, CreateStep2Form, CreateStep3Form, and
* optionally CreateStep4Form.
*
* @return integer The new ticket id.
*/
public function addTicket($ticket_info)
{
global $whups_driver;
if (!is_array($ticket_info)) {
throw new Whups_Exception('Invalid arguments');
}
$vars = new Horde_Variables($ticket_info);
$form1 = new Whups_Form_Ticket_CreateStepOne($vars);
$form2 = new Whups_Form_Ticket_CreateStepTwo($vars);
$form3 = new Whups_Form_Ticket_CreateStepThree($vars);
// FIXME: This is an almighty hack, but we can't have form
// tokens in rpc calls.
$form1->useToken(false);
$form2->useToken(false);
$form3->useToken(false);
// Complain if we've been given bad parameters.
if (!$form1->validate($vars, true)) {
$f1 = var_export($form1->getErrors(), true);
throw new Whups_Exception("Invalid arguments ($f1)");
}
if (!$form2->validate($vars, true)) {
$f2 = var_export($form2->getErrors(), true);
throw new Whups_Exception("Invalid arguments ($f2)");
}
if (!$form3->validate($vars, true)) {
$f3 = var_export($form3->getErrors(), true);
throw new Whups_Exception("Invalid arguments ($f3)");
}
$form1->getInfo($vars, $info);
$form2->getInfo($vars, $info);
$form3->getInfo($vars, $info);
// More checks if we're assigning the ticket at create-time.
if ($GLOBALS['registry']->getAuth() && $whups_driver->isCategory('assigned', $vars->get('state'))) {
$form4 = new Whups_Form_Ticket_CreateStep4Form($vars);
}
if ($GLOBALS['registry']->getAuth() && $whups_driver->isCategory('assigned', $vars->get('state'))) {
$form4 = new Whups_Form_Ticket_CreateStep4Form($vars);
$form4->useToken(false);
if (!$form4->validate($vars, true)) {
throw new Whups_Exception('Invalid arguments (' . var_export($form4->getErrors(), true) . ')');
}
$form4->getInfo($vars, $info);
}
$ticket = Whups_Ticket::newTicket($info, $GLOBALS['registry']->getAuth());
return $ticket->getId();
}
/**
* Update a ticket's properties.
*
* @param integer $ticket_id The id of the id to changes.
* @param array $ticket_info The attributes to set, from the EditTicketForm.
*
* @return boolean True
*/
public function updateTicket($ticket_id, $ticket_info)
{
global $whups_driver;
// Cast as an int for safety.
$ticket = Whups_Ticket::makeTicket((int)$ticket_id);
// Check that we have permission to update the ticket
if (!$GLOBALS['registry']->getAuth() ||
!Whups::hasPermission($ticket->get('queue'), 'queue', 'update')) {
throw new Whups_Exception_PermissionDenied(_('You do not have permission to update this ticket.'));
}
// Populate $vars with existing ticket details.
$vars = new Horde_Variables();
$ticket->setDetails($vars);
// Copy new ticket details in.
foreach ($ticket_info as $detail => $newval) {
$vars->set($detail, $newval);
}
// Create and populate the EditTicketForm for validation. API calls can't
// use form tokens and aren't the result of the EditTicketForm being
// submitted.
$editform = new Whups_Form_Ticket_Edit($vars, null, $ticket);
$editform->useToken(false);
$editform->setSubmitted(true);
// Attempt to validate and update the ticket.
if (!$editform->validate($vars)) {
$form_errors = var_export($editform->getErrors(), true);
throw new Whups_Exception(sprintf(_("Invalid ticket data supplied: %s"), $form_errors));
}
$editform->getInfo($vars, $info);
$ticket->change('summary', $info['summary']);
$ticket->change('state', $info['state']);
$ticket->change('priority', $info['priority']);
if (!empty($info['newcomment'])) {
$ticket->change('comment', $info['newcomment']);
}
// Update attributes.
$whups_driver->setAttributes($info);
// Add attachment if one was uploaded.
if (!empty($info['newattachment']['name'])) {
$ticket->change('attachment',
array('name' => $info['newattachment']['name'],
'tmp_name' => $info['newattachment']['tmp_name']));
}
// If there was a new comment and permissions were specified on
// it, set them.
if (!empty($info['group'])) {
$ticket->change('comment-perms', $info['group']);
}
$ticket->commit();
// Ticket updated successfully
return true;
}
/**
* Add a comment to a ticket.
*
* @param integer $ticket_id The id of the ticket to comment on.
* @param string $comment The comment text to add.
* @param string $group (optional) Restrict this comment to a specific group.
*
* @return boolean True
*/
public function addComment($ticket_id, $comment, $group = null)
{
$ticket_id = (int)$ticket_id;
if (empty($ticket_id)) {
throw new Whups_Exception('Invalid ticket id');
}
$ticket = Whups_Ticket::makeTicket($ticket_id);
if (empty($comment)) {
throw new Whups_Exception('Empty comments are not allowed');
}
// Add comment.
$ticket->change('comment', $comment);
// Add comment permissions, if specified.
// @TODO: validate the user is allowed to specify this group
if (!empty($group)) {
$ticket->change('comment-perms', $group);
}
$ticket->commit();
return true;
}
/**
* Adds an attachment to a ticket.
*
* @param integer $ticket_id The ticket number.
* @param string $name The name of the attachment.
* @param string $data The attachment data.
*
* @throws Whups_Exception
*/
public function addAttachment($ticket_id, $name, $data)
{
$ticket_id = (int)$ticket_id;
if (empty($ticket_id)) {
throw new Whups_Exception(_("Invalid Ticket Id"));
}
$ticket = Whups_Ticket::makeTicket($ticket_id);
if (!strlen($name) || !strlen($data)) {
throw new Whups_Exception(_("Empty attachment"));
}
$tmp_name = Horde_Util::getTempFile('whups', true, $GLOBALS['conf']['tmpdir']);
$fp = fopen($tmp_name, 'wb');
fwrite($fp, $data);
fclose($fp);
$ticket->change('attachment', array('name' => $name, 'tmp_name' => $tmp_name));
$ticket->commit();
}
/**
* Set attributes for a ticket
*
* @TODO fold this into the updateTicket method
*/
public function setTicketAttributes($info)
{
global $whups_driver;
if (!isset($info['ticket_id']) || !isset($info['attributes'])) {
throw new Whups_Exception(_("Invalid arguments: Must supply a ticket number and new attributes."));
}
$ticket = $whups_driver->getTicketDetails($info['ticket_id']);
// Convert the RPC parameters into what we'd expect if we were
// posting the EditAttributes form.
$ainfo = array();
foreach ($info['attributes'] as $attrib) {
if (!isset($attrib['id']) || !isset($attrib['value'])) {
throw new InvalidArgumentException(_("Invalid argument: Missing attribute name or value."));
}
$ainfo['a' . $attrib['id']] = $attrib['value'];
}
$ainfo['id'] = $info['ticket_id'];
return $whups_driver->setAttributes($ainfo);
}
/**
* Get the types that Whups items can be listed as.
*
* @return array Array of list types.
*/
public function getListTypes()
{
return array('taskHash' => true);
}
/**
* Get a list of items from whups as type $type.
*
* @param string $type The list type to use (@see getListTypes). Currently supported: 'taskHash'
*
* @return array An array of tickets.
*/
public function listAs($type)
{
switch ($type) {
case 'taskHash':
global $whups_driver;
$info = array(
'owner' => 'user:' . $GLOBALS['registry']->getAuth(),
'nores' => true);
$tickets = $whups_driver->getTicketsByProperties($info);
$result = array();
foreach ($tickets as $ticket) {
$view_link = Whups::urlFor('ticket', $ticket['id'], true);
$delete_link = Whups::urlFor('ticket_action', array('delete', $ticket['id']), true);
$complete_link = Whups::urlFor('ticket_action', array('update', $ticket['id']), true);
$result['whups/' . $ticket['id']] = array(
'task_id' => $ticket['id'],
'priority' => $ticket['priority_name'],
'tasklist_id' => '**EXTERNAL**',
'completed' => ($ticket['state_category'] == 'resolved'),
'name' => '[#' . $ticket['id'] . '] ' . $ticket['summary'],
'desc' => null,
'due' => null,
'category' => null,
'view_link' => $view_link,
'delete_link' => $delete_link,
'edit_link' => $view_link,
'complete_link' => $complete_link
);
}
break;
default:
$result = array();
break;
}
return $result;
}
/**
* Return a list of queues that the current user has read permissions for
*
* @return array Array of queue details
*/
public function listQueues()
{
return Whups::permissionsFilter($GLOBALS['whups_driver']->getQueuesInternal(), 'queue', Horde_Perms::SHOW);
}
/**
* Return a list of slugs that the current user has read permissions for
*
* @return array Array of queue details
*/
public function listSlugs()
{
return Whups::permissionsFilter($GLOBALS['whups_driver']->getSlugs(), 'queue', Horde_Perms::SHOW);
}
/**
* Get details for a queue
*
* @param array | integer $queue Either an array of queue ids or a single queue id.
*
* @return array An array of queue information (or an array of arrays, if multiple queues were passed).
*/
public function getQueueDetails($queue)
{
if (is_array($queue)) {
$queues = Whups::permissionsFilter($queue, 'queue_id');
$details = array();
foreach ($queues as $id) {
$details[$id] = $GLOBALS['whups_driver']->getQueueInternal($id);
}
return $details;
}
$queues = Whups::permissionsFilter(array($queue), 'queue_id');
if ($queues) {
return $GLOBALS['whups_driver']->getQueueInternal($queue);
}
return array();
}
/**
* List the versions associated with a queue
*
* @param integer $queue The queue id to get versions for.
*
* @return array Array of queue versions
*/
public function listVersions($queue)
{
$queues = Whups::permissionsFilter(array($queue), 'queue_id');
if (!$queues) {
return array();
}
$versions = array();
$version_list = $GLOBALS['whups_driver']->getVersionInfoInternal($queue);
foreach ($version_list as $version) {
$versions[] = array('id' => $version['version_id'],
'name' => $version['version_name'],
'description' => $version['version_description'],
'active' => !empty($version['version_active']),
'readonly' => false);
}
usort($versions, array($this, '_sortVersions'));
return $versions;
}
private function _sortVersions($a, $b)
{
$a_number = (string)(int)$a['name'][0] === $a['name'][0];
$b_number = (string)(int)$b['name'][0] === $b['name'][0];
if ($a_number && $b_number) {
return version_compare($b['name'], $a['name']);
}
if (!$a_number && !$b_number) {
return strcoll($b['name'], $a['name']);
}
return $a_number ? 1 : -1;
}
/**
* Add a version to a queue
*
* @param integer $queue The queue id to add the version to.
* @param string $name The name of the new version.
* @param string $description The descriptive text for the new version.
* @param boolean $active Whether the version is still active.
*/
public function addVersion($queue, $name, $description, $active = true)
{
return $GLOBALS['whups_driver']->addVersion($queue, $name, $description, $active);
}
/**
* Return the details for a queue version
*
* @param integer $version_id The version to fetch
*
* @return array Array of version details
*/
public function getVersionDetails($version_id)
{
return $GLOBALS['whups_driver']->getVersionInternal($version_id);
}
/**
* Get the all tickets for a queue, optionally with a specific state.
*
* @param integer $queue_id The queue to get tickets for
* @param string $state The state filter, if any.
*
* @return array Array of tickets
*/
public function getTicketDetails($queue_id, $state = null)
{
global $whups_driver;
$info['queue_id'] = $queue_id;
if (!empty($state)) {
$info['category'] = $state;
}
$tickets = $whups_driver->getTicketsByProperties($info);
for ($i = 0; $i < count($tickets); $i++) {
$view_link = Whups::urlFor('ticket', $tickets[$i]['id'], true);
$delete_link = Whups::urlFor('ticket_action', array('delete', $tickets[$i]['id']), true);
$complete_link = Whups::urlFor('ticket_action', array('update', $tickets[$i]['id']), true);
$tickets[$i] = array(
'ticket_id' => $tickets[$i]['id'],
'completed' => ($tickets[$i]['state_category'] == 'resolved'),
'assigned' => ($tickets[$i]['state_category'] == 'assigned'),
'name' => $tickets[$i]['queue_name'] . ' #' .
$tickets[$i]['id'] . ' - ' . $tickets[$i]['summary'],
'state' => $tickets[$i]['state_name'],
'type' => $tickets[$i]['type_name'],
'priority' => $tickets[$i]['priority_name'],
'desc' => null,
'due' => null,
'category' => null,
'view_link' => $view_link,
'delete_link' => $delete_link,
'edit_link' => $view_link,
'complete_link' => $complete_link
);
}
return $tickets;
}
/**
* List cost objects
*
* @param array $criteria The list criteria
*
* @return array Tickets (as cost objects) matching $criteria
*/
public function listCostObjects($criteria)
{
global $whups_driver;
$info = array();
if (!empty($criteria['user'])) {
$info['owner'] = 'user:' . $GLOBALS['registry']->getAuth();
}
if (!empty($criteria['active'])) {
$info['nores'] = true;
}
if (!empty($criteria['id'])) {
$info['id'] = $criteria['id'];
}
$tickets = $whups_driver->getTicketsByProperties($info);
$result = array();
foreach ($tickets as $ticket) {
$result[$ticket['id']] = array(
'id' => $ticket['id'],
'active' => ($ticket['state_category'] != 'resolved'),
'name' => sprintf(
_("Ticket %s - %s"), $ticket['id'], $ticket['summary']));
/* If the user has an estimate attribute, use that for cost object
* hour estimates. */
$attributes = $whups_driver->getTicketAttributesWithNames($ticket['id']);
foreach ($attributes as $k => $v) {
if (strtolower($k) == _("estimated time")) {
if (!empty($v)) {
$result[$ticket['id']]['estimate'] = (double) $v;
}
}
}
}
ksort($result);
if (count($result) == 0) {
return array();
} else {
return array(
array(
'category' => _("Tickets"),
'objects' => array_values($result)));
}
}
/**
* List the ways that tickets can be treated as time objects
*
* @return array Array of time object types
*/
public function listTimeObjectCategories()
{
return array('created' => array('title' => _("My tickets by creation date"), 'type' => 'single'),
'assigned' => array('title' => _("My tickets by assignment date"), 'type' => 'single'),
'due' => array('title' => _("My tickets by due date"), 'type' => 'single'),
'resolved' => array('title' => _("My tickets by resolution date"), 'type' => 'single')
);
}
/**
* Lists tickets with due dates as time objects.
*
* @param array $categories The time categories (from listTimeObjectCategories) to list.
* @param mixed $start The start date of the period.
* @param mixed $end The end date of the period.
*/
public function listTimeObjects($categories, $start, $end)
{
global $whups_driver;
$start = new Horde_Date($start);
$start_ts = $start->timestamp();
$end = new Horde_Date($end);
$end_ts = $end->timestamp();
$criteria['owner'] = Whups::getOwnerCriteria($GLOBALS['registry']->getAuth());
/* @TODO Use $categories */
$category = 'due';
switch ($category) {
case 'assigned':
$label = _("Assigned");
$criteria['ass'] = true;
break;
case 'created':
$label = _("Created");
break;
case 'due':
$label = _("Due");
$criteria['nores'] = true;
break;
case 'resolved':
$label = _("Resolved");
$criteria['res'] = true;
break;
}
try {
$tickets = $whups_driver->getTicketsByProperties($criteria);
} catch (Whups_Exception $e) {
return array();
}
$objects = array();
foreach ($tickets as $ticket) {
switch ($category) {
case 'assigned':
$t_start = $ticket['date_assigned'];
break;
case 'created':
$t_start = $ticket['timestamp'];
break;
case 'due':
if (empty($ticket['due'])) {
continue 2;
}
$t_start = $ticket['due'];
break;
case 'resolved':
$t_start = $ticket['date_resolved'];
break;
}
if ($t_start + 1 < $start_ts || $t_start > $end_ts) {
continue;
}
$t = new Whups_Ticket($ticket['id'], $ticket);
$objects[$ticket['id']] = array(
'title' => sprintf('%s: [#%s] %s', $label, $ticket['id'], $ticket['summary']),
'description' => $t->toString(),
'id' => $ticket['id'],
'start' => date('Y-m-d\TH:i:s', $t_start),
'end' => date('Y-m-d\TH:i:s', $t_start + 1),
'params' => array('id' => $ticket['id']),
'link' => Whups::urlFor('ticket', $ticket['id'], true)
);
}
return $objects;
}
}
whups-3.0.0beta1/lib/Application.php 0000664 0001750 0001750 00000021372 12160315153 015425 0 ustar jan jan getInstance('Whups_Factory_Driver')
->create();
/* Set the timezone variable, if available. */
$GLOBALS['registry']->setTimeZone();
}
/**
*/
public function perms()
{
/* Available Whups permissions. */
$perms = array(
'admin' => array(
'title' => _("Administration")
),
'hiddenComments' => array(
'title' => _("Hidden Comments")
),
'queues' => array(
'title' => _("Queues")
),
'replies' => array(
'title' => _("Form Replies")
)
);
/* Loop through queues and add their titles. */
$queues = $GLOBALS['whups_driver']->getQueues();
foreach ($queues as $id => $name) {
$perms['queues:' . $id] = array(
'title' => $name
);
$entries = array(
'assign' => _("Assign"),
'requester' => _("Set Requester"),
'update' => _("Update")
);
foreach ($entries as $key => $val) {
$perms['queues:' . $id . ':' . $key] = array(
'title' => $val,
'type' => 'boolean'
);
}
}
/* Loop through type and replies and add their titles. */
foreach ($GLOBALS['whups_driver']->getAllTypes() as $type_id => $type_name) {
foreach ($GLOBALS['whups_driver']->getReplies($type_id) as $reply_id => $reply) {
$perms['replies:' . $reply_id] = array(
'title' => $type_name . ': ' . $reply['reply_name']
);
}
}
return $perms;
}
public function sidebar($sidebar)
{
$sidebar->addNewButton(
_("_New Ticket"),
Horde::url('ticket/create.php'));
}
/**
*/
public function menu($menu)
{
$menu->add(Horde::url('mybugs.php'), sprintf(_("_My %s"), $GLOBALS['registry']->get('name')), 'whups-mywhups', null, null, null, $GLOBALS['prefs']->getValue('whups_default_view') == 'mybugs' && strpos($_SERVER['PHP_SELF'], $GLOBALS['registry']->get('webroot') . '/index.php') !== false ? 'current' : null);
$menu->add(Horde::url('search.php'), _("_Search"), 'horde-search', null, null, null, $GLOBALS['prefs']->getValue('whups_default_view') == 'search' && strpos($_SERVER['PHP_SELF'], $GLOBALS['registry']->get('webroot') . '/index.php') !== false ? 'current' : null);
$menu->add(Horde::url('query/index.php'), _("_Query Builder"), 'whups-query');
$menu->add(Horde::url('reports.php'), _("_Reports"), 'whups-reports');
/* Administration. */
if ($GLOBALS['registry']->isAdmin(array('permission' => 'whups:admin'))) {
$menu->add(Horde::url('admin/'), _("_Admin"), 'whups-admin');
}
}
/* Topbar method. */
/**
*/
public function topbarCreate(Horde_Tree_Renderer_Base $tree, $parent = null,
array $params = array())
{
$tree->addNode(array(
'id' => $parent . '__new',
'parent' => $parent,
'label' => _("New Ticket"),
'expanded' => false,
'params' => array(
'url' => Horde::url('ticket/create.php')
)
));
$tree->addNode(array(
'id' => $parent . '__search',
'parent' => $parent,
'label' => _("Search"),
'expanded' => false,
'params' => array(
'url' => Horde::url('search.php')
)
));
}
/* Download data. */
/**
* @throws Whups_Exception
*/
public function download(Horde_Variables $vars)
{
global $injector, $whups_driver;
switch ($vars->actionID) {
case 'download_file':
// Get the ticket details first.
if (empty($vars->id)) {
exit;
}
$details = $whups_driver->getTicketDetails($vars->id);
// Check permissions on this ticket.
if (!count(Whups::permissionsFilter($whups_driver->getHistory($vars->id), 'comment', Horde_Perms::READ))) {
throw new Whups_Exception(sprintf(_("You are not allowed to view ticket %d."), $vars->id));
}
try {
$vfs = $injector->getInstance('Horde_Core_Factory_Vfs')->create();
} catch (Horde_Exception $e) {
throw new Whups_Exception(_("The VFS backend needs to be configured to enable attachment uploads."));
}
try {
return array(
'data' => $vfs->read(Whups::VFS_ATTACH_PATH . '/' . $vars->id, $vars->file),
'name' => $vars->file
);
} catch (Horde_Vfs_Exception $e) {
throw Whups_Exception(sprintf(_("Access denied to %s"), $vars->file));
}
break;
case 'report':
$_templates = Horde::loadConfiguration('templates.php', '_templates', 'whups');
$tpl = $vars->template;
if (empty($_templates[$tpl])) {
throw new Whups_Exception(_("The requested template does not exist."));
}
if ($_templates[$tpl]['type'] != 'searchresults') {
throw new Whups_Exception(_("This is not a search results template."));
}
// Fetch all unresolved tickets assigned to the current user.
$info = array('id' => explode(',', $vars->ids));
$tickets = $whups_driver->getTicketsByProperties($info);
foreach ($tickets as $id => $info) {
$tickets[$id]['#'] = $id + 1;
$tickets[$id]['link'] = Whups::urlFor('ticket', $info['id'], true, -1);
$tickets[$id]['date_created'] = strftime('%x', $info['timestamp']);
$tickets[$id]['owners'] = Whups::getOwners($info['id']);
$tickets[$id]['owner_name'] = Whups::getOwners($info['id'], false, true);
$tickets[$id]['owner_email'] = Whups::getOwners($info['id'], true, false);
if (!empty($info['date_assigned'])) {
$tickets[$id]['date_assigned'] = strftime('%x', $info['date_assigned']);
}
if (!empty($info['date_resolved'])) {
$tickets[$id]['date_resolved'] = strftime('%x', $info['date_resolved']);
}
// If the template has a callback function defined for data
// filtering, call it now.
if (!empty($_templates[$tpl]['callback'])) {
array_walk($tickets[$id], $_templates[$tpl]['callback']);
}
}
Whups::sortTickets($tickets,
isset($_templates[$tpl]['sortby']) ? $_templates[$tpl]['sortby'] : null,
isset($_templates[$tpl]['sortdir']) ? $_templates[$tpl]['sortdir'] : null
);
$template = $injector->createInstance('Horde_Template');
$template->set('tickets', $tickets);
$template->set('now', strftime('%x'));
$template->set('values', Whups::getSearchResultColumns(null, true));
return array(
'data' => $template->parse($_templates[$tpl]['template']),
'name' => isset($_templates[$tpl]['filename']) ? $_templates[$tpl]['filename'] : 'report.html'
);
}
}
}
whups-3.0.0beta1/lib/Driver.php 0000664 0001750 0001750 00000057421 12160315153 014421 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*
* @todo Needs updating to include method stubs for all required methods, to
* indicate what methods need to be implemented by other backends.
*
* @author Robert E. Coyle
* @author Jan Schneider
* @package Whups
*/
abstract class Whups_Driver
{
/**
* @var array
*/
protected $_params;
/**
* Constructor
*
* @param array $params Parameter array.
*
* @return Whups_Driver_Base
*/
public function __construct(array $params)
{
$this->_params = $params;
}
/**
* Set ticket attributes
*
* @param array $info Attributes to set
* @param Whups_Ticket $ticket The ticket which attributes to set.
*/
public function setAttributes(array $info, Whups_Ticket &$ticket)
{
$ticket_id = $ticket->getId();
foreach ($info as $name => $value) {
if (substr($name, 0, 10) == 'attribute_' &&
$ticket->get($name) != $value) {
$attribute_id = (int)substr($name, 10);
$serialized = $this->_serializeAttribute($value);
$ticket->change($name, $value);
$this->_setAttributeValue(
$ticket_id,
$attribute_id,
$serialized);
$this->updateLog($ticket_id, $GLOBALS['registry']->getAuth(), array('attribute' => $attribute_id . ':' . $serialized));
}
}
}
/**
* Returns a serialized value, if necessary.
*
* @param mixed The original value.
*
* @return string The JSON encoded value if not already a string.
*/
protected function _serializeAttribute($value)
{
if (!is_string($value)) {
return Horde_Serialize::serialize($value, Horde_Serialize::JSON);
}
return $value;
}
/**
* Fetch ticket history
*
* @param integer $ticket_id The ticket to fetch history for.
*
* @return array
*/
public function getHistory($ticket_id, Horde_Form $form = null)
{
$rows = $this->_getHistory($ticket_id);
$attributes = $attributeDetails = array();
foreach ($rows as $row) {
if ($row['log_type'] == 'attribute' &&
strpos($row['log_value'], ':')) {
$attributes[(int)$row['log_value']] = $row['attribute_name'];
}
if ($row['log_type'] == 'type') {
$attributeDetails += $this->getAttributesForType($row['log_value']);
}
}
$renderer = new Horde_Core_Ui_VarRenderer_Html();
$history = array();
foreach ($rows as $row) {
$label = null;
$human = $value = $row['log_value'];
$type = $row['log_type'];
$transaction = $row['transaction_id'];
$history[$transaction]['timestamp'] = $row['timestamp'];
$history[$transaction]['user_id'] = $row['user_id'];
$history[$transaction]['ticket_id'] = $row['ticket_id'];
switch ($type) {
case 'comment':
$history[$transaction]['comment'] = $row['comment_text'];
$history[$transaction]['changes'][] = array(
'type' => 'comment',
'value' => $row['log_value'],
'comment' => $row['comment_text']);
continue 2;
case 'queue':
$label = $row['queue_name'];
break;
case 'version':
$label = $row['version_name'];
break;
case 'type':
$label = $row['type_name'];
break;
case 'state':
$label = $row['state_name'];
break;
case 'priority':
$label = $row['priority_name'];
break;
case 'attribute':
continue 2;
case 'due':
$label = $row['log_value_num'];
break;
default:
if (strpos($type, 'attribute_') === 0) {
try {
$value = Horde_Serialize::unserialize(
$value, Horde_Serialize::JSON);
} catch (Horde_Serialize_Exception $e) {
}
$attribute = substr($type, 10);
if (isset($attributes[$attribute])) {
$label = $attributes[$attribute];
if ($form) {
if (isset($form->attributes[$attribute])) {
/* Attribute is part of the current type, so we
* have the form field in the current form. */
$field = $form->attributes[$attribute];
} else {
/* Attribute is from a different type, create
* the form field manually. */
$detail = $attributeDetails[$attribute];
$field = new Horde_Form_Variable(
$detail['human_name'],
$type,
$form->getType($detail['type'],
$detail['params']),
$detail['required'],
$detail['readonly'],
$detail['desc']);
}
$human = $renderer->render(
$form,
$field,
new Horde_Variables(array($type => $value)));
}
$type = 'attribute';
} else {
$label = sprintf(_("Attribute %d"), $attribute);
}
}
break;
}
$history[$transaction]['changes'][] = array(
'type' => $type,
'value' => $value,
'human' => $human,
'label' => $label);
}
return $history;
}
/**
*/
public function getQueue($queueId)
{
return $GLOBALS['registry']->call('tickets/getQueueDetails',
array($queueId));
}
/**
*/
public function getQueues()
{
return $GLOBALS['registry']->call('tickets/listQueues');
}
/**
*/
public function getVersionInfo($queue)
{
return $GLOBALS['registry']->call('tickets/listVersions',
array($queue));
}
/**
* Returns a hash of versions suitable for select lists.
*/
public function getVersions($queue, $all = false)
{
if (empty($queue)) {
return array();
}
$versioninfo = $this->getVersionInfo($queue);
$versions = array();
$old_versions = array();
foreach ($versioninfo as $vinfo) {
$name = $vinfo['name'];
if (!empty($vinfo['description'])) {
$name .= ': ' . $vinfo['description'];
}
if ($all && !$vinfo['active']) {
$name .= ' ' . _("(inactive)");
}
if ($vinfo['active']) {
$versions[$vinfo['id']] = $name;
} else {
$old_versions[$vinfo['id']] = $name;
}
}
if ($old_versions && !$all) {
$versions[key($old_versions)] = _("Older? Please update first!");
} else {
$versions += $old_versions;
}
return $versions;
}
/**
*/
public function getVersion($version)
{
return $GLOBALS['registry']->call('tickets/getVersionDetails',
array($version));
}
/**
*/
public function getCategories()
{
return array('unconfirmed' => _("Unconfirmed"),
'new' => _("New"),
'assigned' => _("Assigned"),
'resolved' => _("Resolved"));
}
/**
* Returns the attributes for a ticket type.
*
* @params integer $type A ticket type ID.
*
* @return array A list of attributes.
*/
public function getAttributesForType($type = null)
{
$attributes = $this->_getAttributesForType($type);
foreach ($attributes as $id => $attribute) {
$attributes[$id] = array(
'human_name' => $attribute['attribute_name'],
'type' => $attribute['attribute_type'],
'required' => $attribute['attribute_required'],
'readonly' => false,
'desc' => $attribute['attribute_description'],
'params' => $attribute['attribute_params']);
}
return $attributes;
}
/**
* Returns the attributes for a specific ticket.
*
* This method will check if external attributes need to be fetched from
* hooks or whether to use the standard ones defined within Whups.
*
* @params integer $ticket_id The ticket ID.
*
* @return array List of attributes.
*/
public function getAllTicketAttributesWithNames($ticket_id)
{
$ta = $this->_getAllTicketAttributesWithNames($ticket_id);
$attributes = array();
foreach ($ta as $id => $attribute) {
try {
$value = Horde_Serialize::unserialize(
$attribute['attribute_value'],
Horde_Serialize::JSON);
} catch (Horde_Serialize_Exception $e) {
$value = $attribute['attribute_value'];
}
$attributes[$attribute['attribute_id']] = array(
'id' => $attribute['attribute_id'],
'human_name' => $attribute['attribute_name'],
'type' => $attribute['attribute_type'],
'required' => $attribute['attribute_required'],
'readonly' => false,
'desc' => $attribute['attribute_description'],
'params' => $attribute['attribute_params'],
'value' => $value);
}
return $attributes;
}
/**
* Deletes a queue.
*
* Should be called by driver subclasses after successful removal from the
* backend. Takes only care of cleaning up queue permissions.
*
* @param integer $queueId The id of the queue being deleted.
*/
public function deleteQueue($queueId)
{
$perms = $GLOBALS['injector']->getInstance('Horde_Perms');
try {
$perm = $perms->getPermission("whups:queues:$queueId");
return $perms->removePermission($perm, true);
} catch (Horde_Perms_Exception $e) {}
return true;
}
/**
* Deletes a form reply.
*
* Should be called by driver subclasses after successful removal from the
* backend. Takes only care of cleaning up reply permissions.
*
* @param integer $reply The id of the form reply being deleted.
*/
public function deleteReply($reply)
{
$perms = $GLOBALS['injector']->getInstance('Horde_Perms');
try {
$perm = $perms->getPermission("whups:replies:$reply");
return $perms->removePermission($perm, true);
} catch (Horde_Perms_Exception $e) {}
return true;
}
/**
*/
public function filterTicketsByState($tickets, $state_category = array())
{
/* Take a list of tickets and return only those of the specified
* state_category. */
$tickets_filtered = array();
foreach ($tickets as $ticket) {
foreach ($state_category as $state) {
if ($ticket['state_category'] == $state) {
$tickets_filtered[] = $ticket;
}
}
}
return $tickets_filtered;
}
/**
* Sends email notifications to a list of recipients.
*
* We do some ugly work in here to make sure that no one gets comments
* mailed to them that they shouldn't see (because of group permissions).
*
* @param array $opts Option hash with notification information.
* Possible values:
* - ticket: (Whups_Ticket) A ticket. If not set,
* this is assumed to be a reminder
* message.
* - recipients: (array|string) The list of recipients,
* with user names as keys and user roles
* as values.
* - subject: (string) The email subject.
* - view: (Horde_View) The view object for the
* message text.
* - template: (string) The template file for the
* message text.
* - from: (string) The email sender.
* - new: (boolean, optional) Whether the passed
* ticket was just created.
*/
public function mail(array $opts)
{
global $conf, $registry, $prefs;
$opts = array_merge(array('ticket' => false, 'new' => false), $opts);
/* Set up recipients and message headers. */
$mail = new Horde_Mime_Mail(array(
'X-Whups-Generated' => 1,
'User-Agent' => 'Whups ' . $registry->getVersion(),
'Precedence' => 'bulk',
'Auto-Submitted' => $opts['ticket'] ? 'auto-replied' : 'auto-generated'));
$mail_always = null;
if ($opts['ticket'] && !empty($conf['mail']['always_copy'])) {
$mail_always = $conf['mail']['always_copy'];
if (strpos($mail_always, '<@>') !== false) {
try {
$mail_always = str_replace('<@>', $opts['ticket']->get('queue_name'), $mail_always);
} catch (Whups_Exception $e) {
$mail_always = null;
}
}
if ($mail_always && !isset($opts['recipients'][$mail_always])) {
$opts['recipients'][$mail_always] = 'always';
}
}
if ($opts['ticket'] &&
($queue = $this->getQueue($opts['ticket']->get('queue'))) &&
!empty($queue['email'])) {
$mail->addHeader('From', $queue['email']);
} elseif (!empty($conf['mail']['from_addr'])) {
$mail->addHeader('From', $conf['mail']['from_addr']);
} else {
$mail->addHeader('From', Whups::formatUser($opts['from']));
}
if (!empty($conf['mail']['return_path'])) {
$mail->addHeader('Return-Path', $conf['mail']['return_path']);
}
if ($opts['ticket']) {
$opts['subject'] = '[' . $registry->get('name') . ' #'
. $opts['ticket']->getId() . '] ' . $opts['subject'];
}
$mail->addHeader('Subject', $opts['subject']);
/* Get our array of comments, sorted in the appropriate order. */
if ($opts['ticket']) {
$comments = $this->getHistory($opts['ticket']->getId());
if ($conf['mail']['commenthistory'] == 'new' && count($comments)) {
$comments = array_pop($comments);
$comments = array($comments);
} elseif ($conf['mail']['commenthistory'] != 'chronological') {
$comments = array_reverse($comments);
}
} else {
$comments = array();
}
/* Don't notify any email address more than once. */
$seen_email_addresses = array();
/* Get VFS handle for attachments. */
if ($opts['ticket']) {
$vfs = $GLOBALS['injector']
->getInstance('Horde_Core_Factory_Vfs')
->create();
try {
$attachments = Whups::getAttachments($opts['ticket']->getId());
} catch (Whups_Exception $e) {
$attachments = array();
Horde::logMessage($e);
}
}
foreach ($opts['recipients'] as $user => $role) {
if ($user == $opts['from'] &&
$user == $GLOBALS['registry']->getAuth() &&
$prefs->getValue('email_others_only')) {
continue;
}
/* Make sure to check permissions as a guest for the 'always_copy'
* address, and as the recipient for all others. */
$to = $full_name = '';
if (!empty($mail_always) && $user == $mail_always) {
$details = null;
$mycomments = Whups::permissionsFilter(
$comments, 'comment', Horde_Perms::READ, '');
$to = $mail_always;
} else {
$details = Whups::getUserAttributes($user);
if (!empty($details['email'])) {
$to = Whups::formatUser($details);
$mycomments = Whups::permissionsFilter(
$comments, 'comment', Horde_Perms::READ, $details['user']);
}
$full_name = $details['name'];
}
/* We may have no recipients due to users excluding themselves
* from self notifies. */
if (!$to) {
continue;
}
if ($opts['ticket']) {
/* Add attachments. */
$attachmentAdded = false;
if (empty($GLOBALS['conf']['mail']['link_attach'])) {
/* We need to remove all attachments because the attachment
* list is potentially limited by permissions. */
$mail->clearParts();
foreach ($mycomments as $comment) {
foreach ($comment['changes'] as $change) {
if ($change['type'] == 'attachment') {
foreach ($attachments as $attachment) {
if ($attachment['name'] == $change['value']) {
if (!isset($attachment['part'])) {
$attachment['part'] = new Horde_Mime_Part();
$attachment['part']->setType(Horde_Mime_Magic::filenameToMime($change['value'], false));
$attachment['part']->setDisposition('attachment');
$attachment['part']->setContents($vfs->read(Whups::VFS_ATTACH_PATH . '/' . $opts['ticket']->getId(), $change['value']));
$attachment['part']->setName($change['value']);
}
$mail->addMimePart($attachment['part']);
$attachmentAdded = true;
break;
}
}
}
}
}
}
$formattedComment = $this->formatComments($mycomments, $opts['ticket']->getId());
if (isset($details['type']) && $details['type'] == 'user') {
$user_prefs = $GLOBALS['injector']
->getInstance('Horde_Core_Factory_Prefs')
->create('whups', array('user' => $details['user']));
if (!$attachmentAdded &&
empty($formattedComment) &&
$user_prefs->getValue('email_comments_only')) {
continue;
}
}
$opts['view']->comment = $formattedComment;
}
$addr_ob = new Horde_Mail_Rfc822_Address($to);
if ($addr_ob->valid) {
$bare_address = $addr_ob->bare_address;
if (!empty($seen_email_addresses[$bare_address])) {
continue;
}
$seen_email_addresses[$bare_address] = true;
if (empty($full_name) && !is_null($addr_ob->personal)) {
$full_name = $addr_ob->personal;
}
}
// use email address as fallback
if (empty($full_name)) {
$full_name = $to;
}
$opts['view']->full_name = $full_name;
$opts['view']->role = $role;
$mail->setBody($opts['view']->render($opts['template']));
$mail->addHeader('Message-ID', Horde_Mime::generateMessageId());
if ($opts['ticket']) {
$message_id = 'getId() . '-'
. md5($user) . '@' . $conf['server']['name'] . '>';
if ($opts['new']) {
$mail->addHeader('Message-ID', $message_id);
} else {
$mail->addHeader('In-Reply-To', $message_id);
$mail->addHeader('References', $message_id);
}
}
$mail->clearRecipients();
$mail->addHeader('To', $to);
try {
$mail->send($GLOBALS['injector']->getInstance('Horde_Mail'), true);
$entry = sprintf('%s Message sent to %s from "%s"',
$_SERVER['REMOTE_ADDR'], $to,
$GLOBALS['registry']->getAuth());
Horde::logMessage($entry, 'INFO');
} catch (Horde_Mime_Exception $e) {
Horde::logMessage($e, 'ERR');
}
}
}
/**
* Converts a changeset array to a plain text comment snippet.
*
* @param array $comments A changeset list.
* @param integer $ticket A ticket ID.
*
* @return string The formatted comment text, if any.
*/
public function formatComments($comments, $ticket)
{
$text = '';
foreach ($comments as $comment) {
if (!empty($comment['comment_text'])) {
$text .= "\n"
. sprintf(_("%s (%s) wrote:"),
Whups::formatUser($comment['user_id']),
strftime('%Y-%m-%d %H:%M', $comment['timestamp']))
. "\n\n" . $comment['comment_text'] . "\n\n\n";
}
/* Add attachment links. */
if (empty($GLOBALS['conf']['mail']['link_attach'])) {
continue;
}
foreach ($comment['changes'] as $change) {
if ($change['type'] != 'attachment') {
continue;
}
$url_params = array('actionID' => 'download_file',
'file' => $change['value'],
'ticket' => $ticket);
$text .= "\n"
. sprintf(_("%s (%s) uploaded: %s"),
Whups::formatUser($comment['user_id']),
strftime('%Y-%m-%d %H:%M', $comment['timestamp']),
$change['value'])
. "\n\n"
. Horde::url($GLOBALS['registry']->downloadUrl($change['value'], $url_params), true)
. "\n\n\n";
}
}
return $text;
}
}
whups-3.0.0beta1/lib/Exception.php 0000644 0001750 0001750 00000000100 12160315153 015100 0 ustar jan jan
* @author Jan Schneider
* @package Whups
*/
class Whups_Mail
{
/**
* Parse a MIME message and create a new ticket.
*
* @param string $text This is the full text of the MIME message.
* @param array $info An array of information for the new ticket.
* This should include:
* - 'queue' => queue id
* - 'type' => type id
* - 'state' => state id
* - 'priority' => priority id
* - 'ticket' => ticket id (prevents creation
* of new tickets)
* @param string $auth_user This will be the Horde user that creates the
* ticket. If null, we will try to deduce from
* the message's From: header. We do NOT default
* to $GLOBALS['registry']->getAuth().
*
* @return Whups_Ticket Ticket.
*/
static public function processMail($text, array $info, $auth_user = null)
{
global $conf;
$message = Horde_Mime_Part::parseMessage($text);
if (preg_match("/^(.*?)\r?\n\r?\n/s", $text, $matches)) {
$hdrText = $matches[1];
} else {
$hdrText = $text;
}
$headers = Horde_Mime_Headers::parseHeaders($hdrText);
// If this message was generated by Whups, don't process it.
if ($headers->getValue('X-Whups-Generated')) {
return true;
}
// Try to avoid bounces.
$from = $headers->getValue('from');
if (strpos($headers->getValue('Content-Type'), 'multipart/report') !== false ||
stripos($from, 'mailer-daemon@') !== false ||
stripos($from, 'postmaster@') !== false ||
!is_null($headers->getValue('X-Failed-Recipients'))) {
return true;
}
// Use the message subject as the ticket summary.
$info['summary'] = trim($headers->getValue('subject'));
if (empty($info['summary'])) {
$info['summary'] = _("[No Subject]");
}
// Format the message into a comment.
$comment = _("Received message:") . "\n\n";
if (!empty($GLOBALS['conf']['mail']['include_headers'])) {
foreach ($headers->toArray(array('nowrap' => true)) as $name => $vals) {
if (!in_array(strtolower($name), array('subject', 'from', 'to', 'cc', 'date'))) {
if (is_array($vals)) {
foreach ($vals as $val) {
$comment .= $name . ': ' . $val . "\n";
}
} else {
$comment .= $name . ': ' . $vals . "\n";
}
}
}
$comment .= "\n";
}
// Look for the body part.
$body_id = $message->findBody();
if ($body_id) {
$part = $message->getPart($body_id);
$content = Horde_String::convertCharset(
$part->getContents(), $part->getCharset(), 'UTF-8');
switch ($part->getType()) {
case 'text/plain':
$comment .= $content;
break;
case 'text/html':
$comment .= Horde_Text_Filter::filter(
$content, array('Html2text'), array(array('width' => 0)));;
break;
default:
$comment .= _("[ Could not render body of message. ]");
break;
}
} else {
$comment .= _("[ Could not render body of message. ]");
}
$info['comment'] = $comment . "\n";
// Try to determine the Horde user for creating the ticket.
if (empty($auth_user)) {
$tmp = new Horde_Mail_Rfc822_Address($from);
$auth_user = self::_findAuthUser($tmp->bare_address);
}
$author = $auth_user;
if (empty($auth_user) && !empty($info['default_auth'])) {
$auth_user = $info['default_auth'];
if (!empty($from)) {
$info['user_email'] = $from;
}
}
if (empty($auth_user) && !empty($conf['mail']['username'])) {
$auth_user = $conf['mail']['username'];
if (!empty($from)) {
$info['user_email'] = $from;
}
}
// Authenticate as the correct Horde user.
if (!empty($auth_user) && $auth_user != $GLOBALS['registry']->getAuth()) {
$GLOBALS['registry']->setAuth($auth_user, array());
}
// Attach message.
$attachments = array();
if (!empty($GLOBALS['conf']['mail']['attach_message'])) {
$tmp_name = Horde::getTempFile('whups');
$fp = @fopen($tmp_name, 'wb');
if (!$fp) {
throw new Whups_Exception(
sprintf('Cannot open file %s for writing.', $tmp_name));
}
fwrite($fp, $text);
fclose($fp);
$attachments[] = array(
'name' => _("Original Message") . '.eml',
'tmp_name' => $tmp_name);
}
// Extract attachments.
$dl_list = array_slice(array_keys($message->contentTypeMap()), 1);
foreach ($dl_list as $key) {
$part = $message->getPart($key);
if (($key == $body_id && $part->getType() == 'text/plain') ||
$part->getType() == 'multipart/alternative' ||
$part->getType() == 'multipart/mixed') {
continue;
}
$tmp_name = Horde::getTempFile('whups');
$fp = @fopen($tmp_name, 'wb');
if (!$fp) {
throw new Whups_Exception(
sprintf('Cannot open file %s for writing.', $tmp_name));
}
fwrite($fp, $part->getContents());
fclose($fp);
$part_name = $part->getName(true);
if (!$part_name) {
$ptype = $part->getPrimaryType();
switch ($ptype) {
case 'multipart':
case 'application':
$part_name = sprintf(_("%s part"), ucfirst($part->getSubType()));
break;
default:
$part_name = sprintf(_("%s part"), ucfirst($ptype));
break;
}
if ($ext = Horde_Mime_Magic::mimeToExt($part->getType())) {
$part_name .= '.' . $ext;
}
}
$attachments[] = array(
'name' => $part_name,
'tmp_name' => $tmp_name);
}
// See if we can match this message to an existing ticket.
if ($ticket = self::_findTicket($info)) {
$ticket->change('comment', $info['comment']);
$ticket->change('comment-email', $from);
if ($attachments) {
$ticket->change('attachments', $attachments);
}
$ticket->commit($author);
} elseif (!empty($info['ticket'])) {
// Didn't match an existing ticket though a ticket number had been
// specified.
throw new Whups_Exception(
sprintf(_("Could not find ticket \"%s\"."), $info['ticket']));
} else {
if (!empty($info['guess-queue'])) {
// Try to guess the queue name for the new ticket from the
// message subject.
$queues = $GLOBALS['whups_driver']->getQueues();
foreach ($queues as $queueId => $queueName) {
if (preg_match('/\b' . preg_quote($queueName, '/') . '\b/i',
$info['summary'])) {
$info['queue'] = $queueId;
break;
}
}
}
$info['attachments'] = $attachments;
// Create a new ticket.
$ticket = Whups_Ticket::newTicket($info, $author);
}
}
/**
* Returns the ticket number matching the provided information.
*
* @param array $info A hash with ticket information.
*
* @return integer The ticket number if has been passed in the subject,
* false otherwise.
*/
static protected function _findTicket(array $info)
{
if (!empty($info['ticket'])) {
$ticketnum = $info['ticket'];
} elseif (preg_match('/\[[\w\s]*#(\d+)\]/', $info['summary'], $matches)) {
$ticketnum = $matches[1];
} else {
return false;
}
try {
return Whups_Ticket::makeTicket($ticketnum);
} catch (Whups_Exception $e) {
return false;
}
}
/**
* Searches the From: header for an email address contained in one
* of our users' identities.
*
* @param string $from The From address.
*
* @return string The Horde user name that matches the headers' From:
* address or null if the users can't be listed or no
* match has been found.
*/
static protected function _findAuthUser($from)
{
$auth = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Auth')->create();
if ($auth->hasCapability('list')) {
foreach ($auth->listUsers() as $user) {
$identity = $GLOBALS['injector']
->getInstance('Horde_Core_Factory_Identity')
->create($user);
$addrs = $identity->getAll('from_addr');
foreach ($addrs as $addr) {
if (strcasecmp($from, $addr) == 0) {
return $user;
}
}
}
}
return false;
}
}
whups-3.0.0beta1/lib/Query.php 0000664 0001750 0001750 00000100745 12160315153 014271 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*
* @author Robert E. Coyle
* @author Jan Schneider
* @package Whups
*/
/**
* array(
* 'type' => Whups_Query::TYPE_...
* 'children' => array(...) unless type == Whups_Query::TYPE_CRITERION
* 'criterion' => Whups_Query::CRITERION_... if type == Whups_Query::TYPE_CRITERION
* 'operator' => Whups_Query::OPERATOR_... if type == Whups_Query::TYPE_CRITERION
* 'value' => other argument to operator of criterion
*/
/**
* @package Whups
*/
class Whups_Query
{
/** Mode types. */
const TYPE_AND = 1;
const TYPE_OR = 2;
const TYPE_NOT = 3;
const TYPE_CRITERION = 4;
/** Criterion types. */
const CRITERION_ID = 1;
const CRITERION_QUEUE = 2;
const CRITERION_TYPE = 3;
const CRITERION_STATE = 4;
const CRITERION_PRIORITY = 5;
const CRITERION_OWNERS = 7;
const CRITERION_REQUESTER = 8;
const CRITERION_GROUPS = 9;
const CRITERION_ADDED_COMMENT = 11;
const CRITERION_COMMENT = 12;
const CRITERION_SUMMARY = 13;
const CRITERION_ATTRIBUTE = 14;
const CRITERION_VERSION = 15;
const CRITERION_TIMESTAMP = 16;
const CRITERION_UPDATED = 17;
const CRITERION_RESOLVED = 18;
const CRITERION_ASSIGNED = 19;
const CRITERION_DUE = 20;
/** Operators for integer fields. */
const OPERATOR_GREATER = 1;
const OPERATOR_LESS = 2;
const OPERATOR_EQUAL = 3;
/** Operators for text fields. */
const OPERATOR_CI_SUBSTRING = 4;
const OPERATOR_CS_SUBSTRING = 5;
const OPERATOR_WORD = 6;
const OPERATOR_PATTERN = 7;
/**
* @var Whups_Query_Manager
*/
protected $_qManager;
/**
* Query id.
*
* @var integer
*/
public $id;
/**
* The full name of the query.
*
* @var string
*/
public $name;
/**
* The query slug (short name).
*
* @var string
*/
public $slug;
/**
* @var array
*/
public $query = array(
'type' => Whups_Query::TYPE_AND,
'children' => array());
/**
* @var array
*/
public $parameters = array();
/**
* Constructor
*
* @param Whups_Query_Manager $qManager
* @param array $qDetails
*/
function __construct(Whups_Query_Manager &$qManager, array $qDetails = array())
{
$this->_qManager = &$qManager;
if (isset($qDetails['query_id'])) {
$this->id = $qDetails['query_id'];
}
if (isset($qDetails['query_name'])) {
$this->name = $qDetails['query_name'];
}
if (isset($qDetails['query_slug'])) {
$this->slug = $qDetails['query_slug'];
}
if (isset($qDetails['query_object'])) {
$this->query = @unserialize($qDetails['query_object']);
}
if (isset($qDetails['query_parameters'])) {
$this->parameters = @unserialize($qDetails['query_parameters']);
}
}
/**
* @static
*/
public static function pathToString(&$path)
{
return implode(',', $path);
}
/**
* @static
*/
public static function stringToPath($pathstring)
{
if (!strlen($pathstring)) {
return array();
}
return explode(',', $pathstring);
}
/**
* Returns human readable descriptions of all operator types.
*
* @static
*
* @return array Hash with operator types and descriptions.
*/
public static function textOperators()
{
return array(
Whups_Query::OPERATOR_EQUAL => _("Exact Match"),
Whups_Query::OPERATOR_CI_SUBSTRING => _("Case Insensitive Substring"),
Whups_Query::OPERATOR_CS_SUBSTRING => _("Case Sensitive Substring"),
Whups_Query::OPERATOR_WORD => _("Match Word"),
Whups_Query::OPERATOR_PATTERN => _("Match Pattern"));
}
/**
* Checks to see if a user has a given permission.
*
* @param string $userid The userid of the user.
* @param integer $permission A Horde_Perms::* constant to test for.
* @param string $creator The creator of the event.
*
* @return boolean Whether or not $userid has $permission.
*/
public function hasPermission($userid, $permission, $creator = null)
{
return $this->_qManager->hasPermission($this->id, $userid, $permission, $creator);
}
/**
* Saves any changes to this object to the backend
* permanently. New objects are added instead.
*
*/
public function save()
{
$this->_qManager->save($this);
}
/**
* Delete this object from the backend permanently.
*
*/
public function delete()
{
$this->_qManager->delete($this);
}
/**
* Returns data for this query's feed.
*
* @return array Link data.
*/
public function feedLink()
{
return array(
'href' => Whups::urlFor('query_rss', empty($this->slug) ? array('id' => $this->id) : array('slug' => $this->slug), true, -1),
'title' => $this->name
);
}
/**
* Tab operations for this query.
*
* @params Horde_Variables
*/
public function getTabs(Horde_Variables $vars)
{
// Create a few variables that are reused.
$queryurl = Horde::url('query/index.php');
$edit = $this->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::EDIT);
$delete = $this->hasPermission($GLOBALS['registry']->getAuth(), Horde_Perms::DELETE);
$tabs = new Horde_Core_Ui_Tabs('action', $vars);
$tabs->addTab(_("Ne_w Query"), $queryurl, 'new');
if (!$this->id || $edit) {
$tabs->addTab(_("_Edit Query"), $queryurl, 'edit');
}
if ($this->id && $edit && empty($GLOBALS['conf']['share']['no_sharing'])) {
$GLOBALS['page_output']->addScriptFile('popup.js', 'horde');
$permsurl = Horde::url($GLOBALS['registry']->get('webroot', 'horde') . '/services/shares/edit.php')->add(array(
'app' => 'whups',
'cid' => $this->id));
$tabs->addTab(
_("Edit _Permissions"),
$permsurl,
array(
'tabname' => 'perms',
'onclick' => 'popup(\'' . $permsurl . '\'); return false;',
'target' => '_blank'));
}
$tabs->addTab(_("E_xecute Query"), Horde::url('query/run.php'), 'run');
$tabs->addTab(_("_Load Query"), $queryurl, 'load');
if ((!$this->id && $GLOBALS['registry']->getAuth()) ||
($this->id && $edit)) {
$tabs->addTab(_("Sa_ve Query"), $queryurl, 'save');
}
if ($this->id && $delete) {
$tabs->addTab(_("_Delete Query"), $queryurl, 'delete');
}
return $tabs;
}
/**
* Path to form
*
* @param Horde_Variables $vars
*
* @return string
* @throws Whups_Exception
*/
public function pathToForm(&$vars)
{
$path = Whups_Query::stringToPath($vars->get('path'));
$parent = null;
$qobj = $this->query;
for ($i = 0, $c = count($path); $i < $c; $i++) {
$parent = $qobj;
$qobj = $qobj['children'][$path[$i]];
}
if ($qobj['type'] != Whups_Query::TYPE_CRITERION) {
// Search for any criteria that have been combined automatically
// with an AND or OR.
switch ($qobj['type']) {
case Whups_Query::TYPE_OR:
// Search for multiple ids.
$criteria = array();
foreach ($qobj['children'] as $child) {
if ($child['type'] != Whups_Query::TYPE_CRITERION ||
$child['criterion'] != Whups_Query::CRITERION_ID) {
$criteria = false;
break;
}
$criteria[] = $child['value'];
}
if ($criteria) {
$vars->set('id', implode(',', $criteria));
return 'props';
}
// Search for user criteria.
$criteria = array();
$operator = $value = null;
foreach ($qobj['children'] as $child) {
if ($child['type'] != Whups_Query::TYPE_CRITERION ||
($child['criterion'] != Whups_Query::CRITERION_OWNERS &&
$child['criterion'] != Whups_Query::CRITERION_REQUESTER &&
$child['criterion'] != Whups_Query::CRITERION_ADDED_COMMENT) ||
(isset($operator) && $operator != $child['operator']) ||
(isset($value) && $value != $child['value'])) {
$criteria = false;
break;
}
$criteria[] = $child['criterion'];
$operator = $child['operator'];
$value = $child['value'];
}
if ($criteria) {
$vars->set('user', $value);
$vars->set('operator', $operator);
foreach ($criteria as $criterion) {
switch ($criterion) {
case Whups_Query::CRITERION_OWNERS:
$vars->set('owners', true);
break;
case Whups_Query::CRITERION_REQUESTER:
$vars->set('requester', true);
break;
case Whups_Query::CRITERION_ADDED_COMMENT:
$vars->set('comments', true);
break;
}
}
return 'user';
}
// Search for text criteria.
$criteria = array();
$operator = $value = null;
foreach ($qobj['children'] as $child) {
if ($child['type'] != Whups_Query::TYPE_CRITERION ||
($child['criterion'] != Whups_Query::CRITERION_COMMENT &&
$child['criterion'] != Whups_Query::CRITERION_SUMMARY) ||
(isset($operator) && $operator != $child['operator']) ||
(isset($value) && $value != $child['value'])) {
$criteria = false;
break;
}
$criteria[] = $child['criterion'];
$operator = $child['operator'];
$value = $child['value'];
}
if ($criteria) {
$vars->set('text', $value);
$vars->set('operator', $operator);
foreach ($criteria as $criterion) {
if ($criterion == Whups_Query::CRITERION_COMMENT) {
$vars->set('comments', true);
} elseif ($criterion == Whups_Query::CRITERION_SUMMARY) {
$vars->set('summary', true);
}
}
return 'text';
}
// Search for attributes.
$attribs = array_keys($GLOBALS['whups_driver']->getAttributesForType());
$criteria = array();
$operator = $value = null;
foreach ($qobj['children'] as $child) {
if ($child['type'] != Whups_Query::TYPE_CRITERION ||
$child['criterion'] != Whups_Query::CRITERION_ATTRIBUTE ||
(isset($operator) && $operator != $child['operator']) ||
(isset($value) && $value != $child['value']) ||
!in_array($child['cvalue'], $attribs)) {
$criteria = false;
break;
}
$criteria[] = $child['cvalue'];
$operator = $child['operator'];
$value = $child['value'];
}
if ($criteria) {
$vars->set('text', $value);
$vars->set('operator', $operator);
foreach ($criteria as $criterion) {
$vars->set('a' . $criterion, true);
}
return 'attribs';
}
break;
case Whups_Query::TYPE_AND:
// Search for date criteria.
$criteria = false;
foreach ($qobj['children'] as $child) {
if ($child['type'] != Whups_Query::TYPE_CRITERION ||
($child['criterion'] != Whups_Query::CRITERION_TIMESTAMP &&
$child['criterion'] != Whups_Query::CRITERION_UPDATED &&
$child['criterion'] != Whups_Query::CRITERION_RESOLVED &&
$child['criterion'] != Whups_Query::CRITERION_ASSIGNED &&
$child['criterion'] != Whups_Query::CRITERION_DUE)) {
$criteria = false;
break;
}
$criteria = true;
}
if ($criteria) {
foreach ($qobj['children'] as $child) {
switch ($child['criterion'] . $child['operator']) {
case Whups_Query::CRITERION_TIMESTAMP . Whups_Query::OPERATOR_GREATER:
$vars->set('ticket_timestamp[from]', $child['value']);
break;
case Whups_Query::CRITERION_TIMESTAMP . Whups_Query::OPERATOR_LESS:
$vars->set('ticket_timestamp[to]', $child['value']);
break;
case Whups_Query::CRITERION_UPDATED . Whups_Query::OPERATOR_GREATER:
$vars->set('date_updated[from]', $child['value']);
break;
case Whups_Query::CRITERION_UPDATED . Whups_Query::OPERATOR_LESS:
$vars->set('date_updated[to]', $child['value']);
break;
case Whups_Query::CRITERION_RESOLVED . Whups_Query::OPERATOR_GREATER:
$vars->set('date_resolved[from]', $child['value']);
break;
case Whups_Query::CRITERION_RESOLVED . Whups_Query::OPERATOR_LESS:
$vars->set('date_resolved[to]', $child['value']);
break;
case Whups_Query::CRITERION_ASSIGNED . Whups_Query::OPERATOR_GREATER:
$vars->set('date_assigned[from]', $child['value']);
break;
case Whups_Query::CRITERION_ASSIGNED . Whups_Query::OPERATOR_LESS:
$vars->set('date_assigned[to]', $child['value']);
break;
case Whups_Query::CRITERION_DUE . Whups_Query::OPERATOR_GREATER:
$vars->set('ticket_due[from]', $child['value']);
break;
case Whups_Query::CRITERION_DUE . Whups_Query::OPERATOR_LESS:
$vars->set('ticket_due[to]', $child['value']);
break;
}
}
return 'date';
}
// Search for version criterion.
if (count($qobj['children']) == 2 &&
$qobj['children'][0]['type'] == Whups_Query::TYPE_CRITERION &&
$qobj['children'][0]['criterion'] == Whups_Query::CRITERION_QUEUE &&
$qobj['children'][1]['type'] == Whups_Query::TYPE_CRITERION &&
$qobj['children'][1]['criterion'] == Whups_Query::CRITERION_VERSION) {
$vars->set('queue', $qobj['children'][0]['value']);
$vars->set('version', $qobj['children'][1]['value']);
return 'props';
}
break;
}
throw new Whups_Exception(_("This query element cannot be edited."));
}
switch ($qobj['criterion']) {
case Whups_Query::CRITERION_ID:
$multiple = false;
if ($parent && $parent['type'] == Whups_Query::TYPE_OR) {
$multiple = array();
foreach ($parent['children'] as $child) {
if ($child['type'] != Whups_Query::TYPE_CRITERION ||
$child['criterion'] != Whups_Query::CRITERION_ID) {
$multiple = false;
break;
}
$multiple[] = $child['value'];
}
}
if ($multiple) {
array_pop($path);
$vars->set('path', Whups_Query::pathToString($path));
$vars->set('id', implode(',', $multiple));
} else {
$vars->set('id', $qobj['value']);
}
return 'props';
case Whups_Query::CRITERION_QUEUE:
if ($parent && $parent['type'] == Whups_Query::TYPE_AND &&
count($parent['children']) == 2 &&
$parent['children'][1]['type'] == Whups_Query::TYPE_CRITERION &&
$parent['children'][1]['criterion'] == Whups_Query::CRITERION_VERSION) {
array_pop($path);
$vars->set('path', Whups_Query::pathToString($path));
$vars->set('version', $parent['children'][1]['value']);
}
$vars->set('queue', $qobj['value']);
return 'props';
case Whups_Query::CRITERION_VERSION:
array_pop($path);
$vars->set('path', Whups_Query::pathToString($path));
$vars->set('queue', $parent['children'][0]['value']);
$vars->set('version', $qobj['value']);
return 'props';
case Whups_Query::CRITERION_TYPE:
$vars->set('ttype', $qobj['value']);
return 'props';
case Whups_Query::CRITERION_STATE:
$vars->set('state', $qobj['value']);
return 'props';
case Whups_Query::CRITERION_PRIORITY:
$vars->set('priority', $qobj['value']);
return 'props';
case Whups_Query::CRITERION_TIMESTAMP:
case Whups_Query::CRITERION_UPDATED:
case Whups_Query::CRITERION_RESOLVED:
case Whups_Query::CRITERION_ASSIGNED:
case Whups_Query::CRITERION_DUE:
$criteria = false;
if ($parent && $parent['type'] == Whups_Query::TYPE_AND) {
foreach ($parent['children'] as $child) {
if ($child['type'] != Whups_Query::TYPE_CRITERION ||
($child['criterion'] != Whups_Query::CRITERION_TIMESTAMP &&
$child['criterion'] != Whups_Query::CRITERION_UPDATED &&
$child['criterion'] != Whups_Query::CRITERION_RESOLVED &&
$child['criterion'] != Whups_Query::CRITERION_ASSIGNED &&
$child['criterion'] != Whups_Query::CRITERION_DUE)) {
$criteria = false;
break;
}
$criteria = true;
}
}
if ($criteria) {
array_pop($path);
$vars->set('path', Whups_Query::pathToString($path));
foreach ($parent['children'] as $child) {
switch ($child['criterion'] . $child['operator']) {
case Whups_Query::CRITERION_TIMESTAMP . Whups_Query::OPERATOR_GREATER:
$vars->set('ticket_timestamp[from]', $child['value']);
break;
case Whups_Query::CRITERION_TIMESTAMP . Whups_Query::OPERATOR_LESS:
$vars->set('ticket_timestamp[to]', $child['value']);
break;
case Whups_Query::CRITERION_UPDATED . Whups_Query::OPERATOR_GREATER:
$vars->set('date_updated[from]', $child['value']);
break;
case Whups_Query::CRITERION_UPDATED . Whups_Query::OPERATOR_LESS:
$vars->set('date_updated[to]', $child['value']);
break;
case Whups_Query::CRITERION_RESOLVED . Whups_Query::OPERATOR_GREATER:
$vars->set('date_resolved[from]', $child['value']);
break;
case Whups_Query::CRITERION_RESOLVED . Whups_Query::OPERATOR_LESS:
$vars->set('date_resolved[to]', $child['value']);
break;
case Whups_Query::CRITERION_ASSIGNED . Whups_Query::OPERATOR_GREATER:
$vars->set('date_assigned[from]', $child['value']);
break;
case Whups_Query::CRITERION_ASSIGNED . Whups_Query::OPERATOR_LESS:
$vars->set('date_assigned[to]', $child['value']);
break;
case Whups_Query::CRITERION_DUE . Whups_Query::OPERATOR_GREATER:
$vars->set('ticket_due[from]', $child['value']);
break;
case Whups_Query::CRITERION_DUE . Whups_Query::OPERATOR_LESS:
$vars->set('ticket_due[to]', $child['value']);
break;
}
}
}
return 'date';
case Whups_Query::CRITERION_OWNERS:
case Whups_Query::CRITERION_REQUESTER:
case Whups_Query::CRITERION_ADDED_COMMENT:
$criteria = false;
if ($parent && $parent['type'] == Whups_Query::TYPE_OR) {
$criteria = array();
foreach ($parent['children'] as $child) {
if ($child['type'] != Whups_Query::TYPE_CRITERION ||
!in_array($child['criterion'], array(Whups_Query::CRITERION_OWNERS, Whups_Query::CRITERION_REQUESTER, Whups_Query::CRITERION_ADDED_COMMENT))) {
$criteria = false;
break;
}
$criteria[] = $child['criterion'];
}
if ($criteria) {
array_pop($path);
$vars->set('path', Whups_Query::pathToString($path));
}
}
if (!$criteria) {
$criteria = array($qobj['criterion']);
}
$vars->set('user', $qobj['value']);
$vars->set('operator', $qobj['operator']);
foreach ($criteria as $criterion) {
switch ($criterion) {
case Whups_Query::CRITERION_OWNERS:
$vars->set('owners', true);
break;
case Whups_Query::CRITERION_REQUESTER:
$vars->set('requester', true);
break;
case Whups_Query::CRITERION_ADDED_COMMENT:
$vars->set('comments', true);
break;
}
}
return 'user';
case Whups_Query::CRITERION_GROUPS:
$vars->set('groups', $qobj['value']);
return 'group';
case Whups_Query::CRITERION_COMMENT:
case Whups_Query::CRITERION_SUMMARY:
$criteria = false;
if ($parent && $parent['type'] == Whups_Query::TYPE_OR) {
$criteria = array();
$operator = $value = null;
foreach ($parent['children'] as $child) {
if ($child['type'] != Whups_Query::TYPE_CRITERION ||
($child['criterion'] != Whups_Query::CRITERION_COMMENT &&
$child['criterion'] != Whups_Query::CRITERION_SUMMARY) ||
(isset($operator) && $operator != $child['operator']) ||
(isset($value) && $value != $child['value'])) {
$criteria = false;
break;
}
$criteria[] = $child['criterion'];
$operator = $child['operator'];
$value = $child['value'];
}
if ($criteria) {
array_pop($path);
$vars->set('path', Whups_Query::pathToString($path));
}
} else {
$operator = $qobj['operator'];
$value = $qobj['value'];
}
if (!$criteria) {
$criteria = array($qobj['criterion']);
}
$vars->set('text', $value);
$vars->set('operator', $operator);
foreach ($criteria as $criterion) {
if ($criterion == Whups_Query::CRITERION_COMMENT) {
$vars->set('comments', true);
} elseif ($criterion == Whups_Query::CRITERION_SUMMARY) {
$vars->set('summary', true);
}
}
return 'text';
case Whups_Query::CRITERION_ATTRIBUTE:
$attribs = array_keys($GLOBALS['whups_driver']->getAttributesForType());
$criteria = false;
if ($parent && $parent['type'] == Whups_Query::TYPE_OR) {
$criteria = array();
$operator = $value = null;
foreach ($parent['children'] as $child) {
if ($child['type'] != Whups_Query::TYPE_CRITERION ||
$child['criterion'] != Whups_Query::CRITERION_ATTRIBUTE ||
(isset($operator) && $operator != $child['operator']) ||
(isset($value) && $value != $child['value']) ||
!in_array($child['cvalue'], $attribs)) {
$criteria = false;
break;
}
$criteria[] = $child['cvalue'];
$operator = $child['operator'];
$value = $child['value'];
}
if ($criteria) {
array_pop($path);
$vars->set('path', Whups_Query::pathToString($path));
}
} else {
$operator = $qobj['operator'];
$value = $qobj['value'];
}
if (!$criteria) {
$criteria = array($qobj['cvalue']);
}
$vars->set('text', $value);
$vars->set('operator', $operator);
foreach ($criteria as $criterion) {
$vars->set('a' . $criterion, true);
}
return 'attribs';
}
throw new Whups_Exception(_("This query element cannot be edited."));
}
public function deleteNode($pathstring)
{
$path = Whups_Query::stringToPath($pathstring);
$qobj = &$this->query;
if (!strlen($pathstring)) {
// Deleting the root node isn't supported.
$GLOBALS['notification']->push(_("Choose New Query instead of deleting the root node."), 'horde.warning');
return false;
} else {
$count = count($path) - 1;
for ($i = 0; $i < $count; $i++) {
$qobj = &$qobj['children'][$path[$i]];
}
if (!empty($qobj['children'][$path[$count]]['value']) &&
$this->_getParameterName($qobj['children'][$path[$count]]['value']) !== null) {
unset($this->parameters[array_search($pn, $this->parameters)]);
}
array_splice($qobj['children'], $path[$count], 1);
}
}
public function hoist($pathstring)
{
$path = Whups_Query::stringToPath($pathstring);
$qobj = &$this->query;
if (!strlen($pathstring)) {
// Can't hoist the root node.
} else {
$count = count($path) - 1;
for ($i = 0; $i < $count; $i++) {
$qobj = &$qobj['children'][$path[$i]];
}
$cobj = &$qobj['children'][$path[$count]];
// TODO: make sure we're hoisting a branch.
array_splice($qobj['children'], $path[$count], 0, $cobj['children']);
array_splice($cobj['children'], 0, count($cobj['children']));
}
}
public function insertBranch($pathstring, $type)
{
$path = Whups_Query::stringToPath($pathstring);
$qobj = &$this->query;
$newbranch = array(
'type' => $type,
'children' => array());
$count = count($path);
for ($i = 0; $i < $count; $i++) {
$qobj = &$qobj['children'][$path[$i]];
}
if (!isset($qobj['children']) ||
!is_array($qobj['children'])) {
$qobj['children'] = array();
}
$qobj['children'][] = $newbranch;
$path[] = count($qobj['children']) - 1;
return Whups_Query::pathToString($path);
}
public function insertCriterion($pathstring, $criterion, $cvalue, $operator, $value)
{
$path = Whups_Query::stringToPath($pathstring);
$qobj = &$this->query;
$value = trim($value);
if ($value[0] == '"') {
// FIXME: The last character should be '"' as well.
$value = substr($value, 1, -1);
} else {
$pn = $this->_getParameterName($value);
if ($pn !== null) {
$this->parameters[] = $pn;
}
}
$newbranch = array(
'type' => Whups_Query::TYPE_CRITERION,
'criterion' => $criterion,
'cvalue' => $cvalue,
'operator' => $operator,
'value' => $value);
$count = count($path);
for ($i = 0; $i < $count; $i++) {
$qobj = &$qobj['children'][$path[$i]];
}
$qobj['children'][] = $newbranch;
}
/**
* Top down traversal.
*/
public function walk(&$obj, $method)
{
$path = array();
$more = array();
$this->_walk($this->query, $more, $path, $obj, $method);
}
/**
* @access private
*/
protected function _walk(&$node, &$more, &$path, &$obj, $method)
{
if ($node['type'] == Whups_Query::TYPE_CRITERION) {
$obj->$method($more, $path, Whups_Query::TYPE_CRITERION, $node['criterion'],
$node['cvalue'], $node['operator'], $node['value']);
} else {
$obj->$method($more, $path, $node['type'], null, null, null, null);
}
if (isset($node['children'])) {
$count = count($node['children']);
for ($i = 0; $i < $count; $i++) {
$path[] = $i;
$more[] = ($i < $count - 1);
$this->_walk($node['children'][$i], $more, $path, $obj, $method);
array_pop($more);
array_pop($path);
}
}
}
/**
* Bottom up traversal.
*/
public function reduce($method, &$vars)
{
return $this->_reduce($this->query, $method, $vars);
}
/**
* @access private
*/
protected function _reduce(&$node, $method, &$vars)
{
$args = array();
if (isset($node['children'])) {
$count = count($node['children']);
for ($i = 0; $i < $count; $i++) {
$result = $this->_reduce($node['children'][$i], $method, $vars);
$args[] = $result;
}
}
if ($node['type'] == Whups_Query::TYPE_CRITERION) {
$value = $node['value'];
$pn = $this->_getParameterName($value);
if ($pn !== null) {
$value = $vars->get($pn);
}
return call_user_func(
$method, $args, Whups_Query::TYPE_CRITERION, $node['criterion'],
$node['cvalue'], $node['operator'], $value);
}
return call_user_func($method, $args, $node['type'], null, null, null, null);
}
/**
* @access private
*/
protected function _getParameterName($value)
{
if (strcmp(substr($value, 0, 2), '${'))
return null;
$pn = substr($value, 2, -1);
if (!is_string($pn))
$pn = null;
return $pn;
}
}
whups-3.0.0beta1/lib/Reports.php 0000664 0001750 0001750 00000017407 12160315153 014624 0 ustar jan jan
* @package Whups
*/
class Whups_Reports
{
/**
* @var Whups_Driver
*/
protected $_backend;
/**
* Local cache of open tickets
*
* @var array
*/
protected $_opentickets;
/**
* Local cache of closed tickets
*
* @var array
*/
protected $_closedtickets;
/**
* Local cache of ticket sets
*
* @var array
*/
protected $_alltickets;
/**
* Constructor
*
* @param Whups_Driver $whups_driver The backend driver
*
* @return Whups_Reports
*/
function __construct(Whups_Driver $whups_driver)
{
$this->_backend = $whups_driver;
}
/**
* Get the data set
*
* @param string $report The report
*
* @return array The dataset
*/
public function getDataSet($report)
{
$operation = 'inc';
$state = null;
list($type, $field) = explode('|', $report);
if (substr($type, 0, 1) == '@') {
list($type, $operation, $state) = explode(':', substr($type, 1));
}
$tickets = $this->_getTicketSet($type, ($field == 'owner'));
if (substr($field, 0, 7) == 'user_id' || $field == 'owner') {
$user = true;
} else {
$user = false;
}
$dataset = array();
foreach ($tickets as $info) {
switch ($state) {
case 'open':
$date1 = new Horde_Date($info['date_resolved']);
$newdata = $date1->diff(new Horde_Date($info['timestamp']));
break;
default:
$newdata = 1;
}
if (empty($info[$field])) {
$this->_updateDataSet($dataset, _("None"), $newdata, $operation);
} else {
if ($user) {
$col = Whups::formatUser($info[$field], false);
} else {
$col = $info[$field];
}
$this->_updateDataSet($dataset, $col, $newdata, $operation);
}
}
// Perform any necessary post-processing on the dataset - process
// averages, for example.
switch ($operation) {
case 'avg':
foreach ($dataset as $index => $data) {
$dataset[$index] = number_format(array_sum($data) / count($data), 2);
}
break;
}
// Sort
ksort($dataset);
// Return the final data.
return $dataset;
}
/**
* Update the dataset
*
* @param array $dataset The dataset.
* @param integer $index The index to update.
* @param mixed $newdata The new data to insert.
* @param string $operation The operation being performed.
*/
function _updateDataSet(&$dataset, $index, $newdata, $operation)
{
if (isset($dataset[$index])) {
switch ($operation) {
case 'inc':
$dataset[$index] += $newdata;
break;
case 'max':
case 'min':
$dataset[$index] = $operation($newdata, $dataset[$index]);
break;
case 'avg':
$dataset[$index][] = $newdata;
break;
}
} else {
switch ($operation) {
case 'avg':
$dataset[$index] = array($newdata);
break;
default:
$dataset[$index] = $newdata;
}
}
}
/**
* Returns a time (max, min, avg) that tickets are in a particular state
* (open, assigned, etc.).
*
* @param string $operation One of 'max', 'min', or 'avg'.
* @param string $state The state to measure - 'open', etc.
* @param string $group_by A ticket property by which to group the
* results.
*
* @return integer|array The time value requested, or an array of values,
* if the $group_by parameter has been specified.
*
* @throws Whups_Exception
*/
public function getTime($stat, $group_by = null)
{
list($operation, $state) = explode('|', $stat);
$tickets = $this->_getTicketSet('closed');
if (!count($tickets)) {
throw new Whups_Exception(_("There is no data for this report."));
}
$dataset = array();
if (empty($group_by)) {
$dataset[0] = array();
}
foreach ($tickets as $info) {
if (is_null($info['date_resolved'])) {
continue;
}
switch ($state) {
case 'open':
$date1 = new Horde_Date($info['date_resolved']);
$diff = $date1->diff(new Horde_Date($info['timestamp']));
if (empty($group_by)) {
$dataset[0][] = $diff;
} else {
if (!isset($info[$group_by])) {
continue;
}
if (!isset($dataset[$info[$group_by]])) {
$dataset[$info[$group_by]] = array();
}
$dataset[$info[$group_by]][] = $diff;
}
break;
}
}
if (!count($dataset) || (is_null($group_by) && !count($dataset[0]))) {
return 'N/A';
}
switch ($operation) {
case 'min':
case 'max':
foreach (array_keys($dataset) as $group) {
$dataset[$group] = $operation($dataset[$group]);
}
break;
case 'avg':
foreach (array_keys($dataset) as $group) {
$dataset[$group] = round(array_sum($dataset[$group]) / count($dataset[$group]), 2);
}
break;
}
if (empty($group_by)) {
$dataset = $dataset[0];
}
return $dataset;
}
/**
* Loads a set of tickets, and cache the result inside the Whups_Reports::
* object to save on database access.
*
* @param string $type 'open', 'closed', or 'all' - the set of
* tickets to fetch. A previously cached set
* will be returned if it is available.
* @param boolean $expanded List tickets once for each owner of the
* ticket?
*
* @return array The ticket set.
*/
protected function &_getTicketSet($type, $expanded = false)
{
$queues = array_keys(Whups::permissionsFilter($this->_backend->getQueues(), 'queue'));
$expanded = (int)$expanded;
switch ($type) {
case 'open':
if (is_null($this->_opentickets[$expanded])) {
$this->_opentickets[$expanded] = $this->_backend->getTicketsByProperties(array('nores' => true, 'queue' => $queues), true, $expanded);
}
return $this->_opentickets[$expanded];
case 'closed':
if (is_null($this->_closedtickets[$expanded])) {
$this->_closedtickets[$expanded] = $this->_backend->getTicketsByProperties(array('res' => true, 'queue' => $queues), true, $expanded);
}
return $this->_closedtickets[$expanded];
case 'all':
if (is_null($this->_alltickets[$expanded])) {
$this->_alltickets[$expanded] = $this->_backend->getTicketsByProperties(array('queue' => $queues), true, $expanded);
}
return $this->_alltickets[$expanded];
}
}
}
whups-3.0.0beta1/lib/Scheduler.php 0000664 0001750 0001750 00000002101 12160315153 015065 0 ustar jan jan _runtime = time();
// See if we need to include the reminders config file.
if (filemtime(WHUPS_BASE . '/config/reminders.php') > $this->_filestamp) {
$this->_filestamp = $this->_runtime;
$this->_reminders = Horde::loadConfiguration('reminders.php', 'reminders', 'whups');
}
foreach ($this->_reminders as $reminder) {
$ds = new Horde_Scheduler_Cron_Date($reminder['frequency']);
if ($ds->scheduledAt($this->_runtime)) {
if (!empty($reminder['server_name'])) {
$GLOBALS['conf']['server']['name'] = $reminder['server_name'];
}
$vars = new Horde_Variables($reminder);
Whups::sendReminders($vars);
}
}
}
}
whups-3.0.0beta1/lib/Ticket.php 0000664 0001750 0001750 00000102325 12160315153 014403 0 ustar jan jan
* @author Jan Schneider
* @package Whups
*/
class Whups_Ticket
{
/**
* The id of the ticket this object wraps.
*
* @var integer
*/
protected $_id;
/**
* The current values of the ticket.
*
* @var array
*/
protected $_details;
/**
* Array of changes to make to the ticket.
*
* @var array
*/
protected $_changes = array();
/**
* Returns a ticket object for an id.
*
* @param integer $id The ticket id.
*
* @return Whups_Ticket Whups_Ticket object
*/
static public function makeTicket($id)
{
global $whups_driver;
$details = $whups_driver->getTicketDetails($id);
$ticket = new Whups_Ticket($id, $details);
return $ticket;
}
/**
* Creates a new ticket.
*
* Pretty bare wrapper around Whups_Driver::addTicket().
*
* @static
*
* @param array $info A hash with ticket information.
*
* @return Whups_Ticket Whups_Ticket object.
*/
static public function newTicket($info, $requester)
{
global $whups_driver;
if (!isset($info['type'])) {
$info['type'] = $whups_driver->getDefaultType($info['queue']);
if (!$info['type']) {
$queue = $whups_driver->getQueue($info['queue']);
throw new Whups_Exception(
sprintf(
_("No type for this ticket and no default type for queue \"%s\" specified."),
$queue['name']));
}
}
if (!isset($info['state'])) {
$info['state'] = $whups_driver->getDefaultState($info['type']);
if (!$info['state']) {
throw new Whups_Exception(
sprintf(
_("No state for this ticket and no default state for ticket type \"%s\" specified."),
$whups_driver->getTypeName($info['type'])));
}
}
if (!isset($info['priority'])) {
$info['priority'] = $whups_driver->getDefaultPriority($info['type']);
if (!$info['priority']) {
throw new Whups_Exception(
sprintf(
_("No priority for this ticket and no default priority for ticket type \"%s\" specified."),
$whups_driver->getTypeName($info['type'])));
}
}
$id = $whups_driver->addTicket($info, $requester);
$details = $whups_driver->getTicketDetails($id, false);
$ticket = new Whups_Ticket($id, $details);
// Add attachment if one was uploaded.
if (!empty($info['newattachment']['name'])) {
$ticket->change(
'attachment',
array(
'name' => $info['newattachment']['name'],
'tmp_name' => $info['newattachment']['tmp_name']));
}
// Check for a deferred attachment upload.
if (!empty($info['deferred_attachment']) &&
($a_name = $GLOBALS['session']->get('whups', 'deferred_attachment/' . $info['deferred_attachment']))) {
$ticket->change(
'attachment',
array(
'name' => $info['deferred_attachment'],
'tmp_name' => $a_name));
unlink($a_name);
}
// Check for manually added attachments.
if (!empty($info['attachments'])) {
$ticket->change('attachments', $info['attachments']);
}
// Commit any changes (new attachments, etc.)
$ticket->commit(
$ticket->get('user_id_requester'),
$info['last-transaction'],
false);
// Send email notifications.
$ticket->notify($ticket->get('user_id_requester'), true);
return $ticket;
}
/**
* Constructor.
*
* @param integer $id The ticket id.
* @param array $details The hash of ticket information.
*
* @return Whups_Ticket
*/
public function __construct($id, array $details)
{
$this->_id = $id;
$this->_details = $details;
}
/**
* Returns all ticket information.
*
* @return array The ticket information.
*/
public function getDetails()
{
return $this->_details;
}
/**
* Returns the ticket id.
*
* @return integer The ticket id.
*/
public function getId()
{
return $this->_id;
}
/**
* Returns a piece of information from this ticket.
*
* @param string $detail The detail to return.
*
* @return mixed The detail value.
*/
public function get($detail)
{
return isset($this->_details[$detail])
? $this->_details[$detail]
: null;
}
/**
* Changes a detail of the ticket to a new value.
*
* Never touches the backend; do not use for changes that you want to
* persist.
*
* @param string $detail The detail to change.
* @param string $value The new detail value.
*/
public function set($detail, $value)
{
$this->_details[$detail] = $value;
}
/**
* Tracks that a detail of the ticket should change, but does not actually
* make the change until commit() is called.
*
* @see commit()
*
* @param string $detail The detail to change.
* @param string $value The new detail value.
*/
public function change($detail, $value)
{
$previous_value = isset($this->_details[$detail])
? $this->_details[$detail]
: '';
if ($previous_value != $value) {
$this->_changes[$detail] = array(
'from' => $this->get($detail),
'from_name' => $this->get($detail . '_name'),
'to' => $value);
}
}
/**
* Goes through a list of built-up changes and commits them to the
* backend.
*
* This will send email updates by default, update the ticket log, etc.
*
* @see change()
*
* @param string $user The Horde user of the changes to be made.
* Defaults to the current user.
* @param integer $transaction The transaction these changes are part of.
* Defaults to a new transaction.
* @param boolean $notify Send ticket notifications?
*/
public function commit($user = null, $transaction = null, $notify = true)
{
global $whups_driver;
if (!count($this->_changes)) {
return;
}
if (is_null($user)) {
$user = $GLOBALS['registry']->getAuth();
}
$author_email = isset($this->_changes['comment-email']['to'])
? $this->_changes['comment-email']['to']
: null;
if (is_null($transaction)) {
// Get a new transaction id from the backend.
$transaction = $whups_driver->newTransaction($user, $author_email);
}
// If this is a guest update, the comment id is going to map to the
// requester pseudo-username.
if ($user === false) {
$user = '-' . $transaction . '_transaction';
}
// Run hook before setting the dates.
try {
$this->_changes = Horde::callHook('ticket_update', array($this, $this->_changes), 'whups');
} catch (Horde_Exception_HookNotSet $e) {
}
// Update cached dates.
$timestamp = time();
$this->_changes['date_updated'] = array('to' => $timestamp);
if (isset($this->_changes['state'])) {
$state = $whups_driver->getState($this->_changes['state']['to']);
if ($state['category'] == 'assigned') {
$this->_changes['date_assigned'] = array('to' => $timestamp);
$this->_changes['date_resolved'] = array('to' => null);
} elseif ($state['category'] == 'resolved') {
$this->_changes['date_resolved'] = array('to' => $timestamp);
} else {
$this->_changes['date_resolved'] = array('to' => null);
}
}
$updates = array();
foreach ($this->_changes as $detail => $values) {
$value = $values['to'];
switch ($detail) {
case 'owners':
// Fetch $oldOwners list; then loop through $value adding and
// deleting as needed.
$oldOwners = current($whups_driver->getOwners($this->_id));
$this->_changes['oldowners'] = $oldOwners;
foreach ($value as $owner) {
if (!$oldOwners ||
array_search($owner, $oldOwners) === false) {
$whups_driver->addTicketOwner($this->_id, $owner);
$whups_driver->updateLog(
$this->_id, $user,
array('assign' => $owner),
$transaction);
} else {
// Remove $owner from the old owners list; anyone left
// in $oldOwners will be removed.
unset($oldOwners[array_search($owner, $oldOwners)]);
}
}
// Delete removed owners and log the removals.
if (is_array($oldOwners)) {
foreach ($oldOwners as $owner) {
$whups_driver->deleteTicketOwner($this->_id, $owner);
$whups_driver->updateLog(
$this->_id, $user,
array('unassign' => $owner),
$transaction);
}
}
break;
case 'comment':
$commentId = $whups_driver->addComment(
$this->_id, $value, $user, $author_email);
// Store the comment id in the updates array for the log.
$updates['comment'] = $commentId;
if (!empty($this->_changes['comment-perms'])) {
$this->addCommentPerms(
$commentId,
$this->_changes['comment-perms']['to']);
}
break;
case 'comment-email':
case 'comment-perms':
// Skip these, handled in the comment case.
break;
case 'attachment':
$this->addAttachment($value['name'], $value['tmp_name']);
// Store the new file name in the updates array for the
// log.
$updates['attachment'][] = $value['name'];
break;
case 'attachments':
foreach ($value as $attachment) {
$this->addAttachment($attachment['name'], $attachment['tmp_name']);
// Store the new file name in the updates array for the
// log.
$updates['attachment'][] = $attachment['name'];
}
break;
case 'delete-attachment':
$this->deleteAttachment($value);
// Store the deleted file name in the updates array for
// the log.
$updates['delete-attachment'] = $value;
break;
case 'queue':
// Reset version if new queue is not versioned.
$newqueue = $whups_driver->getQueue($value);
if (empty($newqueue['queue_versioned'])) {
$updates['version'] = 0;
}
$updates['queue'] = $value;
default:
if (strpos($detail, 'attribute_') === 0 &&
!is_string($value)) {
$value = Horde_Serialize::Serialize($value,
Horde_Serialize::JSON);
}
$updates[$detail] = $value;
}
}
if (count($updates)) {
$whups_driver->updateTicket($this->_id, $updates);
$whups_driver->updateLog($this->_id, $user, $updates, $transaction);
}
// Reload $this->_details to make sure we have the latest information.
//
// @todo Only touch the db if we have to.
$details = $whups_driver->getTicketDetails($this->_id);
$this->_details = array_merge($this->_details, $details);
// Send notification emails to all ticket listeners.
if ($notify) {
$this->notify($user, false);
}
// Reset the changes array.
$this->_changes = array();
}
/**
* Deletes this ticket.
*
* @throws Whups_Exception
*/
public function delete()
{
global $whups_driver;
/* Build message template. */
$view = new Horde_View(array('templatePath' => WHUPS_BASE . '/config'));
$view->date = strftime($GLOBALS['prefs']->getValue('date_format'));
$view->auth_name = $GLOBALS['injector']
->getInstance('Horde_Core_Factory_Identity')
->create()
->getValue('fullname');
if (empty($view->auth_name)) {
$view->auth_name = $GLOBALS['registry']->getAuth('bare');
}
/* Get queue specific notification message text, if available. */
$message_file = WHUPS_BASE . '/config/delete_email.plain';
if (file_exists($message_file . '.' . $this->get('queue') . '.php')) {
$message_file .= '.' . $this->get('queue') . '.php';
} elseif (file_exists($message_file . '.local.php')) {
$message_file .= '.local.php';
} else {
$message_file .= '.php';
}
$message_file = basename($message_file);
if ($GLOBALS['conf']['mail']['incl_resp'] ||
!count(current($whups_driver->getOwners($this->_id)))) {
/* Include all responsible. */
$listeners = $whups_driver->getListeners(
$this->_id, true, false, true);
} else {
/* Don't include all responsible unless ticket is assigned. */
$listeners = $whups_driver->getListeners(
$this->_id, true, false, false);
}
$this->change('comment', _("The ticket was deleted."));
$this->commit(null, null, false);
$whups_driver->deleteTicket($this->_id);
$whups_driver->mail(array('ticket' => $this,
'recipients' => $listeners,
'subject' => _("Deleted:") . ' ' . $this->get('summary'),
'view' => $view,
'template' => $message_file,
'from' => $GLOBALS['registry']->getAuth()));
}
/**
* Adds an attachment to this ticket.
*
* @param string $attachment_name The name of the attachment.
* @param string $attachment_file The temporary file containing the data
* to be stored.
*
* @throws Whups_Exception
*/
public function addAttachment(&$attachment_name, $attachment_file)
{
if (!isset($GLOBALS['conf']['vfs']['type'])) {
throw new Whups_Exception(
_("The VFS backend needs to be configured to enable attachment uploads."),
'horde.error');
}
try {
$vfs = $GLOBALS['injector']
->getInstance('Horde_Core_Factory_Vfs')
->create();
} catch (Horde_Vfs_Exception $e) {
throw new Whups_Exception($e);
}
// Get existing attachment names.
$used_names = $this->listAllAttachments();
$dir = Whups::VFS_ATTACH_PATH . '/' . $this->_id;
while ((array_search($attachment_name, $used_names) !== false) ||
$vfs->exists($dir, $attachment_name)) {
if (preg_match('/(.*)\[(\d+)\](\.[^.]*)?$/', $attachment_name,
$match)) {
$attachment_name = $match[1] . '[' . ++$match[2] . ']';
if (isset($match[3])) {
$attachment_name .= $match[3];
}
} else {
$dot = strrpos($attachment_name, '.');
if ($dot === false) {
$attachment_name .= '[1]';
} else {
$attachment_name = substr($attachment_name, 0, $dot)
. '[1]' . substr($attachment_name, $dot);
}
}
}
try {
$vfs->write($dir, $attachment_name, $attachment_file, true);
} catch (Horde_Vfs_Exception $e) {
throw new Whups_Exception($e);
}
}
/**
* Removes an attachment from this ticket.
*
* @param string $attachment_name The name of the attachment.
*
* @throws Whups_Exception
*/
public function deleteAttachment($attachment_name)
{
if (!isset($GLOBALS['conf']['vfs']['type'])) {
throw new Whups_Exception(
_("The VFS backend needs to be configured to enable attachment uploads."),
'horde.error');
}
try {
$vfs = $GLOBALS['injector']
->getInstance('Horde_Core_Factory_Vfs')
->create();
} catch (Horde_Vfs_Exception $e) {
throw Whups_Exception($e);
}
$dir = Whups::VFS_ATTACH_PATH . '/' . $this->_id;
if (!$vfs->exists($dir, $attachment_name)) {
throw new Whups_Exception(
sprintf(_("Attachment %s not found."),
$attachment_name),
'horde.error');
}
try {
$vfs->deleteFile($dir, $attachment_name);
} catch (Horde_Vfs_Exception $e) {
throw new Whups_Exception($e);
}
}
/**
* Returns a list of all files that have been attached to this ticket,
* whether they still exist or not.
*
* @return array The list of file attachments
* @throws Whups_Exception
*/
public function listAllAttachments()
{
$files = array();
$history = $GLOBALS['whups_driver']->getHistory($this->_id);
foreach ($history as $row) {
if (isset($row['changes'])) {
foreach ($row['changes'] as $change) {
if (isset($change['type']) &&
$change['type'] == 'attachment') {
$files[] = $change['value'];
}
}
}
}
return array_unique($files);
}
/**
* Redirects the browser to this ticket's view.
*/
public function show()
{
Whups::urlFor('ticket', $this->_id, true)->redirect();
}
/**
* Returns data for this ticket's feed.
*
* @return array Link data.
*/
public function feedLink()
{
return array(
'href' => Whups::urlFor('ticket_rss', $this->getId(), true, -1),
'title' => '[#' . $this->getId() . '] ' . $this->get('summary')
);
}
/**
* Sets exclusive read permissions on a comment to a certain group.
*
* @param integer $commentId The id of the comment to restrict.
* @param string $group The group name to limit access by.
*
* @return integer The permission id.
*/
static public function addCommentPerms($commentId, $group)
{
if (!empty($group)) {
$perms = $GLOBALS['injector']
->getInstance('Horde_Perms');
$perms_core = $GLOBALS['injector']
->getInstance('Horde_Core_Perms');
if (!$perms->exists('whups')) {
$perm = $perms_core->newPermission('whups');
$perm->addDefaultPermission(Horde_Perms::ALL, false);
$perms->addPermission($perm);
}
if (!$perms->exists('whups:comments')) {
$perms->addPermission($perms_core->newPermission('whups:comments'));
}
$perm = $perms_core->newPermission('whups:comments:' . $commentId);
$perm->addGroupPermission($group, Horde_Perms::READ, false);
return $perms->addPermission($perm);
}
}
/**
* Sets all properties of the ticket necessary to display the
* TicketDetailsForm.
*
* @param Horde_Variables $vars The form variables object to set info in.
*/
public function setDetails(Horde_Variables &$vars)
{
$vars->set('id', $this->getId());
foreach ($this->getDetails() as $varname => $value) {
$vars->set($varname, $value);
}
/* User formatting. */
$vars->set('user_id_requester',
Whups::formatUser($this->get('user_id_requester')));
$vars->set('user_id_owner', Whups::getOwners($this->_id));
/* Attachments. */
$attachments = array();
try {
$files = Whups::getAttachments($this->_id);
} catch (Whups_Exception $e) {
$GLOBALS['notification']->push($e->getMessage());
}
if ($files) {
foreach ($files as $file) {
$attachments[] = Whups::attachmentUrl(
$this->_id, $file, $this->_details['queue']);
}
$vars->set('attachments', implode(" \n", $attachments));
}
}
/**
* Notifies all appropriate people of the creation/update of this ticket.
*
* @param string $author Who created/changed the ticket?
* @param boolean $isNew Is this a new ticket or a change to an existing
* one?
* @param array $listeners The list of listener that should receive the
* notification, with user names as keys and user
* roles as values. If empty, the list will be
* created automatically.
*/
public function notify($author, $isNew, $listeners = array())
{
global $conf, $whups_driver;
/* Get the attributes for this ticket. */
$attributes = $whups_driver->getAttributesForType($this->get('type'));
$fields = array(
'queue' => _("Queue"),
'version' => _("Version"),
'type' => _("Type"),
'state' => _("State"),
'priority' => _("Priority"),
'due' => _("Due"),
);
$field_names = array_merge($fields, array(_("Created By"),
_("Updated By"),
_("Summary"),
_("Owners"),
_("New Attachment"),
_("Deleted Attachment")));
foreach ($attributes as $attribute) {
$field_names[] = $attribute['human_name'];
}
/* Find the longest translated field name. */
$length = 0;
foreach ($field_names as $field_name) {
$length = max($length, Horde_String::length($field_name));
}
$wrap_break = "\n" . str_repeat(' ', $length + 2) . '| ';
$wrap_width = 73 - $length;
/* Ticket URL. */
$url = sprintf(_("Ticket URL: %s"),
Whups::urlFor('ticket', $this->_id, true, -1));
/* Ticket properties. */
$table = "------------------------------------------------------------------------------\n"
. ' ' . Horde_String::pad(_("Ticket"), $length) . ' | '
. $this->_id . "\n" . ' '
. Horde_String::pad($isNew ? _("Created By") : _("Updated By"), $length)
. ' | ' . Whups::formatUser($author) . "\n";
if (isset($this->_changes['summary'])) {
$table .= '-' . Horde_String::pad(_("Summary"), $length) . ' | '
. Horde_String::wrap($this->_changes['summary']['from'],
$wrap_width, $wrap_break)
. "\n" . '+' . Horde_String::pad(_("Summary"), $length) . ' | '
. Horde_String::wrap($this->get('summary'), $wrap_width, $wrap_break)
. "\n";
} else {
$table .= ' ' . Horde_String::pad(_("Summary"), $length) . ' | '
. Horde_String::wrap($this->get('summary'), $wrap_width, $wrap_break)
. "\n";
}
foreach ($fields as $field => $label) {
if ($name = $this->get($field . '_name')) {
if (isset($this->_changes[$field])) {
$table .= '-' . Horde_String::pad($label, $length) . ' | '
. Horde_String::wrap($this->_changes[$field]['from_name'],
$wrap_width, $wrap_break)
. "\n" . '+' . Horde_String::pad($label, $length) . ' | '
. Horde_String::wrap($name, $wrap_width, $wrap_break) . "\n";
} else {
$table .= ' ' . Horde_String::pad($label, $length) . ' | '
. Horde_String::wrap($name, $wrap_width, $wrap_break) . "\n";
}
}
}
/* Attribute changes. */
foreach ($attributes as $id => $attribute) {
$attribute_id = 'attribute_' . $id;
$label = $attribute['human_name'];
if (isset($this->_changes[$attribute_id])) {
$table .= '-' . Horde_String::pad($label, $length) . ' | '
. Horde_String::wrap($this->_changes[$attribute_id]['from'],
$wrap_width, $wrap_break)
. "\n" . '+' . Horde_String::pad($label, $length) . ' | '
. Horde_String::wrap($this->_changes[$attribute_id]['to'],
$wrap_width, $wrap_break)
. "\n";
} else {
$table .= ' ' . Horde_String::pad($label, $length) . ' | '
. Horde_String::wrap($this->get($attribute_id),
$wrap_width, $wrap_break)
. "\n";
}
}
/* Show any change in ticket owners. */
$owners = $oldOwners = Horde_String::wrap(
Whups::getOwners($this->_id, false, true),
$wrap_width, $wrap_break);
if (isset($this->_changes['oldowners'])) {
$oldOwners = Horde_String::wrap(
Whups::getOwners($this->_id, false, true,
$this->_changes['oldowners']),
$wrap_width, $wrap_break);
}
if ($owners != $oldOwners) {
$table .= '-' . Horde_String::pad(_("Owners"), $length) . ' | '
. $oldOwners . "\n" . '+' . Horde_String::pad(_("Owners"), $length)
. ' | ' . $owners . "\n";
} else {
$table .= ' ' . Horde_String::pad(_("Owners"), $length) . ' | '
. $owners . "\n";
}
/* New Attachments. */
if (isset($this->_changes['attachment'])) {
$table .= '+' . Horde_String::pad(_("New Attachment"), $length) . ' | '
. $this->_changes['attachment']['to']['name'] . "\n";
}
if (!empty($this->_changes['attachments'])) {
foreach ($this->_changes['attachments']['to'] as $attachment) {
$table .= '+' . Horde_String::pad(_("New Attachment"), $length)
. ' | ' . $attachment['name'] . "\n";
}
}
/* Deleted Attachments. */
if (isset($this->_changes['delete-attachment'])) {
$table .= '+' . Horde_String::pad(_("Deleted Attachment"), $length)
. ' | ' . $this->_changes['delete-attachment']['to'] . "\n";
}
$table .= "------------------------------------------------------------------------------";
/* Add the "do not reply" tag if we don't monitor incoming mail. */
if (empty($conf['mail']['reply'])) {
$dont_reply = _("DO NOT REPLY TO THIS MESSAGE. THIS EMAIL ADDRESS IS NOT MONITORED.") . "\n\n";
} else {
$dont_reply = '';
}
/* Build message template. */
$view = new Horde_View(array('templatePath' => WHUPS_BASE . '/config'));
$view->ticket_url = $url;
$view->table = $table;
$view->dont_reply = empty($conf['mail']['reply']);
$view->date = strftime($GLOBALS['prefs']->getValue('date_format'));
$view->auth_name = $GLOBALS['injector']
->getInstance('Horde_Core_Factory_Identity')
->create()
->getValue('fullname');
if (empty($view->auth_name)) {
$view->auth_name = $GLOBALS['registry']->getAuth('bare');
}
/* Get queue specific notification message text, if available. */
$message_file = WHUPS_BASE . '/config/'
. ($isNew ? 'create_email.plain' : 'notify_email.plain');
if (file_exists($message_file . '.' . $this->get('queue') . '.php')) {
$message_file .= '.' . $this->get('queue') . '.php';
} elseif (file_exists($message_file . '.local.php')) {
$message_file .= '.local.php';
} else {
$message_file .= '.php';
}
$message_file = basename($message_file);
/* Include Re: if the ticket isn't new for easy
* filtering/eyeballing. */
$subject = $this->get('summary');
if (!$isNew) {
$subject = 'Re: ' . $subject;
}
if (empty($listeners)) {
if ($conf['mail']['incl_resp'] ||
!count(current($whups_driver->getOwners($this->_id)))) {
/* Include all responsible. */
$listeners = $whups_driver->getListeners(
$this->_id, true, true, true);
} else {
/* Don't include all responsible unless ticket is assigned. */
$listeners = $whups_driver->getListeners(
$this->_id, true, true, false);
}
/* Notify both old and new queue users if the queue has changed. */
if (isset($this->_changes['queue'])) {
foreach ($whups_driver->getQueueUsers($this->_changes['queue']['from_name']) as $user) {
$listeners[$user] = 'queue';
}
}
}
/* Pass off to Whups_Driver::mail() to do the actual comment fetching,
* permissions checks, etc. */
$whups_driver->mail(array('ticket' => $this,
'recipients' => $listeners,
'subject' => $subject,
'view' => $view,
'template' => $message_file,
'from' => $author,
'new' => $isNew));
}
/**
* Returns a plain text representation of a ticket.
*/
public function toString()
{
$fields = array('queue' => _("Queue"),
'version' => _("Version"),
'type' => _("Type"),
'state' => _("State"),
'priority' => _("Priority"),
'due' => _("Due"));
/* Find longest translated field name. */
$length = 0;
foreach (array_merge($fields, array(_("Summary"), _("Owners")))
as $field) {
$length = max($length, Horde_String::length($field));
}
$wrap_break = "\n" . str_repeat(' ', $length + 2) . '| ';
$wrap_width = 73 - $length;
/* Ticket properties. */
$message = ' ' . Horde_String::pad(_("Ticket"), $length) . ' | '
. $this->_id . "\n" . ' ' . Horde_String::pad(_("Summary"), $length)
. ' | ' . Horde_String::wrap($this->get('summary'),
$wrap_width, $wrap_break)
. "\n";
foreach ($fields as $field => $label) {
if ($name = $this->get($field . '_name')) {
$message .= ' ' . Horde_String::pad($label, $length) . ' | '
. Horde_String::wrap($name, $wrap_width, $wrap_break) . "\n";
}
}
$message .= ' ' . Horde_String::pad(_("Owners"), $length) . ' | '
. Horde_String::wrap(Whups::getOwners($this->_id, false, true),
$wrap_width, $wrap_break)
. "\n";
return $message;
}
public function __toString()
{
return $this->toString();
}
/**
* Adds ticket attribute values to the ticket's details, and returns the
* list of attributes.
*
* @return array List of ticket attribute hashes.
*/
public function addAttributes()
{
$attributes = $GLOBALS['whups_driver']
->getAllTicketAttributesWithNames($this->getId());
foreach ($attributes as $attribute_id => $attribute) {
$this->set('attribute_' . $attribute_id, $attribute['value']);
}
return $attributes;
}
}
whups-3.0.0beta1/lib/Whups.php 0000664 0001750 0001750 00000122015 12160315153 014264 0 ustar jan jan
* Copyright 2001-2013 Horde LLC (http://www.horde.org/)
*
* See the enclosed file LICENSE for license information (BSD). If you
* did not receive this file, see http://www.horde.org/licenses/bsdl.php.
*
* @package Whups
*/
/**
* The Whups class provides functionality that all of Whups needs, or that
* should be encapsulated from other parts of the Whups system.
*
* @author Robert E. Coyle
* @author Jan Schneider
* @package Whups
*/
class Whups
{
/**
* Path to ticket attachments in the VFS.
*/
const VFS_ATTACH_PATH = '.horde/whups/attachments';
/**
* The current sort field.
*
* @see sortBy()
* @var string
*/
static protected $_sortBy;
/**
* The current sort direction.
*
* @see sortDir()
* @var integer
*/
static protected $_sortDir;
/**
* Cached list of user information.
*
* @see getUserAttributes()
* @var array
*/
static protected $_users = array();
/**
* All available form field types including all type information
* from the Horde_Form classes.
*
* @see fieldTypes()
* @var array
*/
static protected $_fieldTypes = array();
/**
* URL factory.
*
* @param string $controller The controller to link to, one of
* 'queue', 'ticket', 'ticket_rss',
* 'ticket_action', 'query', 'query_rss'.
* @param array|string $data URL data, depending on the controller.
* @param boolean $full @see Horde::url()
* @param integer $append_session @see Horde::url()
*
* @return Horde_Url The generated URL.
*/
static public function urlFor($controller, $data, $full = false,
$append_session = 0)
{
$rewrite = isset($GLOBALS['conf']['urls']['pretty']) &&
$GLOBALS['conf']['urls']['pretty'] == 'rewrite';
switch ($controller) {
case 'queue':
if ($rewrite) {
if (is_array($data)) {
if (empty($data['slug'])) {
$slug = (int)$data['id'];
} else {
$slug = $data['slug'];
}
} else {
$slug = (int)$data;
}
return Horde::url('queue/' . $slug, $full, $append_session);
} else {
if (is_array($data)) {
$id = $data['id'];
} else {
$id = $data;
}
return Horde::url('queue/?id=' . $id, $full, $append_session);
}
break;
case 'ticket':
$id = (int)$data;
if ($rewrite) {
return Horde::url('ticket/' . $id, $full, $append_session);
} else {
return Horde::url('ticket/?id=' . $id, $full, $append_session);
}
break;
case 'ticket_rss':
$id = (int)$data;
if ($rewrite) {
return Horde::url('ticket/' . $id . '/rss', $full, $append_session);
} else {
return Horde::url('ticket/rss.php?id=' . $id, $full, $append_session);
}
break;
case 'ticket_action':
list($controller, $id) = $data;
if ($rewrite) {
return Horde::url('ticket/' . $id . '/' . $controller, $full, $append_session = 0);
} else {
return Horde::url('ticket/' . $controller . '.php?id=' . $id, $full, $append_session = 0);
}
case 'query':
case 'query_rss':
if ($rewrite) {
if (is_array($data)) {
if (isset($data['slug'])) {
$slug = $data['slug'];
} else {
$slug = $data['id'];
}
} else {
$slug = (int)$data;
}
$url = 'query/' . $slug;
if ($controller == 'query_rss') {
$url .= '/rss';
}
return Horde::url($url, $full, $append_session);
} else {
if (is_array($data)) {
if (isset($data['slug'])) {
$param = array('slug' => $data['slug']);
} else {
$param = array('query' => $data['id']);
}
} else {
$param = array('query' => $data);
}
$url = $controller == 'query' ? 'query/run.php' : 'query/rss.php';
return Horde::url($url, $full, $append_session)->add($param);
}
break;
}
}
/**
* Sorts tickets by requested direction and fields.
*
* @param array $tickets The list of tickets to sort.
* @param string $by The field to sort by. If omitted, obtain from
* preferences.
* @param string $dir The direction to sort. If omitted, obtain from
* preferences.
*/
static public function sortTickets(&$tickets, $by = null, $dir = null)
{
if (is_null($by)) {
$by = $GLOBALS['prefs']->getValue('sortby');
}
if (is_null($dir)) {
$dir = $GLOBALS['prefs']->getValue('sortdir');
}
self::sortBy($by);
self::sortDir($dir);
// Do some prep for sorting.
$tickets = array_map(array('Whups', '_prepareSort'), $tickets);
usort($tickets, array('Whups', '_sort'));
}
/**
* Sets or returns the current sort field.
*
* @param string $b The field to sort by.
*
* @return string If $b is null, returns the previously set value.
*/
static public function sortBy($b = null)
{
if (!is_null($b)) {
self::$_sortBy = $b;
} else {
return self::$_sortBy;
}
}
/**
* Sets or returns the current sort direction.
*
* @param integer $d The direction to sort by.
*
* @return integer If $d is null, returns the previously set value.
*/
static public function sortDir($d = null)
{
if (!is_null($d)) {
self::$_sortDir = $d;
} else {
return self::$_sortDir;
}
}
/**
* Helper method to prepare an array of tickets for sorting.
*
* Adds a sort_by key to each ticket array, with values lowercased. Used as
* a callback to array_map().
*
* @param array $ticket The ticket array to prepare.
*
* @return array The altered $ticket array
*/
static protected function _prepareSort(array $ticket)
{
$by = self::sortBy();
$ticket['sort_by'] = array();
if (is_array($by)) {
foreach ($by as $field) {
if (!isset($ticket[$field])) {
$ticket['sort_by'][$field] = '';
} else {
$ticket['sort_by'][$field] = Horde_String::lower($ticket[$field], true, 'UTF-8');
}
}
} else {
if (!isset($ticket[$by])) {
$ticket['sort_by'][$by] = '';
} elseif (is_array($ticket[$by])) {
natcasesort($ticket[$by]);
$ticket['sort_by'][$by] = implode('', $ticket[$by]);
} else {
$ticket['sort_by'][$by] = Horde_String::lower($ticket[$by], true, 'UTF-8');
}
}
return $ticket;
}
/**
* Helper method to sort an array of tickets.
*
* Used as callback to usort().
*
* @param array $a The first ticket to compare.
* @param array $b The second ticket to compare.
* @param string $sortby The field to sort by. If null, uses the field
* from self::sortBy().
* @param string $sortdir The direction to sort. If null, uses the value
* from self::sortDir().
*
* @return integer
*/
static protected function _sort($a, $b, $sortby = null, $sortdir = null)
{
if (is_null($sortby)) {
$sortby = self::$_sortBy;
}
if (is_null($sortdir)) {
$sortdir = self::$_sortDir;
}
if (is_array($sortby)) {
if (!isset($a[$sortby[0]])) {
$a[$sortby[0]] = null;
}
if (!isset($b[$sortby[0]])) {
$b[$sortby[0]] = null;
}
if (!count($sortby)) {
return 0;
}
if ($a['sort_by'][$sortby[0]] > $b['sort_by'][$sortby[0]]) {
return $sortdir[0] ? -1 : 1;
}
if ($a['sort_by'][$sortby[0]] === $b['sort_by'][$sortby[0]]) {
array_shift($sortby);
array_shift($sortdir);
return self::_sort($a, $b, $sortby, $sortdir);
}
return $sortdir[0] ? 1 : -1;
}
$a_val = isset($a['sort_by'][$sortby]) ? $a['sort_by'][$sortby] : null;
$b_val = isset($b['sort_by'][$sortby]) ? $b['sort_by'][$sortby] : null;
// Take care of the simplest case first
if ($a_val === $b_val) {
return 0;
}
if ((is_numeric($a_val) || is_null($a_val)) &&
(is_numeric($b_val) || is_null($b_val))) {
// Numeric comparison
return (int)($sortdir ? ($b_val > $a_val) : ($a_val > $b_val));
}
// Some special case sorting
if (is_array($a_val) || is_array($b_val)) {
$a_val = implode('', $a_val);
$b_val = implode('', $b_val);
}
// String comparison
return $sortdir ? strcoll($b_val, $a_val) : strcoll($a_val, $b_val);
}
/**
* Returns a new or the current CAPTCHA string.
*
* @param boolean $new If true, a new CAPTCHA is created and returned.
* The current, to-be-confirmed string otherwise.
*
* @return string A CAPTCHA string.
*/
static public function getCAPTCHA($new = false)
{
global $session;
if ($new || !$session->get('whups', 'captcha')) {
$captcha = '';
for ($i = 0; $i < 5; ++$i) {
$captcha .= chr(rand(65, 90));
}
$session->set('whups', 'captcha', $captcha);
}
return $session->get('whups', 'captcha');
}
/**
* Lists all templates of a given type.
*
* @param string $type The kind of template ('searchresults', etc.) to
* list.
*
* @return array All templates of the requested type.
*/
static public function listTemplates($type)
{
$templates = array();
$_templates = Horde::loadConfiguration('templates.php', '_templates', 'whups');
foreach ($_templates as $name => $info) {
if ($info['type'] == $type) {
$templates[$name] = $info['name'];
}
}
return $templates;
}
/**
* Returns the current ticket.
*
* Uses the 'id' request variable to determine what to look for. Will
* redirect to the default view if the ticket isn't found or if permissions
* checks fail.
*
* @return Whups_Ticket The current ticket.
*/
static public function getCurrentTicket()
{
$default = Horde::url($GLOBALS['prefs']->getValue('whups_default_view') . '.php', true);
$id = Horde_Util::getFormData('searchfield');
if (empty($id)) {
$id = Horde_Util::getFormData('id');
}
$id = preg_replace('|\D|', '', $id);
if (!$id) {
$GLOBALS['notification']->push(_("Invalid Ticket Id"), 'horde.error');
$default->redirect();
}
try {
return Whups_Ticket::makeTicket($id);
} catch (Whups_Exception $e) {
if ($ticket->code === 0) {
// No permissions to this ticket.
$GLOBALS['notification']->push($e->getMessage(), 'horde.warning');
$default->redirect();
}
} catch (Exception $e) {
$GLOBALS['notification']->push($e);
$default->redirect();
}
}
/**
* Adds topbar search to page
*/
static public function addTopbarSearch() {
$topbar = $GLOBALS['injector']->getInstance('Horde_View_Topbar');
$topbar->search = true;
$topbar->searchAction = Horde::url('ticket');
$topbar->searchLabel = $GLOBALS['session']->get('whups', 'search') ?: _("Ticket #Id");
}
/**
* Returns the tabs for navigating between ticket actions.
*/
static public function getTicketTabs(&$vars, $id)
{
$tabs = new Horde_Core_Ui_Tabs(null, $vars);
$queue = $vars->get('queue');
$tabs->addTab(_("_History"), self::urlFor('ticket', $id), 'history');
if (self::hasPermission($queue, 'queue', 'update')) {
$tabs->addTab(_("_Update"),
self::urlFor('ticket_action', array('update', $id)),
'update');
} else {
$tabs->addTab(_("_Comment"),
self::urlFor('ticket_action', array('comment', $id)),
'comment');
}
$tabs->addTab(_("_Watch"),
self::urlFor('ticket_action', array('watch', $id)),
'watch');
if (self::hasPermission($queue, 'queue', Horde_Perms::DELETE)) {
$tabs->addTab(_("S_et Queue"),
self::urlFor('ticket_action', array('queue', $id)),
'queue');
}
if (self::hasPermission($queue, 'queue', 'update')) {
$tabs->addTab(_("Set _Type"),
self::urlFor('ticket_action', array('type', $id)),
'type');
}
if (self::hasPermission($queue, 'queue', Horde_Perms::DELETE)) {
$tabs->addTab(_("_Delete"),
self::urlFor('ticket_action', array('delete', $id)),
'delete');
}
return $tabs;
}
/**
* Returns whether a user has a certain permission on a single resource.
*
* @param mixed $in A single resource to check.
* @param string $filter The kind of resource specified in
* $in, currently only 'queue'.
* @param string|integer $permission A permission, either 'assign' or
* 'update', 'requester', or one of the
* PERM_* constants.
* @param string $user A user name.
*
* @return boolean True if the user has the specified permission.
*/
static public function hasPermission($in, $filter, $permission, $user = null)
{
if (is_null($user)) {
$user = $GLOBALS['registry']->getAuth();
}
if ($permission == 'update' ||
$permission == 'assign' ||
$permission == 'requester') {
$admin_perm = Horde_Perms::EDIT;
} else {
$admin_perm = $permission;
}
$admin = $GLOBALS['registry']->isAdmin(array('permission' => 'whups:admin', 'permlevel' => $admin_perm, 'user' => $user));
$perms = $GLOBALS['injector']->getInstance('Horde_Perms');
switch ($filter) {
case 'queue':
if ($admin) {
return true;
}
switch ($permission) {
case Horde_Perms::SHOW:
case Horde_Perms::READ:
case Horde_Perms::EDIT:
case Horde_Perms::DELETE:
if ($perms->hasPermission('whups:queues:' . $in, $user,
$permission)) {
return true;
}
break;
default:
if ($perms->exists('whups:queues:' . $in . ':' . $permission)) {
if (($permission == 'update' ||
$permission == 'assign' ||
$permission == 'requester') &&
$perms->getPermissions(
'whups:queues:' . $in . ':' . $permission, $user)) {
return true;
}
} else {
// If the sub-permission doesn't exist, use the queue
// permission at an EDIT level and lock out guests.
if ($permission != 'requester' &&
$GLOBALS['registry']->getAuth() &&
$perms->hasPermission('whups:queues:' . $in, $user,
Horde_Perms::EDIT)) {
return true;
}
}
break;
}
break;
}
return false;
}
/**
* Filters a list of resources based on whether a user has certain
* permissions on it.
*
* @param array $in A list of resources to check.
* @param string $filter The kind of resource specified in $in,
* one of 'queue', 'queue_id', 'reply', or
* 'comment'.
* @param integer $permission A permission, one of the PERM_* constants.
* @param string $user A user name.
* @param string $creator The creator of an object in the resource,
* e.g. a ticket creator.
*
* @return array The list of resources matching the permission criteria.
*/
static public function permissionsFilter($in, $filter,
$permission = Horde_Perms::READ,
$user = null, $creator = null)
{
if (is_null($user)) {
$user = $GLOBALS['registry']->getAuth();
}
$admin = $GLOBALS['registry']->isAdmin(array('permission' => 'whups:admin', 'permlevel' => $permission, 'user' => $user));
$perms = $GLOBALS['injector']->getInstance('Horde_Perms');
$out = array();
switch ($filter) {
case 'queue':
if ($admin) {
return $in;
}
foreach ($in as $queueID => $name) {
if (!$perms->exists('whups:queues:' . $queueID) ||
$perms->hasPermission('whups:queues:' . $queueID, $user,
$permission, $creator)) {
$out[$queueID] = $name;
}
}
break;
case 'queue_id':
if ($admin) {
return $in;
}
foreach ($in as $queueID) {
if (!$perms->exists('whups:queues:' . $queueID) ||
$perms->hasPermission('whups:queues:' . $queueID, $user,
$permission, $creator)) {
$out[] = $queueID;
}
}
break;
case 'reply':
if ($admin) {
return $in;
}
foreach ($in as $replyID => $name) {
if (!$perms->exists('whups:replies:' . $replyID) ||
$perms->hasPermission('whups:replies:' . $replyID,
$user, $permission, $creator)) {
$out[$replyID] = $name;
}
}
break;
case 'comment':
foreach ($in as $key => $row) {
foreach ($row as $rkey => $rval) {
if ($rkey != 'changes') {
$out[$key][$rkey] = $rval;
continue;
}
foreach ($rval as $i => $change) {
if ($change['type'] != 'comment' ||
!$perms->exists('whups:comments:' . $change['value'])) {
$out[$key][$rkey][$i] = $change;
if (isset($change['comment'])) {
$out[$key]['comment_text'] = $change['comment'];
}
} elseif ($perms->exists('whups:comments:' . $change['value'])) {
$change['private'] = true;
$out[$key][$rkey][$i] = $change;
if (isset($change['comment'])) {
if ($admin ||
$perms->hasPermission('whups:comments:' . $change['value'],
$user, Horde_Perms::READ, $creator)) {
$out[$key]['comment_text'] = $change['comment'];
} else {
$out[$key][$rkey][$i]['comment'] = _("[Hidden]");
}
}
}
}
}
}
break;
default:
$out = $in;
break;
}
return $out;
}
/**
* Builds a list of criteria for Whups_Driver#getTicketsByProperties() that
* match a certain user.
*
* Merges the user's groups with the user name.
*
* @param string $user A user name.
*
* @return array A list of criteria that would match the user.
*/
static public function getOwnerCriteria($user)
{
$criteria = array('user:' . $user);
$mygroups = $GLOBALS['injector']
->getInstance('Horde_Group')
->listGroups($GLOBALS['registry']->getAuth());
foreach ($mygroups as $id => $group) {
$criteria[] = 'group:' . $id;
}
return $criteria;
}
/**
* Returns a hash with user information.
*
* @param string $user A (Whups) user name, defaults to the current user.
*
* @return array An information hash with 'user', 'name', 'email', and
* 'type' values.
*/
static public function getUserAttributes($user = null)
{
if (is_null($user)) {
$user = $GLOBALS['registry']->getAuth();
} elseif (empty($user)) {
return array('user' => '',
'name' => '',
'email' => '');
}
if (isset(self::$_users[$user])) {
return self::$_users[$user];
}
if (strpos($user, ':') !== false) {
list($type, $user) = explode(':', $user, 2);
} else {
$type = 'user';
}
// Default this; some of the cases below might change it.
self::$_users[$user]['user'] = $user;
self::$_users[$user]['type'] = $type;
switch ($type) {
case 'user':
if (substr($user, 0, 2) == '**') {
unset(self::$_users[$user]);
$user = substr($user, 2);
self::$_users[$user]['user'] = $user;
self::$_users[$user]['name'] = '';
self::$_users[$user]['email'] = '';
$addr_ob = new Horde_Mail_Rfc822_Address($user);
if ($addr_ob->valid) {
self::$_users[$user]['name'] = is_null($addr_ob->personal)
? ''
: $addr_ob->personal;
self::$_users[$user]['email'] = $addr_ob->bare_address;
}
} elseif ($user < 0) {
global $whups_driver;
self::$_users[$user]['user'] = '';
self::$_users[$user]['name'] = '';
self::$_users[$user]['email'] = $whups_driver->getGuestEmail($user);
$addr_ob = new Horde_Mail_Rfc822_Address(self::$_users[$user]['email']);
if ($addr_ob->valid) {
self::$_users[$user]['name'] = is_null($addr_ob->personal)
? ''
: $addr_ob->personal;
self::$_users[$user]['email'] = $addr_ob->bare_address;
}
} else {
$identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($user);
self::$_users[$user]['name'] = $identity->getValue('fullname');
self::$_users[$user]['email'] = $identity->getValue('from_addr');
}
break;
case 'group':
try {
$group = $GLOBALS['injector']
->getInstance('Horde_Group')
->getData($user);
self::$_users[$user]['user'] = $group['name'];
self::$_users[$user]['name'] = $group['name'];
self::$_users[$user]['email'] = $group['email'];
} catch (Horde_Exception $e) {
self::$_users['user']['name'] = '';
self::$_users['user']['email'] = '';
}
break;
}
return self::$_users[$user];
}
/**
* Returns a user string from the user's name and email address.
*
* @param string|array $user A user name or a hash as returned from
* {@link self::getUserAttributes()}.
* @param boolean $showemail Whether to include the email address.
* @param boolean $showname Whether to include the full name.
* @param boolean $html Whether to "prettify" the result. If true,
* email addresses are obscured, the result is
* escaped for HTML output, and a group icon
* might be added.
*/
static public function formatUser($user = null, $showemail = true,
$showname = true, $html = false)
{
if (!is_null($user) && empty($user)) {
return '';
}
if (is_array($user)) {
$details = $user;
} else {
$details = self::getUserAttributes($user);
}
if (!empty($details['name'])) {
$name = $details['name'];
} else {
$name = $details['user'];
}
if (($showemail || empty($name) || !$showname) &&
!empty($details['email'])) {
if ($html && strpos($details['email'], '@') !== false) {
$details['email'] = str_replace(array('@', '.'),
array(' (at) ', ' (dot) '),
$details['email']);
}
if (!empty($name) && $showname) {
$name .= ' <' . $details['email'] . '>';
} else {
$name = $details['email'];
}
}
if ($html) {
$name = htmlspecialchars($name);
if ($details['type'] == 'group') {
$name = Horde::img('group.png',
!empty($details['name'])
? $details['name']
: $details['user'])
. $name;
}
}
return $name;
}
/**
* Formats a ticket property for a tabular ticket listing.
*
* @param array $info A ticket information hash.
* @param string $value The column/property to format.
*
* @return string The formatted property.
*/
static public function formatColumn($info, $value)
{
$url = Whups::urlFor('ticket', $info['id']);
$thevalue = isset($info[$value]) ? $info[$value] : '';
if ($value == 'timestamp' || $value == 'due' ||
substr($value, 0, 5) == 'date_') {
require_once 'Horde/Form/Type.php';
$thevalue = Horde_Form_Type_date::getFormattedTime(
$thevalue,
$GLOBALS['prefs']->getValue('report_time_format'),
false);
} elseif ($value == 'user_id_requester') {
$thevalue = $info['requester_formatted'];
} elseif ($value == 'id' || $value == 'summary') {
$thevalue = Horde::link($url) . '' . htmlspecialchars($thevalue) . '';
} elseif ($value == 'owners') {
if (!empty($info['owners_formatted'])) {
$thevalue = implode(', ', $info['owners_formatted']);
}
}
return $thevalue;
}
/**
* Returns the set of columns and their associated parameter from the
* backend that should be displayed to the user.
*
* The results can depend on the current user preferences, which search
* function was executed, and the $columns parameter.
*
* @param integer $search_type The type of search that was executed.
* Currently only 'block' is supported.
* @param array $columns The columns to return, overriding the
* defaults for some $search_type.
*/
static public function getSearchResultColumns($search_type = null,
$columns = null)
{
$all = array(
_("Id") => 'id',
_("Summary") => 'summary',
_("State") => 'state_name',
_("Type") => 'type_name',
_("Priority") => 'priority_name',
_("Queue") => 'queue_name',
_("Requester") => 'user_id_requester',
_("Owners") => 'owners',
_("Created") => 'timestamp',
_("Updated") => 'date_updated',
_("Assigned") => 'date_assigned',
_("Due") => 'due',
_("Resolved") => 'date_resolved',
);
if ($search_type != 'block') {
return $all;
}
if (is_null($columns)) {
$columns = array('summary', 'priority_name', 'state_name');
}
$result = array(_("Id") => 'id');
foreach ($columns as $param) {
if (($label = array_search($param, $all)) !== false) {
$result[$label] = $param;
}
}
return $result;
}
/**
* Sends reminders, one email per user.
*
* @param Horde_Variables $vars The selection criteria:
* - 'id' (integer) for individual tickets
* - 'queue' (integer) for tickets of a queue.
* - 'category' (array) for ticket
* categories, defaults to unresolved
* tickets.
* - 'unassigned' (boolean) for unassigned
* tickets.
*
* @throws Whups_Exception
*/
static public function sendReminders($vars)
{
global $whups_driver;
if ($vars->get('id')) {
$info = array('id' => $vars->get('id'));
} elseif ($vars->get('queue')) {
$info['queue'] = $vars->get('queue');
if ($vars->get('category')) {
$info['category'] = $vars->get('category');
} else {
// Make sure that resolved tickets aren't returned.
$info['category'] = array('unconfirmed', 'new', 'assigned');
}
} else {
throw new Whups_Exception(_("You must select at least one queue to send reminders for."));
}
$tickets = $whups_driver->getTicketsByProperties($info);
self::sortTickets($tickets);
if (!count($tickets)) {
throw new Whups_Exception(_("No tickets matched your search criteria."));
}
$unassigned = $vars->get('unassigned');
$remind = array();
foreach ($tickets as $info) {
$info['link'] = self::urlFor('ticket', $info['id'], true, -1);
$owners = current($whups_driver->getOwners($info['id']));
if (!empty($owners)) {
foreach ($owners as $owner) {
$remind[$owner][] = $info;
}
} elseif (!empty($unassigned)) {
$remind['**' . $unassigned][] = $info;
}
}
/* Build message template. */
$view = new Horde_View(array('templatePath' => WHUPS_BASE . '/config'));
$view->date = strftime($GLOBALS['prefs']->getValue('date_format'));
/* Get queue specific notification message text, if available. */
$message_file = WHUPS_BASE . '/config/reminder_email.plain';
if (file_exists($message_file . '.local.php')) {
$message_file .= '.local.php';
} else {
$message_file .= '.php';
}
$message_file = basename($message_file);
foreach ($remind as $user => $utickets) {
if (empty($user) || !count($utickets)) {
continue;
}
$view->tickets = $utickets;
$subject = _("Reminder: Your open tickets");
$whups_driver->mail(array('recipients' => array($user => 'owner'),
'subject' => $subject,
'view' => $view,
'template' => $message_file,
'from' => $user));
}
}
/**
* Returns attachment information hashes from the VFS backend.
*
* @param integer $ticket A ticket ID.
* @param string $name An attachment name.
*
* @return array If $name is empty a list of all attachments' information
* hashes, otherwise only the hash for the attachment of
* that name.
*
* @throws Whups_Exception if the VFS object cannot be created.
*/
static public function getAttachments($ticket, $name = null)
{
if (empty($GLOBALS['conf']['vfs']['type'])) {
return;
}
try {
$vfs = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Vfs')->create();
} catch (Horde_Vfs_Exception $e) {
throw new Whups_Exception($e);
}
if (!$vfs->isFolder(self::VFS_ATTACH_PATH, $ticket)) {
return;
}
try {
$files = $vfs->listFolder(self::VFS_ATTACH_PATH . '/' . $ticket);
} catch (Horde_Vfs_Exception $e) {
$files = array();
}
if (is_null($name)) {
return $files;
}
foreach ($files as $file) {
if ($file['name'] == $name) {
return $file;
}
}
}
/**
* Returns the links to view, download, and delete an attachment.
*
* @param integer $ticket A ticket ID.
* @param string $file An attachment name.
* @param integer $queue The ticket's queue ID.
*/
static public function attachmentUrl($ticket, $file, $queue)
{
$link = '';
// Can we view the attachment online?
$mime_part = new Horde_Mime_Part();
$mime_part->setType(Horde_Mime_Magic::extToMime($file['type']));
$viewer = $GLOBALS['injector']->getInstance('Horde_Core_Factory_MimeViewer')->create($mime_part);
if ($viewer && !($viewer instanceof Horde_Mime_Viewer_Default)) {
$url = Horde::url('view.php')->add(array(
'actionID' => 'view_file',
'type' => $file['type'],
'file' => $file['name'],
'ticket' => $ticket));
$link .= Horde::link($url, $file['name'], null, '_blank') . $file['name'] . '';
} else {
$link .= $file['name'];
}
// We can always download attachments.
$url_params = array('actionID' => 'download_file',
'file' => $file['name'],
'ticket' => $ticket);
$link .= ' ' . Horde::link($GLOBALS['registry']->downloadUrl($file['name'], $url_params), $file['name']) . Horde::img('download.png', _("Download")) . '';
// Admins can delete attachments.
if (self::hasPermission($queue, 'queue', Horde_Perms::DELETE)) {
$url = Horde::url('ticket/delete_attachment.php')->add(
array('file' => $file['name'],
'id' => $ticket,
'url' => Horde::selfUrl(true, false, true)));
$link .= ' ' . Horde::link($url, sprintf(_("Delete %s"), $file['name']), '', '', 'return window.confirm(\'' . addslashes(sprintf(_("Permanently delete %s?"), $file['name'])) . '\');') .
Horde::img('delete.png', sprintf(_("Delete %s"), $file['name'])) . '';
}
return $link;
}
/**
* Returns formatted owner names of a ticket.
*
* @param integer $ticket A ticket id. Only used if $owners is null.
* @param boolean $showmail Should we include the email address in the
* output?
* @param boolean $showname Should we include the name in the output?
* @param array $owners An array of owners as returned from
* Whups_Driver::getOwners() to be formatted. If
* this is provided, they are used instead of
* the owners from $ticket.
*
* @return string The formatted owner string.
*/
static public function getOwners($ticket, $showemail = true,
$showname = true, $owners = null)
{
if (is_null($owners)) {
$owners = $GLOBALS['whups_driver']->getOwners($ticket);
}
$results = array();
$owners = reset($owners);
if ($owners !== false) {
foreach ($owners as $owner) {
$results[] = self::formatUser($owner, $showemail, $showname);
}
}
return implode(', ', $results);
}
/**
* Returns all available form field types including all type information
* from the Horde_Form classes.
*
* @todo Doesn't work with autoloading.
*
* @return array The full field types array.
*/
static public function fieldTypes()
{
if (!empty(self::$_fieldTypes)) {
return self::$_fieldTypes;
}
/* Fetch all declared classes. */
$classes = get_declared_classes();
/* Filter for the Horde_Form_Type classes. */
$blacklist = array('invalid', 'addresslink', 'spacer', 'description',
'captcha', 'figlet', 'header');
foreach ($classes as $class) {
if (stripos($class, 'horde_form_type_') !== false) {
$field_type = substr($class, 16);
/* Don't bother including the types that cannot be handled
* usefully. */
if (in_array($field_type, $blacklist)) {
continue;
}
self::$_fieldTypes[$field_type] = @call_user_func(
array('Horde_Form_Type_' . $field_type, 'about'));
}
}
return self::$_fieldTypes;
}
/**
* Returns the available field type names from the Horde_Form classes.
*
* @return array A hash The with available field types and names.
*/
static public function fieldTypeNames()
{
/* Fetch the field type information from the Horde_Form classes. */
$fields = self::fieldTypes();
/* Strip out the name element from the array. */
$available_fields = array();
foreach ($fields as $field_type => $info) {
$available_fields[$field_type] = $info['name'];
}
/* Sort for display purposes. */
asort($available_fields);
return $available_fields;
}
/**
* Returns the parameters for a certain Horde_Form field type.
*
* @param string $field_type A field type.
*
* @return array A list of field type parameters.
*/
static public function fieldTypeParams($field_type)
{
$fields = self::fieldTypes();
return isset($fields[$field_type]['params'])
? $fields[$field_type]['params']
: array();
}
/**
* Returns the parameters necessary to run an address search.
*
* @return array An array with two keys: 'sources' and 'fields'.
*/
static public function getAddressbookSearchParams()
{
$src = json_decode($GLOBALS['prefs']->getValue('search_sources'));
if (!is_array($src)) {
$src = array();
}
$fields = json_decode($GLOBALS['prefs']->getValue('search_fields'), true);
if (!is_array($fields)) {
$fields = array();
}
return array(
'fields' => $fields,
'sources' => $src
);
}
static public function addFeedLink()
{
$GLOBALS['page_output']->addLinkTag(array(
'href' => Horde::url('opensearch.php', true, -1),
'rel' => 'search',
'type' => 'application/opensearchdescription+xml',
'title' => $GLOBALS['registry']->get('name') . ' (' . Horde::url('', true) . ')'
));
}
}
whups-3.0.0beta1/locale/bg/LC_MESSAGES/whups.mo 0000644 0001750 0001750 00000277677 12160315153 017045 0 ustar jan jan 9 L M L M d M DN O C O <
' . $link . ''; } return $link; } public function end() { echo '