7072f2b732c1e8a3b9f15b1eecd333863627b494
[timetracker.git] / WEB-INF / lib / ttExportHelper.class.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 import('ttTeamHelper');
30 import('ttTimeHelper');
31
32 // ttExportHelper - this class is used to export group data to a file.
33 class ttExportHelper {
34   var $fileName    = null;    // Name of the file with data.
35
36   // The following arrays are maps between entity ids in the file versus the database.
37   // We write to the file sequentially (1,2,3...) while in the database the entities have different ids.
38   var $userMap     = array(); // User ids.
39   var $roleMap     = array(); // Role ids.
40   var $projectMap  = array(); // Project ids.
41   var $taskMap     = array(); // Task ids.
42   var $clientMap   = array(); // Client ids.
43   var $invoiceMap  = array(); // Invoice ids.
44   var $customFieldMap       = array(); // Custom field ids.
45   var $customFieldOptionMap = array(); // Custop field option ids.
46   var $logMap      = array(); // Time log ids.
47
48   // createDataFile creates a file with all data for a given group.
49   function createDataFile($compress = false) {
50     global $user;
51     $group_id = $user->getActiveGroup();
52
53     // Create a temporary file.
54     $dirName = dirname(TEMPLATE_DIR . '_c/.');
55     $tmp_file = tempnam($dirName, 'tt');
56
57     // Open the file for writing.
58     $file = fopen($tmp_file, 'wb');
59     if (!$file) return false;
60
61     // Write XML to the file.
62     fwrite($file, "<?xml version=\"1.0\"?>\n");
63     fwrite($file, "<org>\n");
64
65     // Write group info.
66     fwrite($file, "<group currency=\"".$user->currency."\" decimal_mark=\"".$user->decimal_mark."\" lang=\"".$user->lang.
67       "\" date_format=\"".$user->date_format."\" time_format=\"".$user->time_format."\" week_start=\"".$user->week_start.
68       "\" tracking_mode=\"".$user->tracking_mode."\" project_required=\"".$user->project_required."\" task_required=\"".$user->task_required.
69       "\" record_type=\"".$user->record_type."\" bcc_email=\"".$user->bcc_email.
70       "\" plugins=\"".$user->plugins."\" lock_spec=\"".$user->lock_spec."\" workday_minutes=\"".$user->workday_minutes.
71       "\" config=\"".$user->config.
72       "\">\n");
73     fwrite($file, "  <name><![CDATA[".$user->group_name."]]></name>\n");
74     fwrite($file, "  <allow_ip><![CDATA[".$user->allow_ip."]]></allow_ip>\n");
75     fwrite($file, "  <password_complexity><![CDATA[".$user->password_complexity."]]></password_complexity>\n");
76     fwrite($file, "</group>\n");
77
78     // Prepare role map.
79     $roles = $this->getRoles();
80     foreach ($roles as $key=>$role_item)
81       $this->roleMap[$role_item['id']] = $key + 1;
82
83     // Prepare user map.
84     $users = $this->getUsers();
85     foreach ($users as $key=>$user_item)
86       $this->userMap[$user_item['id']] = $key + 1;
87
88     // Prepare project map.
89     $projects = ttTeamHelper::getAllProjects($group_id, true);
90     foreach ($projects as $key=>$project_item)
91       $this->projectMap[$project_item['id']] = $key + 1;
92
93     // Prepare task map.
94     $tasks = ttTeamHelper::getAllTasks($group_id, true);
95     foreach ($tasks as $key=>$task_item)
96       $this->taskMap[$task_item['id']] = $key + 1;
97
98     // Prepare client map.
99     $clients = ttTeamHelper::getAllClients($group_id, true);
100     foreach ($clients as $key=>$client_item)
101       $this->clientMap[$client_item['id']] = $key + 1;
102
103     // Prepare invoice map.
104     $invoices = ttTeamHelper::getAllInvoices();
105     foreach ($invoices as $key=>$invoice_item)
106       $this->invoiceMap[$invoice_item['id']] = $key + 1;
107
108     // Prepare custom fields map.
109     $custom_fields = ttTeamHelper::getAllCustomFields($group_id);
110     foreach ($custom_fields as $key=>$custom_field)
111       $this->customFieldMap[$custom_field['id']] = $key + 1;
112
113     // Prepare custom field options map.
114     $custom_field_options = ttTeamHelper::getAllCustomFieldOptions($group_id);
115     foreach ($custom_field_options as $key=>$option)
116       $this->customFieldOptionMap[$option['id']] = $key + 1;
117
118     // Write roles.
119     fwrite($file, "<roles>\n");
120     foreach ($roles as $role) {
121       fwrite($file, "  <role id=\"".$this->roleMap[$role['id']]."\" rank=\"".$role['rank']."\"".
122         " rights=\"".$role['rights']."\" status=\"".$role['status']."\">\n");
123       fwrite($file, "    <name><![CDATA[".$role['name']."]]></name>\n");
124       fwrite($file, "    <description><![CDATA[".$role['description']."]]></description>\n");
125       fwrite($file, "  </role>\n");
126     }
127     fwrite($file, "</roles>\n");
128     unset($roles);
129
130     // Write users.
131     fwrite($file, "<users>\n");
132     foreach ($users as $user_item) {
133       $role_id = $user_item['rank'] == 512 ? 0 : $this->roleMap[$user_item['role_id']]; // Special role_id 0 (not null) for top manager.
134       fwrite($file, "  <user id=\"".$this->userMap[$user_item['id']]."\" login=\"".htmlentities($user_item['login'])."\" password=\"".$user_item['password']."\" role_id=\"".$role_id."\" client_id=\"".$this->clientMap[$user_item['client_id']]."\" rate=\"".$user_item['rate']."\" email=\"".$user_item['email']."\" status=\"".$user_item['status']."\">\n");
135       fwrite($file, "    <name><![CDATA[".$user_item['name']."]]></name>\n");
136       fwrite($file, "  </user>\n");
137     }
138     fwrite($file, "</users>\n");
139
140     // Write tasks.
141     fwrite($file, "<tasks>\n");
142     foreach ($tasks as $task_item) {
143       fwrite($file, "  <task id=\"".$this->taskMap[$task_item['id']]."\" status=\"".$task_item['status']."\">\n");
144       fwrite($file, "    <name><![CDATA[".$task_item['name']."]]></name>\n");
145       fwrite($file, "    <description><![CDATA[".$task_item['description']."]]></description>\n");
146       fwrite($file, "  </task>\n");
147     }
148     fwrite($file, "</tasks>\n");
149     unset($tasks);
150
151     // Write projects.
152     fwrite($file, "<projects>\n");
153     foreach ($projects as $project_item) {
154       if($project_item['tasks']){
155         $tasks = explode(',', $project_item['tasks']);
156         $tasks_mapped = array();
157         foreach ($tasks as $item)
158           $tasks_mapped[] = $this->taskMap[$item];
159         $tasks_str = implode(',', $tasks_mapped);
160       }
161       fwrite($file, "  <project id=\"".$this->projectMap[$project_item['id']]."\" tasks=\"".$tasks_str."\" status=\"".$project_item['status']."\">\n");
162       fwrite($file, "    <name><![CDATA[".$project_item['name']."]]></name>\n");
163       fwrite($file, "    <description><![CDATA[".$project_item['description']."]]></description>\n");
164       fwrite($file, "  </project>\n");
165     }
166     fwrite($file, "</projects>\n");
167     unset($projects);
168
169     // Write user to project binds.
170     fwrite($file, "<user_project_binds>\n");
171     $user_binds = ttTeamHelper::getUserToProjectBinds($group_id);
172     foreach ($user_binds as $bind) {
173       $user_id = $this->userMap[$bind['user_id']];
174       $project_id = $this->projectMap[$bind['project_id']];
175       fwrite($file, "  <user_project_bind user_id=\"{$user_id}\" project_id=\"{$project_id}\" rate=\"".$bind['rate']."\" status=\"".$bind['status']."\"/>\n");
176     }
177     fwrite($file, "</user_project_binds>\n");
178     unset($user_binds);
179
180     // Write clients.
181     fwrite($file, "<clients>\n");
182     foreach ($clients as $client_item) {
183       if($client_item['projects']){
184         $projects = explode(',', $client_item['projects']);
185         $projects_mapped = array();
186         foreach ($projects as $item)
187           $projects_mapped[] = $this->projectMap[$item];
188         $projects_str = implode(',', $projects_mapped);
189       }
190       fwrite($file, "  <client id=\"".$this->clientMap[$client_item['id']]."\" tax=\"".$client_item['tax']."\" projects=\"".$projects_str."\" status=\"".$client_item['status']."\">\n");
191       fwrite($file, "    <name><![CDATA[".$client_item['name']."]]></name>\n");
192       fwrite($file, "    <address><![CDATA[".$client_item['address']."]]></address>\n");
193       fwrite($file, "  </client>\n");
194     }
195     fwrite($file, "</clients>\n");
196     unset($clients);
197
198     // Write invoices.
199     fwrite($file, "<invoices>\n");
200     foreach ($invoices as $invoice_item) {
201       fwrite($file, "  <invoice id=\"".$this->invoiceMap[$invoice_item['id']]."\" date=\"".$invoice_item['date']."\" client_id=\"".$this->clientMap[$invoice_item['client_id']]."\" status=\"".$invoice_item['status']."\">\n");
202       fwrite($file, "    <name><![CDATA[".$invoice_item['name']."]]></name>\n");
203       fwrite($file, "  </invoice>\n");
204     }
205     fwrite($file, "</invoices>\n");
206     unset($invoices);
207
208     // Write custom fields.
209     fwrite($file, "<custom_fields>\n");
210     foreach ($custom_fields as $custom_field) {
211       fwrite($file, "  <custom_field id=\"".$this->customFieldMap[$custom_field['id']]."\" type=\"".$custom_field['type']."\" required=\"".$custom_field['required']."\" status=\"".$custom_field['status']."\">\n");
212       fwrite($file, "    <label><![CDATA[".$custom_field['label']."]]></label>\n");
213       fwrite($file, "  </custom_field>\n");
214     }
215     fwrite($file, "</custom_fields>\n");
216     unset($custom_fields);
217
218     // Write custom field options.
219     fwrite($file, "<custom_field_options>\n");
220     foreach ($custom_field_options as $option) {
221       fwrite($file, "  <custom_field_option id=\"".$this->customFieldOptionMap[$option['id']]."\" field_id=\"".$this->customFieldMap[$option['field_id']]."\">\n");
222       fwrite($file, "    <value><![CDATA[".$option['value']."]]></value>\n");
223       fwrite($file, "  </custom_field_option>\n");
224     }
225     fwrite($file, "</custom_field_options>\n");
226     unset($custom_field_options);
227
228     // Write monthly quotas.
229     $quotas = ttTeamHelper::getMonthlyQuotas($group_id);
230     fwrite($file, "<monthly_quotas>\n");
231     foreach ($quotas as $quota) {
232       fwrite($file, "  <monthly_quota year=\"".$quota['year']."\" month=\"".$quota['month']."\" minutes=\"".$quota['minutes']."\"/>\n");
233     }
234     fwrite($file, "</monthly_quotas>\n");
235
236     // Write time log entries.
237     fwrite($file, "<log>\n");
238     $key = 0;
239     foreach ($users as $user_item) {
240       $records = ttTimeHelper::getAllRecords($user_item['id']);
241       foreach ($records as $record) {
242         $key++;
243         $this->logMap[$record['id']] = $key;
244         fwrite($file, "  <log_item id=\"$key\" user_id=\"".$this->userMap[$record['user_id']]."\" date=\"".$record['date']."\" start=\"".$record['start']."\" finish=\"".$record['finish']."\" duration=\"".($record['start']?"":$record['duration'])."\" client_id=\"".$this->clientMap[$record['client_id']]."\" project_id=\"".$this->projectMap[$record['project_id']]."\" task_id=\"".$this->taskMap[$record['task_id']]."\" invoice_id=\"".$this->invoiceMap[$record['invoice_id']]."\" billable=\"".$record['billable']."\" paid=\"".$record['paid']."\" status=\"".$record['status']."\">\n");
245         fwrite($file, "    <comment><![CDATA[".$record['comment']."]]></comment>\n");
246         fwrite($file, "  </log_item>\n");
247       }
248     }
249     fwrite($file, "</log>\n");
250     unset($records);
251
252     // Write custom field log.
253     $custom_field_log = ttTeamHelper::getCustomFieldLog($group_id);
254     fwrite($file, "<custom_field_log>\n");
255     foreach ($custom_field_log as $entry) {
256       fwrite($file, "  <custom_field_log_entry log_id=\"".$this->logMap[$entry['log_id']]."\" field_id=\"".$this->customFieldMap[$entry['field_id']]."\" option_id=\"".$this->customFieldOptionMap[$entry['option_id']]."\" status=\"".$entry['status']."\">\n");
257       fwrite($file, "    <value><![CDATA[".$entry['value']."]]></value>\n");
258       fwrite($file, "  </custom_field_log_entry>\n");
259     }
260     fwrite($file, "</custom_field_log>\n");
261     unset($custom_field_log);
262
263     // Write expense items.
264     $expense_items = ttTeamHelper::getExpenseItems($group_id);
265     fwrite($file, "<expense_items>\n");
266     foreach ($expense_items as $expense_item) {
267       fwrite($file, "  <expense_item date=\"".$expense_item['date']."\" user_id=\"".$this->userMap[$expense_item['user_id']]."\" client_id=\"".$this->clientMap[$expense_item['client_id']]."\" project_id=\"".$this->projectMap[$expense_item['project_id']]."\" cost=\"".$expense_item['cost']."\" invoice_id=\"".$this->invoiceMap[$expense_item['invoice_id']]."\" paid=\"".$expense_item['paid']."\" status=\"".$expense_item['status']."\">\n");
268       fwrite($file, "    <name><![CDATA[".$expense_item['name']."]]></name>\n");
269       fwrite($file, "  </expense_item>\n");
270     }
271     fwrite($file, "</expense_items>\n");
272     unset($expense_items);
273
274     // Write fav reports.
275     fwrite($file, "<fav_reports>\n");
276     $fav_reports = ttTeamHelper::getFavReports($group_id);
277     foreach ($fav_reports as $fav_report) {
278       $user_list = '';
279       if (strlen($fav_report['users']) > 0) {
280         $arr = explode(',', $fav_report['users']);
281         foreach ($arr as $k=>$v) {
282           if (array_key_exists($arr[$k], $this->userMap))
283             $user_list .= (strlen($user_list) == 0? '' : ',').$this->userMap[$v];
284         }
285       }
286       fwrite($file, "  <fav_report user_id=\"".$this->userMap[$fav_report['user_id']]."\"".
287         " client_id=\"".$this->clientMap[$fav_report['client_id']]."\"".
288         " cf_1_option_id=\"".$this->customFieldOptionMap[$fav_report['cf_1_option_id']]."\"".
289         " project_id=\"".$this->projectMap[$fav_report['project_id']]."\"".
290         " task_id=\"".$this->taskMap[$fav_report['task_id']]."\"".
291         " billable=\"".$fav_report['billable']."\"".
292         " users=\"".$user_list."\"".
293         " period=\"".$fav_report['period']."\"".
294         " period_start=\"".$fav_report['period_start']."\"".
295         " period_end=\"".$fav_report['period_end']."\"".
296         " show_client=\"".$fav_report['show_client']."\"".
297         " show_invoice=\"".$fav_report['show_invoice']."\"".
298         " show_paid=\"".$fav_report['show_paid']."\"".
299         " show_ip=\"".$fav_report['show_ip']."\"".
300         " show_project=\"".$fav_report['show_project']."\"".
301         " show_start=\"".$fav_report['show_start']."\"".
302         " show_duration=\"".$fav_report['show_duration']."\"".
303         " show_cost=\"".$fav_report['show_cost']."\"".
304         " show_task=\"".$fav_report['show_task']."\"".
305         " show_end=\"".$fav_report['show_end']."\"".
306         " show_note=\"".$fav_report['show_note']."\"".
307         " show_custom_field_1=\"".$fav_report['show_custom_field_1']."\"".
308         " show_work_units=\"".$fav_report['show_work_units']."\"".
309         " group_by1=\"".$fav_report['group_by1']."\"".
310         " group_by2=\"".$fav_report['group_by2']."\"".
311         " group_by3=\"".$fav_report['group_by3']."\"".
312         " show_totals_only=\"".$fav_report['show_totals_only']."\">\n");
313       fwrite($file, "    <name><![CDATA[".$fav_report["name"]."]]></name>\n");
314       fwrite($file, "  </fav_report>\n");
315     }
316     fwrite($file, "</fav_reports>\n");
317     unset($fav_reports);
318
319     // Cleanup.
320     unset($users);
321     $this->roleMap = array();
322     $this->userMap = array();
323     $this->projectMap = array();
324     $this->taskMap = array();
325
326     fwrite($file, "</org>\n");
327     fclose($file);
328
329     if ($compress) {
330       $this->fileName = tempnam($dirName, 'tt');
331       $this->compress($tmp_file, $this->fileName);
332       unlink($tmp_file);
333     } else
334       $this->fileName = $tmp_file;
335
336     return true;
337   }
338
339   // getFileName - returns file name.
340   function getFileName() {
341     return $this->fileName;
342   }
343
344   // compress - compresses the content of the $in file into $out file.
345   function compress($in, $out) {
346     // Initial checks of file names and permissions.
347     if (!file_exists($in) || !is_readable ($in))
348       return false;
349     if ((!file_exists($out) && !is_writable(dirname($out))) || (file_exists($out) && !is_writable($out)))
350       return false;
351
352     $in_file = fopen($in, 'rb');
353
354     if (function_exists('bzopen')) {
355       if (!$out_file = bzopen($out, 'w'))
356         return false;
357
358       while (!feof ($in_file)) {
359         $buffer = fread($in_file, 4096);
360         bzwrite($out_file, $buffer, 4096);
361       }
362       bzclose($out_file);
363     }
364     fclose ($in_file);
365     return true;
366   }
367
368   /*
369    * Note about the utility functions below.
370    * We have roughly 4 groups of operations:
371    *   1) Regular system usage for tracking time, etc.
372    *   2) Registration process - used infrequently.
373    *   3) Admin usage - used infrequently.
374    *   4) Export - used infrequently.
375    *
376    * It is tempting to have a generic function to get things done for
377    * all situations. However, as registration, export and admin access are one-off
378    * operations, while regular system usage is daily and must be efficient,
379    * the current approach is to have SEPARATE functions for each mode.
380    *
381    * This is because each mode requires a slightly different approach,
382    * and we don't want to over-complicate things.
383    */
384
385   // getRoles - obtains all roles defined for group.
386   function getRoles() {
387     global $user;
388     $mdb2 = getConnection();
389
390     $result = array();
391     $sql = "select * from tt_roles where group_id = ".$user->getActiveGroup();
392     $res = $mdb2->query($sql);
393     $result = array();
394     if (!is_a($res, 'PEAR_Error')) {
395       while ($val = $res->fetchRow()) {
396         $result[] = $val;
397       }
398       return $result;
399     }
400     return false;
401   }
402
403   // The getUsers obtains all users in group for the purpose of export.
404   function getUsers() {
405     global $user;
406     $mdb2 = getConnection();
407
408     $sql = "select u.*, r.rank from tt_users u left join tt_roles r on (u.role_id = r.id) where u.group_id = ".
409             $user->getActiveGroup()." order by upper(u.name)"; // Note: deleted users are included.
410     $res = $mdb2->query($sql);
411     $result = array();
412     if (!is_a($res, 'PEAR_Error')) {
413       while ($val = $res->fetchRow()) {
414         $result[] = $val;
415       }
416       return $result;
417     }
418     return false;
419   }
420 }