<?php /** * webtrees: online genealogy * Copyright (C) 2016 webtrees development team * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ namespace Fisharebest\Webtrees; /** * Defined in session.php * * @global Tree $WT_TREE */ global $WT_TREE; use Fisharebest\Webtrees\Controller\SimpleController; use Fisharebest\Webtrees\Functions\FunctionsDate; use Fisharebest\Webtrees\Functions\FunctionsImport; define('WT_SCRIPT_NAME', 'edit_changes.php'); require './includes/session.php'; $controller = new SimpleController; $controller ->restrictAccess(Auth::isModerator($WT_TREE)) ->setPageTitle(I18N::translate('Pending changes')) ->pageHeader() ->addInlineJavascript(" function show_diff(diffurl) { window.opener.location = diffurl; return false; } "); $action = Filter::get('action'); $change_id = Filter::getInteger('change_id'); $index = Filter::get('index'); $ged = Filter::getInteger('ged'); echo '<div id="pending"><h2>', I18N::translate('Pending changes'), '</h2>'; switch ($action) { case 'undo': $gedcom_id = Database::prepare("SELECT gedcom_id FROM `##change` WHERE change_id=?")->execute(array($change_id))->fetchOne(); $xref = Database::prepare("SELECT xref FROM `##change` WHERE change_id=?")->execute(array($change_id))->fetchOne(); // Undo a change, and subsequent changes to the same record Database::prepare( "UPDATE `##change`" . " SET status = 'rejected'" . " WHERE status = 'pending'" . " AND gedcom_id = ?" . " AND xref = ?" . " AND change_id >= ?" )->execute(array($gedcom_id, $xref, $change_id)); break; case 'accept': $gedcom_id = Database::prepare("SELECT gedcom_id FROM `##change` WHERE change_id=?")->execute(array($change_id))->fetchOne(); $xref = Database::prepare("SELECT xref FROM `##change` WHERE change_id=?")->execute(array($change_id))->fetchOne(); // Accept a change, and all previous changes to the same record $changes = Database::prepare( "SELECT change_id, gedcom_id, gedcom_name, xref, old_gedcom, new_gedcom" . " FROM `##change` c" . " JOIN `##gedcom` g USING (gedcom_id)" . " WHERE c.status = 'pending'" . " AND gedcom_id = ?" . " AND xref = ?" . " AND change_id <= ?" . " ORDER BY change_id" )->execute(array($gedcom_id, $xref, $change_id))->fetchAll(); foreach ($changes as $change) { if (empty($change->new_gedcom)) { // delete FunctionsImport::updateRecord($change->old_gedcom, $gedcom_id, true); } else { // add/update FunctionsImport::updateRecord($change->new_gedcom, $gedcom_id, false); } Database::prepare("UPDATE `##change` SET status='accepted' WHERE change_id=?")->execute(array($change->change_id)); Log::addEditLog("Accepted change {$change->change_id} for {$change->xref} / {$change->gedcom_name} into database"); } break; case 'undoall': Database::prepare( "UPDATE `##change`" . " SET status='rejected'" . " WHERE status='pending' AND gedcom_id=?" )->execute(array($WT_TREE->getTreeId())); break; case 'acceptall': $changes = Database::prepare( "SELECT change_id, gedcom_id, gedcom_name, xref, old_gedcom, new_gedcom" . " FROM `##change` c" . " JOIN `##gedcom` g USING (gedcom_id)" . " WHERE c.status='pending' AND gedcom_id=?" . " ORDER BY change_id" )->execute(array($WT_TREE->getTreeId()))->fetchAll(); foreach ($changes as $change) { if (empty($change->new_gedcom)) { // delete FunctionsImport::updateRecord($change->old_gedcom, $change->gedcom_id, true); } else { // add/update FunctionsImport::updateRecord($change->new_gedcom, $change->gedcom_id, false); } Database::prepare("UPDATE `##change` SET status='accepted' WHERE change_id=?")->execute(array($change->change_id)); Log::addEditLog("Accepted change {$change->change_id} for {$change->xref} / {$change->gedcom_name} into database"); } break; } $changed_gedcoms = Database::prepare( "SELECT g.gedcom_name" . " FROM `##change` c" . " JOIN `##gedcom` g USING (gedcom_id)" . " WHERE c.status='pending'" . " GROUP BY g.gedcom_name" )->fetchOneColumn(); if ($changed_gedcoms) { $changes = Database::prepare( "SELECT c.*, UNIX_TIMESTAMP(c.change_time) + :offset AS change_timestamp, u.user_name, u.real_name, g.gedcom_name, new_gedcom, old_gedcom" . " FROM `##change` c" . " JOIN `##user` u USING (user_id)" . " JOIN `##gedcom` g USING (gedcom_id)" . " WHERE c.status='pending'" . " ORDER BY gedcom_id, c.xref, c.change_id" ) ->execute(array('offset' => WT_TIMESTAMP_OFFSET)) ->fetchAll(); $output = '<br><br><table class="list_table">'; $prev_xref = null; $prev_gedcom_id = null; foreach ($changes as $change) { $tree = Tree::findById($change->gedcom_id); preg_match('/^0 (?:@' . WT_REGEX_XREF . '@ )?(' . WT_REGEX_TAG . ')/', $change->old_gedcom . $change->new_gedcom, $match); switch ($match[1]) { case 'INDI': $record = new Individual($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; case 'FAM': $record = new Family($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; case 'SOUR': $record = new Source($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; case 'REPO': $record = new Repository($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; case 'OBJE': $record = new Media($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; case 'NOTE': $record = new Note($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; default: $record = new GedcomRecord($change->xref, $change->old_gedcom, $change->new_gedcom, $tree); break; } if ($change->xref != $prev_xref || $change->gedcom_id != $prev_gedcom_id) { if ($prev_xref) { $output .= '</table></td></tr>'; } $prev_xref = $change->xref; $prev_gedcom_id = $change->gedcom_id; $output .= '<tr><td class="list_value">'; $output .= '<b><a href="#" onclick="return show_diff(\'' . $record->getHtmlUrl() . '\');"> ' . $record->getFullName() . '</a></b>'; $output .= '<div class="indent">'; $output .= '<table class="list_table"><tr>'; $output .= '<td class="list_label">' . I18N::translate('Accept') . '</td>'; $output .= '<td class="list_label">' . I18N::translate('Changes') . '</td>'; $output .= '<td class="list_label">' . I18N::translate('User') . '</td>'; $output .= '<td class="list_label">' . I18N::translate('Date') . '</td>'; $output .= '<td class="list_label">' . I18N::translate('Family tree') . '</td>'; $output .= '<td class="list_label">' . I18N::translate('Reject') . '</td>'; $output .= '</tr>'; } $output .= '<td class="list_value"><a href="edit_changes.php?action=accept&change_id=' . $change->change_id . '">' . I18N::translate('Accept') . '</a></td>'; $output .= '<td class="list_value">'; foreach ($record->getFacts() as $fact) { if ($fact->getTag() != 'CHAN') { if ($fact->isPendingAddition()) { $output .= '<div class="new" title="' . strip_tags($fact->summary()) . '">' . $fact->getLabel() . '</div>'; } elseif ($fact->isPendingDeletion()) { $output .= '<div class="old" title="' . strip_tags($fact->summary()) . '">' . $fact->getLabel() . '</div>'; } } } echo '</td>'; $output .= '<td class="list_value"><a href="#" onclick="return reply(\'' . $change->user_name . '\', \'' . I18N::translate('Moderate pending changes') . '\')" title="' . I18N::translate('Send a message') . '">'; $output .= Filter::escapeHtml($change->real_name); $output .= ' - ' . Filter::escapeHtml($change->user_name) . '</a></td>'; $output .= '<td class="list_value">' . FunctionsDate::formatTimestamp($change->change_timestamp) . '</td>'; $output .= '<td class="list_value">' . $change->gedcom_name . '</td>'; $output .= '<td class="list_value"><a href="edit_changes.php?action=undo&change_id=' . $change->change_id . '">' . I18N::translate('Reject') . '</a></td>'; $output .= '</tr>'; } $output .= '</table></td></tr></td></tr></table>'; //-- Now for the global Action bar: $output2 = '<br><table class="list_table">'; // Row 1 column 1: title "Accept all" $output2 .= '<tr><td class="list_label">' . I18N::translate('Accept all changes') . '</td>'; // Row 1 column 2: title "Undo all" $output2 .= '<td class="list_label">' . I18N::translate('Reject all changes') . '</td></tr>'; // Row 2 column 1: action "Accept all" $output2 .= '<tr><td class="list_value">'; $count = 0; foreach ($changed_gedcoms as $gedcom_name) { if ($count != 0) { $output2 .= '<br>'; } $output2 .= $gedcom_name . ' — ' . '<a href="edit_changes.php?action=acceptall&ged=' . rawurlencode($gedcom_name) . '">' . I18N::translate('Accept all changes') . '</a>'; $count++; } $output2 .= '</td>'; // Row 2 column 2: action "Undo all" $output2 .= '<td class="list_value">'; $count = 0; foreach ($changed_gedcoms as $gedcom_name) { if ($count != 0) { $output2 .= '<br>'; } $output2 .= $gedcom_name . ' — ' . '<a href="edit_changes.php?action=undoall&ged=' . rawurlencode($gedcom_name) . '" onclick="return confirm(\'' . I18N::translate('Are you sure you want to reject all the changes to this family tree?') . '\');">' . I18N::translate('Reject all changes') . '</a>'; $count++; } $output2 .= '</td></tr></table>'; echo $output2, $output, $output2, '<br><br><br><br>', '<p id="save-cancel">', '<input type="button" class="cancel" value="', I18N::translate('close'), '" onclick="closePopupAndReloadParent();">', '</p>'; } else { // No pending changes - refresh the parent window and close this one $controller->addInlineJavascript('closePopupAndReloadParent();'); } echo '</div>';