Introduced feature_disabled.php for better error description.
[timetracker.git] / charts.php
1 <?php
2 // +----------------------------------------------------------------------+
3 // | Anuko Time Tracker
4 // +----------------------------------------------------------------------+
5 // | Copyright (c) Anuko International Ltd. (https://www.anuko.com)
6 // +----------------------------------------------------------------------+
7 // | LIBERAL FREEWARE LICENSE: This source code document may be used
8 // | by anyone for any purpose, and freely redistributed alone or in
9 // | combination with other software, provided that the license is obeyed.
10 // |
11 // | There are only two ways to violate the license:
12 // |
13 // | 1. To redistribute this code in source form, with the copyright
14 // |    notice or license removed or altered. (Distributing in compiled
15 // |    forms without embedded copyright notices is permitted).
16 // |
17 // | 2. To redistribute modified versions of this code in *any* form
18 // |    that bears insufficient indications that the modifications are
19 // |    not the work of the original author(s).
20 // |
21 // | This license applies to this document only, not any other software
22 // | that it may be combined with.
23 // |
24 // +----------------------------------------------------------------------+
25 // | Contributors:
26 // | https://www.anuko.com/time_tracker/credits.htm
27 // +----------------------------------------------------------------------+
28
29 // Note: This script uses Lichart PHP library and requires GD 2.0.1 or later.
30
31 require_once('initialize.php');
32 import('form.Form');
33 import('DateAndTime');
34 import('ttChartHelper');
35 import('ttSysConfig');
36 import('PieChartEx');
37 import('ttUserHelper');
38 import('ttTeamHelper');
39
40 // Access checks.
41 if (!ttAccessAllowed('view_own_charts')) {
42   header('Location: access_denied.php');
43   exit();
44 }
45 if (!$user->isPluginEnabled('ch')) {
46   header('Location: feature_disabled.php');
47   exit();
48 }
49
50
51
52 // Initialize and store date in session.
53 $cl_date = $request->getParameter('date', @$_SESSION['date']);
54 if(!$cl_date) {
55   $now = new DateAndTime(DB_DATEFORMAT);
56   $cl_date = $now->toString(DB_DATEFORMAT);
57 }
58 $_SESSION['date'] = $cl_date;
59
60 // Initialize chart interval.
61 $cl_interval = $_SESSION['chart_interval'];
62 if (!$cl_interval) {
63   $sc = new ttSysConfig($user->id);
64   $cl_interval = $sc->getValue(SYSC_CHART_INTERVAL);
65 }
66 if (!$cl_interval) $cl_interval = INTERVAL_THIS_MONTH;
67 $_SESSION['chart_interval'] = $cl_interval;
68
69 // Initialize chart type.
70 $cl_type = $_SESSION['chart_type'];
71 if (!$cl_type) {
72   $sc = new ttSysConfig($user->id);
73   $cl_type = $sc->getValue(SYSC_CHART_TYPE);
74 }
75 if (MODE_TIME == $user->tracking_mode) {
76   if ($user->isPluginEnabled('cl'))
77     $cl_type = CHART_CLIENTS;
78 } else {
79   if ($cl_type == CHART_CLIENTS) {
80     if (!$user->isPluginEnabled('cl'))
81       $cl_type = CHART_PROJECTS;        
82   } elseif ($cl_type == CHART_TASKS) {
83     if (MODE_PROJECTS_AND_TASKS != $user->tracking_mode)
84       $cl_type = CHART_PROJECTS;
85   }
86 }
87 if (!$cl_type) $cl_type = CHART_PROJECTS;
88 $_SESSION['chart_type'] = $cl_type;
89
90 // Who do we draw charts for?
91 $on_behalf_id = $request->getParameter('onBehalfUser', (isset($_SESSION['behalf_id'])? $_SESSION['behalf_id'] : $user->id));
92
93 if ($request->isPost()) {
94   // If chart interval changed - save it.
95   $cl_interval = $request->getParameter('interval');
96   if ($cl_interval) {
97     // Save in the session
98     $_SESSION['chart_interval'] = $cl_interval;
99     // and permanently.
100     $sc = new ttSysConfig($user->id);
101     $sc->setValue(SYSC_CHART_INTERVAL, $cl_interval);
102   }
103   // If chart type changed - save it.
104   $cl_type = $request->getParameter('type');
105   if ($cl_type) {
106     // Save in the session
107     $_SESSION['chart_type'] = $cl_type;
108     // and permanently.
109     $sc = new ttSysConfig($user->id);
110     $sc->setValue(SYSC_CHART_TYPE, $cl_type);
111   }
112   // If user has changed - set behalf_id accordingly in the session.
113   if ($request->getParameter('onBehalfUser')) {
114     if($user->canManageTeam()) {
115       unset($_SESSION['behalf_id']);
116       unset($_SESSION['behalf_name']);
117
118       if($on_behalf_id != $user->id) {
119         $_SESSION['behalf_id'] = $on_behalf_id;
120         $_SESSION['behalf_name'] = ttUserHelper::getUserName($on_behalf_id);
121       }
122       header('Location: charts.php');
123       exit();
124     }
125   }
126 } // isPost
127
128 // Elements of chartForm.
129 $chart_form = new Form('chartForm');
130
131 // User dropdown. Changes the user "on behalf" of whom we are working. 
132 if ($user->canManageTeam()) {
133   $user_list = ttTeamHelper::getActiveUsers(array('putSelfFirst'=>true));
134   if (count($user_list) > 1) {
135     $chart_form->addInput(array('type'=>'combobox',
136       'onchange'=>'this.form.submit();',
137       'name'=>'onBehalfUser',
138       'value'=>$on_behalf_id,
139       'data'=>$user_list,
140       'datakeys'=>array('id','name'),
141     ));
142     $smarty->assign('on_behalf_control', 1);
143   }
144 }
145
146 // Chart interval options.
147 $intervals = array();
148 $intervals[INTERVAL_THIS_DAY] = $i18n->get('dropdown.selected_day');
149 $intervals[INTERVAL_THIS_WEEK] = $i18n->get('dropdown.selected_week');
150 $intervals[INTERVAL_THIS_MONTH] = $i18n->get('dropdown.selected_month');
151 $intervals[INTERVAL_THIS_YEAR] = $i18n->get('dropdown.selected_year');
152 $intervals[INTERVAL_ALL_TIME] = $i18n->get('dropdown.all_time');
153
154 // Chart interval dropdown.
155 $chart_form->addInput(array('type' => 'combobox',
156   'onchange' => 'if(this.form) this.form.submit();',
157   'name' => 'interval',
158   'value' => $cl_interval,
159   'data' => $intervals
160 ));
161
162 // Chart type options.
163 $chart_selector = (MODE_PROJECTS_AND_TASKS == $user->tracking_mode || $user->isPluginEnabled('cl'));
164 if ($chart_selector) {
165   $types = array();
166   if (MODE_PROJECTS == $user->tracking_mode || MODE_PROJECTS_AND_TASKS == $user->tracking_mode)
167     $types[CHART_PROJECTS] = $i18n->get('dropdown.projects');
168   if (MODE_PROJECTS_AND_TASKS == $user->tracking_mode)
169     $types[CHART_TASKS] = $i18n->get('dropdown.tasks');
170   if ($user->isPluginEnabled('cl'))
171     $types[CHART_CLIENTS] = $i18n->get('dropdown.clients');
172
173   // Add chart type dropdown.
174   $chart_form->addInput(array('type' => 'combobox',
175     'onchange' => 'if(this.form) this.form.submit();',
176     'name' => 'type',
177     'value' => $cl_type,
178     'data' => $types
179   ));
180 }
181
182 // Calendar.
183 $chart_form->addInput(array('type'=>'calendar','name'=>'date','value'=>$cl_date)); // calendar
184
185 // Get data for our chart.
186 $totals = ttChartHelper::getTotals($on_behalf_id, $cl_type, $cl_date, $cl_interval);
187 $smarty->assign('totals', $totals);
188
189 // Prepare chart for drawing.
190 /*
191  * We use libchart.php library to draw chart images. It can draw chart labels, too (embed in the image).
192  * But quality of such auto-scaled text is not good. Therefore, we only use libchart to draw a pie-chart picture with
193  * auto-calculated percentage markers around it. We print labels (to the side of the picture) ourselves,
194  * using the same colors libchart is using. For labels printout, the $totals array (which is used for picture points)
195  * is also passed to charts.tpl Smarty template.
196  *
197  * To make all of the above possible with only one database call to obtain $totals we have to print the chart image
198  * to a file here (see code below). Once the image is available as a .png file, the charts.tpl can render it.
199  *
200  * PieChartEx class is a little extension to libchart-provided PieChart class. It allows us to print the chart
201  * without title, logo, and labels.
202  */
203 $chart = new PieChartEx(300, 300);
204 $data_set = new XYDataSet();
205 foreach($totals as $total) {
206   $data_set->addPoint(new Point( $total['name'], $total['time']));
207 }
208 $chart->setDataSet($data_set); 
209
210 // Prepare a file name.
211 $img_dir = TEMPLATE_DIR.'_c/'; // Directory.
212 $file_name = uniqid('chart_').'.png'; // Short file name. Unique ID here is to avoid problems with browser caching.
213 $img_ref = 'WEB-INF/templates_c/'.$file_name; // Image reference for html.
214 $file_name = $img_dir.$file_name; // Full file name. 
215
216 // Clean up the file system from older images.
217 $img_files = glob($img_dir.'chart_*.png');
218 foreach($img_files as $file) {
219   // If the create time of file is older than 1 minute, delete it.
220   if (filemtime($file) < (time() - 60)) {
221     unlink($file);
222   }
223 }
224
225 // Write chart image to file system.
226 $chart->renderEx(array('fileName'=>$file_name,'hideLogo'=>true,'hideTitle'=>true,'hideLabel'=>true));
227 // At this point libchart usage is complete and we have chart image on disk.
228
229 $smarty->assign('img_file_name', $img_ref);
230 $smarty->assign('chart_selector', $chart_selector);
231 $smarty->assign('forms', array($chart_form->getName() => $chart_form->toArray()));
232 $smarty->assign('title', $i18n->get('title.charts'));
233 $smarty->assign('content_page_name', 'charts.tpl');
234 $smarty->display('index.tpl');