[Fusionforge-commits] FusionForge branch master updated. 6e43c9a26ed4e88486924f518fc5705b69a546ca

Thorsten Glaser mirabilos at fusionforge.org
Wed Jul 16 20:24:34 CEST 2014


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "FusionForge".

The branch, master has been updated
       via  6e43c9a26ed4e88486924f518fc5705b69a546ca (commit)
      from  153169d511a8185705a722b2ae86006622d49f7d (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 6e43c9a26ed4e88486924f518fc5705b69a546ca
Author: Thorsten Glaser <t.glaser at tarent.de>
Date:   Wed Jul 16 20:24:11 2014 +0200

    import from Evolvis commit 7979d1b6db649f25583fac2f8e791ea061a4ba52
    
    I believe we now import everything tracker-export.php generates.

diff --git a/src/utils/one-off-scripts/tracker-import.php b/src/utils/one-off-scripts/tracker-import.php
index 5eab9cb..9b542f3 100644
--- a/src/utils/one-off-scripts/tracker-import.php
+++ b/src/utils/one-off-scripts/tracker-import.php
@@ -22,7 +22,8 @@
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *-
  * Edit below; comments inline.  Imports a JSON generated by tracker-export
- * into a tracker, although only a very small part of the data.
+ * into a tracker; I believe that all fields are imported, except assignee,
+ * which is by design; missing data is recorded still.
  *
  * Note: this script may require editing to adjust to the instance
  * and version of the forge used, e.g. it uses a form of ->addHistory()
@@ -41,6 +42,11 @@ require_once $gfwww.'tracker/include/ArtifactHtml.class.php';
 require_once $gfcommon.'tracker/ArtifactCanned.class.php';
 require_once $gfcommon.'tracker/ArtifactTypeFactory.class.php';
 
+/* compat */
+/*XXX what about aljeux’ ARTIFACT_EXTRAFIELDTYPE_FORMULA ? */
+if (!defined('ARTIFACT_EXTRAFIELDTYPE_DATETIME'))
+	define('ARTIFACT_EXTRAFIELDTYPE_DATETIME', 12);
+
 function usage($rc=1) {
 	echo "E: Usage: .../tracker-import.php 123 <t_123.json\n" .
 	    "N: where 123 is the group_artifact_id of the tracker to append to\n";
@@ -84,12 +90,19 @@ define('ICK_SC', 2);	// schema check (only IT_LST[*] and IT_ARR)
 define('ICK_FN', 3);	// function (false=bad, true=ok, array=rpl)
 
 /* ICK_FN called with (parent, fieldname, value, IT_*, IP_*); */
+/* IT_LST calls ICK_SC, ICK_FN once per entry */
 
 /*
  * These are the fields we require in each entry. Note how we only
  * list those we actually import; so, if you change the below code
  * to import more, list them here, too.
  */
+$schema_backlinks = array(
+	array("field",			IT_STR, IP_REQ, ICK_NO, 0),
+	array("group",			IT_STR, IP_REQ, ICK_NO, 0),
+	array("item",			IT_NAT, IP_REQ, ICK_NO, 0),
+	array("tracker",		IT_STR, IP_REQ, ICK_NO, 0),
+    );
 $schema_changelog = array(
 	array("by",			IT_STR, IP_REQ, ICK_NO, 0),
 	array("entrydate",		IT_NAT, IP_REQ, ICK_NO, 0),
@@ -108,6 +121,13 @@ $schema_extrafields = array(
 	array("type",			IT_NAT, IP_REQ, ICK_NO, 0),
 	array("value",			IT_ANY, IP_REQ, ICK_NO, 0),
     );
+$schema_files = array(
+	array("adddate",		IT_NAT, IP_REQ, ICK_NO, 0),
+	array("base64_data",		IT_STR, IP_REQ, ICK_NO, 0),
+	array("description",		IT_STR, IP_OPT, ICK_NO, 0),
+	array("filename",		IT_STR, IP_REQ, ICK_NO, 0),
+	array("submitter",		IT_STR, IP_OPT, ICK_NO, 0),
+    );
 $schema_votes = array(
 	array("votage_percent",		IT_NAT, IP_REQ, ICK_NO, 0),
 	array("voters",			IT_NAT, IP_REQ, ICK_NO, 0),
@@ -115,7 +135,7 @@ $schema_votes = array(
     );
 $schema_item = array(
 	array("_rpl_itempermalink",	IT_STR, IP_REQ, ICK_NO, 0),
-	array("_rpl_taskpermalink",	IT_STR, IP_OPT, ICK_NO, 0),	// ignored
+	array("_rpl_taskpermalink",	IT_STR, IP_OPT, ICK_NO, 0),
 	array("_votes",			IT_ARR, IP_OPT, ICK_SC, $schema_votes),
 	array("assigned_email",		IT_STR, IP_OPT, ICK_NO, 0),
 	array("assigned_realname",	IT_STR, IP_OPT, ICK_NO, 0),
@@ -133,9 +153,12 @@ $schema_item = array(
 	array("submitted_realname",	IT_STR, IP_OPT, ICK_NO, 0),
 	array("submitted_unixname",	IT_STR, IP_REQ, ICK_NO, 0),
 	array("summary",		IT_STR, IP_REQ, ICK_NO, 0),
+	array("~backlinks",		IT_LST, IP_OPT, ICK_SC, $schema_backlinks),
 	array("~changelog",		IT_LST, IP_OPT, ICK_SC, $schema_changelog),
 	array("~comments",		IT_LST, IP_OPT, ICK_SC, $schema_comments),
 	array("~extrafields",		IT_LST, IP_OPT, ICK_SC, $schema_extrafields),
+	array("~files",			IT_LST, IP_OPT, ICK_SC, $schema_files),
+	array("~related_tasks",		IT_LST, IP_OPT, ICK_FN, 'schema_ick_nat'),
     );
 
 function jsn_check_one($v, $schema, &$errstr, $nested) {
@@ -242,8 +265,31 @@ function jsn_check_one($v, $schema, &$errstr, $nested) {
 			break;
 		case ICK_FN:
 			$s = "failing user function check";
-			$ickres = call_user_func($icfn, $nested,
-			    $in, $vv, $it, $ip);
+			switch ($it) {
+			case IT_ARR:
+				$ickres = call_user_func($icfn, $nested,
+				    $in, $vv, $it, $ip);
+				break;
+			case IT_LST:
+				$ickres = array();
+				foreach ($vv as $ick_k => $ick_v) {
+					$icktmp = call_user_func($icfn,
+					    $nested, $in . "[" . $ick_k . "]",
+					    $ick_v, $it, $ip);
+					if ($icktmp === false) {
+						$ickres = false;
+						break;
+					}
+					$ickres[$ick_k] =
+					    ($icktmp === true) ?
+					    $ick_v : $icktmp;
+				}
+				break;
+			default:
+				echo "E: internal error: ICK_SC type " .
+				    $it . " for " . $nested . "." . $in . "\n";
+				die;
+			}
 			break;
 		default:
 			/* someone made a boo-boo editing this script */
@@ -291,6 +337,10 @@ function jsn_check($arr, $schema, &$errstr, $nested="") {
 	return $rv;
 }
 
+function schema_ick_nat($nested, $in, $vv, $it, $ip) {
+	return util_nat0($vv);
+}
+
 $ic = count($iv);
 echo "I: $ic tracker items to consider\n";
 
@@ -317,6 +367,22 @@ if (!$at || !is_object($at) || $at->isError()) {
 	die;
 }
 
+$eflist = $at->getExtraFields();
+$efnames = array();
+$efaliases = array();
+foreach ($eflist as $ef) {
+	$efid = (int)$ef["extra_field_id"];
+	$efnames[$ef["field_name"]] = $efid;
+	if (isset($ef["alias"]))
+		$efaliases[preg_replace('/^@/', '', $ef["alias"])] = $efid;
+	$efelems[$efid] = array();
+	foreach ($at->getExtraFieldElements($efid) as $efelem) {
+		$efelems[$efid][$efelem["element_name"]] = $efelem;
+	}
+}
+$efnames_lo = array_change_key_case($efnames);
+$efaliases_lo = array_change_key_case($efaliases);
+
 /* absolute minimum needed for creating tracker items in $at */
 $extra_fields = array();
 if ($at->usesCustomStatuses()) {
@@ -328,16 +394,26 @@ if ($at->usesCustomStatuses()) {
 		LIMIT 1 OFFSET 0',
 	    array($i));
 	$extra_fields[$i] = db_result($res, 0, 'element_id');
+	$cselems_lo = array_change_key_case($efelems[$efid]);
 }
 
+/* count all items, for relation fields */
+$all_items = array();
+foreach ($iv as $k => $v) {
+	$all_items[(int)$k] = true;
+}
+$tbd_links = array();
+
 /* now import the items, one by one */
 
-$i = 0;
+$j = 0;
 db_begin();
 foreach ($iv as $k => $v) {
-	echo "I: importing $k (" . ++$i . "/$ic)\n";
+	echo "I: importing $k (" . ++$j . "/$ic)\n";
 	$importData = array();
 	$missingData = array();
+	$tbd_thislinks = array();
+	$new_extra_fields = $extra_fields;
 	if (isset($v["~~not-in-schema"]))
 		$missingData['unrecognised JSON slots'] = $v["~~not-in-schema"];
 	if (isset($v["_votes"]))
@@ -360,7 +436,7 @@ foreach ($iv as $k => $v) {
 			$missingData['assignee']['unixname'] = $v["assigned_unixname"];
 	}
 	$missingData['status'] = array();
-	if (isset($v["close_date"]))
+	if (util_ifsetor($v["close_date"]))
 		$missingData['status']['close date'] = $v["close_date"];
 	if (isset($v["status_id"]) || isset($v["status_name"])) {
 		$missingData['status']['forge'] = array();
@@ -372,18 +448,25 @@ foreach ($iv as $k => $v) {
 			    $v["status_name"];
 	}
 	if (isset($v["~extrafields"])) {
-		/* for now */
-		$missingData['extrafields'] = $v["~extrafields"];
+		$efx = $v["~extrafields"];
 		/* search for custom status */
 		$fe = false;
-		foreach ($missingData['extrafields'] as $fn => $tmp) {
-			if ($tmp["type"] == 7) {
-				$fe = $fn;
-				break;
+		foreach ($efx as $fn => $tmp) {
+			if (util_ifsetor($tmp["value"]) &&
+			    ($tmp["type"] == ARTIFACT_EXTRAFIELDTYPE_STATUS)) {
+				if ($fe === false) {
+					$fe = $fn;
+				} else {
+					/* multiple status fields */
+					$fe = false;
+					$missingData['status']['error'] =
+					    'multiple status fields found';
+					break;
+				}
 			}
 		}
 		if ($fe) {
-			$tmp = $missingData['extrafields'][$fe];
+			$tmp = $efx[$fe];
 			$missingData['status']['user'] = array(
 				'field' => $fe,
 				'status' => $tmp["value"],
@@ -391,11 +474,249 @@ foreach ($iv as $k => $v) {
 			if (isset($tmp["alias"]))
 				$missingData['status']['user']['alias'] =
 				    $tmp["alias"];
-			unset($missingData['extrafields'][$fe]);
+			unset($efx[$fe]);
+		}
+		/* try to mix and match */
+		$efkeys = array_keys($efx);
+		$efdone = array();
+		$efused = array();
+		/* 0. remove all entries with value NULL */
+		foreach ($efkeys as $efkey) {
+			if ($efx[$efkey]["value"] === NULL)
+				unset($efx[$efkey]);
+		}
+		$efkeys = array_keys($efx);
+		/* 1. case-sensitive name match */
+		foreach ($efkeys as $efkey) {
+			if (isset($efnames[$efkey])) {
+				$efdone[$efkey] = $efnames[$efkey];
+				$efused[$efnames[$efkey]] = true;
+			}
+		}
+		/* 2. case-sensitive alias match */
+		foreach ($efkeys as $efkey) {
+			if (isset($efdone[$efkey]))
+				continue;
+			$efalias = preg_replace('/^@/', '',
+			    util_ifsetor($efx[$efkey]["alias"], ''));
+			if (!$efalias)
+				continue;
+			if (isset($efaliases[$efalias])) {
+				$efid = $efaliases[$efalias];
+			} else
+				continue;
+			if (!isset($efused[$efid])) {
+				$efdone[$efkey] = $efid;
+				$efused[$efid] = true;
+			}
+		}
+		/* 3. case-insensitive name/alias mix-match */
+		foreach ($efkeys as $efkey) {
+			if (isset($efdone[$efkey]))
+				continue;
+			$efalias = strtolower(preg_replace('/^@/', '',
+			    util_ifsetor($efx[$efkey]["alias"], '')));
+			if (isset($efnames_lo[strtolower($efkey)])) {
+				$efid = $efnames_lo[strtolower($efkey)];
+			} elseif (isset($efaliases_lo[strtolower($efkey)])) {
+				$efid = $efaliases_lo[strtolower($efkey)];
+			} elseif ($efalias && isset($efnames_lo[$efalias])) {
+				$efid = $efnames_lo[$efalias];
+			} elseif ($efalias && isset($efaliases_lo[$efalias])) {
+				$efid = $efaliases_lo[$efalias];
+			} else
+				continue;
+			if (!isset($efused[$efid])) {
+				$efdone[$efkey] = $efid;
+				$efused[$efid] = true;
+			}
+		}
+		/* 4. process all found ones */
+		foreach ($efdone as $efkey => $efid) {
+			$ef = $efx[$efkey];
+			$value = $ef["value"];
+			/* more or less same as Artifact::update() */
+			/* except we decide by target field type */
+			$type = (int)$eflist[$efid]["field_type"];
+			if ($ef["type"] == ARTIFACT_EXTRAFIELDTYPE_STATUS ||
+			    $type == ARTIFACT_EXTRAFIELDTYPE_STATUS) {
+				/* handled at some other place in the code */
+ lose_extrafield:
+				continue;
+			}
+			$was_array = true;
+			if ($type == ARTIFACT_EXTRAFIELDTYPE_TEXT ||
+			    $type == ARTIFACT_EXTRAFIELDTYPE_INTEGER ||
+			    $type == ARTIFACT_EXTRAFIELDTYPE_DATETIME ||
+			    $type == ARTIFACT_EXTRAFIELDTYPE_TEXTAREA) {
+				if (is_array($value)) {
+					/* eh now what? */
+					$value = implode(",", $value);
+				}
+				/* straight value copy */
+				goto found_extrafield;
+			} elseif ($type == ARTIFACT_EXTRAFIELDTYPE_RELATION) {
+				if (is_array($value))
+					$value = implode(" ", $value);
+				$value = preg_replace('/\[\#(\d+)\]/', "\\1",
+				    trim($value));
+				$value = preg_replace('/\\s+/', ' ', $value);
+				$value = explode(' ', $value);
+				foreach ($value as $tv) {
+					if (!preg_match('/^(\d+)$/', $tv))
+						/* invalid data */
+						goto lose_extrafield;
+					if (!isset($all_items[(int)$tv]))
+						/* not imported */
+						goto lose_extrafield;
+				}
+				/* fill in later */
+				$tbd_thislinks[$efid] = $value;
+				$value = '';
+				goto found_extrafield;
+			} elseif (!is_array($value)) {
+				$was_array = false;
+				$value = array($value);
+			}
+			$nv = array();
+			foreach ($value as $tv) {
+				if (!isset($efelems[$efid][$tv])) {
+					/* value not found, lose import */
+					goto lose_extrafield;
+				}
+				$nv[] = (int)$efelems[$efid][$tv]["element_id"];
+			}
+			$value = $was_array ? $nv : $nv[0];
+ found_extrafield:
+			/* import and remove not-imported mark */
+			$new_extra_fields[$efid] = $value;
+			unset($efx[$efkey]);
+		}
+		/* assign rest to unimported data, if any */
+		if ($efx)
+			$missingData['extrafields'] = $efx;
+	}
+	$didstatus = false;
+	$do_status = false;
+	$do_c_time = false;
+	if ($at->usesCustomStatuses() &&
+	    isset($missingData['status']['user'])) {
+		/* custom status fields in both src and dst, try to match */
+		$efid = $at->getCustomStatusField();
+		$value = $missingData['status']['user']['status'];
+		$i = util_ifsetor($missingData['status']['forge']['mapping'],
+		    /* 0 is not used, only 1|2|3 */ 0);
+		if (isset($efelems[$efid][$value])) {
+			/* same element name */
+			$value = $efelems[$efid][$value];
+		} elseif (isset($cselems_lo[strtolower($value)])) {
+			$value = $cselems_lo[strtolower($value)];
+		} else
+			goto status_no_extrafield_mapping;
+		if ($i && ($i != $value["status_id"]))
+			/* but not same status mapping */
+			goto status_no_extrafield_mapping;
+		/* mapping is imported */
+		$didstatus = $value["status_id"];
+		$new_extra_fields[$efid] = $value["element_id"];
+		unset($missingData['status']['user']['status']);
+		/* check names; if they match, everything is imported */
+		$xa = $eflist[$efid]["field_name"];
+		$xb = preg_replace('/^@/', '',
+		    util_ifsetor($eflist[$efid]["alias"], ""));
+		$xc = $missingData['status']['user']['field'];
+		$xd = preg_replace('/^@/', '',
+		    util_ifsetor($missingData['status']['user']['alias'], ""));
+		if (!strcasecmp($xa, $xc) ||
+		    ($xb && !strcasecmp($xb, $xc)) ||
+		    ($xd && !strcasecmp($xa, $xd)) ||
+		    ($xb && $xd && !strcasecmp($xb, $xd)))
+			unset($missingData['status']['user']);
+		goto status_mapping_done;
+	}
+ status_no_extrafield_mapping:
+	/* try to map status to extrafield */
+	if ($at->usesCustomStatuses() &&
+	    isset($missingData['status']['forge']) &&
+	    util_ifsetor($missingData['status']['forge']['status']) &&
+	    isset($cselems_lo[($value = strtolower($missingData['status']['forge']['status']))]) &&
+	    (!util_ifsetor($missingData['status']['forge']['mapping'], 0) ||
+	    $missingData['status']['forge']['mapping'] == $cselems_lo[$value]["status_id"])) {
+		$didstatus = $cselems_lo[$value]["status_id"];
+		$new_extra_fields[$at->getCustomStatusField()] =
+		    $cselems_lo[$value]["element_id"];
+		unset($missingData['status']['forge']);
+		goto status_mapping_done;
+	}
+	/* try to map status code to any extrafield value matching it */
+	if ($at->usesCustomStatuses() &&
+	    isset($missingData['status']['forge']) &&
+	    util_ifsetor($missingData['status']['forge']['mapping'], 0)) {
+		$i = $at->getCustomStatusField();
+		$tmp = (int)$missingData['status']['forge']['mapping'];
+		$res = db_query_params('SELECT element_id
+			FROM artifact_extra_field_elements
+			WHERE extra_field_id=$1
+			    AND status_id=$2
+			ORDER BY element_pos ASC, element_id ASC
+			LIMIT 1 OFFSET 0',
+		    array($i, $tmp));
+		if ($res && db_numrows($res) > 0) {
+			$didstatus = (int)db_result($res, 0, 'element_id');
+			$new_extra_fields[$i] = $didstatus;
+			goto status_mapping_done;
 		}
 	}
+	if (!$at->usesCustomStatuses() &&
+	    isset($missingData['status']['forge']) &&
+	    util_ifsetor($missingData['status']['forge']['mapping'], 0)) {
+		$do_status = (int)$missingData['status']['forge']['mapping'];
+		$didstatus = $do_status;
+		goto status_mapping_done;
+	}
+ status_mapping_done:
+	/* if we have a mapping… */
+	if ($didstatus !== false) {
+		/* figure out if it’s known, and its name */
+		$res = db_query_params('SELECT status_name
+			FROM artifact_status
+			WHERE id=$1
+			LIMIT 1 OFFSET 0',
+		    array($didstatus));
+		/* if so… */
+		if ($res && db_numrows($res) > 0) {
+			/* compare with the mapping in the JSON */
+			$i = util_ifsetor($missingData['status']['forge']['mapping'], 0);
+			if ($i && ($i == $didstatus))
+				unset($missingData['status']['forge']['mapping']);
+			/* compare with the name in the JSON */
+			$i = db_result($res, 0, 'status_name');
+			if ($i && isset($missingData['status']['forge']) &&
+			    isset($missingData['status']['forge']['status']) &&
+			    !strcasecmp($i,
+			    $missingData['status']['forge']['status'])) {
+				/* same name, unset */
+				unset($missingData['status']['forge']['status']);
+			}
+			/* check for merging closed date on !Open items */
+			if ($didstatus != 1) {
+				/* not Open => Closed or Deleted, most likely */
+				if (isset($missingData['status']['close date'])) {
+					$do_status = $didstatus;
+					$do_c_time = $missingData['status']['close date'];
+					unset($missingData['status']['close date']);
+				}
+			}
+		}
+	}
+	foreach (array('forge', 'user') as $i)
+		if (isset($missingData['status'][$i]) &&
+		    !$missingData['status'][$i])
+			unset($missingData['status'][$i]);
 	if (!$missingData['status'])
 		unset($missingData['status']);
+	$x_rpl_taskpermalink = util_ifsetor($v["_rpl_taskpermalink"]);
+	$x_rpl_taskpermalink = $x_rpl_taskpermalink ? : '#';
 
 	/* get all standard data fields (we use) */
 
@@ -459,11 +780,16 @@ foreach ($iv as $k => $v) {
 
 	/* actually create the item */
 	if (!$ah->create($summary, $details, $assigned_to, $priority,
-	    $extra_fields, $importData)) {
+	    $new_extra_fields, $importData)) {
 		echo "E: cannot import: " . $ah->getErrorMessage() . "\n";
 		db_rollback();
 		die;
 	}
+	if (($do_status !== false) && !$ah->setStatus($do_status, $do_c_time)) {
+		echo "E: cannot set status: " . $ah->getErrorMessage() . "\n";
+		db_rollback();
+		die;
+	}
 
 	/* import comments */
 	if (isset($v["~comments"])) {
@@ -538,6 +864,125 @@ foreach ($iv as $k => $v) {
 		}
 	}
 
+	/* import files */
+	if (isset($v["~files"])) {
+		$missingData['lost files'] = array();
+		foreach ($v["~files"] as $tmp) {
+			$importData = array();
+			$importData['time'] = (int)$tmp["adddate"];
+			$importData['user'] = 100;
+			$fe = util_ifsetor($tmp["description"], 'None');
+			$fu = util_ifsetor($tmp["submitter"], 100);
+			if ($fu != 100 && strcasecmp($fu, "nobody")) {
+				if (($tu = user_get_object_by_name($fu)) &&
+				    is_object($tu) && !($tu->isError())) {
+					$importData['user'] = $tu->getID();
+				} else {
+					$fe = "(by " . $fu . ") " . $fe;
+				}
+			}
+			$fb = base64_decode($tmp["base64_data"]);
+			if ($fb === false) {
+				$missingData['lost files'][] = $tmp;
+				continue;
+			}
+			$fi = new ArtifactFile($ah);
+			if (!$fi || !is_object($fi) || $fi->isError()) {
+				echo "E: cannot get the file object\n";
+				db_rollback();
+				die;
+			}
+			if (!$fi->create($tmp["filename"],
+			    'application/octet-stream',
+			    strlen($fb), $fb, $fe, $importData)) {
+				echo "E: cannot create the file: " .
+				    $fi->getErrorMessage() . "\n";
+				db_rollback();
+				die;
+			}
+		}
+		if (!$missingData['lost files'])
+			unset($missingData['lost files']);
+	}
+
+	/* import backlinks (from dst only; mixed are handled in tbd_links) */
+	if (isset($v["~backlinks"])) {
+		/* put into arrays */
+		$fi = array();
+		foreach ($v["~backlinks"] as $tmp) {
+			$fg = $tmp["group"];
+			$ft = $tmp["tracker"];
+			$ff = $tmp["field"];
+
+			if (!isset($fi[$fg]))
+				$fi[$fg] = array();
+			if (!isset($fi[$fg][$ft]))
+				$fi[$fg][$ft] = array();
+			if (!isset($fi[$fg][$ft][$ff]))
+				$fi[$fg][$ft][$ff] = array();
+			$fi[$fg][$ft][$ff][$tmp["item"]] = true;
+		}
+		/* put into order */
+		$fu = array();
+		$kg = array_keys($fi);
+		natcasesort($kg);
+		foreach ($kg as $ig) {
+			$kt = array_keys($fi[$ig]);
+			natcasesort($kt);
+			foreach ($kt as $it) {
+				$kf = array_keys($fi[$ig][$it]);
+				natcasesort($kf);
+				foreach ($kf as $if) {
+					$ki = array_keys($fi[$ig][$it][$if]);
+					natcasesort($ki);
+					foreach ($ki as $ii) {
+						$fu[] = array($ig, $it, $if, $ii);
+					}
+				}
+			}
+		}
+		/* put into text */
+		$fb = "Backlinks:\n";
+		$last_gn = false;
+		$last_tn = false;
+		$last_fn = false;
+		foreach ($fu as $fi) {
+			list($ig, $it, $if, $ii) = $fi;
+			if ($ig !== $last_gn || $it !== $last_tn ||
+			    $if !== $last_fn) {
+				$fb .= "\n$ig: $it <<<i:(Relation: $if)>>>";
+				$last_gn = $ig;
+				$last_tn = $it;
+				$last_fn = $if;
+			}
+			$fb .= "\n" . str_replace('#', sprintf('%d', $ii),
+			    $v["_rpl_itempermalink"]);
+		}
+		if (!$ah->addMessage($fb)) {
+			echo "E: cannot add backrel: " .
+			    $ah->getErrorMessage() .
+			    " / " . db_error() . "\n";
+			db_rollback();
+			die;
+		}
+	}
+
+	/* import task relationships */
+	if (isset($v["~related_tasks"])) {
+		$fb = "Task relationships:\n";
+		foreach ($v["~related_tasks"] as $tmp) {
+			$fb .= "\n" . str_replace('#', sprintf('%d', $tmp),
+			    $x_rpl_taskpermalink);
+		}
+		if (!$ah->addMessage($fb)) {
+			echo "E: cannot add taskrel: " .
+			    $ah->getErrorMessage() .
+			    " / " . db_error() . "\n";
+			db_rollback();
+			die;
+		}
+	}
+
 	/* note import fallout */
 	if ($missingData && !($ah->addMessage('"Lost data importing from ' .
 	    $old_permalink . "\" =\t" . minijson_encode($missingData)))) {
@@ -566,7 +1011,41 @@ foreach ($iv as $k => $v) {
 		db_rollback();
 		die;
 	}
+	$all_items[(int)$k] = $ah->getID();
+	if ($tbd_thislinks)
+		$tbd_links[$ah->getID()] = $tbd_thislinks;
 	echo "D: imported $k as " . $ah->getID() . "\n";
 }
+if ($tbd_links) {
+	echo "I: importing relationships between items...\n";
+	foreach ($tbd_links as $aid => $fields) {
+		foreach ($fields as $efid => $values) {
+			$efd = array();
+			foreach ($values as $v) {
+				$efd[] = $all_items[$v];
+			}
+			$nfd = implode(" ", $efd);
+			echo "D: #$aid $efid (" . implode(" ", $values) .
+			    ") => ($nfd)\n";
+			$res = db_query_params('DELETE FROM artifact_extra_field_data
+				WHERE artifact_id=$1 AND extra_field_id=$2',
+			    array($aid, $efid));
+			if (!$res) {
+				echo "E: could not delete data: " . db_error() . "\n";
+				db_rollback();
+				die;
+			}
+			$res = db_query_params('INSERT INTO artifact_extra_field_data
+				(artifact_id,extra_field_id,field_data)
+				VALUES ($1,$2,$3)',
+			    array($aid, $efid, htmlspecialchars($nfd)));
+			if (!$res) {
+				echo "E: could not write data: " . db_error() . "\n";
+				db_rollback();
+				die;
+			}
+		}
+	}
+}
 db_commit();
 echo "I: done\n";

-----------------------------------------------------------------------

Summary of changes:
 src/utils/one-off-scripts/tracker-import.php |  511 +++++++++++++++++++++++++-
 1 file changed, 495 insertions(+), 16 deletions(-)


hooks/post-receive
-- 
FusionForge



More information about the Fusionforge-commits mailing list