public static function updateImageLink($tag, $oldTitle, $newTitle, $caption, &$text, &$textChanged) { // TODO if you allow renaming images you must find a way to preserve caption and primary attributes here $old = "<image id=\"I(\\d+)\" filename=\"" . StructuredData::protectRegexSearch(StructuredData::escapeXml($oldTitle)) . "\".*?/>\n"; $matches = array(); $id = 0; $oldFound = false; if (preg_match('$' . $old . '$', $text, $matches)) { $id = (int) $matches[1]; $oldFound = true; } else { $old = "</{$tag}>"; } if ($newTitle) { $newTitle = StructuredData::escapeXml($newTitle); // get the last image number in the text if ($id == 0) { $id = ESINHandler::getLastImageId($text) + 1; } if ($caption) { $caption = " caption=\"{$caption}\""; } $new = "<image id=\"I{$id}\" filename=\"{$newTitle}\"{$caption}/>\n"; } else { $new = ''; } if (!$oldFound) { $new .= $old; } $result = preg_replace('$' . $old . '$', StructuredData::protectRegexReplace($new), $text); if ($result != $text) { $text = $result; $textChanged = true; } }
/** * Propagate data in xml property to other articles if necessary * @param string $oldText contains text being replaced * @param String $text which we never touch when propagating places * @param bool $textChanged which we never touch when propagating places * @return bool true if propagation was successful */ protected function propagateEditData($oldText, &$text, &$textChanged) { global $wrIsGedcomUpload, $wgESINHandler; $result = true; // cache new xml - it's used right away to generate family badges on the related person pages, // if you don't cache it, the badges pick up the old html $this->cachePageXml(); // update people that link to this family, because the family-badge contents could have changed // TODO this could be made more efficient by only invalidating if names, birthdates, or deathdates have changed $u = new HTMLCacheUpdate($this->title, 'pagelinks'); $u->doUpdate(); // get current info $propagatedData = Family::getPropagatedData($this->xml); $redirTitle = Title::newFromRedirect($text); // get original info $origPropagatedData = Family::getPropagatedData(null); // don't bother construction page text from WLH in a gedcom upload because nothing will link to this new page if (!@$wrIsGedcomUpload && (!$oldText || mb_strpos($oldText, '<family>') === false)) { // oldText contains MediaWiki:noarticletext if the article is being created // construct <family> text from What Links Here $oldText = $this->getPageTextFromWLH(false); } $origXml = null; if ($oldText) { $origXml = StructuredData::getXml('family', $oldText); if (isset($origXml)) { $origPropagatedData = Family::getPropagatedData($origXml); } } // TODO!!! // Revert, Unmerge, and eventually Undo should be getting the current attrs for existing people from origPropagatedData // and getting the current attrs and redirect-titles for newly-added people from the Person pages when adding the family title to them // then unmerge wouldn't need to get them in unmerge, and revert wouldn't be broken, and undo won't break things. // This duplicates the functionality found in fromEditFields, but it allows us to update the pages without going through fromEditFields // and it doesn't require reading any pages that we weren't reading already. // Also, instead of isMerging, if this Family page is on the propagation manager blacklist, then you can't trust the prior version // and we should get the person attrs from the Person pages for _all_ family members. // Finally, make sure that after redirects we don't have 2 links to the same Person (and also two links to the same Family on Person pages). // ignore changes of the husband <-> wife role for the same person $temp = array_diff($propagatedData['husbands'], $origPropagatedData['wives']); $origPropagatedData['wives'] = array_diff($origPropagatedData['wives'], $propagatedData['husbands']); $propagatedData['husbands'] = $temp; $temp = array_diff($propagatedData['wives'], $origPropagatedData['husbands']); $origPropagatedData['husbands'] = array_diff($origPropagatedData['husbands'], $propagatedData['wives']); $propagatedData['wives'] = $temp; $result = $result && $this->propagateFamilyMemberEditData($propagatedData['husbands'], $origPropagatedData['husbands'], 'husband', 'spouse_of_family', $text, $textChanged); $result = $result && $this->propagateFamilyMemberEditData($propagatedData['wives'], $origPropagatedData['wives'], 'wife', 'spouse_of_family', $text, $textChanged); $result = $result && $this->propagateFamilyMemberEditData($propagatedData['children'], $origPropagatedData['children'], 'child', 'child_of_family', $text, $textChanged); if (StructuredData::removeDuplicateLinks('husband|wife|child', $text)) { $textChanged = true; } $result = $result && $wgESINHandler->propagateSINEdit($this->title, 'family', $this->titleString, $propagatedData, $origPropagatedData, $text, $textChanged); // ensure footer tag is still there (might have been removed by editing the last section) if ($redirTitle == null && strpos($text, ESINHandler::ESIN_FOOTER_TAG) === false) { if (strlen($text) > 0 && substr($text, strlen($text) - 1) != "\n") { $text .= "\n"; } $text .= ESINHandler::ESIN_FOOTER_TAG; $textChanged = true; } // update watchlist summary if changed $summary = Family::getSummary($this->xml, $this->title); $origSummary = Family::getSummary($origXml, $this->title); if ($summary != $origSummary) { StructuredData::updateWatchlistSummary($this->title, $summary); } // if it's a redirect, add the people, families, and images that were on this page to the redirect target // but don't bother updating the redir target during a merge if ($redirTitle != null && PropagationManager::isPropagatablePage($redirTitle)) { // get the text of the redir page $article = StructuredData::getArticle($redirTitle, true); if ($article) { $content =& $article->fetchContent(); $updated = false; // add husbands from this page to the redir page foreach ($origPropagatedData['husbands'] as $p) { // get propagated data for p $pd = Person::getPropagatedData(StructuredData::getXmlForTitle('person', Title::newFromText($p, NS_PERSON))); Family::updatePersonLink('husband', $p, $p, $pd, 'spouse_of_family', $content, $updated); } // add wives from this page to the redir page foreach ($origPropagatedData['wives'] as $p) { $pd = Person::getPropagatedData(StructuredData::getXmlForTitle('person', Title::newFromText($p, NS_PERSON))); Family::updatePersonLink('wife', $p, $p, $pd, 'spouse_of_family', $content, $updated); } // add children from this page to the redir page foreach ($origPropagatedData['children'] as $p) { $pd = Person::getPropagatedData(StructuredData::getXmlForTitle('person', Title::newFromText($p, NS_PERSON))); Family::updatePersonLink('child', $p, $p, $pd, 'child_of_family', $content, $updated); } // add images from this page to the redir page foreach ($origPropagatedData['images'] as $i) { ESINHandler::updateImageLink('family', $i['filename'], $i['filename'], $i['caption'], $content, $updated); } // update the redir page if necessary if ($updated) { $result = $result && $article->doEdit($content, 'Copy data from [[' . $this->title->getPrefixedText() . ']]', PROPAGATE_EDIT_FLAGS); } } } if (!$result) { error_log("ERROR! Family edit/rollback not propagated: {$this->titleString}\n"); } return $result; }
private function addNamesToRequestData(&$requestData, &$keepKeys, &$count, &$primaryNameFound, &$notesMap, &$sourcesMap, $elements, &$noteAdoptions, &$sourceAdoptions) { if (is_array($elements)) { foreach ($elements as $element) { if (@$keepKeys[$element['key']]) { if ($count == 0) { $count = 1; } if ($element['type'] == self::$PRIMARY_NAME) { if (!$primaryNameFound) { $i = 0; $type = ''; $primaryNameFound = true; } else { $type = Person::$ALT_NAME_TAG; $i = $count; $count++; } } else { $type = $element['type']; $i = $count; $count++; } $notes = $this->addAdoptions($element['key'], ESINHandler::mapSourcesImagesNotes($notesMap, $element['notes']), $noteAdoptions); $sources = $this->addAdoptions($element['key'], ESINHandler::mapSourcesImagesNotes($sourcesMap, $element['sources']), $sourceAdoptions); Person::addNameToRequestData($requestData, $i, $type, $element['given'], $element['surname'], $element['title_prefix'], $element['title_suffix'], $sources, $notes); } } } }
/** * Propagate data in xml property to other articles if necessary * @param string $oldText contains text being replaced * @param String $text new text * @param bool $textChanged which we never touch when propagating places * @return bool true if propagation was successful */ protected function propagateEditData($oldText, &$text, &$textChanged) { global $wrIsGedcomUpload, $wgESINHandler; $result = true; // clear xml cache $this->clearPageXmlCache(); // get current info $propagatedData = Person::getPropagatedData($this->xml); $redirTitle = Title::newFromRedirect($text); // get original info $origPropagatedData = Person::getPropagatedData(null); // don't bother construction page text from WLH in a gedcom upload because nothing will link to this new page if (!@$wrIsGedcomUpload && (!$oldText || mb_strpos($oldText, '<person>') === false)) { // oldText contains MediaWiki:noarticletext if the article is being created // construct <person> text from What Links Here $oldText = $this->getPageTextFromWLH(false); } $origXml = null; if ($oldText) { $origXml = StructuredData::getXml('person', $oldText); if (isset($origXml)) { $origPropagatedData = Person::getPropagatedData($origXml); } } $result = $result && $this->propagateFamilyEditData($propagatedData['parentFamilies'], $origPropagatedData['parentFamilies'], 'child_of_family', 'child', 'child', $propagatedData, $origPropagatedData, $text, $textChanged); $oldTag = Person::getSpouseTagFromGender($origPropagatedData['gender']); $newTag = Person::getSpouseTagFromGender($propagatedData['gender']); $result = $result && $this->propagateFamilyEditData($propagatedData['spouseFamilies'], $origPropagatedData['spouseFamilies'], 'spouse_of_family', $oldTag, $newTag, $propagatedData, $origPropagatedData, $text, $textChanged); if (StructuredData::removeDuplicateLinks('child_of_family|spouse_of_family', $text)) { $textChanged = true; } $result = $result && $wgESINHandler->propagateSINEdit($this->title, 'person', $this->titleString, $propagatedData, $origPropagatedData, $text, $textChanged); // ensure footer tag is still there (might have been removed by editing the last section) if ($redirTitle == null && strpos($text, ESINHandler::ESIN_FOOTER_TAG) === false) { if (strlen($text) > 0 && substr($text, strlen($text) - 1) != "\n") { $text .= "\n"; } $text .= ESINHandler::ESIN_FOOTER_TAG; $textChanged = true; } // update watchlist summary if changed $summary = Person::getSummary($this->xml, $this->title); $origSummary = Person::getSummary($origXml, $this->title); if ($summary != $origSummary) { StructuredData::updateWatchlistSummary($this->title, $summary); } // if it's a redirect, add the people, families, and images that were on this page to the redirect target // but don't bother updating the redir target during a merge if ($redirTitle != null && PropagationManager::isPropagatablePage($redirTitle)) { // get the text of the redir page $article = StructuredData::getArticle($redirTitle, true); if ($article) { $content =& $article->fetchContent(); $updated = false; // add parent families from this page to the redir page foreach ($origPropagatedData['parentFamilies'] as $f) { Person::updateFamilyLink('child_of_family', $f, $f, $content, $updated); } // add spouse families from this page to the redir page foreach ($origPropagatedData['spouseFamilies'] as $f) { Person::updateFamilyLink('spouse_of_family', $f, $f, $content, $updated); } // add images from this page to the redir page foreach ($origPropagatedData['images'] as $i) { ESINHandler::updateImageLink('person', $i['filename'], $i['filename'], $i['caption'], $content, $updated); } // update the redir page if necessary if ($updated) { $result = $result && $article->doEdit($content, 'Copy data from [[' . $this->title->getPrefixedText() . ']]', PROPAGATE_EDIT_FLAGS); } } } if (!$result) { error_log("ERROR! Person edit/rollback not propagated: {$this->titleString}\n"); } return $result; }
/** * Create family tree page * * This is also called by search.js * * @param unknown_type $args * @return GE_SUCCESS, GE_INVALID_ARG, GE_NOT_LOGGED_IN, GE_NOT_AUTHORIZED, GE_NOT_FOUND, GE_DUP_KEY, GE_DB_ERROR */ function wfAddPage($args) { global $wgUser, $wgAjaxCachePolicy, $wgArticle, $wgTitle, $wgLang; // set cache policy $wgAjaxCachePolicy->setPolicy(0); $status = GE_SUCCESS; $title = null; $titleString = null; $error = ''; $args = AjaxUtil::getArgs($args); $ns = $wgLang->getNsIndex($args['ns']); $titleString = @$args['title']; $update = $args['update'] == 'true'; if (!$wgUser->isLoggedIn()) { $status = GE_NOT_LOGGED_IN; } else { if ($wgUser->isBlocked() || wfReadOnly()) { $status = GE_NOT_AUTHORIZED; } } if ($status == GE_SUCCESS) { $dbw =& wfGetDB(DB_MASTER); $dbw->ignoreErrors(true); $dbw->begin(); $text = ''; if ($titleString) { // user passed in existing title; just add to watchlist and trees $title = Title::newFromText($titleString, $ns); } else { if ($ns == NS_PERSON) { if (ESINHandler::isLivingDates($args['bd'], null, $args['dd'], $args['dp'])) { $error = 'Living people cannot be added to WeRelate. People born in the last 110 years must have a death date'; } else { if (ESINHandler::isAmbiguousDate($args['bd']) || ESINHandler::isAmbiguousDate($args['dd'])) { $error = "Please write dates in D MMM YYYY format so they are unambiguous (ie 5 Jan 1900)"; } else { if (!$title) { $title = StructuredData::constructPersonTitle($args['g'], $args['s']); } if ($title) { if ($args['bt'] == 'chr') { $bird = ''; $birp = ''; $chrd = $args['bd']; $chrp = $args['bp']; } else { $bird = $args['bd']; $birp = $args['bp']; $chrd = ''; $chrp = ''; } if ($args['dt'] == 'bur') { $dead = ''; $deap = ''; $burd = $args['dd']; $burp = $args['dp']; } else { $dead = $args['dd']; $deap = $args['dp']; $burd = ''; $burp = ''; } $text = Person::getPageText($args['g'], $args['s'], $args['gnd'], $bird, $birp, $dead, $deap, $title->getText(), null, @$args['pf'], @$args['sf'], $chrd, $chrp, $burd, $burp); } } } } else { if ($ns == NS_FAMILY) { if (ESINHandler::isAmbiguousDate($args['md'])) { $error = "Please write dates in D MMM YYYY format so they are unambiguous (ie 5 Jan 1900)"; } else { $title = StructuredData::constructFamilyTitle($args['hg'], $args['hs'], $args['wg'], $args['ws']); if ($title) { $text = Family::getPageText($args['md'], $args['mp'], $title->getText(), null, @$args['ht'], @$args['wt'], @$args['ct']); } } } else { if ($ns == NS_SOURCE) { $title = StructuredData::constructSourceTitle($args['sty'], $args['st'], $args['a'], $args['p'], $args['pi'], $args['pu']); if ($title) { $text = Source::getPageText($args['sty'], $args['st'], $args['a'], $args['p'], $args['pi'], $args['pu']); } else { $error = 'Required source fields are missing; please press the Back button on your browser to enter the required fields.'; } } else { if ($ns == NS_MYSOURCE) { $t = $args['t']; if (mb_strpos($t, $wgUser->getName() . '/') != 0) { $t = $wgUser->getName() . '/' . $t; } $title = Title::newFromText($t, NS_MYSOURCE); if ($title) { $text = MySource::getPageText($args['a'], $args['p'], $args['s']); } } else { if ($ns == NS_PLACE) { $title = StructuredData::constructPlaceTitle($args['pn'], $args['li']); $text = Place::getPageText(); // check existing located-in, not root $titleText = $title->getFullText(); $pos = mb_strpos($titleText, ','); if ($pos === false) { $title = null; $error = 'You need to fill in the country'; } else { $locatedIn = Title::newFromText(trim(mb_substr($titleText, $pos + 1)), NS_PLACE); if (!$locatedIn->exists()) { $title = null; $error = 'Before you can add this place, you must first add ' . $locatedIn->getFullText(); } } } } } } } } if ($status == GE_SUCCESS && $title == null) { $status = GE_INVALID_ARG; if (!$error) { $error = 'Invalid page title; unable to create page'; } } // don't update in the case of the user passing in a non-existing titleString if ($update && !($titleString && !$title->exists())) { if ($status == GE_SUCCESS) { $article = new Article($title, 0); // don't set the global article and title to this; we don't need to propagate -- but we do for places // NOTE: This doesn't execute the code in FamilyTreePropagator to update familytree_page and add page to tree, but we don't want that to be called // because we add the page to the tree below if ($title->exists()) { // don't update the page if it already exists, except to add a spouse-family if ($ns == NS_PERSON && @$args['sf']) { $content =& $article->fetchContent(); $updated = false; Person::updateFamilyLink('spouse_of_family', '', $args['sf'], $content, $updated); if ($updated) { $article->doEdit($content, 'Add spouse family: [[Family:' . $args['sf'] . ']]', EDIT_UPDATE); StructuredData::purgeTitle($title, +1); // purge person with a fudge factor so family link will be blue } } $revid = 0; // ok for revid to be 0 if page exists because we no longer use revid } else { if (!$article->doEdit($text, '')) { $status = GE_WIKI_ERROR; } else { $revid = $article->mRevIdEdited; } } } if ($status == GE_SUCCESS) { // add the page to the trees (or to no trees) $allTrees = FamilyTreeUtil::getFamilyTrees($wgUser->getName()); $trees = explode('|', @$args['tree']); $checkedTreeIds = array(); foreach ($allTrees as $tree) { if (in_array(FamilyTreeUtil::toInputName($tree['name']), $trees)) { $checkedTreeIds[] = $tree['id']; // if (!FamilyTreeUtil::addPage($dbw, $wgUser, $tree['id'], $title, $revid, 0)) { // $status = GE_DB_ERROR; // } } } // update which trees are checked FamilyTreeUtil::updateTrees($dbw, $title, $revid, $allTrees, array(), $checkedTreeIds); } // watch the page if ($status == GE_SUCCESS) { StructuredData::addWatch($wgUser, $article, true); } } if ($status == GE_SUCCESS) { $dbw->commit(); } else { $dbw->rollback(); if (!$error) { $error = 'Unable to create page'; } } } // return status $titleString = ''; if ($title) { $titleString = StructuredData::escapeXml($title->getText()); } return "<addpage status=\"{$status}\" title=\"{$titleString}\" error=\"{$error}\"></addpage>"; }
private function updatePage($linkTitle, $tag, $newTitle, &$text, &$textChanged) { if (!PropagationManager::isPropagatablePage($linkTitle)) { return true; } $result = true; $article = StructuredData::getArticle($linkTitle, true); if ($article) { $content =& $article->fetchContent(); $updated = false; ESINHandler::updateImageLink($tag, $this->titleString, $newTitle, '', $content, $updated); if ($updated) { $result = $article->doEdit($content, self::PROPAGATE_MESSAGE . ' [[' . $this->title->getPrefixedText() . ']]', PROPAGATE_EDIT_FLAGS); } else { error_log("propagating image " . $this->titleString . " nothing changed in " . $linkTitle->getPrefixedText()); } // if we're not deleting this entry (newTitle is not empty), and the page to update is a redirect (article title != linkTitle), // we need to update the page title in the image page text if ($newTitle && $linkTitle->getText() != $article->getTitle()->getText()) { $old = 'title="' . StructuredData::escapeXml($linkTitle->getText()) . '"'; $new = 'title="' . StructuredData::escapeXml($article->getTitle()->getText()) . '"'; $text = str_replace($old, $new, $text); $textChanged = true; } } return $result; }