phpide-d10
[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('ttUserConfig');
36 import('PieChartEx');
37 import('ttUserHelper');
38 import('ttTeamHelper');
39
40 // Access checks.
41 if (!(ttAccessAllowed('view_own_charts') || ttAccessAllowed('view_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 if (!$user->exists()) {
50   header('Location: access_denied.php'); // Nobody to display a chart for.
51   exit();
52 }
53 if ($user->behalf_id && (!$user->can('view_charts') || !$user->checkBehalfId())) {
54   header('Location: access_denied.php'); // Trying on behalf, but no right or wrong user.
55   exit();
56 }
57 if (!$user->behalf_id && !$user->can('view_own_charts') && !$user->adjustBehalfId()) {
58   header('Location: access_denied.php'); // Trying as self, but no right for self, and noone to view on behalf.
59   exit();
60 }
61 if ($request->isPost() && $request->getParameter('user')) {
62   if (!$user->isUserValid($request->getParameter('user'))) {
63     header('Location: access_denied.php'); // Wrong user id on post.
64     exit();
65   }
66 }
67 // End of access checks.
68
69 // Determine user for which we display this page.
70 $userChanged = $request->getParameter('user_changed');
71 if ($request->isPost() && $userChanged) {
72   $user_id = $request->getParameter('user');
73   $user->setOnBehalfUser($user_id);
74 } else {
75   $user_id = $user->getUser();
76 }
77
78 $uc = new ttUserConfig();
79 $tracking_mode = $user->getTrackingMode();
80
81 // Initialize and store date in session.
82 $cl_date = $request->getParameter('date', @$_SESSION['date']);
83 if(!$cl_date) {
84   $now = new DateAndTime(DB_DATEFORMAT);
85   $cl_date = $now->toString(DB_DATEFORMAT);
86 }
87 $_SESSION['date'] = $cl_date;
88
89 if ($request->isPost()) {
90   $cl_interval = $request->getParameter('interval');
91   if (!$cl_interval) $cl_interval = INTERVAL_THIS_MONTH;
92   $_SESSION['chart_interval'] = $cl_interval;
93   $uc->setValue(SYSC_CHART_INTERVAL, $cl_interval);
94
95   $cl_type = $request->getParameter('type');
96   if (!$cl_type) $cl_type = ttChartHelper::adjustType($cl_type);
97   $_SESSION['chart_type'] = $cl_type;
98   $uc->setValue(SYSC_CHART_TYPE, $cl_type);
99 } else {
100   // Initialize chart interval.
101   $cl_interval = $_SESSION['chart_interval'];
102   if (!$cl_interval) $cl_interval = $uc->getValue(SYSC_CHART_INTERVAL);
103   if (!$cl_interval) $cl_interval = INTERVAL_THIS_MONTH;
104   $_SESSION['chart_interval'] = $cl_interval;
105
106   // Initialize chart type.
107   $cl_type = $_SESSION['chart_type'];
108   if (!$cl_type) $cl_type = $uc->getValue(SYSC_CHART_TYPE);
109   $cl_type = ttChartHelper::adjustType($cl_type);
110   $_SESSION['chart_type'] = $cl_type;
111 }
112
113 // Elements of chartForm.
114 $chart_form = new Form('chartForm');
115
116 // User dropdown. Changes the user "on behalf" of whom we are working. 
117 if ($user->can('view_charts')) {
118   $rank = $user->getMaxRankForGroup($user->getGroup());
119   if ($user->can('view_own_charts'))
120     $options = array('status'=>ACTIVE,'max_rank'=>$rank,'include_self'=>true,'self_first'=>true);
121   else
122     $options = array('status'=>ACTIVE,'max_rank'=>$rank);
123   $user_list = $user->getUsers($options);
124   if (count($user_list) >= 1) {
125     $chart_form->addInput(array('type'=>'combobox',
126       'onchange'=>'this.form.user_changed.value=1;this.form.submit();',
127       'name'=>'user',
128       'value'=>$user_id,
129       'data'=>$user_list,
130       'datakeys'=>array('id','name'),
131     ));
132     $chart_form->addInput(array('type'=>'hidden','name'=>'user_changed'));
133     $smarty->assign('user_dropdown', 1);
134   }
135 }
136
137 // Chart interval options.
138 $intervals = array();
139 $intervals[INTERVAL_THIS_DAY] = $i18n->get('dropdown.selected_day');
140 $intervals[INTERVAL_THIS_WEEK] = $i18n->get('dropdown.selected_week');
141 $intervals[INTERVAL_THIS_MONTH] = $i18n->get('dropdown.selected_month');
142 $intervals[INTERVAL_THIS_YEAR] = $i18n->get('dropdown.selected_year');
143 $intervals[INTERVAL_ALL_TIME] = $i18n->get('dropdown.all_time');
144
145 // Chart interval dropdown.
146 $chart_form->addInput(array('type' => 'combobox',
147   'onchange' => 'this.form.submit();',
148   'name' => 'interval',
149   'value' => $cl_interval,
150   'data' => $intervals
151 ));
152
153 // Chart type options.
154 $chart_selector = (MODE_PROJECTS_AND_TASKS == $tracking_mode || $user->isPluginEnabled('cl'));
155 if ($chart_selector) {
156   $types = array();
157   if (MODE_PROJECTS == $tracking_mode || MODE_PROJECTS_AND_TASKS == $tracking_mode)
158     $types[CHART_PROJECTS] = $i18n->get('dropdown.projects');
159   if (MODE_PROJECTS_AND_TASKS == $tracking_mode)
160     $types[CHART_TASKS] = $i18n->get('dropdown.tasks');
161   if ($user->isPluginEnabled('cl'))
162     $types[CHART_CLIENTS] = $i18n->get('dropdown.clients');
163
164   // Add chart type dropdown.
165   $chart_form->addInput(array('type' => 'combobox',
166     'onchange' => 'this.form.submit();',
167     'name' => 'type',
168     'value' => $cl_type,
169     'data' => $types
170   ));
171 }
172
173 // Calendar.
174 $chart_form->addInput(array('type'=>'calendar','name'=>'date','value'=>$cl_date)); // calendar
175
176 // Get data for our chart.
177 $totals = ttChartHelper::getTotals($user_id, $cl_type, $cl_date, $cl_interval);
178 $smarty->assign('totals', $totals);
179
180 // Prepare chart for drawing.
181 /*
182  * We use libchart.php library to draw chart images. It can draw chart labels, too (embed in the image).
183  * But quality of such auto-scaled text is not good. Therefore, we only use libchart to draw a pie-chart picture with
184  * auto-calculated percentage markers around it. We print labels (to the side of the picture) ourselves,
185  * using the same colors libchart is using. For labels printout, the $totals array (which is used for picture points)
186  * is also passed to charts.tpl Smarty template.
187  *
188  * To make all of the above possible with only one database call to obtain $totals we have to print the chart image
189  * to a file here (see code below). Once the image is available as a .png file, the charts.tpl can render it.
190  *
191  * PieChartEx class is a little extension to libchart-provided PieChart class. It allows us to print the chart
192  * without title, logo, and labels.
193  */
194 $chart = new PieChartEx(300, 300);
195 $data_set = new XYDataSet();
196 foreach($totals as $total) {
197   $data_set->addPoint(new Point( $total['name'], $total['time']));
198 }
199 $chart->setDataSet($data_set); 
200
201 // Prepare a file name.
202 $img_dir = TEMPLATE_DIR.'_c/'; // Directory.
203 $file_name = uniqid('chart_').'.png'; // Short file name. Unique ID here is to avoid problems with browser caching.
204 $img_ref = 'WEB-INF/templates_c/'.$file_name; // Image reference for html.
205 $file_name = $img_dir.$file_name; // Full file name. 
206
207 // Clean up the file system from older images.
208 $img_files = glob($img_dir.'chart_*.png');
209 foreach($img_files as $file) {
210   // If the create time of file is older than 1 minute, delete it.
211   if (filemtime($file) < (time() - 60)) {
212     unlink($file);
213   }
214 }
215
216 // Write chart image to file system.
217 $chart->renderEx(array('fileName'=>$file_name,'hideLogo'=>true,'hideTitle'=>true,'hideLabel'=>true));
218 // At this point libchart usage is complete and we have chart image on disk.
219
220 $smarty->assign('img_file_name', $img_ref);
221 $smarty->assign('chart_selector', $chart_selector);
222 $smarty->assign('forms', array($chart_form->getName() => $chart_form->toArray()));
223 $smarty->assign('title', $i18n->get('title.charts'));
224 $smarty->assign('content_page_name', 'charts.tpl');
225 $smarty->display('index.tpl');