3 * one-off script to export tracker items (limited)
5 * Copyright © 2012, 2013
6 * Thorsten “mirabilos” Glaser <t.glaser@tarent.de>
9 * This file is part of FusionForge. FusionForge is free software;
10 * you can redistribute it and/or modify it under the terms of the
11 * GNU General Public License as published by the Free Software
12 * Foundation; either version 2 of the Licence, or (at your option)
15 * FusionForge is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License along
21 * with FusionForge; if not, write to the Free Software Foundation, Inc.,
22 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * Edit below; comments inline. Exports all items in a tracker as JSON.
25 * Warning: may not work without forge-specific modifications; this code
26 * was written for use with EvolvisForge 5.1 and only as a quick hack.
27 * It does not export the “linked commits” information, but that’s mostly
28 * via plugins anyway, so…
31 require '/usr/share/gforge/common/include/env.inc.php';
32 require_once $gfcommon."include/pre.php";
33 require_once $gfcommon.'include/minijson.php';
34 require_once $gfcommon.'tracker/Artifact.class.php';
35 require_once $gfcommon.'tracker/ArtifactFile.class.php';
36 require_once $gfwww.'tracker/include/ArtifactFileHtml.class.php';
37 require_once $gfcommon.'tracker/ArtifactType.class.php';
38 require_once $gfwww.'tracker/include/ArtifactTypeHtml.class.php';
39 require_once $gfwww.'tracker/include/ArtifactHtml.class.php';
40 require_once $gfcommon.'tracker/ArtifactCanned.class.php';
41 require_once $gfcommon.'tracker/ArtifactTypeFactory.class.php';
43 function dbe2jsn($v) {
44 /* fix mistake of how stuff is stored in the DB */
45 $v = util_unconvert_htmlspecialchars($v);
46 /* fix issue with how stuff may be stored in the DB */
47 $v = util_sanitise_multiline_submission($v);
48 /* but export using logical newlines */
49 $v = str_replace("\r\n", "\n", $v);
50 /* now we’ve got something we can use */
58 if (($u = user_get_object($id)) && is_object($u) &&
60 return $u->getUnixName();
62 return sprintf('u%u', $id);
65 function usage($rc=1) {
66 echo "Usage: .../tracker-export.php 123\n" .
67 "\twhere 123 is the group_artifact_id of the tracker to export\n";
71 if (count($argv) != 2) {
74 $argv0 = array_shift($argv);
75 $argv1 = array_shift($argv);
80 if (!($trk = util_nat0($argv1))) {
86 /* pull a list of all tracker items */
87 $res = db_query_params('SELECT artifact_id FROM artifact
88 WHERE group_artifact_id=$1',
90 if (!$res || db_numrows($res) < 1 ||
91 !($srclist = util_result_column_to_array($res))) {
92 echo "error: " . db_error() . "\n";
97 function initialise_at($atx) {
98 global $at, $efarr, $efmap, $efval, $usespm, $out;
100 if (!($at = $atx) || !is_object($at) || $at->isError()) {
101 echo "error no AT\n";
104 $efarr = $at->getExtraFields();
106 $usespm = $at->getGroup()->usesPM();
109 foreach ($efarr as $f) {
110 $efmap[($efid = (int)$f['extra_field_id'])] = array(
111 'name' => util_unconvert_htmlspecialchars($f['field_name']),
112 'alias' => preg_replace('/^@/', '',
113 preg_replace('/[0-9.]+$/', '', $f['alias'])),
114 'type' => (int)$f['field_type'],
116 if (!strcasecmp($efmap[$efid]['name'], $efmap[$efid]['alias'])) {
117 /* skip when alias is the same as name */
118 $efmap[$efid]['alias'] = "";
120 $efval[$efid] = array();
121 foreach (ArtifactExtraField_getAvailableValues($efid) as $k => $v) {
122 $efval[$efid][(int)$v['element_id']] =
123 util_unconvert_htmlspecialchars($v['element_name']);
129 foreach ($srclist as $aidx) {
130 /* retrieve the current item */
132 $ah =& artifact_get_object($aid);
133 if (!$ah || !is_object($ah) || $ah->isError()) {
134 echo "error item $aidx\n";
139 initialise_at($ah->getArtifactType());
142 /* prepare an export record */
144 foreach ($ah->data_array as $k => $v) {
145 /* skip numeric fields */
146 if (!preg_match('/^[a-z]/', $k)) {
150 /* distinguish actions for specific fields */
154 $rec[$k] = dbe2jsn($v);
158 case 'group_artifact_id':
165 case 'last_modified_date':
179 /* add pseudo-fields to aid in permalink construction */
180 $rec['_rpl_itempermalink'] = util_make_url('/tracker/t_follow.php/#');
181 $rec['_rpl_taskpermalink'] = util_make_url('/pm/t_follow.php/#');
184 $rec['_votes'] = array_combine(array(
190 /* copy related tasks and add task permalink format pseudo-field */
193 $taskcount = db_numrows($ah->getRelatedTasks());
194 if ($taskcount >= 1) for ($i = 0; $i < $taskcount; ++$i) {
195 $taskinfo = db_fetch_array($ah->relatedtasks, $i);
196 $fv[] = (int)$taskinfo['project_task_id'];
198 sort($fv, SORT_NUMERIC);
200 $rec['~related_tasks'] = $fv;
204 /* copy backwards relations of other tracker items to this one */
205 $res = db_query_params('SELECT *
206 FROM artifact_extra_field_list, artifact_extra_field_data, artifact_group_list, artifact, groups
208 AND artifact_extra_field_list.extra_field_id=artifact_extra_field_data.extra_field_id
209 AND artifact_group_list.group_artifact_id = artifact_extra_field_list.group_artifact_id
210 AND artifact.artifact_id = artifact_extra_field_data.artifact_id
211 AND groups.group_id = artifact_group_list.group_id
212 AND (field_data = $1 OR field_data LIKE $2 OR field_data LIKE $3 OR field_data LIKE $4)
213 ORDER BY artifact_group_list.group_id ASC, name ASC, field_name ASC, artifact.artifact_id ASC',
221 if ($res) while (($row = db_fetch_array($res))) {
223 'group' => dbe2jsn($row['group_name']),
224 'tracker' => dbe2jsn($row['name']),
225 'item' => (int)$row['artifact_id'],
226 'field' => dbe2jsn($row['field_name']),
230 $rec['~backlinks'] = $fv;
234 $res = $ah->getMessages();
236 if ($res) while (($row = db_fetch_array($res))) {
238 'adddate' => (int)$row['adddate'],
239 'from_email' => $row['from_email'],
240 'body' => dbe2jsn($row['body']),
241 'from_user' => u2jsn($row['user_id']),
245 $rec['~comments'] = $fv;
248 /* copy extra fields */
249 foreach ($ah->getExtraFieldData() as $k => $v) {
251 switch ((int)$efarr[$k]['field_type']) {
252 case 2: /* ARTIFACT_EXTRAFIELDTYPE_CHECKBOX */
253 case 5: /* ARTIFACT_EXTRAFIELDTYPE_MULTISELECT */
254 /* stored as arrays, values as-is */
261 /* all others are stored crippled */
266 switch ((int)$efarr[$k]['field_type']) {
268 case 10: /* ARTIFACT_EXTRAFIELDTYPE_INTEGER */
273 case 1: /* ARTIFACT_EXTRAFIELDTYPE_SELECT */
274 case 3: /* ARTIFACT_EXTRAFIELDTYPE_RADIO */
275 case 7: /* ARTIFACT_EXTRAFIELDTYPE_STATUS */
276 $res = util_ifsetor($efval[$k][(int)$v], NULL);
279 /* arrays of list values */
280 case 2: /* ARTIFACT_EXTRAFIELDTYPE_CHECKBOX */
281 case 5: /* ARTIFACT_EXTRAFIELDTYPE_MULTISELECT */
283 foreach ($v as $fv) {
284 $res[] = util_ifsetor($efval[$k][(int)$fv],
289 /* special handling */
290 case 9: /* ARTIFACT_EXTRAFIELDTYPE_RELATION */
292 foreach (preg_split("/\D+/", $v) as $fv) {
293 if (!util_nat0($fv)) {
301 case 4: /* ARTIFACT_EXTRAFIELDTYPE_TEXT */
302 case 6: /* ARTIFACT_EXTRAFIELDTYPE_TEXTAREA */
304 case 8: /* ARTIFACT_EXTRAFIELDTYPE_ASSIGNEE */
310 'type' => $efmap[$k]['type'],
313 if ($efmap[$k]['alias']) {
314 $v['alias'] = $efmap[$k]['alias'];
316 if (!isset($rec['~extrafields'])) {
317 $rec['~extrafields'] = array();
319 $rec['~extrafields'][$efmap[$k]['name']] = $v;
324 $res = db_query_params('SELECT * FROM artifact_file_user_vw
326 ORDER BY adddate, id',
327 array($ah->getID()));
328 if ($res) while (($row = db_fetch_array($res))) {
330 'description' => $row['description'],
331 'filename' => $row['filename'],
332 'adddate' => (int)$row['adddate'],
333 'submitter' => u2jsn($row['submitted_by']),
334 'base64_data' => $row['bin_data'],
338 $rec['~files'] = $fv;
343 $res = db_query_params('SELECT * FROM artifact_history
345 ORDER BY entrydate, id',
346 array($ah->getID()));
347 if ($res) while (($row = db_fetch_array($res))) {
349 'field_name' => dbe2jsn($row['field_name']),
350 'old_value' => dbe2jsn($row['old_value']),
351 'new_value' => dbe2jsn($row['new_value']),
352 'by' => u2jsn($row['mod_by']),
353 'entrydate' => (int)$row['entrydate'],
356 $rec['~changelog'] = $fv;
358 /* append to list of records to emit */
362 /* generate output */
363 echo minijson_encode($out) . "\n";