$savedRecord['nonce'] = $nonce;
        }
        array_push($out["record"], $savedRecord);
    }
}
/*****DEBUG****/
//error_log("updating titlemasks ");
if (count($retitleRecs) > 0) {
    foreach ($retitleRecs as $id) {
        // calculate title, do an update
        $query = "select rty_TitleMask, rty_ID from defRecTypes left join Records on rty_ID=rec_RecTypeID where rec_ID = {$id}";
        $res = mysql_query($query);
        $mask = mysql_fetch_assoc($res);
        $type = $mask["rty_ID"];
        $mask = $mask["rty_TitleMask"];
        $title = fill_title_mask($mask, $id, $type);
        if ($title) {
            mysql_query("update Records set rec_Title = '" . addslashes($title) . "' where rec_ID = {$id}");
        }
    }
}
/*****DEBUG****/
//error_log("committing changes");
print json_format($out);
return;
function jsonError($message)
{
    mysql_query("rollback");
    print "{\"error\":\"" . addslashes($message) . "\"}";
    exit(0);
}
function rollRecordBack($rec_id, $changes)
{
    if (count($changes["updates"]) == 0 && count($changes["inserts"]) == 0 && count($changes["deletes"]) == 0) {
        return true;
    }
    mysql_query("start transaction");
    mysql_query("update Records set rec_Modified = now() where rec_ID = {$rec_id}");
    if (mysql_error()) {
        mysql_query("rollback");
        return false;
    }
    foreach ($changes["updates"] as $update) {
        $rd_id = $update["ard_ID"];
        $rd_val = $update["ard_Value"] ? "'" . mysql_real_escape_string($update["ard_Value"]) . "'" : "null";
        $rd_file_id = $update["ard_UploadedFileID"] ? $update["ard_UploadedFileID"] : "null";
        $rd_geo = $update["ard_Geo"] ? "geomfromtext('" . $update["ard_Geo"] . "')" : "null";
        mysql_query("\n\t\t\tupdate recDetails\n\t\t\tset dtl_Value = {$rd_val}, dtl_UploadedFileID = {$rd_file_id}, dtl_Geo = {$rd_geo}\n\t\t\twhere dtl_RecID = {$rec_id}\n\t\t\tand dtl_ID = {$rd_id}\n\t\t");
        if (mysql_error()) {
            mysql_query("rollback");
            return false;
        }
    }
    foreach ($changes["inserts"] as $insert) {
        $rd_id = $insert["ard_ID"];
        $rd_type = $insert["ard_DetailTypeID"];
        $rd_val = $insert["ard_Value"] ? "'" . mysql_real_escape_string($insert["ard_Value"]) . "'" : "null";
        $rd_file_id = $insert["ard_UploadedFileID"] ? $insert["ard_UploadedFileID"] : "null";
        $rd_geo = $insert["ard_Geo"] ? "geomfromtext('" . $insert["ard_Geo"] . "')" : "null";
        mysql_query("\n\t\t\tinsert into recDetails (dtl_RecID, dtl_DetailTypeID, dtl_Value, dtl_UploadedFileID, dtl_Geo)\n\t\t\tvalues ({$rec_id}, {$rd_type}, {$rd_val}, {$rd_file_id}, {$rd_geo})\n\t\t");
        if (mysql_error()) {
            mysql_query("rollback");
            return false;
        }
    }
    foreach ($changes["deletes"] as $ard_id) {
        mysql_query("delete from recDetails where dtl_ID = {$ard_id}");
        if (mysql_error()) {
            mysql_query("rollback");
            return false;
        }
    }
    // update record title if necessary
    $res = mysql_query("\n\t\tselect rec_RecTypeID, rty_TitleMask\n\t\tfrom Records, defRecTypes\n\t\twhere rec_ID = {$rec_id}\n\t\tand rty_ID = rec_RecTypeID\n\t");
    if ($res) {
        $row = mysql_fetch_row($res);
        if ($row) {
            $title = fill_title_mask($row[1], $rec_id, $row[0]);
            if ($title) {
                mysql_query("set @suppress_update_trigger := 1");
                mysql_query("update Records set rec_Title = '" . mysql_real_escape_string($title) . "' where rec_ID = {$rec_id}");
                if (mysql_error()) {
                    mysql_query("rollback");
                    mysql_query("set @suppress_update_trigger := NULL");
                    return false;
                }
                mysql_query("set @suppress_update_trigger := NULL");
            }
        }
    }
    mysql_query("commit");
    updateCachedRecord($rec_id);
    return true;
}
function saveRecord($recordID, $rectype, $url, $notes, $wg, $vis, $personalised, $pnotes, $rating, $tags, $wgTags, $details, $notifyREMOVE, $notifyADD, $commentREMOVE, $commentMOD, $commentADD, &$nonces = null, &$retitleRecs = null, $modeImport = 0)
{
    global $msgInfoSaveRec;
    $msgInfoSaveRec = array();
    // reset the message array
    mysql_query("start transaction");
    //	$log = " saving record ($recordID) ";
    $recordID = intval($recordID);
    $wg = intval($wg);
    if ($wg || !is_logged_in()) {
        // non-member saves are not allowed
        $res = mysql_query("select * from " . USERS_DATABASE . ".sysUsrGrpLinks where ugl_UserID=" . get_user_id() . " and ugl_GroupID=" . $wg);
        if (mysql_num_rows($res) < 1) {
            errSaveRec("invalid workgroup, record save aborted");
            return $msgInfoSaveRec;
        }
    }
    $rectype = intval($rectype);
    if ($recordID && !$rectype) {
        errSaveRec("cannot change existing record to private note, record save aborted");
        return $msgInfoSaveRec;
    }
    if ($vis && !in_array(strtolower($vis), array('hidden', 'viewable', 'pending', 'public'))) {
        $vis = null;
    }
    $now = date('Y-m-d H:i:s');
    // public records data
    if (!$recordID) {
        //		$log .= "- inserting record ";
        mysql__insert("Records", array("rec_RecTypeID" => $rectype, "rec_URL" => $url, "rec_ScratchPad" => $notes, "rec_OwnerUGrpID" => $wg || $wg == 0 ? $wg : get_user_id(), "rec_NonOwnerVisibility" => $vis ? $vis : "viewable", "rec_AddedByUGrpID" => get_user_id(), "rec_Added" => $now, "rec_Modified" => $now, "rec_AddedByImport" => $modeImport > 0 ? 1 : 0));
        if (mysql_error()) {
            errSaveRec("database record insert error - " . mysql_error());
            return $msgInfoSaveRec;
        }
        $recordID = mysql_insert_id();
    } else {
        $res = mysql_query("select * from Records left join " . USERS_DATABASE . ".sysUsrGrpLinks on ugl_GroupID=rec_OwnerUGrpID and ugl_UserID=" . get_user_id() . " where rec_ID={$recordID}");
        $record = mysql_fetch_assoc($res);
        if ($wg != $record["rec_OwnerUGrpID"] && $record["rec_OwnerUGrpID"] != get_user_id()) {
            if ($record["rec_OwnerUGrpID"] > 0 && $record["ugl_Role"] != "admin") {
                // user is trying to change the workgroup when they are not an admin
                errSaveRec("user is not a workgroup admin");
                return $msgInfoSaveRec;
            } else {
                if (!is_admin()) {
                    // you must be an database admin to change a public record into a workgroup record
                    errSaveRec("user does not have sufficient authority to change public record to workgroup record");
                    return $msgInfoSaveRec;
                }
            }
        }
        //		$log .= "- updating record ";
        mysql__update("Records", "rec_ID={$recordID}", array("rec_RecTypeID" => $rectype, "rec_URL" => $url, "rec_ScratchPad" => $notes, "rec_OwnerUGrpID" => $wg || $wg == 0 ? $wg : get_user_id(), "rec_NonOwnerVisibility" => $vis ? $vis : "viewable", "rec_FlagTemporary" => 0, "rec_Modified" => $now));
        if (mysql_error()) {
            errSaveRec("database record update error - " . mysql_error());
            return $msgInfoSaveRec;
        }
    }
    // public recDetails data
    if ($details) {
        //		$log .= "- inserting details ";
        $dtlIDsByAction = doDetailInsertion($recordID, $details, $rectype, $wg, $nonces, $retitleRecs, $modeImport);
        if (@$dtlIDsByAction['error']) {
            array_push($msgInfoSaveRec['error'], $dtlIDsByAction['error']);
            return $msgInfoSaveRec;
        }
    }
    // check that all the required fields are present
    $res = mysql_query("select rst_ID, rst_DetailTypeID, rst_DisplayName" . " from defRecStructure" . " left join recDetails on dtl_RecID={$recordID} and rst_DetailTypeID=dtl_DetailTypeID" . " where rst_RecTypeID={$rectype} and rst_RequirementType='required' and dtl_ID is null");
    if (mysql_num_rows($res) > 0) {
        //		$log .= "- testing missing detatils ";
        $missed = "";
        while ($row = mysql_fetch_row($res)) {
            $missed = $missed . $row[2] . " ";
        }
        /*****DEBUG****/
        //error_log("MISSED ".$missed);
        // at least one missing field
        if ($modeImport == 2) {
            warnSaveRec("record is missing required field(s): " . $missed);
        } else {
            errSaveRec("record is missing required field(s): " . $missed);
            return $msgInfoSaveRec;
        }
    }
    mysql_query("commit");
    // if we get to here we have a valid save of the core record.
    // calculate title, do an update
    //	$log .= "- filling titlemask ";
    $mask = mysql__select_array("defRecTypes", "rty_TitleMask", "rty_ID={$rectype}");
    $mask = $mask[0];
    $title = fill_title_mask($mask, $recordID, $rectype);
    /*****DEBUG****/
    //error_log("DEBUG >>>>>>MASK=".$mask."=".$title);
    if ($title) {
        mysql_query("update Records set rec_Title = '" . addslashes($title) . "' where rec_ID = {$recordID}");
    }
    // Update memcache: we can do this here since it's only the public data that we cache.
    updateCachedRecord($recordID);
    // private data
    $bkmk = @mysql_fetch_row(mysql_query("select bkm_ID from usrBookmarks where bkm_UGrpID=" . get_user_id() . " and bkm_recID=" . $recordID));
    $bkm_ID = @$bkmk[0];
    if ($personalised) {
        if (!$bkm_ID) {
            // Record is not yet bookmarked, but we want it to be
            mysql_query("insert into usrBookmarks (bkm_Added,bkm_Modified,bkm_UGrpID,bkm_recID) values (now(),now()," . get_user_id() . ",{$recordID})");
            if (mysql_error()) {
                warnSaveRec("trying to create a bookmark - database error - " . mysql_error());
            } else {
                $bkm_ID = mysql_insert_id();
            }
        }
        //		$log .= "- updating bookmark ";
        mysql__update("usrBookmarks", "bkm_ID={$bkm_ID}", array("bkm_Rating" => $rating, "bkm_Modified" => date('Y-m-d H:i:s')));
        //WARNING  tags is assumed to be a complete replacement list for personal tags on this record.
        doTagInsertion($recordID, $bkm_ID, $tags);
    } else {
        if ($bkm_ID) {
            // Record is bookmarked, but the user doesn't want it to be
            //		$log .= "- deleting bookmark ";
            $query = "delete usrBookmarks, usrRecTagLinks " . "from usrBookmarks left join usrRecTagLinks on rtl_RecID = bkm_recID " . "left join usrTags on tag_ID = rtl_TagID " . "where bkm_ID={$bkm_ID} and bkm_recID={$recordID} and bkm_UGrpID = tag_UGrpID and bkm_UGrpID=" . get_user_id();
            /*****DEBUG****/
            //error_log("saveRecord delete bkmk - q = $query");
            mysql_query($query);
            if (mysql_error()) {
                warnSaveRec("database error while removing bookmark- " . mysql_error());
            }
            //saw TODO: add code to remove other personal data reminders, personal notes (woots), etc.
        }
    }
    doWgTagInsertion($recordID, $wgTags);
    if ($notifyREMOVE || $notifyADD) {
        $notifyIDs = handleNotifications($recordID, $notifyREMOVE, $notifyADD);
    }
    if ($commentREMOVE || $commentMOD || $commentADD) {
        $commentIDs = handleComments($recordID, $commentREMOVE, $commentMOD, $commentADD);
    }
    $rval = array("bibID" => $recordID, "bkmkID" => $bkm_ID, "modified" => $now);
    if ($title) {
        $rval["title"] = $title;
    }
    if (@$dtlIDsByAction) {
        $rval["detail"] = $dtlIDsByAction;
    }
    if (@$notifyIDs) {
        $rval["notify"] = $notifyIDs;
    }
    if (@$commentIDs) {
        $rval["comment"] = $commentIDs;
    }
    if (@$msgInfoSaveRec['warning']) {
        $rval["warning"] = $msgInfoSaveRec['warning'];
    }
    if (@$msgInfoSaveRec['error']) {
        //should never get here with error set
        $rval["error"] = $msgInfoSaveRec['error'];
    } else {
        //$rval["usageCount"] =
        updateRecTypeUsageCount();
    }
    /*****DEBUG****/
    //error_log($log);
    return $rval;
}
            <?php 
flush_buffers();
$blanks = array();
$reparables = array();
$step_uiupdate = 10;
if (count($recs) > 1000) {
    $step_uiupdate = ceil(count($recs) / 100);
}
foreach ($recs as $rec_id => $rec) {
    if ($rec_id % $step_uiupdate == 0) {
        print '<script type="text/javascript">update_counts(' . $processed_count . ',' . $blank_count . ',' . $repair_count . ',' . count($updates) . ')</script>' . "\n";
        flush_buffers();
    }
    $mask = $masks[$rec['rec_RecTypeID']];
    $new_title = trim(fill_title_mask($mask, $rec_id, $rec['rec_RecTypeID']));
    ++$processed_count;
    $rec_title = trim($rec['rec_Title']);
    if ($new_title && $rec_title && $new_title == $rec_title && strstr($new_title, $rec_title)) {
        continue;
    }
    if (!preg_match('/^\\s*$/', $new_title)) {
        // if new title is blank, leave the existing title
        $updates[$rec_id] = $new_title;
    } else {
        if ($rec['rec_RecTypeID'] == 1 && $rec['rec_Title']) {
            array_push($reparables, $rec_id);
            ++$repair_count;
        } else {
            array_push($blanks, $rec_id);
            ++$blank_count;
function checkRectypeMask($rtID, $rtName, $mask, $coMask, $recID, $check)
{
    if (!@$mask && @$rtID) {
        $mask = mysql__select_array("defRecTypes", "rty_TitleMask", "rty_ID={$rtID}");
        $mask = $mask[0];
    }
    if (!@$coMask && @$rtID) {
        $coMask = mysql__select_array("defRecTypes", "rty_CanonicalTitleMask", "rty_ID={$rtID}");
        $coMask = $coMask[0];
    }
    //echo print_r($_REQUEST,true);
    if ($check > 0 || !$recID) {
        ?>
			<div>
				<h3>Checking rectype "<b><i><?php 
        echo $rtName;
        ?>
</i></b>"[<?php 
        echo $rtID;
        ?>
]</h3>
			</div>
<?php 
        $retMaskCheck = check_title_mask2($mask, $rtID, true);
        echo "<div class='resultsRow'><div class='statusCell " . ($retMaskCheck == "" ? "valid'>" : "invalid'>in") . "valid</div>";
        echo "<div class='maskCell'>mask = <i>{$mask}</i></div>";
        if ($retMaskCheck != "") {
            echo "<div class='errorCell'>" . $retMaskCheck . "</div>";
        }
        echo "</div>";
        $retCoMaskCheck = check_title_mask2($coMask, $rtID, true);
        echo "<div class='resultsRow'><div class='statusCell " . ($retCoMaskCheck == "" ? "valid'>" : "invalid'>in") . "valid</div>";
        echo "<div class='maskCell'>canonical mask = <i>{$coMask}</i></div>";
        if ($retCoMaskCheck != "") {
            echo "<div class='errorCell'>" . $retCoMaskCheck . "</div>";
        }
        echo "</div>";
        if ($retCoMaskCheck !== "" && $retMaskCheck == "") {
            $coMask = make_canonical_title_mask($mask, $rtID);
            if ($check != 2) {
                echo "<div class='resultsRow'><div class='statusCell'></div><div class='maskCell'>Correct canonical mask = <span class='valid'>{$coMask}</span></div></div>";
            } else {
                // repair canonical
                mysql_query("update defRecTypes set rty_CanonicalTitleMask='{$coMask}' where rty_ID={$rtID}");
                $error = mysql_error();
                echo "<div class='resultsRow'><div class='statusCell " . ($error == "" ? "valid'>Update successful" : "invalid'>Failed to update") . "</div>";
                echo "<div class='maskCell'>Correct canonical mask = <span class='valid'>{$coMask}</span></div>";
                echo ($error ? "<div class='errorCell invalid'> Error : " . $error . "</div>" : "") . "</div>";
            }
        }
        echo "<hr>\n";
    } else {
        echo "checking type mask {$mask} for recType {$rtID} and rec {$recID} <br/>";
        echo fill_title_mask($mask, $recID, $rtID);
    }
}
/**
 * Main method that parses POST and update details for given record ID
 *
 * @param int $recID
 */
function updateRecord($recID, $rtyID = null)
{
    // Update the given record.
    // This is non-trivial: so that the versioning stuff (achive_*) works properly
    // we need to separate this into updates, inserts and deletes.
    // We get the currect record details and compare them against the post
    // if the details id is in the post[dtyID][dtlID] then compare the values
    $recID = intval($recID);
    // Check that the user has permissions to edit it.
    $res = mysql_query("select * from Records" . " left join sysUsrGrpLinks on ugl_GroupID=rec_OwnerUGrpID" . " left join defRecTypes on rty_ID=rec_RecTypeID" . " where rec_ID={$recID} and (! rec_OwnerUGrpID or rec_OwnerUGrpID=" . get_user_id() . " or ugl_UserID=" . get_user_id() . ")");
    if (mysql_num_rows($res) == 0) {
        $res = mysql_query("select grp.ugr_Name from Records, " . USERS_DATABASE . ".sysUGrps grp where rec_ID={$recID} and grp.ugr_ID=rec_OwnerUGrpID");
        $grpName = mysql_fetch_row($res);
        $grpName = $grpName[0];
        print '({ error: "\\nSorry - you can\'t edit this record.\\nYou aren\'t in the ' . slash($grpName) . ' workgroup" })';
        return;
    }
    $record = mysql_fetch_assoc($res);
    /*****DEBUG****/
    error_log("save record dtls POST " . print_r($_POST, true));
    // Upload any files submitted ... (doesn't have to take place right now, but may as well)
    uploadFiles();
    //Artem: it does not work here - since we uploaded files at once
    // Get the existing records details and compare them to the incoming data
    $recDetails = getRecordDetails($recID);
    // find UPDATES - everything that is in current record and has a post value is treated as an update
    $recDetailUpdates = array();
    /*****DEBUG****/
    //error_log("save record dtls ".print_r($recDetails,true));
    foreach ($recDetails as $dtyID => $dtlIDs) {
        $eltName = "type:" . $dtyID;
        if (!(@$_POST[$eltName] && is_array($_POST[$eltName]))) {
            // element wasn't in POST: ignore it -this could be a non-rectype detail
            unset($recDetails[$dtyID]);
            // remove from details so it's not deleted
            continue;
        }
        if (count($_POST[$eltName]) == 0) {
            // element was in POST but without content: values have been deleted client-side (need to be deleted in DB so leave POST)
            continue;
        }
        $bdInputHandler = getInputHandlerForType($dtyID);
        //returns the particular handler (processor) for given field type
        foreach ($dtlIDs as $dtlID => $val) {
            /*****DEBUG****/
            //error_log(" in saveRecord details loop  $dtyID,  $dtlID, ".print_r($val,true));
            $eltID = "bd:" . $dtlID;
            $val = @$_POST[$eltName][$eltID];
            if (!$bdInputHandler->inputOK($val, $dtyID, $rtyID)) {
                /*****DEBUG****/
                //error_log(" in saveRecord update details value check error  $dtyID,  $dtlID, ".print_r($val,true));
                continue;
                // faulty input ... ignore
            }
            $toadd = $bdInputHandler->convertPostToMysql($val);
            /*****DEBUG****/
            //error_log(" in saveRecord update details value converted from $val to $toadd");
            if ($toadd == null) {
                continue;
            }
            $recDetailUpdates[$dtlID] = $toadd;
            $recDetailUpdates[$dtlID]["dtl_DetailTypeID"] = $dtyID;
            /*
            @TODO Since this function is utilized in (email)import we need to add verification of values according to detail type
            at the first for terms (enumeration field type)
            */
            unset($_POST[$eltName][$eltID]);
            // remove data from post submission
            if (count($_POST[$eltName]) == 0) {
                // if nothing left in post dtyID then remove it also
                unset($_POST[$eltName]);
            }
            unset($recDetails[$dtyID][$dtlID]);
            // remove data from local reflection of the database
        }
    }
    /*****DEBUG****/
    //error_log("save record dtls POST after updates removed ".print_r($_POST,true));
    /*****DEBUG****/
    //error_log("save record dtls after updates removed ".print_r($recDetails,true));
    // find DELETES
    // Anything left in recDetails now represents recDetails rows that need to be deleted
    $bibDetailDeletes = array();
    foreach ($recDetails as $dtyID => $dtlIDs) {
        foreach ($dtlIDs as $dtlID => $val) {
            array_push($bibDetailDeletes, $dtlID);
        }
    }
    // find INSERTS
    // Try to insert anything left in POST as new recDetails rows
    $bibDetailInserts = array();
    /*****DEBUG****/
    error_log(" in saveRecord checking for inserts  _POST =" . print_r($_POST, true));
    foreach ($_POST as $eltName => $bds) {
        // if not properly formatted or empty or an empty array then skip it
        if (!preg_match("/^type:\\d+\$/", $eltName) || !$_POST[$eltName] || count($_POST[$eltName]) == 0) {
            continue;
        }
        $dtyID = substr($eltName, 5);
        $bdInputHandler = getInputHandlerForType($dtyID);
        foreach ($bds as $eltID => $val) {
            if (!$bdInputHandler->inputOK($val, $dtyID, $rtyID)) {
                /*****DEBUG****/
                //error_log(" in saveRecord insert details value check error for $eltName,  $eltID, ".print_r($val,true));
                continue;
                // faulty input ... ignore
            }
            $newBibDetail = $bdInputHandler->convertPostToMysql($val);
            $newBibDetail["dtl_DetailTypeID"] = $dtyID;
            $newBibDetail["dtl_RecID"] = $recID;
            /*****DEBUG****/
            //error_log("new detail ".print_r($newBibDetail,true));
            array_push($bibDetailInserts, $newBibDetail);
            unset($_POST[$eltName][$eltID]);
            // remove data from post submission
        }
    }
    // Anything left in POST now is stuff that we have no intention of inserting ... ignore it
    // We now have:
    //  - $recDetailUpdates: an assoc. array of dtl_ID => column values to be updated in recDetails
    //  - $bibDetailInserts: an array of column values to be inserted into recDetails
    //  - $bibDetailDeletes: an array of dtl_ID values corresponding to rows to be deleted from recDetails
    // Commence versioning ...
    mysql_query("start transaction");
    $recUpdates = array("rec_Modified" => array("now()"), "rec_FlagTemporary" => 0);
    $recUpdates["rec_ScratchPad"] = $_POST["notes"];
    if (intval(@$_POST["rectype"])) {
        $recUpdates["rec_RecTypeID"] = intval($_POST["rectype"]);
    }
    if (array_key_exists("rec_url", $_POST)) {
        $recUpdates["rec_URL"] = $_POST["rec_url"];
    }
    $owner = $record['rec_OwnerUGrpID'];
    if (is_admin() || is_admin('group', $owner) || $owner == get_user_id()) {
        // must be grpAdmin or record owner to changes ownership or visibility
        if (array_key_exists("rec_owner", $_POST)) {
            $recUpdates["rec_OwnerUGrpID"] = $_POST["rec_owner"];
        }
        if (array_key_exists("rec_visibility", $_POST)) {
            $recUpdates["rec_NonOwnerVisibility"] = $_POST["rec_visibility"];
        } else {
            if ($record['rec_NonOwnerVisibility'] == 'public' && HEURIST_PUBLIC_TO_PENDING) {
                $recUpdates["rec_NonOwnerVisibility"] = 'pending';
            }
        }
    }
    /*****DEBUG****/
    error_log(" in saveRecord update recUpdates = " . print_r($recUpdates, true));
    mysql__update("Records", "rec_ID={$recID}", $recUpdates);
    $biblioUpdated = mysql_affected_rows() > 0 ? true : false;
    if (mysql_error()) {
        error_log("error rec update" . mysql_error());
    }
    $updatedRowCount = 0;
    foreach ($recDetailUpdates as $bdID => $vals) {
        /*****DEBUG****/
        error_log(" in saveRecord update details dtl_ID = {$bdID} value =" . print_r($vals, true));
        mysql__update("recDetails", "dtl_ID={$bdID} and dtl_RecID={$recID}", $vals);
        if (mysql_affected_rows() > 0) {
            ++$updatedRowCount;
        }
    }
    if (mysql_error()) {
        error_log("error detail updates" . mysql_error());
    }
    $insertedRowCount = 0;
    foreach ($bibDetailInserts as $vals) {
        /*****DEBUG****/
        error_log(" in saveRecord insert details detail =" . print_r($vals, true));
        mysql__insert("recDetails", $vals);
        if (mysql_affected_rows() > 0) {
            ++$insertedRowCount;
        }
    }
    if (mysql_error()) {
        error_log("error detail inserts" . mysql_error());
    }
    $deletedRowCount = 0;
    if ($bibDetailDeletes) {
        /*****DEBUG****/
        error_log(" in saveRecord delete details " . print_r($bibDetailDeletes, true));
        mysql_query("delete from recDetails where dtl_ID in (" . join($bibDetailDeletes, ",") . ") and dtl_RecID={$recID}");
        if (mysql_affected_rows() > 0) {
            $deletedRowCount = mysql_affected_rows();
        }
    }
    if (mysql_error()) {
        error_log("error detail deletes" . mysql_error());
    }
    // eliminate any duplicated lines
    $notesIn = explode("\n", str_replace("\r", "", $_POST["notes"]));
    $notesOut = "";
    $notesMap = array();
    for ($i = 0; $i < count($notesIn); ++$i) {
        if (!@$notesMap[$notesIn[$i]] || !$notesIn[$i]) {
            // preserve blank lines
            $notesOut .= $notesIn[$i] . "\n";
            $notesMap[$notesIn[$i]] = true;
        }
    }
    $_POST["notes"] = preg_replace("/\n\n+/", "\n", $notesOut);
    if ($updatedRowCount > 0 || $insertedRowCount > 0 || $deletedRowCount > 0 || $biblioUpdated) {
        /* something changed: update the records title and commit all changes */
        $title_check = check_title_mask2($record["rty_TitleMask"], $record["rec_RecTypeID"], true);
        if ($title_check != '') {
            $new_title = "Please go to Designer View > Essentials > Record types/fields and edit the title mask for this record type";
        } else {
            $new_title = fill_title_mask($record["rty_TitleMask"], $record["rec_ID"], $record["rec_RecTypeID"]);
        }
        mysql_query("update Records\n                set rec_Title = '" . addslashes($new_title) . "'\n                where rec_ID = {$recID}");
        mysql_query("commit");
        // Update memcached's copy of record (if it is cached)
        updateCachedRecord($recID);
        return true;
    } else {
        /* nothing changed: rollback the transaction so we don't get false versioning */
        mysql_query("rollback");
        return false;
    }
}
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
/**
* Generates the title from mask, recid and rectype
*
* @author      Artem Osmakov   <artem.osmakov@sydney.edu.au>
* @copyright   (C) 2005-2013 University of Sydney
* @link        http://Sydney.edu.au/Heurist
* @version     3.1.0
* @license     http://www.gnu.org/licenses/gpl-3.0.txt GNU License 3.0
* @package     Heurist academic knowledge management system
* @subpackage  AdminStructure
*/
require_once dirname(__FILE__) . '/../../common/connect/applyCredentials.php';
require_once dirname(__FILE__) . '/../../common/php/dbMySqlWrappers.php';
require_once dirname(__FILE__) . '/../../common/php/utilsTitleMask.php';
mysql_connection_select(DATABASE);
$rectypeID = @$_REQUEST['rty_id'];
$mask = @$_REQUEST['mask'];
if (array_key_exists("check", @$_REQUEST)) {
    $check = check_title_mask2($mask, $rectypeID, true);
    if (!empty($check)) {
        echo $check;
    }
} else {
    $recID = @$_REQUEST['rec_id'];
    echo fill_title_mask($mask, $recID, $rectypeID);
}
exit;
*/
require_once dirname(__FILE__) . '/../../common/connect/applyCredentials.php';
require_once dirname(__FILE__) . '/../../common/php/dbMySqlWrappers.php';
require_once dirname(__FILE__) . '/../../common/php/getRecordInfoLibrary.php';
mysql_connection_select(DATABASE);
require_once dirname(__FILE__) . '/../../common/php/utilsTitleMask.php';
$mask = @$_REQUEST['mask'];
//
$rt = @$_REQUEST['rtID'];
//
$recID = @$_REQUEST['recID'];
//
if (!$rt or !$mask) {
    echo "please pass in at least a mask and a rectype ID  as mask=validMaskStringHere&rtID=# <br />";
    echo "you may also padd in a record ID of rectype to calculate the title <br />";
    echo "be sure to add the db=databaseName for the database you are working on.<br />";
    exit;
}
echo ($ret = check_title_mask($mask, $rt)) ? $ret . "<br /><br /><br />" : "title mask\"<b>{$mask}</b>\"checks out to be valid for rectype {$rt}<br /><br /><br />";
echo "canonical form for mask is \"<b>" . make_canonical_title_mask($mask, $rt) . "</b>\"<br /><br /><br />";
if (!$ret && $recID) {
    echo "Title for record {$recID} :     <b>" . fill_title_mask($mask, $recID, $rt) . "</b><br />";
}
//echo json_format(_title_mask__get_rec_detail_types(),true)."<br><br><br>";
//echo json_format(_title_mask__get_rec_detail_requirements(),true)."<br><br><br>";
//echo json_format(getTermTree("reltype","prefix"),true).";\n";
//echo print_r(getTermSets('reltypevocab'),true)."<br><br><br>";
//require_once(dirname(__FILE__).'/../../hapi/php/loadHapiCommonInfo.php');
//echo json_format(getAllRectypeConstraint(),true)."<br>";
//require_once(dirname(__FILE__).'/../../common/php/loadCommonInfo.php');//echo print_r(getRectypeStructureFields("174"),true)."c14<br>";
//require_once(dirname(__FILE__).'/../../import/bookmarklet/getRectypesAsJSON.php');//echo print_r(getRectypeStructureFields("174"),true)."c14<br>";
/**
* updateRecTitles : updates the constructed record titles following modification of data values (details)
*
* @param mixed $data
*/
function updateRecTitles($recIDs)
{
    if (!is_array($recIDs)) {
        if (is_numeric($recIDs)) {
            $recIDs = array($recIDs);
        } else {
            return false;
        }
    }
    $res = mysql_query("select rec_ID, rec_Title, rec_RecTypeID from Records" . " where ! rec_FlagTemporary and rec_ID in (" . join(",", $recIDs) . ") order by rand()");
    $recs = array();
    while ($row = mysql_fetch_assoc($res)) {
        $recs[$row['rec_ID']] = $row;
    }
    $masks = mysql__select_assoc('defRecTypes', 'rty_ID', 'rty_TitleMask', '1');
    foreach ($recIDs as $recID) {
        $rtyID = $recs[$recID]['rec_RecTypeID'];
        $new_title = fill_title_mask($masks[$rtyID], $recID, $rtyID);
        mysql_query("update Records set rec_Title = '" . addslashes($new_title) . "'where rec_ID = {$recID}");
    }
}
Exemple #10
0
function saveRecord($recordID, $rectype, $url, $notes, $wg, $vis, $personalised, $pnotes, $rating, $tags, $wgTags, $details, $notifyREMOVE, $notifyADD, $commentREMOVE, $commentMOD, $commentADD, &$nonces = null, &$retitleRecs = null, $modeImport = 0)
{
    global $msgInfoSaveRec;
    $msgInfoSaveRec = array();
    // reset the message array
    mysql_query("start transaction");
    //	$log = " saving record ($recordID) ";
    $recordID = intval($recordID);
    $wg = intval($wg);
    if (!is_logged_in()) {
        errSaveRec("It is not possible to save record if not logged in, record save aborted");
        return $msgInfoSaveRec;
    } else {
        if ($wg != null && intval($wg) > 0 && intval($wg) != get_user_id()) {
            // non-member saves are not allowed
            $uquery = "select * from " . USERS_DATABASE . ".sysUsrGrpLinks where ugl_UserID=" . get_user_id() . " and ugl_GroupID=" . $wg;
            $res = mysql_query($uquery);
            if (mysql_num_rows($res) < 1) {
                errSaveRec("Current user " . get_user_id() . " is not a member of required workgroup " . $wg . ", record save aborted ");
                return $msgInfoSaveRec;
            }
        }
    }
    $rectype = intval($rectype);
    if ($recordID && !$rectype) {
        errSaveRec("cannot change existing record to private note, record save aborted");
        return $msgInfoSaveRec;
    }
    $rectypeName = null;
    $res = mysql_query("select rty_Name from defRecTypes where rty_ID=" . $rectype);
    if ($res) {
        $row = mysql_fetch_row($res);
        if ($row) {
            $rectypeName = $row[0];
        }
    }
    if (!$rectypeName) {
        errSaveRec("record type #{$rectype} is not valid");
        return $msgInfoSaveRec;
    }
    if ($vis) {
        $vis = strtolower(str_replace('"', "", $vis));
        $isvalid = in_array(strtolower($vis), array('hidden', 'viewable', 'pending', 'public'));
        if ($isvalid == false) {
            $vis = null;
        }
    }
    $now = date('Y-m-d H:i:s');
    $wg = $wg >= 0 ? $wg : get_user_id();
    // public records data
    if (!$recordID || $recordID < 0) {
        //new record
        //		$log .= "- inserting record ";
        $recheader = array("rec_RecTypeID" => $rectype, "rec_URL" => $url, "rec_ScratchPad" => $notes, "rec_OwnerUGrpID" => $wg, "rec_NonOwnerVisibility" => $vis ? $vis : "viewable", "rec_AddedByUGrpID" => get_user_id(), "rec_Added" => $now, "rec_Modified" => $now, "rec_AddedByImport" => $modeImport > 0 ? 1 : 0);
        if ($recordID < 0) {
            $recordID = abs($recordID);
            $recheader["rec_ID"] = $recordID;
        }
        mysql__insert("Records", $recheader);
        if (mysql_error()) {
            errSaveRec("Database record insert error - " . mysql_error() . "  " . print_r($recheader, true));
            return $msgInfoSaveRec;
        }
        $recordID = mysql_insert_id();
    } else {
        $res = checkPermission($recordID, $wg);
        if ($res !== true) {
            errSaveRec($res);
            return $msgInfoSaveRec;
        }
        //		$log .= "- updating record ";
        mysql__update("Records", "rec_ID={$recordID}", array("rec_RecTypeID" => $rectype, "rec_URL" => $url, "rec_ScratchPad" => $notes, "rec_OwnerUGrpID" => $wg, "rec_NonOwnerVisibility" => $vis ? $vis : "viewable", "rec_FlagTemporary" => 0, "rec_Modified" => $now));
        updateRecordIndexEntry(DATABASE, $rectype, $recordID);
        // TODO: Doesn't properly update Elasticsearch
        if (mysql_error()) {
            errSaveRec("Database record update error - " . mysql_error());
            return $msgInfoSaveRec;
        }
    }
    // public recDetails data
    if ($details) {
        //		$log .= "- inserting details ";
        $dtlIDsByAction = doDetailInsertion($recordID, $details, $rectype, $wg, $nonces, $retitleRecs, $modeImport);
        if (@$dtlIDsByAction['error']) {
            array_push($msgInfoSaveRec['error'], $dtlIDsByAction['error']);
            return $msgInfoSaveRec;
        }
    }
    // check that all the required fields are present
    $res = mysql_query("select rst_ID, rst_DetailTypeID, rst_DisplayName" . " from defRecStructure" . " left join recDetails on dtl_RecID={$recordID} and rst_DetailTypeID=dtl_DetailTypeID" . " where rst_RecTypeID={$rectype} and rst_RequirementType='required' and dtl_ID is null");
    if (mysql_num_rows($res) > 0) {
        //		$log .= "- testing missing detatils ";
        $missed = "";
        while ($row = mysql_fetch_row($res)) {
            //ij asked to remove$conceptCode = getDetailTypeConceptID($row[1]);
            $missed = $missed . $row[2];
            //ij asked to remove ." (Code:".$conceptCode.") ";
        }
        // at least one missing field
        if ($missed) {
            $msg = "Missing data for Required field(s) in '{$rectypeName}'. You may need to make fields optional. Missing data: " . $missed;
            if ($modeImport == 2) {
                warnSaveRec($msg);
            } else {
                errSaveRec($msg);
                return $msgInfoSaveRec;
            }
        }
    }
    mysql_query("commit");
    // if we get to here we have a valid save of the core record.
    // calculate title, do an update
    //	$log .= "- filling titlemask ";
    $mask = mysql__select_array("defRecTypes", "rty_TitleMask", "rty_ID={$rectype}");
    $mask = $mask[0];
    $title = fill_title_mask($mask, $recordID, $rectype);
    if ($title) {
        mysql_query("update Records set rec_Title = '" . mysql_real_escape_string($title) . "' where rec_ID = {$recordID}");
    }
    // Update memcache: we can do this here since it's only the public data that we cache.
    updateCachedRecord($recordID);
    updateRecordIndexEntry(USERS_DATABASE, $rectype, $recordID);
    // private data
    $bkmk = @mysql_fetch_row(mysql_query("select bkm_ID from usrBookmarks where bkm_UGrpID=" . get_user_id() . " and bkm_recID=" . $recordID));
    $bkm_ID = @$bkmk[0];
    if ($personalised) {
        if (!$bkm_ID) {
            // Record is not yet bookmarked, but we want it to be
            mysql_query("insert into usrBookmarks (bkm_Added,bkm_Modified,bkm_UGrpID,bkm_recID) values (now(),now()," . get_user_id() . ",{$recordID})");
            if (mysql_error()) {
                warnSaveRec("trying to create a bookmark - database error - " . mysql_error());
            } else {
                $bkm_ID = mysql_insert_id();
            }
        }
        //		$log .= "- updating bookmark ";
        mysql__update("usrBookmarks", "bkm_ID={$bkm_ID}", array("bkm_Rating" => $rating, "bkm_Modified" => date('Y-m-d H:i:s')));
        //WARNING  tags is assumed to be a complete replacement list for personal tags on this record.
        doTagInsertion($recordID, $bkm_ID, $tags);
    } else {
        if ($bkm_ID) {
            // Record is bookmarked, but the user doesn't want it to be
            //		$log .= "- deleting bookmark ";
            $query = "delete usrBookmarks, usrRecTagLinks " . "from usrBookmarks left join usrRecTagLinks on rtl_RecID = bkm_recID " . "left join usrTags on tag_ID = rtl_TagID " . "where bkm_ID={$bkm_ID} and bkm_recID={$recordID} and bkm_UGrpID = tag_UGrpID and bkm_UGrpID=" . get_user_id();
            mysql_query($query);
            if (mysql_error()) {
                warnSaveRec("database error while removing bookmark- " . mysql_error());
            }
            //saw TODO: add code to remove other personal data reminders, personal notes (woots), etc.
        }
    }
    doWgTagInsertion($recordID, $wgTags);
    if ($notifyREMOVE || $notifyADD) {
        $notifyIDs = handleNotifications($recordID, $notifyREMOVE, $notifyADD);
    }
    if ($commentREMOVE || $commentMOD || $commentADD) {
        $commentIDs = handleComments($recordID, $commentREMOVE, $commentMOD, $commentADD);
    }
    $rval = array("bibID" => $recordID, "bkmkID" => $bkm_ID, "modified" => $now);
    if ($title) {
        $rval["title"] = $title;
    }
    if (@$dtlIDsByAction) {
        $rval["detail"] = $dtlIDsByAction;
    }
    if (@$notifyIDs) {
        $rval["notify"] = $notifyIDs;
    }
    if (@$commentIDs) {
        $rval["comment"] = $commentIDs;
    }
    if (@$msgInfoSaveRec['warning']) {
        $rval["warning"] = $msgInfoSaveRec['warning'];
    }
    if (@$msgInfoSaveRec['error']) {
        //should never get here with error set
        $rval["error"] = $msgInfoSaveRec['error'];
    } else {
        //$rval["usageCount"] =
        updateRecTypeUsageCount();
    }
    return $rval;
}
function do_fix_dupe()
{
    $master_rec_id = $_SESSION['master_rec_id'];
    $master_details = $_SESSION['master_details'];
    unset($_SESSION['master_details']);
    //clear master_details so we don't re-enter this code
    unset($_SESSION['master_rec_id']);
    $_SESSION['finished_merge'] = 1;
    // set state variable for next loop
    $dup_rec_ids = array();
    if (in_array($master_rec_id, explode(',', $_REQUEST['bib_ids']))) {
        $dup_rec_ids = array_diff(explode(',', $_REQUEST['bib_ids']), array($master_rec_id));
    }
    $dup_rec_list = '(' . join(',', $dup_rec_ids) . ')';
    $add_dt_ids = array();
    // array of detail ids to insert for the master record grouped by detail type is
    $update_dt_ids = array();
    // array of detail ids to get value for updating the master record
    $keep_dt_ids = array();
    // array of master record repeatable detail ids to keep grouped by detail type id- used to find master details to remove
    //parse form data
    foreach ($_REQUEST as $key => $value) {
        preg_match('/(add|update|keep)(\\d+)/', $key, $matches);
        if (!$matches) {
            continue;
        }
        switch (strtolower($matches[1])) {
            case 'add':
                $add_dt_ids[$matches[2]] = $value;
                break;
            case 'update':
                if ($value != "master") {
                    $update_dt_ids[$matches[2]] = $value;
                }
                break;
            case 'keep':
                $keep_dt_ids[$matches[2]] = $value;
                break;
        }
    }
    //   mysql_connection_overwrite("`heuristdb-nyirti`");   //for debug
    mysql_connection_overwrite(DATABASE);
    //    mysql_query('set @suppress_update_trigger:=1'); // shut off update triggers to let us munge the records with out worrying about the archive.
    // set modified on master so the changes will stick  aslo update url if there is one.
    $now = date('Y-m-d H:i:s');
    $pairs = @$_REQUEST['URL'] ? array("rec_URL" => $_REQUEST['URL'], "rec_Modified" => $now) : array("rec_Modified" => $now);
    mysql__update("Records", "rec_ID={$master_rec_id}", $pairs);
    //process keeps - which means find repeatables in master record to delete  all_details - keeps = deletes
    //get array of repeatable detail ids for master
    $master_rep_dt_ids = array();
    $res = mysql_query('select rst_DetailTypeID from defRecStructure where rst_MaxValues != 1 and rst_RecTypeID = ' . $_SESSION['rty_ID']);
    while ($row = mysql_fetch_array($res)) {
        array_push($master_rep_dt_ids, $row[0]);
    }
    $master_rep_detail_ids = array();
    foreach ($master_rep_dt_ids as $rep_dt_id) {
        if (array_key_exists($rep_dt_id, $master_details)) {
            foreach ($master_details[$rep_dt_id] as $detail) {
                array_push($master_rep_detail_ids, $detail['dtl_ID']);
            }
        }
    }
    //get flat array of keep detail ids
    if ($keep_dt_ids && count($keep_dt_ids)) {
        $master_keep_ids = array();
        foreach ($keep_dt_ids as $dt_id => $details) {
            foreach ($details as $detail) {
                array_push($master_keep_ids, $detail);
            }
        }
    }
    //diff the arrays  don't delet yet as the user might be adding an existing value
    $master_delete_dt_ids = array();
    if ($master_rep_detail_ids) {
        $master_delete_dt_ids = array_diff($master_rep_detail_ids, $master_keep_ids);
    }
    //ART HERE   $master_keep_ids
    //FIXME add code to remove any none repeatable extra details
    //for each update
    if ($update_dt_ids) {
        $update_detail = array();
        foreach ($update_dt_ids as $rdt_id => $rd_id) {
            //look up data for detail and
            $update_detail = mysql_fetch_assoc(mysql_query('select * from recDetails where dtl_ID=' . $rd_id));
            // if exist in master details  update val
            if (in_array($rdt_id, array_keys($master_details))) {
                mysql__update("recDetails", "dtl_ID=" . $master_details[$rdt_id][0]['dtl_ID'], array("dtl_Value" => $update_detail['dtl_Value']));
                // else  insert the data as detail for master record
            } else {
                unset($update_detail['dtl_ID']);
                //get rid of the detail id the insert will create a new one.
                $update_detail['dtl_RecID'] = $master_rec_id;
                // set this as a detail of the master record
                mysql__insert('recDetails', $update_detail);
            }
        }
    }
    //process adds
    if ($add_dt_ids) {
        $add_details = array();
        // for each add detail
        foreach ($add_dt_ids as $key => $detail_ids) {
            foreach ($detail_ids as $detail_id) {
                // since adds are only for repeatables check if it exist in delete array ?yes - remove from delete list if there
                if ($key_remove = array_search($detail_id, $master_delete_dt_ids) !== FALSE) {
                    //FIXME need to compare teh value not the dtl_ID (they will always be diff)
                    //remove from array
                    unset($master_delete_dt_ids[$key_remove]);
                } else {
                    //no  then lookup data for detail and insert the data as detail under the master rec id
                    $add_detail = mysql_fetch_assoc(mysql_query('select * from recDetails where dtl_ID=' . $detail_id));
                    unset($add_detail['dtl_ID']);
                    //the id is auto set during insert
                    $add_detail['dtl_RecID'] = $master_rec_id;
                    mysql__insert('recDetails', $add_detail);
                }
            }
        }
    }
    foreach ($dup_rec_ids as $dup_rec_id) {
        //saw FIXME we should be updating the chain of links
        mysql_query('insert into recForwarding (rfw_OldRecID, rfw_NewRecID) values (' . $dup_rec_id . ', ' . $master_rec_id . ')');
        //saw FIXME  we should update the relationship table on both rr_rec_idxxx  fields
    }
    // move dup bookmarks and tags to master unless they are already there
    //get bookmarkid =>userid for bookmarks of master record
    $master_bkm_UGrpIDs = mysql__select_assoc('usrBookmarks', 'bkm_ID', 'bkm_UGrpID', 'bkm_recID = ' . $master_rec_id);
    //get kwd_ids for  all bookmarks of master record
    $master_tag_ids = mysql__select_array('usrRecTagLinks', 'rtl_TagID', 'rtl_RecID = ' . $master_rec_id);
    //get bookmarkid => userid of bookmarks for dup records
    $dup_bkm_UGrpIDs = mysql__select_assoc('usrBookmarks', 'bkm_ID', 'bkm_UGrpID', 'bkm_recID in' . $dup_rec_list);
    // if dup userid already has a bookmark on master record then add dup bkm_ID to delete_bkm_IDs_list else add to  update_bkm_IDs
    $update_bkm_IDs = array();
    $delete_bkm_IDs = array();
    $dup_delete_bkm_ID_to_master_bkm_id = array();
    //for every user or group that bookmarks a dup record if it already bookmarks the master then mark it for deletion
    // otherwise mark it for update to point to the master record
    foreach ($dup_bkm_UGrpIDs as $dup_bkm_ID => $dup_bkm_UGrpID) {
        if (count(@$master_bkm_UGrpIDs) && ($matching_master_bkm_ID = array_search($dup_bkm_UGrpID, $master_bkm_UGrpIDs))) {
            array_push($delete_bkm_IDs, $dup_bkm_ID);
            $dup_delete_bkm_ID_to_master_bkm_id[$dup_bkm_ID] = $matching_master_bkm_ID;
        } else {
            array_push($update_bkm_IDs, $dup_bkm_ID);
            $master_bkm_UGrpIDs[$dup_bkm_ID] = $dup_bkm_UGrpID;
        }
    }
    //move duplicate record bookmarks for users without bookmarks on the master record
    $update_bkm_IDs_list = '(' . join(',', $update_bkm_IDs) . ")";
    $delete_bkm_IDs_list = '(' . join(',', $delete_bkm_IDs) . ")";
    if (strlen($update_bkm_IDs_list) > 2) {
        // update the bookmarks and tags that are not in the master
        mysql_query('update usrBookmarks set bkm_recID=' . $master_rec_id . ' where bkm_ID in ' . $update_bkm_IDs_list);
        //        mysql_query('update usrRecTagLinks set rtl_RecID='.$master_rec_id.' where kwl_pers_id in '.$update_bkm_IDs_list);
    }
    // process to be deleted dup bookmarks
    foreach ($delete_bkm_IDs as $delete_dup_bkm_ID) {
        //copy soon to be deleted dup bookmark data to master record bookmark  by concat notes and pwd_reminder, max of ratings and copy zotero if non existant
        $master_bkm_ID = @$dup_delete_bkm_ID_to_master_bkm_id[$delete_dup_bkm_ID];
        $res1 = mysql_query('select * from usrBookmarks where bkm_ID=' . $master_bkm_ID);
        $res2 = mysql_query('select * from usrBookmarks where bkm_ID=' . $delete_dup_bkm_ID);
        if (!($res1 && $res2)) {
            continue;
        }
        $master_pers_record = mysql_fetch_assoc($res1);
        $delete_dup_pers_record = mysql_fetch_assoc($res2);
        //        $master_pers_record['pers_notes'] .= $delete_dup_pers_record['pers_notes'];
        $master_pers_record['bkm_PwdReminder'] .= "; " . $delete_dup_pers_record['bkm_PwdReminder'];
        $master_pers_record['bkm_Rating'] = max($master_pers_record['bkm_Rating'], $delete_dup_pers_record['bkm_Rating']);
        if (!$master_pers_record['bkm_ZoteroID']) {
            $master_pers_record['bkm_ZoteroID'] = $delete_dup_pers_record['bkm_ZoteroID'];
        }
        unset($master_pers_record['bkm_ID']);
        mysql__update('usrBookmarks', 'bkm_ID=' . $master_bkm_ID, $master_pers_record);
    }
    //for every delete dup tag link whoses tag id is not already linked to the master record change the record id to master
    //get tag links for the soon to be deleted dup records
    $delete_dup_rtl_ids = mysql__select_assoc('usrRecTagLinks', 'rtl_ID', 'rtl_TagID', 'rtl_RecID in' . $dup_rec_list);
    foreach ($delete_dup_rtl_ids as $rtl_ID => $tag_id) {
        if (count($master_tag_ids) && array_search($tag_id, $master_tag_ids)) {
            //if it's already linked to the master delete it
            mysql_query('delete from usrRecTagLinks where rtl_ID = ' . $rtl_ID);
            //FIXME add error code
        } else {
            // otherwise point it to the master record
            mysql_query('update usrRecTagLinks set rtl_RecID=' . $master_rec_id . ', where rtl_ID = ' . $rtl_ID);
            array_push($master_tag_ids, $tag_id);
            // add to the array of tagids already on the master record
        }
    }
    // move reminders to master
    mysql_query('update usrReminders set rem_RecID=' . $master_rec_id . ' where rem_RecID in ' . $dup_rec_list);
    //?FIXME  do we need to check reminders like we checked usrBookmarks
    //delete master details
    if ($master_delete_dt_ids && count($master_delete_dt_ids)) {
        $master_detail_delete_list = '(' . join(',', $master_delete_dt_ids) . ')';
        mysql_query('delete from recDetails where dtl_ID in ' . $master_detail_delete_list);
        //FIXME add error code
    }
    //delete dup details
    mysql_query('delete from recDetails where dtl_RecID in ' . $dup_rec_list);
    //delete dup usrBookmarks
    if (strlen($delete_bkm_IDs_list) > 2) {
        mysql_query('delete from usrBookmarks where bkm_ID in ' . $delete_bkm_IDs_list);
    }
    // move dup record pointers to master record
    mysql_query('update recDetails left join defDetailTypes on dty_ID=dtl_DetailTypeID set dtl_Value=' . $master_rec_id . ' where dtl_Value in ' . $dup_rec_list . ' and dty_Type="resource"');
    //delete dups
    mysql_query('delete from Records where rec_ID in ' . $dup_rec_list);
    //delete unwanted details in master
    //if ($master_delete_dt_ids && $master_delete_dt_ids[0]){
    //    $master_delete_dt_ids_list = '('.join(',',$master_delete_dt_ids). ')' ;
    //    mysql_query('delete from recDetails where dtl_ID in '.$master_delete_dt_ids_list);
    // }
    //try to get the record to update title and hash
    // calculate title, do an update
    $type = $_SESSION['rty_ID'];
    $mask = mysql__select_array("defRecTypes", "rty_TitleMask", "rty_ID=" . $type);
    if ($mask && count($mask) > 0) {
        $mask = $mask[0];
        $title = fill_title_mask($mask, $master_rec_id, $type);
        if ($title) {
            mysql_query("update Records set rec_Title = '" . mysql_real_escape_string($title) . "' where rec_ID = {$master_rec_id}");
        }
    }
    mysql_query('update Records set rec_Hash = hhash(rec_ID) where rec_ID=' . $master_rec_id);
    header('Location: combineDuplicateRecords.php?db=' . HEURIST_DBNAME . '&bib_ids=' . $_REQUEST['bib_ids']);
}
 function getTitle()
 {
     // Construct/retrieve the formatted title for this entry,
     // based on the reference type's title mask.
     global $heurist_rectypes;
     if (!$heurist_rectypes) {
         load_heurist_rectypes();
     }
     if (!$this->getBiblioID()) {
         return "";
     }
     if ($this->_title) {
         return $this->_title;
     }
     $mask = $heurist_rectypes[$this->_rectype]['rty_TitleMask'];
     $this->_title = fill_title_mask($mask, $this->getBiblioID(), $this->getReferenceType());
     return $this->_title;
     // fin     FIXME  the code below never executes, looks old and refactored into TitleMask.php ?remove?
     global $heurist_rectypes, $bib_type_names;
     if (!$heurist_rectypes) {
         load_heurist_rectypes();
     }
     if (!$bib_type_names) {
         load_bib_type_names();
     }
     $mask = $heurist_rectypes[$this->_rectype]['rty_TitleMask'];
     if (!$mask) {
         return '';
     }
     if (!preg_match_all('/\\[\\[|\\]\\]|(\\s*(\\[\\s*([^]]+)\\s*\\]))/s', $mask, $matches)) {
         return $this->_title = $mask;
     }
     // nothing to do -- no substitutions
     $replacements = array();
     for ($i = 0; $i < count($matches[1]); ++$i) {
         /*
          * $matches[3][$i] contains the field name as supplied (the string that we look up),
          * $matches[2][$i] contains the field plus surrounding whitespace and containing brackets
          *        (this is what we replace if there is a substitution)
          * $matches[1][$i] contains the field plus surrounding whitespace and containing brackets and LEADING WHITESPACE
          *        (this is what we replace with an empty string if there is no substitution value available)
          */
         $value = $this->get_field_value($matches[3][$i]);
         if ($value) {
             $replacements[$matches[2][$i]] = $value;
         } else {
             $replacements[$matches[1][$i]] = '';
         }
     }
     $replacements['magic-open-bracket'] = '[';
     $replacements['magic-close-bracket'] = ']';
     $title = array_str_replace(array_keys($replacements), array_values($replacements), $mask);
     $title = preg_replace('!^[-:;,./\\s]*(.*?)[-:;,/\\s]*$!s', '\\1', $title);
     $title = preg_replace('!\\([-:;,./\\s]+\\)!s', '', $title);
     $title = preg_replace('!\\([-:;,./\\s]*(.*?)[-:;,./\\s]*\\)!s', '(\\1)', $title);
     $title = preg_replace('!\\([-:;,./\\s]*\\)|\\[[-:;,./\\s]*\\]!s', '', $title);
     $title = preg_replace('!,,+!s', ',', $title);
     $title = preg_replace('!\\s+,!s', ',', $title);
     $title = preg_replace('!  +!s', ' ', $title);
     /* Clean up miscellaneous stray punctuation &c. */
     return $this->_title = trim($title);
 }
function checkRectypeMask($rtID, $rtName, $mask, $coMask, $recID, $mode)
{
    global $mode;
    if (!@$mask && @$rtID) {
        $mask = mysql__select_array("defRecTypes", "rty_TitleMask", "rty_ID={$rtID}");
        $mask = $mask[0];
    }
    if ($mode > 0 || !$recID) {
        echo "<h3><b> {$rtID} : <i>{$rtName}</i></b> <br/> </h3>";
        if ($mask == null || trim($mask) == "") {
            $res = array();
            $res[0] = "Title mask is not defined";
        } else {
            $res = titlemask_make($mask, $rtID, 2, null, _ERR_REP_MSG);
            //get human readable
        }
        echo "<div class='resultsRow'><div class='statusCell " . (is_array($res) ? "invalid'>in" : "valid'>") . "valid</div>";
        echo "<div class='maskCell'>Mask: <i>{$mask}</i></div>";
        if (is_array($res)) {
            echo "<div class='errorCell'><b>< < < < < " . $res[0] . "</b></div>";
        } else {
            if ($mask == "") {
                echo "<div class='errorCell'><b>< < < < < EMPTY TITLE MASK</b></div>";
            } else {
                if (strcasecmp($res, $mask) != 0) {
                    echo "<div><br/>&nbsp;Decoded Mask: {$res}</div>";
                }
            }
        }
        echo "</div>";
        echo "\n";
    } else {
        echo "checking title mask {$mask} for record type {$rtID} and record {$recID} <br/>";
        echo fill_title_mask($mask, $recID, $rtID);
    }
}