/** * @return bool|int|null */ protected function saveContent() { global $wgLogRestrictions; $dbw = wfGetDB(DB_MASTER); $log_id = $dbw->nextSequenceValue('logging_log_id_seq'); $this->timestamp = $now = wfTimestampNow(); $data = array('log_id' => $log_id, 'log_type' => $this->type, 'log_action' => $this->action, 'log_timestamp' => $dbw->timestamp($now), 'log_user' => $this->doer->getId(), 'log_user_text' => $this->doer->getName(), 'log_namespace' => $this->target->getNamespace(), 'log_title' => $this->target->getDBkey(), 'log_page' => $this->target->getArticleId(), 'log_comment' => $this->comment, 'log_params' => $this->params); $dbw->insert('logging', $data, __METHOD__); $newId = !is_null($log_id) ? $log_id : $dbw->insertId(); # And update recentchanges if ($this->updateRecentChanges) { $titleObj = SpecialPage::getTitleFor('Log', $this->type); RecentChange::notifyLog($now, $titleObj, $this->doer, $this->getRcComment(), '', $this->type, $this->action, $this->target, $this->comment, $this->params, $newId); } elseif ($this->sendToUDP) { # Don't send private logs to UDP if (isset($wgLogRestrictions[$this->type]) && $wgLogRestrictions[$this->type] != '*') { return true; } # Notify external application via UDP. # We send this to IRC but do not want to add it the RC table. $titleObj = SpecialPage::getTitleFor('Log', $this->type); $rc = RecentChange::newLogEntry($now, $titleObj, $this->doer, $this->getRcComment(), '', $this->type, $this->action, $this->target, $this->comment, $this->params, $newId); $rc->notifyRC2UDP(); } return $newId; }
function saveContent() { if (wfReadOnly()) { return false; } global $wgUser; $fname = 'LogPage::saveContent'; $dbw =& wfGetDB(DB_MASTER); $uid = $wgUser->getID(); $this->timestamp = $now = wfTimestampNow(); $dbw->insert('logging', array('log_type' => $this->type, 'log_action' => $this->action, 'log_timestamp' => $dbw->timestamp($now), 'log_user' => $uid, 'log_namespace' => $this->target->getNamespace(), 'log_title' => $this->target->getDBkey(), 'log_comment' => $this->comment, 'log_params' => $this->params), $fname); # And update recentchanges if ($this->updateRecentChanges) { $titleObj = Title::makeTitle(NS_SPECIAL, 'Log/' . $this->type); $rcComment = $this->actionText; if ('' != $this->comment) { if ($rcComment == '') { $rcComment = $this->comment; } else { $rcComment .= ': ' . $this->comment; } } RecentChange::notifyLog($now, $titleObj, $wgUser, $rcComment, '', $this->type, $this->action, $this->target, $this->comment, $this->params); } return true; }
function saveContent() { if (wfReadOnly()) { return false; } global $wgUser; $fname = 'LogPage::saveContent'; $dbw = wfGetDB(DB_MASTER); $uid = $wgUser->getID(); $log_id = $dbw->nextSequenceValue('log_log_id_seq'); $this->timestamp = $now = wfTimestampNow(); $data = array('log_type' => $this->type, 'log_action' => $this->action, 'log_timestamp' => $dbw->timestamp($now), 'log_user' => $uid, 'log_namespace' => $this->target->getNamespace(), 'log_title' => $this->target->getDBkey(), 'log_comment' => $this->comment, 'log_params' => $this->params); # log_id doesn't exist on Wikimedia servers yet, and it's a tricky # schema update to do. Hack it for now to ignore the field on MySQL. if (!is_null($log_id)) { $data['log_id'] = $log_id; } $dbw->insert('logging', $data, $fname); # And update recentchanges if ($this->updateRecentChanges) { $titleObj = SpecialPage::getTitleFor('Log', $this->type); $rcComment = $this->getRcComment(); RecentChange::notifyLog($now, $titleObj, $wgUser, $rcComment, '', $this->type, $this->action, $this->target, $this->comment, $this->params); } return true; }
protected function saveContent() { global $wgUser, $wgLogRestrictions; $fname = 'LogPage::saveContent'; $dbw = wfGetDB(DB_MASTER); $log_id = $dbw->nextSequenceValue('log_log_id_seq'); $this->timestamp = $now = wfTimestampNow(); $data = array('log_id' => $log_id, 'log_type' => $this->type, 'log_action' => $this->action, 'log_timestamp' => $dbw->timestamp($now), 'log_user' => $this->doer->getId(), 'log_namespace' => $this->target->getNamespace(), 'log_title' => $this->target->getDBkey(), 'log_comment' => $this->comment, 'log_params' => $this->params); $dbw->insert('logging', $data, $fname); $newId = !is_null($log_id) ? $log_id : $dbw->insertId(); if (!($dbw->affectedRows() > 0)) { wfDebugLog("logging", "LogPage::saveContent failed to insert row - Error {$dbw->lastErrno()}: {$dbw->lastError()}"); } # And update recentchanges if ($this->updateRecentChanges) { # Don't add private logs to RC! if (!isset($wgLogRestrictions[$this->type]) || $wgLogRestrictions[$this->type] == '*') { $titleObj = SpecialPage::getTitleFor('Log', $this->type); $rcComment = $this->getRcComment(); RecentChange::notifyLog($now, $titleObj, $this->doer, $rcComment, '', $this->type, $this->action, $this->target, $this->comment, $this->params, $newId); } } return true; }
/** * Add log to RecentChange * @param Title $title * @param string $action * @param string $reason */ public function addLog($title, $action, $reason = '') { $user = $this->wg->User; RecentChange::notifyLog(wfTimestampNow(), $title, $user, '', '', RC_EDIT, $action, $title, $reason, ''); }
protected function customActionNotifyRC($user, $action, $reason) { $articleId = $this->getArticleId(); $target = $this->getTitle(); RecentChange::notifyLog(wfTimestampNow(), $target, $user, '', '', RC_EDIT, $action, $target, $reason, '', 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; }
public function unmerge() { global $wgUser; $nonFamilyPages = array(); // contains revid, next_revid, title $familyPages = array(); // ditto $manualPages = array(); // ditto $unchangedPages = array(); // ditto $dbw =& wfGetDB(DB_MASTER); // break into different arrays $seenTitles = array(); foreach ($this->merges as $merge) { $fields = explode('|', $merge); $role = $fields[0]; $revidSets = explode('#', $fields[1]); foreach ($revidSets as $revidSet) { if ($revidSet) { $revids = explode('/', $revidSet); foreach ($revids as $revid) { if ($revid) { // get two following revisions $rows = $dbw->query('SELECT r2.rev_page, r2.rev_id, r2.rev_comment FROM revision AS r1, revision AS r2' . ' WHERE r1.rev_id = ' . $revid . ' AND r1.rev_page = r2.rev_page AND r2.rev_id > ' . $revid . ' ORDER BY r2.rev_id LIMIT 2'); $cnt = 0; $cmt = ''; $nextRevid = ''; $pageId = ''; while ($row = $dbw->fetchObject($rows)) { $cnt++; if ($cnt == 1) { $pageId = $row->rev_page; $nextRevid = $row->rev_id; $cmt = $row->rev_comment; } } $dbw->freeResult($rows); if ($cnt == 0) { $revision = Revision::newFromId($revid); if ($revision) { $title = $revision->getTitle(); } else { // page must have been deleted $title = null; } } else { $title = Title::newFromId($pageId); } // TODO if title doesn't exist, then unmerged pages could have red links; oh well if ($title && !@$seenTitles[$title->getPrefixedText()]) { $seenTitles[$title->getPrefixedText()] = 1; $entry = array('revid' => $revid, 'next_revid' => $nextRevid, 'title' => $title); if ($cnt == 0 || strpos($cmt, '[[Special:ReviewMerge/' . $this->mergeId . '|') === false) { $unchangedPages[] = $entry; // page was not edited in the merge } else { if ($cnt > 1) { $manualPages[] = $entry; } else { if ($role == 'Family') { PropagationManager::addBlacklistPage($title); $familyPages[] = $entry; } else { PropagationManager::addBlacklistPage($title); $nonFamilyPages[] = $entry; } } } } } } } } } // update nonFamilyPages foreach ($nonFamilyPages as $page) { $this->revert($page, false); } // update familyPages foreach ($familyPages as $page) { $this->revert($page, true); } // update mergelog $dbw->update('mergelog', array('ml_unmerge_user' => $wgUser->getID(), 'ml_unmerge_timestamp' => $dbw->timestamp(wfTimestampNow())), array('ml_id' => $this->mergeId), 'ReviewForm::unmerge'); // add log and RC $mergeComment = 'Unmerge [[' . $this->mergeTitle->getPrefixedText() . ']]' . ($this->comment ? ' - ' . $this->comment : ''); $log = new LogPage('merge', false); $t = Title::makeTitle(NS_SPECIAL, "ReviewMerge/{$this->mergeId}"); $log->addEntry('unmerge', $t, $mergeComment); RecentChange::notifyLog(wfTimestampNow(), $t, $wgUser, $mergeComment, '', 'merge', 'unmerge', $t->getPrefixedText(), $mergeComment, '', 0, 0); // list pages $output = ''; $skin =& $wgUser->getSkin(); if (count($manualPages) == 0) { $output .= "<h2>Unmerge successful</h2>\n"; } else { $output .= "<h2>Unmerge partially completed</h2><p><b><font color=\"red\">The following page(s) must still be unmerged</font></b></p><ul>"; foreach ($manualPages as $page) { $output .= "<li>" . htmlspecialchars($page['title']->getPrefixedText()) . ' <b>' . $skin->makeKnownLinkObj($page['title'], 'changes to undo', 'diff=' . $page['next_revid'] . '&oldid=' . $page['revid']) . '</b> => <b>' . $skin->makeKnownLinkObj($page['title'], 'edit', 'action=edit') . "</b></li>\n"; error_log("Unmerge may be needed: {$page['title']->getPrefixedText()} id={$this->mergeId}"); } $output .= <<<END </ul> <p>For each page listed above, click on the <b>changes to undo</b> link to see what changes need to be manually undone: <ol> <li>For each item that was removed in the merge (listed on the left side of the screen in yellow), you need to add that item back to the page.</li> <li>For each item that was added in the merge (listed on the right side of the screen in green), you need to remove that item from the page.</li> </ol></p> <p>Once you know which items need to be added/removed, click on the <b>edit</b> link to edit the page and add/remove the items.</p> <p>Additional notes: <ul> <li>Some of the items may have been added/removed already.</li> <li>You can ignore place changes that simply fill in missing place levels.</li> <li>When reviewing changes to Family pages, you can ignore changes to personal information (birth, death, etc.) associated with the family members: <i>husband</i>, <i>wife</i>, or <i>child</i>. Just re-add family members that were removed in the merge, and remove ones that were added.</li> </ul></p> <p>If you have questions, send an email to <b>solveig@quass.org</b> containing the titles of the pages listed above and the URL appearing at the top of your browser window and we will finish the unmerge for you.</p> <p> </p> END; } if (count($familyPages) + count($nonFamilyPages) + count($unchangedPages) > 0) { $output .= "<p><b>The following pages have been successfully unmerged:</b></p><ul>\n"; foreach ($familyPages as $page) { $output .= "<li>" . $skin->makeKnownLinkObj($page['title']) . "</li>\n"; } foreach ($nonFamilyPages as $page) { $output .= "<li>" . $skin->makeKnownLinkObj($page['title']) . "</li>\n"; } // $output .= '</ul>'; // } // if (count($unchangedPages) > 0) { // $output .= "<p><b>The following pages were not merged and so did not need to be unmerged:</b></p><ul>\n"; foreach ($unchangedPages as $page) { $output .= "<li>" . $skin->makeKnownLinkObj($page['title']) . "</li>\n"; } $output .= "</ul>"; } return $output; }