1: <?php
2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
12: class Hermes
13: {
14: 15: 16: 17: 18: 19: 20: 21:
22: public static function listClients($name = '')
23: {
24: static $clients;
25:
26: if (is_null($clients) || empty($clients[$name])) {
27: try {
28: $result = $GLOBALS['registry']->clients->searchClients(array($name), array('name'), true);
29: } catch (Horde_Exception $e) {
30:
31: }
32: $client_name_field = $GLOBALS['conf']['client']['field'];
33: $clients = is_null($clients) ? array() : $clients;
34: if (!empty($result)) {
35: $result = $result[$name];
36: foreach ($result as $client) {
37: $clients[$name][$client['id']] = $client[$client_name_field];
38: }
39: }
40: if (!empty($clients[$name])) {
41: uasort($clients[$name], 'strcoll');
42: } else {
43: $clients[$name] = array();
44: }
45: }
46:
47: return $clients[$name];
48: }
49:
50: public static function getClientSelect($id)
51: {
52: $clients = self::listClients();
53: $select = '<select name="client" id="' . $id . '">';
54: $select .= '<option value="">' . _("--- Select A Client ---") . '</option>';
55: foreach ($clients as $cid => $client) {
56: $select .= '<option value="' . $cid . '">' . $client . '</option>';
57: }
58:
59: return $select . '</select>';
60: }
61:
62: 63: 64: 65:
66: public static function getJobTypeSelect($id)
67: {
68: $types = $GLOBALS['injector']->getInstance('Hermes_Driver')->listJobTypes(array('enabled' => true));
69: $select = '<select name="type" id="' . $id . '">';
70: foreach ($types as $tid => $type) {
71: $select .= '<option value="' . $tid . '">' . $type['name'] . '</option>';
72: }
73:
74: return $select . '</select>';
75: }
76:
77: 78: 79: 80: 81: 82: 83: 84: 85:
86: public static function canEditTimeslice($id)
87: {
88: $perms = $GLOBALS['injector']->getInstance('Horde_Perms');
89:
90: if ($perms->hasPermission('hermes:review', $GLOBALS['registry']->getAuth(), Horde_Perms::EDIT)) {
91: return true;
92: }
93:
94: $hours = $GLOBALS['injector']->getInstance('Hermes_Driver')->getHours(array('id' => $id));
95: if (!is_array($hours) || count($hours) != 1) {
96: return false;
97: }
98: $slice = $hours[0];
99:
100:
101: if ($slice['employee'] == $GLOBALS['registry']->getAuth() && !$slice['submitted']) {
102: return true;
103: }
104:
105: return false;
106: }
107:
108: 109: 110: 111: 112: 113: 114: 115:
116: public static function makeExportHours($hours)
117: {
118: if (is_null($hours)) {
119: return null;
120: }
121:
122: $clients = Hermes::listClients();
123: $namecache = array();
124: for ($i = 0; $i < count($hours); $i++) {
125: $timeentry = &$hours[$i];
126: $timeentry['item'] = $timeentry['_type_name'];
127: if (isset($clients[$timeentry['client']])) {
128: $timeentry['client'] = $clients[$timeentry['client']];
129: }
130:
131: $emp = &$timeentry['employee'];
132: if (isset($namecache[$emp])) {
133: $emp = $namecache[$emp];
134: } else {
135: $ident = $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($emp);
136: $fullname = $ident->getValue('fullname');
137: if ($fullname) {
138: $namecache[$emp] = $emp = $fullname;
139: } else {
140: $namecache[$emp] = $emp;
141: }
142: }
143: }
144:
145: return $hours;
146: }
147:
148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158:
159: public static function getEmployeesType($enumtype = 'multienum')
160: {
161: $auth = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Auth')->create();
162: if (!$auth->hasCapability('list')) {
163: return array('text', array());
164: }
165: try {
166: $users = $auth->listUsers();
167: } catch (Exception $e) {
168: return array('invalid',
169: array(sprintf(_("An error occurred listing users: %s"), $e->getMessage())));
170: }
171:
172: $employees = array();
173: foreach ($users as $user) {
174: $identity = $GLOBALS['injector']->getInstance('Horde_Core_Factory_Identity')->create($user);
175: $label = $identity->getValue('fullname');
176: if (empty($label)) {
177: $label = $user;
178: }
179: $employees[$user] = $label;
180: }
181:
182: return array($enumtype, array($employees));
183: }
184:
185: public static function getCostObjectByID($id)
186: {
187: static $cost_objects;
188:
189: if (strpos($id, ':') !== false) {
190: list($app, $app_id) = explode(':', $id, 2);
191:
192: if (!isset($cost_objects[$app])) {
193: $results = $GLOBALS['registry']->callByPackage($app, 'listCostObjects', array(array()));
194: $cost_objects[$app] = $results;
195: }
196:
197: foreach (array_keys($cost_objects[$app]) as $catkey) {
198: foreach (array_keys($cost_objects[$app][$catkey]['objects']) as $objkey) {
199: if ($cost_objects[$app][$catkey]['objects'][$objkey]['id'] == $app_id) {
200: return $cost_objects[$app][$catkey]['objects'][$objkey];
201: }
202: }
203: }
204: }
205:
206: throw new Horde_Exception_NotFound();
207: }
208:
209: 210:
211: public static function getCostObjectType($clientID = null)
212: {
213: global $registry;
214:
215: 216:
217: $criteria = array('user' => $GLOBALS['registry']->getAuth(),
218: 'active' => true);
219: if (!empty($clientID)) {
220: $criteria['client_id'] = $clientID;
221: }
222:
223: $costobjects = array();
224: foreach ($registry->listApps() as $app) {
225: if (!$registry->hasMethod('listCostObjects', $app)) {
226: continue;
227: }
228:
229: try {
230: $result = $registry->callByPackage($app, 'listCostObjects', array($criteria));
231: } catch (Horde_Exception $e) {
232: $GLOBALS['notification']->push(sprintf(_("Error retrieving cost objects from \"%s\": %s"), $registry->get('name', $app), $e->getMessage()), 'horde.error');
233: continue;
234: }
235:
236: foreach (array_keys($result) as $catkey) {
237: foreach (array_keys($result[$catkey]['objects']) as $okey){
238: $result[$catkey]['objects'][$okey]['id'] = $app . ':' .
239: $result[$catkey]['objects'][$okey]['id'];
240: }
241: }
242:
243: if ($app == $registry->getApp()) {
244: $costobjects = array_merge($result, $costobjects);
245: } else {
246: $costobjects = array_merge($costobjects, $result);
247: }
248: }
249:
250: $elts = array('' => _("--- No Cost Object ---"));
251: $counter = 0;
252: foreach ($costobjects as $category) {
253: Horde_Array::arraySort($category['objects'], 'name');
254: $elts['category%' . $counter++] = sprintf('--- %s ---', $category['category']);
255: foreach ($category['objects'] as $object) {
256: $name = $object['name'];
257: if (Horde_String::length($name) > 80) {
258: $name = Horde_String::substr($name, 0, 76) . ' ...';
259: }
260:
261: $hours = 0.0;
262: $filter = array('costobject' => $object['id']);
263: if (!empty($GLOBALS['conf']['time']['sum_billable_only'])) {
264: $filter['billable'] = true;
265: }
266: $result = $GLOBALS['injector']->getInstance('Hermes_Driver')->getHours($filter, array('hours'));
267: foreach ($result as $entry) {
268: if (!empty($entry['hours'])) {
269: $hours += $entry['hours'];
270: }
271: }
272:
273: 274:
275: if (empty($object['estimate'])) {
276: $name .= sprintf(_(" (%0.2f hours)"), $hours);
277: } else {
278: $name .= sprintf(_(" (%d%%, %0.2f of %0.2f hours)"),
279: (int)($hours / $object['estimate'] * 100),
280: $hours, $object['estimate']);
281: }
282:
283: $elts[$object['id']] = $name;
284: }
285: }
286:
287: return $elts;
288: }
289:
290: public static function tabs()
291: {
292:
293: $sUrl = Horde::selfUrl();
294: $tabs = new Horde_Core_Ui_Tabs('search_mode', Horde_Variables::getDefaultVariables());
295: $tabs->addTab(_("Summary"), $sUrl, 'summary');
296: $tabs->addTab(_("By Date"), $sUrl, 'date');
297: $tabs->addTab(_("By Employee"), $sUrl, 'employee');
298: $tabs->addTab(_("By Client"), $sUrl, 'client');
299: $tabs->addTab(_("By Job Type"), $sUrl, 'jobtype');
300: $tabs->addTab(_("By Cost Object"), $sUrl, 'costobject');
301: if ($mode = Horde_Util::getFormData('search_mode')) {
302: $GLOBALS['session']->set('hermes', 'search_mode', $mode);
303: } elseif (!$GLOBALS['session']->exists('hermes', 'search_mode')) {
304: $GLOBALS['session']->set('hermes', 'search_mode', 'summary');
305: }
306: return $tabs->render($GLOBALS['session']->get('hermes', 'search_mode'));
307: }
308:
309: 310: 311: 312:
313: public static function header()
314: {
315:
316: $datejs = str_replace('_', '-', $GLOBALS['language']) . '.js';
317: if (!file_exists($GLOBALS['registry']->get('jsfs', 'horde') . '/date/' . $datejs)) {
318: $datejs = 'en-US.js';
319: }
320: Horde::addScriptFile('effects.js', 'horde');
321: Horde::addScriptFile('horde.js', 'horde');
322: Horde::addScriptFile('growler.js', 'horde');
323: Horde::addScriptFile('redbox.js', 'horde');
324: Horde::addScriptFile('tooltips.js', 'horde');
325: Horde::addScriptFile('date/' . $datejs, 'horde');
326: Horde::addScriptFile('date/date.js', 'horde');
327: Horde::addScriptFile('quickfinder.js', 'horde');
328: Horde::addScriptFile('hermes.js', 'hermes');
329: Horde_Core_Ui_JsCalendar::init(array('short_weekdays' => true));
330:
331: if (isset($GLOBALS['language'])) {
332: header('Content-type: text/html; charset=UTF-8');
333: header('Vary: Accept-Language');
334: }
335:
336: echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "DTD/xhtml1-transitional.dtd">' . "\n" .
337: (!empty($GLOBALS['language']) ? '<html lang="' . strtr($GLOBALS['language'], '_', '-') . '"' : '<html') . ">\n".
338: "<head>\n" .
339: '<title>' . htmlspecialchars($GLOBALS['registry']->get('name')) . "</title>\n";
340:
341: Horde::includeFavicon();
342: echo Horde::wrapInlineScript(self::includeJSVars());
343: Horde::includeStylesheetFiles();
344:
345: echo "</head>\n";
346:
347:
348:
349:
350: echo Horde::endBuffer();
351: flush();
352: }
353:
354: public static function includeJSVars()
355: {
356: global $prefs, $registry;
357:
358: $hermes_webroot = $registry->get('webroot');
359: $horde_webroot = $registry->get('webroot', 'horde');
360: $has_tasks = $registry->hasInterface('tasks');
361: $app_urls = array();
362: if (isset($GLOBALS['conf']['menu']['apps']) &&
363: is_array($GLOBALS['conf']['menu']['apps'])) {
364: foreach ($GLOBALS['conf']['menu']['apps'] as $app) {
365: $app_urls[$app] = (string)Horde::url($registry->getInitialPage($app), true)->add('ajaxui', 1);
366: }
367: }
368:
369:
370: $code['conf'] = array(
371: 'URI_AJAX' => (string)Horde::getServiceLink('ajax', 'hermes'),
372: 'SESSION_ID' => defined('SID') ? SID : '',
373: 'images' => array(
374: 'timerlog' => (string)Horde_Themes::img('log.png'),
375: 'timerplay' => (string)Horde_Themes::img('play.png'),
376: 'timerpause' => (string)Horde_Themes::img('pause.png')
377: ),
378: 'user' => $GLOBALS['registry']->convertUsername($GLOBALS['registry']->getAuth(), false),
379: 'prefs_url' => (string)Horde::getServiceLink('prefs', 'hermes')->setRaw(true)->add('ajaxui', 1),
380: 'app_urls' => $app_urls,
381: 'name' => $registry->get('name'),
382: 'login_view' => 'time',
383: 'date_format' => str_replace(array('%e', '%d', '%a', '%A', '%m', '%h', '%b', '%B', '%y', '%Y'),
384: array('d', 'dd', 'ddd', 'dddd', 'MM', 'MMM', 'MMM', 'MMMM', 'yy', 'yyyy'),
385: Horde_Nls::getLangInfo(D_FMT)),
386: 'client_name_field' => $GLOBALS['conf']['client']['field']
387: );
388: if (!empty($GLOBALS['conf']['logo']['link'])) {
389: $code['conf']['URI_HOME'] = $GLOBALS['conf']['logo']['link'];
390: }
391:
392:
393: $code['text'] = array(
394: 'ajax_error' => _("Error when communicating with the server."),
395: 'ajax_timeout' => _("There has been no contact with the server for several minutes. The server may be temporarily unavailable or network problems may be interrupting your session. You will not see any updates until the connection is restored."),
396: 'ajax_recover' => _("The connection to the server has been restored."),
397: 'noalerts' => _("No Notifications"),
398: 'alerts' => sprintf(_("%s notifications"), '#{count}'),
399: 'hidelog' => _("Hide Notifications"),
400: 'growlerinfo' => _("This is the notification backlog"),
401: 'more' => _("more..."),
402: 'prefs' => _("Preferences"),
403: 'wrong_auth' => _("The authentication information you specified wasn't accepted."),
404: 'fix_form_values' => _("Please enter correct values in the form first."),
405: );
406:
407: return Horde::addInlineJsVars(array(
408: 'var Hermes' => $code
409: ), array('ret_vars' => true));
410: }
411:
412: 413: 414: 415: 416:
417: public static function showAjaxView()
418: {
419: global $prefs, $session;
420:
421: $mode = $session->get('horde', 'mode');
422: return ($mode == 'dynamic' || ($prefs->getValue('dynamic_view') && $mode == 'auto')) && Horde::ajaxAvailable();
423: }
424:
425: 426: 427: 428: 429: 430: 431:
432: public static function newTimer($description)
433: {
434: $now = time();
435: $timer = array(
436: 'name' => $description,
437: 'time' => $now,
438: 'paused' => false,
439: 'elapsed' => 0);
440:
441: self::updateTimer($now, $timer);
442:
443: return $now;
444: }
445:
446: public static function getTimer($id)
447: {
448: global $prefs;
449:
450: $timers = $prefs->getValue('running_timers');
451: if (!empty($timers)) {
452: $timers = @unserialize($timers);
453: } else {
454: $timers = array();
455: }
456:
457: if (empty($timers[$id])) {
458: return false;
459: }
460:
461: return $timers[$id];
462: }
463:
464: public static function clearTimer($id)
465: {
466: global $prefs;
467:
468: $timers = @unserialize($prefs->getValue('running_timers'));
469: if (!is_array($timers)) {
470: $timers = array();
471: } else {
472: unset($timers[$id]);
473: }
474: $prefs->setValue('running_timers', serialize($timers));
475: }
476:
477: public static function updateTimer($id, $timer)
478: {
479: global $prefs;
480:
481: $timers = @unserialize($prefs->getValue('running_timers'));
482: if (!is_array($timers)) {
483: $timers = array();
484: }
485: $timers[$id] = $timer;
486: $prefs->setValue('running_timers', serialize($timers));
487: }
488:
489: }
490: