Пример #1
0
 /**
  * Return HTML for displaying search results
  * @return string HTML
  */
 public function getCompareResults()
 {
     global $wgUser;
     $this->setMergeTargets();
     list($compareData, $compareChildren, $maxChildren) = $this->readCompareData();
     $dataLabels = $this->getDataLabels();
     list($compareClass, $husbandScores, $wifeScores, $totalScores) = $this->scoreCompareData($dataLabels, $compareData);
     $output = '';
     $semiProtected = false;
     $isLoggedIn = $wgUser->isLoggedIn();
     if (!$isLoggedIn) {
         $output .= '<p><font color=red>You need to sign in to match and merge pages</font></p>';
     }
     $gedcomExtra = $this->gedcomDataString ? '?gedcomtab=' . htmlspecialchars($this->gedcomTab) . '&gedcomkey=' . htmlspecialchars($this->gedcomKey) : '';
     $output .= "<form id=\"compare\" name=\"compare\" action=\"/wiki/Special:Merge{$gedcomExtra}\" method=\"post\">" . "<input type=\"hidden\" id=\"ns\" name=\"ns\" value=\"{$this->namespace}\">" . "<input type=\"hidden\" id=\"maxpages\" name=\"maxpages\" value=\"" . count($this->compareTitles) . "\">" . ($this->namespace == 'Family' ? "<input id=\"maxchildren\" type=\"hidden\" name=\"maxchildren\" value=\"{$maxChildren}\">" : '') . '<table border="0" cellspacing="0" cellpadding="4">';
     foreach ($dataLabels as $label) {
         $labelClass = CompareForm::getLabelClass($label);
         if ($labelClass == self::$COMPARE_ULC_CLASS) {
             $output .= CompareForm::insertEmptyRow(count($this->compareTitles) + 1);
         }
         $found = !in_array($label, self::$OPTIONAL_LABELS);
         if (!$found) {
             foreach ($this->compareTitles as $t) {
                 if (is_array(@$compareData[$t][$label]) && count($compareData[$t][$label]) > 0) {
                     $found = true;
                     break;
                 }
             }
         }
         if ($found) {
             $output .= "<tr><td class=\"{$labelClass}\">" . CompareForm::formatLabel($label) . "</td>";
             // show target left if gedcom; right otherwise
             $i = $this->gedcomDataString ? 0 : count($this->compareTitles) - 1;
             while ($this->gedcomDataString && $i < count($this->compareTitles) || !$this->gedcomDataString && $i >= 0) {
                 $t = $this->compareTitles[$i];
                 $class = $compareClass[$label][$i];
                 $output .= "<td class=\"{$class}\">";
                 $first = true;
                 if (is_array(@$compareData[$t][$label])) {
                     foreach ($compareData[$t][$label] as $value) {
                         if (!$first) {
                             $output .= '<br>';
                         }
                         $output .= CompareForm::formatValue($label, $value);
                         $first = false;
                     }
                 }
                 if ($first) {
                     $output .= '&nbsp;';
                 }
                 if ($class == self::$COMPARE_PAGE_CLASS) {
                     $titlesCnt = count(@$compareData[$t][$label]);
                     $baseTitlesCnt = count(@$compareData[$this->compareTitles[0]][$label]);
                     if ($titlesCnt > 0) {
                         $value = htmlspecialchars($compareData[$t][$label][0]);
                         if ($label == 'husbandTitle') {
                             $relative = 'husband';
                             $relativeAbbrev = 'h';
                             $score = $husbandScores[$i];
                         } else {
                             if ($label == 'wifeTitle') {
                                 $relative = 'wife';
                                 $relativeAbbrev = 'w';
                                 $score = $wifeScores[$i];
                             } else {
                                 $relative = '';
                                 $relativeAbbrev = '';
                                 $score = 0;
                             }
                         }
                         if (!$compareData[$t]['Exists']) {
                             // base person/family not found
                             if (!$relative) {
                                 $output .= '<br>Not found';
                             }
                         } else {
                             if ($compareData[$t]['Redirect']) {
                                 // base person/family has been merged
                                 if (!$relative) {
                                     $output .= '<br>Already merged';
                                 }
                             } else {
                                 if ($compareData[$t][$relative . 'Redirect']) {
                                     // husband/wife has been merged
                                     $output .= '<br>Already merged';
                                 } else {
                                     if ($i == 0 && $this->gedcomDataString) {
                                         if (@$compareData[$t][$relative . 'GedcomMatchTitle']) {
                                             $skin =& $wgUser->getSkin();
                                             $gedcomMatchTitle = $compareData[$t][$relative . 'GedcomMatchTitle'];
                                             $temp = Title::newFromText($gedcomMatchTitle, StructuredData::endsWith($label, 'familyTitle', true) ? NS_FAMILY : NS_PERSON);
                                             $title = $skin->makeLinkObj($temp, htmlspecialchars($gedcomMatchTitle));
                                             $output .= "<br>Matched with {$title}";
                                         }
                                         $output .= "<input type=\"hidden\" id=\"m{$relativeAbbrev}_{$i}\" name=\"m{$relativeAbbrev}_{$i}\" value=\"{$value}\">";
                                     } else {
                                         if ($titlesCnt == 1 && $baseTitlesCnt <= 1) {
                                             //								if ($i == 0 || $baseTitlesCnt == 0 || $compareData[$this->compareTitles[0]][$label][0] != $compareData[$t][$label][0]) { // don't allow merge if same title
                                             if ($i == 0) {
                                                 $extra = " checked";
                                             } else {
                                                 if ($relative) {
                                                     // always check spouses
                                                     $extra = 'disabled checked';
                                                     //if ($score > self::$SPOUSE_MATCH_THRESHOLD) $extra .= ' checked';
                                                 } else {
                                                     $extra = '';
                                                 }
                                             }
                                             if ($this->namespace == 'Family' && !$relative) {
                                                 $extra .= " onClick=\"compareClick({$i})\"";
                                             }
                                             $output .= "<br><input id=\"m{$relativeAbbrev}_{$i}\" type=\"checkbox\" name=\"m{$relativeAbbrev}_{$i}\" value=\"{$value}\" {$extra}>&nbsp;Match";
                                             //								}
                                         } else {
                                             $output .= "<br>Multiple spouses - merge after merging family";
                                         }
                                     }
                                 }
                             }
                         }
                         $nomergeTitles = $this->getNomergeTitleMatches($compareData, $t, -1, $relative, '<br>');
                         if ($nomergeTitles) {
                             $output .= '<br><b>Do not merge with</b><br>' . $nomergeTitles;
                         }
                         if ((!$this->gedcomDataString || $i > 0) && !$compareData[$t][$relative . 'Updatable']) {
                             $output .= "<br><font color=\"red\">Semi-protected</font> (see below)";
                             $semiProtected = true;
                         }
                     }
                 }
                 $output .= '</td>';
                 $i += $this->gedcomDataString ? 1 : -1;
             }
             $output .= '</tr>';
         }
     }
     if ($this->namespace == 'Family') {
         for ($c = 0; $c < $maxChildren; $c++) {
             foreach (CompareForm::$CHILD_COMPARE_LABELS as $label) {
                 $labelClass = CompareForm::getLabelClass($label);
                 if ($labelClass == self::$COMPARE_ULC_CLASS) {
                     $output .= CompareForm::insertEmptyRow(count($this->compareTitles) + 1);
                 }
                 $found = !in_array($label, self::$OPTIONAL_LABELS);
                 if (!$found) {
                     foreach ($this->compareTitles as $t) {
                         if (is_array(@$compareChildren[$t][$c][$label]) && count($compareChildren[$t][$c][$label]) > 0) {
                             $found = true;
                             break;
                         }
                     }
                 }
                 if ($found) {
                     $output .= "<tr><td class=\"{$labelClass}\">" . CompareForm::formatLabel($label, $c + 1) . "</td>";
                     $baseStdValues =& CompareForm::standardizeValues($label, @$compareChildren[$this->compareTitles[0]][$c][$label]);
                     $i = $this->gedcomDataString ? 0 : count($this->compareTitles) - 1;
                     while ($this->gedcomDataString && $i < count($this->compareTitles) || !$this->gedcomDataString && $i >= 0) {
                         $t = $this->compareTitles[$i];
                         if ($i == 0) {
                             $stdValues = $baseStdValues;
                         } else {
                             $stdValues =& CompareForm::standardizeValues($label, @$compareChildren[$t][$c][$label]);
                         }
                         list($score, $class) = CompareForm::getCompareScoreClass($i == 0, $label, $baseStdValues, $stdValues);
                         $output .= "<td class=\"{$class}\">";
                         $children =& $compareChildren[$t];
                         $first = true;
                         if (count($children) > $c) {
                             if (is_array(@$children[$c][$label])) {
                                 foreach ($children[$c][$label] as $value) {
                                     if (!$first) {
                                         $output .= '<br>';
                                     }
                                     $output .= CompareForm::formatValue($label, $value);
                                     $first = false;
                                 }
                             }
                         }
                         if ($first) {
                             $output .= '&nbsp;';
                         }
                         if ($class == self::$COMPARE_PAGE_CLASS) {
                             if (count(@$compareChildren[$t][$c][$label]) == 1) {
                                 $value = htmlspecialchars($compareChildren[$t][$c][$label][0]);
                                 $output .= "<input type=\"hidden\" id=\"mc_{$i}_{$c}\" name=\"mc_{$i}_{$c}\" value=\"{$value}\">";
                                 if ($compareData[$t]['Redirect']) {
                                     // family has already been merged
                                 } else {
                                     if ($compareChildren[$t][$c]['childRedirect']) {
                                         // child has already been merged
                                         $output .= '<br>Already merged';
                                     } else {
                                         if ($i == 0 && $this->gedcomDataString) {
                                             if (@$compareChildren[$t][$c]['childGedcomMatchTitle']) {
                                                 $skin =& $wgUser->getSkin();
                                                 $gedcomMatchTitle = $compareChildren[$t][$c]['childGedcomMatchTitle'];
                                                 $temp = Title::newFromText($gedcomMatchTitle, StructuredData::endsWith($label, 'familyTitle', true) ? NS_FAMILY : NS_PERSON);
                                                 $title = $skin->makeLinkObj($temp, htmlspecialchars($gedcomMatchTitle));
                                                 $output .= "<br>Matched with {$title}";
                                             }
                                             $c1 = $c + 1;
                                             $output .= "<input type=\"hidden\" id=\"mcr_0_{$c}\" name=\"mcr_0_{$c}\" value=\"{$c1}\">";
                                         } else {
                                             //									else if (@$compareChildren[$this->compareTitles[0]][$c][$label][0] != $compareChildren[$t][$c][$label][0]) { // don't allow merge if same title
                                             //										$mergeChild = (count(@$compareChildren[$this->compareTitles[0]][$c][$label]) == 1 ? $c+1 : 0);
                                             $mergeChild = $c + 1;
                                             $extra = $i == 0 ? '' : 'disabled';
                                             $mergeChildSelectOptions = $this->getMergeChildSelectOptions($c, $maxChildren);
                                             $output .= '<br>' . StructuredData::addSelectToHtml(0, "mcr_{$i}_{$c}", $mergeChildSelectOptions, $mergeChild, $extra, false);
                                         }
                                     }
                                 }
                                 $nomergeTitles = $this->getNomergeTitleMatches($compareChildren, $t, $c, 'child', '<br>');
                                 if ($nomergeTitles) {
                                     $output .= '<br><b>Do not merge with</b><br>' . $nomergeTitles;
                                 }
                                 if ((!$this->gedcomDataString || $i > 0) && !$compareChildren[$t][$c]['childUpdatable']) {
                                     $output .= "<br><font color=\"red\">Semi-protected</font> (see below)";
                                     $semiProtected = true;
                                 }
                             }
                         }
                         $output .= '</td>';
                         $i += $this->gedcomDataString ? 1 : -1;
                     }
                     $output .= '</tr>';
                 }
             }
         }
     }
     if ($this->gedcomDataString) {
         $mergeLabel = 'Prepare to update';
         $mergeFunction = 'doGedcomPrepareToMerge()';
         $notMatchFunction = 'doGedcomNotMatch()';
         $notMatchTitle = 'GEDCOM family does not match any of the families shown';
     } else {
         $mergeLabel = 'Prepare to merge';
         $mergeFunction = 'doPrepareToMerge()';
         $notMatchFunction = 'doNotMatch()';
         $notMatchTitle = 'Notify others not to merge the selected ' . ($this->namespace == 'Family' ? 'families' : 'people');
     }
     $mergeTitle = 'Prepare to combine the selected ' . ($this->namespace == 'Family' ? 'families' : 'people');
     $output .= '<tr><td align=right colspan="' . (count($this->compareTitles) + 1) . '"><input type="hidden" name="formAction">' . ($this->gedcomDataString ? '<input type="button" title="Match people in your GEDCOM to people in the selected family" value="Match" onClick="doGedcomMatch()"/> &nbsp; ' : '') . ($this->gedcomDataString ? '' : "<input type=\"button\" title=\"{$mergeTitle}\" value=\"{$mergeLabel}\" onClick=\"{$mergeFunction}\"/> &nbsp; ") . "<input type=\"button\" title=\"{$notMatchTitle}\" value=\"Not a match\" onClick=\"{$notMatchFunction}\"/>";
     '</td></tr></table></form>';
     if ($semiProtected) {
         $output .= CompareForm::getSemiprotectedMessage(CompareForm::isTrustedMerger($wgUser, $this->gedcomDataString));
     }
     return $output;
 }
Пример #2
0
 public function doMerge()
 {
     global $wgOut, $wgUser;
     $skin =& $wgUser->getSkin();
     if ($this->isGedcom()) {
         $editFlags = EDIT_UPDATE;
         $mergeText = 'updated';
     } else {
         // create a mergelog record
         $mergeScore = $this->getMergeScore();
         $isTrustedUser = CompareForm::isTrustedMerger($wgUser, false);
         $isTrustedMerge = MergeForm::isTrustedMerge($mergeScore, $isTrustedUser);
         $mergeLogId = $this->logMerge($mergeScore, $isTrustedMerge);
         wfDebug("MERGESCORE mergeLogId={$mergeLogId} total score={$mergeScore}\n");
         if (!$isTrustedUser && $mergeScore < self::$LOW_MATCH_THRESHOLD) {
             error_log("WARNING suspect merge: id={$mergeLogId} user={$wgUser->getName()} score={$mergeScore}");
         }
         $editFlags = EDIT_UPDATE | EDIT_FORCE_BOT;
         $mergeText = 'merged';
     }
     // get merging people and families
     // add merging people and families to blacklist so propagation doesn't also try to update them
     $mergingPeople = array();
     $mergingFamilies = array();
     for ($m = 0; $m < count($this->data); $m++) {
         for ($p = 0; $p < count($this->data[$m]); $p++) {
             $titleString = $this->data[$m][$p]['title'];
             if ($this->namespace == 'Family' && $m == 0) {
                 if ($p > 0) {
                     $mergingFamilies[$titleString] = $this->data[$m][0]['title'];
                 }
                 $ns = NS_FAMILY;
             } else {
                 if ($p > 0) {
                     $mergingPeople[$titleString] = $this->data[$m][0]['title'];
                 }
                 $ns = NS_PERSON;
             }
             if (!GedcomUtil::isGedcomTitle($titleString)) {
                 $title = Title::newFromText($titleString, $ns);
                 PropagationManager::addBlacklistPage($title);
             }
         }
     }
     $output = "<H2>Pages {$mergeText} successfully</H2>";
     $output .= $this->getWarnings();
     $output .= '<ul>';
     $outputRows = array();
     $emptyRequest = new FauxRequest(array(), true);
     $mergeCmtSuffix = $this->isGedcom() ? '' : " - [[Special:ReviewMerge/{$mergeLogId}|review/undo]]";
     if ($this->namespace == 'Family' && !$this->isGedcom()) {
         $t = Title::newFromText($this->data[0][0]['title'], NS_FAMILY);
         $mergeCmtFamily = $this->namespace == 'Family' ? " in merge of [[{$t->getPrefixedText()}]]" : '';
     } else {
         $mergeCmtFamily = '';
     }
     // backwards, because you must merge family last, so that propagated person data in family xml is correct
     // and so that mergeCmtFamily can be cleared at the end and mergeSummary and mergeTargetTitle are correct after the for loop
     for ($m = count($this->data) - 1; $m >= 0; $m--) {
         $requestData = array();
         $contents = '';
         $talkContents = '';
         $outputRow = '';
         $mainOutput = '';
         $talkOutput = '';
         $nameCount = $eventCount = $sourceCount = $imageCount = $noteCount = $husbandCount = $wifeCount = $childrenCount = $parentFamilyCount = $spouseFamilyCount = 0;
         $primaryNameFound = $primaryImageFound = $birthFound = $christeningFound = $deathFound = $burialFound = $marriageFound = false;
         if ($this->namespace == 'Family' && $m == 0) {
             $mergeTargetNs = NS_FAMILY;
             $mergeTargetTalkNs = NS_FAMILY_TALK;
             $mergeCmtFamily = '';
         } else {
             $mergeTargetNs = NS_PERSON;
             $mergeTargetTalkNs = NS_PERSON_TALK;
         }
         $mergeTargetTitle = Title::newFromText($this->data[$m][0]['title'], $mergeTargetNs);
         if ($mergeTargetTitle->getNamespace() != $mergeTargetNs) {
             error_log("Merge glitch:{$mergeTargetNs}:{$this->data[$m][0]['title']}:{$mergeTargetTitle->getNamespace()}:");
         }
         $mergeTargetTalkTitle = Title::newFromText($this->data[$m][0]['title'], $mergeTargetTalkNs);
         $mergeSummary = '';
         $talkMergeSummary = '';
         $keepKeys = $this->generateKeepKeys($this->data[$m], $this->add[$m], $this->key[$m]);
         $notesMap = array();
         $noteAdoptions = array();
         $this->generateMapAdoptions('notes', 'N', $mergeTargetNs, $this->data[$m], $this->add[$m], $this->key[$m], $keepKeys, $notesMap, $noteAdoptions);
         $sourcesMap = array();
         $sourceAdoptions = array();
         $this->generateMapAdoptions('sources', 'S', $mergeTargetNs, $this->data[$m], $this->add[$m], $this->key[$m], $keepKeys, $sourcesMap, $sourceAdoptions);
         $imagesMap = array();
         $imageAdoptions = array();
         $this->generateMapAdoptions('images', 'I', $mergeTargetNs, $this->data[$m], $this->add[$m], $this->key[$m], $keepKeys, $imagesMap, $imageAdoptions);
         // get request data for merge target
         for ($p = 0; $p < count($this->data[$m]); $p++) {
             if ($this->isMergeable($this->data[$m][$p])) {
                 $this->addNotesToRequestData($requestData, $keepKeys[$p], $noteCount, $notesMap[$p], $this->data[$m][$p]['notes']);
                 $this->addImagesToRequestData($requestData, $keepKeys[$p], $imageCount, $imagesMap[$p], $primaryImageFound, $this->data[$m][$p]['images']);
                 $this->addSourcesToRequestData($requestData, $keepKeys[$p], $sourceCount, $sourcesMap[$p], $notesMap[$p], $imagesMap[$p], $this->data[$m][$p]['sources'], $noteAdoptions, $imageAdoptions);
                 $this->addEventsToRequestData($requestData, $keepKeys[$p], $eventCount, $mergeTargetNs == NS_PERSON ? Person::$STD_EVENT_TYPES : Family::$STD_EVENT_TYPES, $birthFound, $christeningFound, $deathFound, $burialFound, $marriageFound, $notesMap[$p], $imagesMap[$p], $sourcesMap[$p], $this->data[$m][$p]['events'], $noteAdoptions, $sourceAdoptions, $imageAdoptions);
                 if ($mergeTargetNs == NS_PERSON) {
                     $this->addNamesToRequestData($requestData, $keepKeys[$p], $nameCount, $primaryNameFound, $notesMap[$p], $sourcesMap[$p], $this->data[$m][$p]['names'], $noteAdoptions, $sourceAdoptions);
                     $this->addFamilyToRequestData($requestData, $mergingFamilies, 'child_of_family', $parentFamilyCount, $this->data[$m][$p]['child_of_families']);
                     $this->addFamilyToRequestData($requestData, $mergingFamilies, 'spouse_of_family', $spouseFamilyCount, $this->data[$m][$p]['spouse_of_families']);
                 } else {
                     $this->addFamilyMembersToRequestData($requestData, $mergingPeople, 'husband', $husbandCount, $this->data[$m][$p]['husbands']);
                     $this->addFamilyMembersToRequestData($requestData, $mergingPeople, 'wife', $wifeCount, $this->data[$m][$p]['wives']);
                     $this->addFamilyMembersToRequestData($requestData, $mergingPeople, 'child', $childrenCount, $this->data[$m][$p]['children']);
                 }
                 $pageContents = $this->mapContents($sourcesMap[$p], $imagesMap[$p], $notesMap[$p], $this->data[$m][$p]['contents']);
                 $this->addContents($contents, $keepKeys[$p], $pageContents);
                 if ($p > 0) {
                     if ($mergeSummary) {
                         $mergeSummary .= ', ';
                     }
                     if ($mainOutput) {
                         $mainOutput .= ', ';
                     }
                     if ($this->data[$m][$p]['gedcom']) {
                         $mergeSummary .= 'gedcom';
                         $mainOutput .= htmlspecialchars(($mergeTargetNs == NS_FAMILY ? 'Family:' : 'Person:') . $this->data[$m][$p]['title']);
                     } else {
                         $title = Title::newFromText($this->data[$m][$p]['title'], $mergeTargetNs);
                         $mergeSummary .= "[[" . $title->getPrefixedText() . "]]";
                         $mainOutput .= $skin->makeKnownLinkObj($title, htmlspecialchars($title->getPrefixedText()), 'redirect=no');
                     }
                 }
             }
         }
         // redirect other pages to merge target
         $redir = "#REDIRECT [[" . $mergeTargetTitle->getPrefixedText() . "]]";
         $talkRedir = "#REDIRECT [[" . $mergeTargetTalkTitle->getPrefixedText() . "]]";
         for ($p = 1; $p < count($this->data[$m]); $p++) {
             if (!$this->data[$m][$p]['gedcom']) {
                 $obj = $this->data[$m][$p]['object'];
                 $comment = $this->makeComment($this->userComment, "merge into [[" . $mergeTargetTitle->getPrefixedText() . "]]" . $mergeCmtFamily, $mergeCmtSuffix);
                 $obj->editPage($emptyRequest, $redir, $comment, $editFlags, false);
                 // redir talk page as well
                 if ($this->data[$m][$p]['talkrevid']) {
                     // if talk page exists
                     $talkTitle = Title::newFromText($this->data[$m][$p]['title'], $mergeTargetTalkNs);
                     $article = new Article($talkTitle, 0);
                     if ($article) {
                         $this->addTalkContents($talkContents, $talkTitle, $article->fetchContent());
                         if ($talkMergeSummary) {
                             $talkMergeSummary .= ', ';
                         }
                         if ($talkOutput) {
                             $talkOutput .= ', ';
                         }
                         $talkMergeSummary .= "[[" . $talkTitle->getPrefixedText() . "]]";
                         $talkOutput .= $skin->makeKnownLinkObj($talkTitle, htmlspecialchars($talkTitle->getPrefixedText()), 'redirect=no');
                         $comment = $this->makeComment($this->userComment, "merge into [[" . $mergeTargetTalkTitle->getPrefixedText() . "]]" . $mergeCmtFamily, $mergeCmtSuffix);
                         $article->doEdit($talkRedir, $comment, $editFlags);
                     }
                 }
             }
         }
         // update merge target talk
         if ($talkContents) {
             $article = new Article($mergeTargetTalkTitle, 0);
             if ($article) {
                 $mergeTargetTalkContents = $article->fetchContent();
                 if ($mergeTargetTalkContents) {
                     $mergeTargetTalkContents = rtrim($mergeTargetTalkContents) . "\n\n";
                 }
                 $comment = $this->makeComment($this->userComment, 'merged with ' . $talkMergeSummary . $mergeCmtFamily, $mergeCmtSuffix);
                 $article->doEdit($mergeTargetTalkContents . $talkContents, $comment, $editFlags);
                 if ($this->addWatches) {
                     StructuredData::addWatch($wgUser, $article, true);
                 }
             }
             $outputRow .= '<li>Merged ' . $talkOutput . ' into ' . $skin->makeKnownLinkObj($mergeTargetTalkTitle, htmlspecialchars($mergeTargetTalkTitle->getPrefixedText())) . "</li>";
         }
         $obj = $this->data[$m][0]['object'];
         if ($mergeTargetNs == NS_PERSON) {
             Person::addGenderToRequestData($requestData, $this->data[$m][0]['gender']);
         } else {
             // family
             $obj->isMerging(true);
             // to read propagated data from person pages, not from prev family revision
         }
         // update merge target
         $req = new FauxRequest($requestData, true);
         $comment = $this->makeComment($this->userComment, ($mergeSummary == 'gedcom' ? 'Add data from gedcom' : 'merged with ' . $mergeSummary) . $mergeCmtFamily, $mergeCmtSuffix);
         $obj->editPage($req, $contents, $comment, $editFlags, $this->addWatches);
         $outputRow .= '<li>Merged ' . $mainOutput . ' into ' . $skin->makeKnownLinkObj($mergeTargetTitle, htmlspecialchars($mergeTargetTitle->getPrefixedText())) . "</li>";
         $outputRows[] = $outputRow;
     }
     // add log and recent changes
     if (!$this->isGedcom()) {
         if (!$mergeSummary) {
             $mergeSummary = 'members of other families';
         }
         $mergeComment = 'Merge [[' . $mergeTargetTitle->getPrefixedText() . ']] and ' . $mergeSummary;
         $log = new LogPage('merge', false);
         $t = Title::makeTitle(NS_SPECIAL, "ReviewMerge/{$mergeLogId}");
         $log->addEntry('merge', $t, $mergeComment);
         RecentChange::notifyLog(wfTimestampNow(), $t, $wgUser, $mergeComment, '', 'merge', 'merge', $t->getPrefixedText(), $mergeComment, '', $isTrustedMerge, 0);
     }
     $nonmergedPages = $this->getNonmergedPages();
     $output .= join("\n", array_reverse($outputRows)) . '</ul>' . ($nonmergedPages ? '<p>In addition to the people listed above, the following have also been included in the target family' . ($this->isGedcom() ? '<br/>(GEDCOM people listed will be added when the GEDCOM is imported)' : '') . $nonmergedPages . "</p>\n" : '') . ($this->isGedcom() ? '' : '<p>' . $skin->makeKnownLinkObj(Title::makeTitle(NS_SPECIAL, 'ReviewMerge/' . $mergeLogId), htmlspecialchars("Review/undo merge")) . '<br>' . $skin->makeKnownLinkObj(Title::makeTitle(NS_SPECIAL, 'ShowDuplicates'), htmlspecialchars("Show more duplicates")) . '</p>');
     return $output;
 }
Пример #3
0
 function writeMerge($userid, &$userMerge)
 {
     $foundFamilyTitle = null;
     $foundPeopleCount = 0;
     $familyCount = 0;
     $mergeCount = count($userMerge->merges);
     $preMergeTimestamp = wfTimestamp(TS_MW, wfTimestamp(TS_UNIX, $userMerge->firstTimestamp) - 2);
     foreach ($userMerge->merges as $merge) {
         $mergeNs = $merge->target->title->getNamespace();
         if ($mergeNs != NS_PERSON && $mergeNs != NS_FAMILY && $mergeNs != NS_PERSON_TALK && $mergeNs != NS_FAMILY_TALK) {
             return "invalid target for merge: title={$merge->target->title->getPrefixedText()}";
         }
         if ($foundFamilyTitle && $mergeNs == NS_FAMILY) {
             return "invalid merge sequence - {$merge->target->title->getPrefixedText()} after family: {$foundFamilyTitle->getPrefixedText()}";
         }
         if ($mergeNs == NS_FAMILY) {
             $familyCount = count($merge->sources) + 1;
             $foundFamilyTitle = $merge->target->title;
         } else {
             if ($mergeNs == NS_PERSON) {
                 $foundPeopleCount++;
             }
         }
         // get target preRevid
         $revid = StructuredData::getRevidForTimestamp($merge->target->title, $preMergeTimestamp);
         // its ok if revid was created during the merge for talk pages
         if ($revid == 0 || $revid > $userMerge->lastRevid || $revid >= $userMerge->firstRevid && $mergeNs != NS_PERSON_TALK && $mergeNs != NS_FAMILY_TALK) {
             return "revision not found for target={$merge->target->title->getPrefixedText()} revid={$revid} firstRevid={$userMerge->firstRevid} timestamp={$preMergeTimestamp}";
         }
         $merge->target->preRevid = $revid >= $userMerge->firstRevid ? 0 : $revid;
         // 0 if created during the merge
         $revision = Revision::newFromId($revid);
         $merge->target->revPage = $revision->getPage();
         // get target postRevid and comment
         list($revid, $comment) = $this->getNextRevidComment($merge->target->revPage, $merge->target->preRevid);
         if ($revid != 0 && $revid <= $userMerge->lastRevid) {
             // if target was edited in the merge
             $merge->target->postRevid = $revid;
             $merge->target->comment = $comment;
         }
         // get source preRevid's and titles
         foreach ($merge->sources as $source) {
             $revid = $this->getPrevRevid($source->revPage, $source->postRevid);
             if (!$revid) {
                 return "previous revision not found for source={$source->postRevid}";
             }
             $source->preRevid = $revid;
             $revision = Revision::newFromId($revid);
             $title = $revision->getTitle();
             if (!$title) {
                 return "title not found for source={$source->postRevid}";
             }
             $source->title = $title;
             if ($title->getNamespace() != $mergeNs) {
                 return "invalid source={$title->getPrefixedText()} target={$merge->target->title->getPrefixedText()}";
             }
         }
     }
     if ($foundPeopleCount > 1 && !$foundFamilyTitle) {
         return "invalid merge sequence: multiple merges without a family: count={$mergeCount}";
     }
     if (!$foundFamilyTitle && $foundPeopleCount == 0) {
         return "invalid merge sequence: no people or families count={$mergeCount}";
     }
     // put merge revids into their proper rows and columns, and add roles
     $mergeRows = array();
     for ($m = 0; $m < count($userMerge->merges); $m++) {
         $mergeRows[$m] = (object) array('role' => '', 'revids' => array());
         if ($foundFamilyTitle && $userMerge->merges[$m]->target->title->getNamespace() == NS_PERSON) {
             for ($p = 0; $p < count($familyCount); $p++) {
                 $mergeRows[$m]->revids[$p] = array();
             }
         }
     }
     $mainTitle = null;
     $totalScore = 0;
     $totalCount = 0;
     $seenRevids = array();
     for ($m = 0; $m < count($userMerge->merges); $m++) {
         $merge =& $userMerge->merges[$m];
         $ns = $merge->target->title->getNamespace();
         // read baseData and data, calc match score
         if ($ns == NS_PERSON || $ns == NS_FAMILY) {
             $baseData = $this->readData($merge->target->title, $merge->target->preRevid);
             if (!$baseData) {
                 return "unable to read data for {$merge->target->title->getPrefixedText()} revid={$merge->target->preRevid}";
             }
             if ($ns == NS_FAMILY) {
                 $baseStdData = MergeForm::standardizeFamilyData($baseData);
             } else {
                 $baseStdData = MergeForm::standardizePersonData($baseData);
             }
             $data = array();
             for ($p = 0; $p < count($merge->sources); $p++) {
                 $data[$p] = $this->readData($merge->sources[$p]->title, $merge->sources[$p]->preRevid);
                 if (!$data[$p]) {
                     return "unable to read data for {$merge->sources[$p]->title->getPrefixedText()} revid={$merge->sources[$p]->preRevid}";
                 }
                 if ($ns == NS_FAMILY) {
                     $stdData = MergeForm::standardizeFamilyData($data[$p]);
                 } else {
                     $stdData = MergeForm::standardizePersonData($data[$p]);
                 }
                 $totalScore += MergeForm::calcMatchScore($baseStdData, $stdData);
                 $totalCount++;
             }
         }
         if ($foundFamilyTitle && $ns == NS_FAMILY) {
             // use pre-merge family revisions to get roles, row numbers
             $this->recordFamilyMembers($baseData['husbands'], 'husband', 0, $userMerge->merges, $preMergeTimestamp, $familyCount, $mergeRows, $seenRevids);
             $this->recordFamilyMembers($baseData['wives'], 'wife', 0, $userMerge->merges, $preMergeTimestamp, $familyCount, $mergeRows, $seenRevids);
             $this->recordFamilyMembers($baseData['children'], 'child', 0, $userMerge->merges, $preMergeTimestamp, $familyCount, $mergeRows, $seenRevids);
             for ($p = 0; $p < count($data); $p++) {
                 $this->recordFamilyMembers($data[$p]['husbands'], 'husband', $p + 1, $userMerge->merges, $preMergeTimestamp, $familyCount, $mergeRows, $seenRevids);
                 $this->recordFamilyMembers($data[$p]['wives'], 'wife', $p + 1, $userMerge->merges, $preMergeTimestamp, $familyCount, $mergeRows, $seenRevids);
                 $this->recordFamilyMembers($data[$p]['children'], 'child', $p + 1, $userMerge->merges, $preMergeTimestamp, $familyCount, $mergeRows, $seenRevids);
             }
         }
         if (!$foundFamilyTitle || $ns != NS_PERSON) {
             // handle people in families above
             $mergeRows[$m]->revids[0] = array();
             $mergeRows[$m]->revids[0][] = $merge->target->preRevid;
             for ($p = 0; $p < count($merge->sources); $p++) {
                 $mergeRows[$m]->revids[$p + 1] = array();
                 $mergeRows[$m]->revids[$p + 1][] = $merge->sources[$p]->preRevid;
             }
             if ($ns == NS_PERSON_TALK || $ns == NS_FAMILY_TALK) {
                 $mergeRows[$m]->role = 'talk';
             } else {
                 if ($ns == NS_PERSON) {
                     $mergeRows[$m]->role = 'Person';
                 } else {
                     if ($ns == NS_FAMILY) {
                         $mergeRows[$m]->role = 'Family';
                     }
                 }
             }
         }
         if ($ns == NS_FAMILY || $ns == NS_PERSON && !$foundFamilyTitle) {
             $mainTitle = $merge->target->title;
         }
     }
     if ($foundFamilyTitle && $mainTitle->getPrefixedText() != $foundFamilyTitle->getPrefixedText()) {
         return "family titles not equal: {$mainTitle->getPrefixedText()} and {$foundFamilyTitle->getPrefixedText()}";
     }
     if ($foundFamilyTitle) {
         // verify that all merging people have been recorded in mergeRows somewhere
         foreach ($userMerge->merges as &$merge) {
             if ($merge->target->title->getNamespace() == NS_PERSON) {
                 if (!@$seenRevids[$merge->target->preRevid]) {
                     return "target person not found: {$merge->target->title->getPrefixedText()}";
                 }
                 foreach ($merge->sources as &$source) {
                     if (!@$seenRevids[$source->preRevid]) {
                         return "source person not found: {$source->title->getPrefixedText()}";
                     }
                 }
             }
         }
     }
     // write mergelog record
     $mergeScore = $totalCount > 0 ? $totalScore / $totalCount : 0;
     $isTrustedUser = CompareForm::isTrustedMerger(User::newFromName(User::whois($userid)));
     $isTrustedMerge = MergeForm::isTrustedMerge($mergeScore, $isTrustedUser);
     $mergeId = $this->writeMergelog($userid, $userMerge, $mergeScore, $isTrustedMerge, $mainTitle, $mergeRows);
     // update post-merge comments with ml_id
     $this->updateMergeComments($userMerge, $mainTitle, $mergeId);
     $this->log("INFO", "writeMerge id={$mergeId} score={$mergeScore} isTrusted={$isTrustedMerge} merges={$mergeCount} title={$mainTitle->getPrefixedText()}", $userid, $userMerge->firstTimestamp);
     return '';
 }
Пример #4
0
    /**
     * Return HTML for displaying search results
     * @return string HTML
     */
    public function getReviewResults()
    {
        $data = array();
        $roles = array();
        $this->getCompareData($data, $roles);
        $cols = count($data[0]);
        $tblCols = $cols + 1;
        $childNum = 0;
        $output = <<<END
<form name="unmerge" action="/wiki/Special:ReviewMerge/{$this->mergeId}" method="get">
<input type="hidden" name="action" value="unmerge"/>
<table border="0" cellspacing="0" cellpadding="4">
END;
        for ($i = 0; $i < count($data); $i++) {
            $output .= CompareForm::insertEmptyRow($tblCols);
            if ($roles[0] == 'Person') {
                $labels = self::$PERSON_COMPARE_LABELS;
            } else {
                if ($i == 0) {
                    $labels = self::$FAMILY_COMPARE_LABELS;
                } else {
                    $labels = self::$FAMILY_MEMBER_COMPARE_LABELS;
                }
            }
            foreach ($labels as $label) {
                $found = !in_array($label, self::$OPTIONAL_LABELS);
                if (!$found) {
                    for ($j = 0; $j < $cols; $j++) {
                        if (is_array(@$data[$i][$j][$label]) && count($data[$i][$j][$label]) > 0) {
                            $found = true;
                            break;
                        }
                    }
                }
                if ($found) {
                    $baseStdValues =& CompareForm::standardizeValues($label, @$data[$i][1][$label]);
                    if ($label == 'Title') {
                        $role = $roles[$i];
                        if ($role == 'child') {
                            $roleLabel = $role . $label;
                            $childNum++;
                        } else {
                            if ($role == 'Person' || $role == 'Family') {
                                $roleLabel = $label;
                            } else {
                                $roleLabel = $role . $label;
                            }
                        }
                    } else {
                        $roleLabel = $label;
                    }
                    if ($label == 'familyTitle') {
                        $revidLabel = 'Revid';
                    } else {
                        if (strpos($label, 'Title') !== false) {
                            $revidLabel = str_replace('Title', 'Revid', $label);
                        } else {
                            $revidLabel = '';
                        }
                    }
                    $labelClass = CompareForm::getLabelClass($roleLabel);
                    $output .= "<tr><td class=\"{$labelClass}\">" . CompareForm::formatLabel($roleLabel, $childNum) . "</td>";
                    for ($j = $cols - 1; $j >= 0; $j--) {
                        if ($j == 1) {
                            $stdValues = $baseStdValues;
                        } else {
                            $stdValues =& CompareForm::standardizeValues($label, @$data[$i][$j][$label]);
                        }
                        list($score, $class) = CompareForm::getCompareScoreClass($j == 0 || $j == 1, $label, $baseStdValues, $stdValues);
                        $output .= "<td class=\"{$class}\">";
                        $valueFound = false;
                        if (is_array(@$data[$i][$j][$label])) {
                            for ($v = 0; $v < count($data[$i][$j][$label]); $v++) {
                                $value = $data[$i][$j][$label][$v];
                                if (strpos($label, 'Title') !== false) {
                                    if (($label == 'familyTitle' || $label == 'Title') && @$data[$i][$j]['mergeresult']) {
                                        $formattedValue = 'Merge<br>result';
                                    } else {
                                        if (GedcomUtil::getGedcomMergeLogKey(@$data[$i][$j]['Revid'][$v])) {
                                            $formattedValue = '<b>GEDCOM page</b>';
                                        } else {
                                            $formattedValue = CompareForm::formatValue($label, $value, StructuredData::endsWith($label, 'FamilyTitle') ? '' : 'oldid=' . $data[$i][$j][$revidLabel][$v]);
                                        }
                                    }
                                } else {
                                    $formattedValue = CompareForm::formatValue($label, $value);
                                }
                                if ($v) {
                                    $output .= '<hr>';
                                }
                                $output .= $formattedValue;
                                $valueFound = true;
                            }
                        }
                        if (!$valueFound) {
                            $output .= '&nbsp;';
                        }
                        if ($class == CompareForm::$COMPARE_PAGE_CLASS) {
                            $titlesCnt = count(@$data[$i][$j][$label]);
                            if ($titlesCnt > 0) {
                                if (!$data[$i][$j]['Exists']) {
                                    // person/family not found
                                    $output .= '<br>Not found';
                                } else {
                                    if ($data[$i][$j]['Redirect']) {
                                        // person/family has been merged
                                        $output .= '<br>Already merged';
                                    } else {
                                        if ($data[$i][$j]['mergeTarget']) {
                                            $output .= '<br>' . ($data[$i][$j][$label][0] == $data[$i][$j]['mergeTarget'] ? 'Same as ' : 'Merged with ') . htmlspecialchars($data[$i][$j]['mergeTarget']);
                                        } else {
                                            if ($j == 1 && @$data[$i][0]['mergeresult']) {
                                                $output .= '<br>(merge target)';
                                            }
                                        }
                                    }
                                }
                            } else {
                                if (@$data[$i][$j]['deleted']) {
                                    $output .= 'Page has been deleted';
                                }
                            }
                        }
                        $output .= '</td>';
                    }
                    $output .= '</tr>';
                }
            }
        }
        if ($this->unmergeTimestamp) {
            $unmergeButton = 'Merge has been undone';
        } else {
            $unmergeButton = 'Unmerge reason: <input type="text" name="comment" size=36/><br><input type="submit" value="Unmerge"/>';
        }
        $output .= <<<END
<tr><td align=right colspan="{$tblCols}">{$unmergeButton}</td></tr>
</table>
</form>
END;
        return $output;
    }
Пример #5
0
function wfMatchFamily($args)
{
    global $wgUser, $wgAjaxCachePolicy;
    $wgAjaxCachePolicy->setPolicy(0);
    $status = GE_SUCCESS;
    $result = '';
    $gedcomId = GedcomUtil::getGedcomId($args);
    if (!$wgUser->isLoggedIn()) {
        $status = GE_NOT_LOGGED_IN;
    } else {
        if ($wgUser->isBlocked() || wfReadOnly()) {
            $status = GE_NOT_AUTHORIZED;
        } else {
            if (!$args || !$gedcomId || !preg_match('/^<gedcom [^>]*id="([^"]+)"/', $args, $idMatches) || !preg_match('/^<gedcom [^>]*match="([^"]+)"/', $args, $titleMatches)) {
                $status = GE_INVALID_ARG;
            } else {
                // calc family match scores
                $id = $idMatches[1];
                $matchTitle = Title::newFromText($titleMatches[1], NS_FAMILY);
                $matchTitleString = $matchTitle->getText();
                $gedcomData = GedcomUtil::getGedcomDataMap($args);
                $gedcomTitleString = $gedcomData[$id]['title'];
                if (strpos($gedcomTitleString, 'Person:') === 0 || strpos($gedcomTitleString, 'Family:') === 0) {
                    $gedcomTitleString = substr($gedcomTitleString, 7);
                }
                $compare = new CompareForm('Family', array($gedcomTitleString, $matchTitleString), $gedcomData, $args);
                list($compareData, $compareChildren, $maxChildren) = $compare->readCompareData();
                $dataLabels = $compare->getDataLabels();
                list($compareClass, $husbandScores, $wifeScores, $totalScores) = $compare->scoreCompareData($dataLabels, $compareData);
                // matched if not multiple husbands/wives, total score > threshold, husband + wife scores > threshold, and all gedcom children matched
                $gedcomHusbandCount = count($compareData[$gedcomTitleString]['husbandTitle']);
                $gedcomWifeCount = count($compareData[$gedcomTitleString]['wifeTitle']);
                $matchHusbandCount = count($compareData[$matchTitleString]['husbandTitle']);
                $matchWifeCount = count($compareData[$matchTitleString]['wifeTitle']);
                $matched = $gedcomHusbandCount <= 1 && $gedcomWifeCount <= 1 && $matchHusbandCount <= 1 && $matchWifeCount <= 1 && $totalScores[1] >= 4 && ($gedcomHusbandCount == 0 || $matchHusbandCount == 0 || $husbandScores[1] > 0) && ($gedcomWifeCount == 0 || $matchWifeCount == 0 || $wifeScores[1] > 0);
                //wfDebug("MATCHCOMPARE gedcomTitle=$gedcomTitleString matchTitle=$matchTitleString ghc=$gedcomHusbandCount gwc=$gedcomWifeCount mhc=$matchHusbandCount mwc=$matchWifeCount".
                //			" totalScore={$totalScores[1]} husbandScore={$husbandScores[1]} wifeScore={$wifeScores[1]} matched=$matched\n");
                if ($matched) {
                    $unmatchedGedcomChild = false;
                    $unmatchedWikiChild = false;
                    for ($i = 0; $i < $maxChildren; $i++) {
                        if (count(@$compareChildren[$gedcomTitleString][$i]['childTitle']) == 1 && count(@$compareChildren[$matchTitleString][$i]['childTitle']) != 1) {
                            $unmatchedGedcomChild = true;
                        } else {
                            if (count(@$compareChildren[$gedcomTitleString][$i]['childTitle']) != 1 && count(@$compareChildren[$matchTitleString][$i]['childTitle']) == 1) {
                                $unmatchedWikiChild = true;
                            }
                        }
                    }
                    if ($unmatchedGedcomChild && $unmatchedWikiChild) {
                        // could be a mismatched child
                        $matched = false;
                        //wfDebug("MATCHCOMPARE failed on children\n");
                    }
                }
                if ($matched) {
                    // save matches and return related matches
                    $keys = array();
                    $keys[] = $id;
                    $matches = array();
                    $matches[] = $matchTitle->getPrefixedText();
                    $merged = array();
                    $merged[] = 'false';
                    if ($gedcomHusbandCount == 1 && $matchHusbandCount == 1) {
                        $key = GedcomUtil::getKeyFromTitle($compareData[$gedcomTitleString]['husbandTitle'][0]);
                        if ($key) {
                            // not already merged
                            $keys[] = $key;
                            $matches[] = 'Person:' . $compareData[$matchTitleString]['husbandTitle'][0];
                            $merged[] = 'false';
                        }
                    }
                    if ($gedcomWifeCount == 1 && $matchWifeCount == 1) {
                        $key = GedcomUtil::getKeyFromTitle($compareData[$gedcomTitleString]['wifeTitle'][0]);
                        if ($key) {
                            $keys[] = $key;
                            $matches[] = 'Person:' . $compareData[$matchTitleString]['wifeTitle'][0];
                            $merged[] = 'false';
                        }
                    }
                    for ($i = 0; $i < $maxChildren; $i++) {
                        if (count(@$compareChildren[$gedcomTitleString][$i]['childTitle']) == 1 && count(@$compareChildren[$matchTitleString][$i]['childTitle']) == 1) {
                            $key = GedcomUtil::getKeyFromTitle($compareChildren[$gedcomTitleString][$i]['childTitle'][0]);
                            if ($key) {
                                $keys[] = $key;
                                $matches[] = 'Person:' . $compareChildren[$matchTitleString][$i]['childTitle'][0];
                                $merged[] = 'false';
                            }
                        }
                    }
                    $status = fgUpdateMatches($gedcomId, $keys, $matches, $merged);
                    if ($status == GE_SUCCESS) {
                        $result = fgGetRelatedMatches($keys, $matches);
                    }
                } else {
                    // save as potential match and return
                    $keys = array($id);
                    $matches = array($matchTitleString);
                    $status = fgUpdatePotentialMatches($gedcomId, $keys, $matches);
                    if ($status == GE_SUCCESS) {
                        $result = '<match id="' . StructuredData::escapeXml($id) . '" matches="' . StructuredData::escapeXml($matchTitleString) . '"/>';
                    }
                }
            }
        }
    }
    return "<matchfamily status=\"{$status}\">{$result}</matchfamily>";
}