mirror of
https://github.com/YunoHost-Apps/webtrees_ynh.git
synced 2024-09-03 18:26:37 +02:00
441 lines
14 KiB
PHP
441 lines
14 KiB
PHP
<?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\Module;
|
|
|
|
use Fisharebest\Webtrees\Auth;
|
|
use Fisharebest\Webtrees\Controller\PageController;
|
|
use Fisharebest\Webtrees\Database;
|
|
use Fisharebest\Webtrees\Family;
|
|
use Fisharebest\Webtrees\Filter;
|
|
use Fisharebest\Webtrees\Functions\FunctionsEdit;
|
|
use Fisharebest\Webtrees\GedcomRecord;
|
|
use Fisharebest\Webtrees\I18N;
|
|
use Fisharebest\Webtrees\Individual;
|
|
use Fisharebest\Webtrees\Media;
|
|
use Fisharebest\Webtrees\Module\BatchUpdate\BatchUpdateBasePlugin;
|
|
use Fisharebest\Webtrees\Note;
|
|
use Fisharebest\Webtrees\Repository;
|
|
use Fisharebest\Webtrees\Source;
|
|
use Fisharebest\Webtrees\Tree;
|
|
|
|
/**
|
|
* Class BatchUpdateModule
|
|
*/
|
|
class BatchUpdateModule extends AbstractModule implements ModuleConfigInterface {
|
|
/** @var string Form parameter: chosen plugin*/
|
|
private $plugin;
|
|
|
|
/** @var string Form parameter: record to update */
|
|
private $xref;
|
|
|
|
/** @var string Form parameter: how to update record */
|
|
private $action;
|
|
|
|
/** @var string Form parameter: additional details for $action */
|
|
private $data;
|
|
|
|
/** @var BatchUpdateBasePlugin[] All available plugins */
|
|
private $plugins;
|
|
|
|
/** @var BatchUpdateBasePlugin The current plugin */
|
|
private $PLUGIN;
|
|
|
|
/** @var string[] n array of all xrefs that might need to be updated */
|
|
private $all_xrefs;
|
|
|
|
/** @var string The previous xref to process */
|
|
private $prev_xref;
|
|
|
|
/** @var String The current xref being process */
|
|
private $curr_xref;
|
|
|
|
/** @var string The next xref to process */
|
|
private $next_xref;
|
|
|
|
/** @var GedcomRecord The record corresponding to $curr_xref */
|
|
private $record;
|
|
|
|
/**
|
|
* How should this module be labelled on tabs, menus, etc.?
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getTitle() {
|
|
return /* I18N: Name of a module */ I18N::translate('Batch update');
|
|
}
|
|
|
|
/**
|
|
* A sentence describing what this module does.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getDescription() {
|
|
return /* I18N: Description of the “Batch update” module */ I18N::translate('Apply automatic corrections to your genealogy data.');
|
|
}
|
|
|
|
/**
|
|
* This is a general purpose hook, allowing modules to respond to routes
|
|
* of the form module.php?mod=FOO&mod_action=BAR
|
|
*
|
|
* @param string $mod_action
|
|
*/
|
|
public function modAction($mod_action) {
|
|
switch ($mod_action) {
|
|
case 'admin_batch_update':
|
|
echo $this->main();
|
|
break;
|
|
|
|
default:
|
|
http_response_code(404);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Main entry point
|
|
*
|
|
* @return string
|
|
*/
|
|
private function main() {
|
|
global $WT_TREE;
|
|
|
|
$this->plugins = $this->getPluginList(); // List of available plugins
|
|
$this->plugin = Filter::get('plugin'); // User parameters
|
|
$this->xref = Filter::get('xref', WT_REGEX_XREF);
|
|
$this->action = Filter::get('action');
|
|
$this->data = Filter::get('data');
|
|
|
|
// Don't do any processing until a plugin is chosen.
|
|
if ($this->plugin && array_key_exists($this->plugin, $this->plugins)) {
|
|
$this->PLUGIN = new $this->plugin;
|
|
$this->PLUGIN->getOptions();
|
|
$this->getAllXrefs();
|
|
|
|
switch ($this->action) {
|
|
case 'update':
|
|
$record = self::getLatestRecord($this->xref, $this->all_xrefs[$this->xref]);
|
|
if ($this->PLUGIN->doesRecordNeedUpdate($this->xref, $record)) {
|
|
$newrecord = $this->PLUGIN->updateRecord($this->xref, $record);
|
|
if ($newrecord != $record) {
|
|
if ($newrecord) {
|
|
GedcomRecord::getInstance($this->xref, $WT_TREE)->updateRecord($newrecord, $this->PLUGIN->chan);
|
|
} else {
|
|
GedcomRecord::getInstance($this->xref, $WT_TREE)->deleteRecord();
|
|
}
|
|
}
|
|
}
|
|
$this->xref = $this->findNextXref($this->xref);
|
|
break;
|
|
case 'update_all':
|
|
foreach ($this->all_xrefs as $xref => $type) {
|
|
$record = self::getLatestRecord($xref, $type);
|
|
if ($this->PLUGIN->doesRecordNeedUpdate($xref, $record)) {
|
|
$newrecord = $this->PLUGIN->updateRecord($xref, $record);
|
|
if ($newrecord != $record) {
|
|
if ($newrecord) {
|
|
GedcomRecord::getInstance($xref, $WT_TREE)->updateRecord($newrecord, $this->PLUGIN->chan);
|
|
} else {
|
|
GedcomRecord::getInstance($xref, $WT_TREE)->deleteRecord();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$this->xref = '';
|
|
break;
|
|
}
|
|
|
|
// Make sure that our requested record really does need updating.
|
|
// It may have been updated in another session, or may not have
|
|
// been specified at all.
|
|
if (array_key_exists($this->xref, $this->all_xrefs) &&
|
|
$this->PLUGIN->doesRecordNeedUpdate($this->xref, self::getLatestRecord($this->xref, $this->all_xrefs[$this->xref]))) {
|
|
$this->curr_xref = $this->xref;
|
|
}
|
|
// The requested record doesn't need updating - find one that does
|
|
if (!$this->curr_xref) {
|
|
$this->curr_xref = $this->findNextXref($this->xref);
|
|
}
|
|
if (!$this->curr_xref) {
|
|
$this->curr_xref = $this->findPrevXref($this->xref);
|
|
}
|
|
// If we've found a record to update, get details and look for the next/prev
|
|
if ($this->curr_xref) {
|
|
$this->prev_xref = $this->findPrevXref($this->curr_xref);
|
|
$this->next_xref = $this->findNextXref($this->curr_xref);
|
|
}
|
|
}
|
|
|
|
// HTML common to all pages
|
|
$controller = new PageController;
|
|
$controller
|
|
->setPageTitle(I18N::translate('Batch update'))
|
|
->restrictAccess(Auth::isAdmin())
|
|
->pageHeader();
|
|
|
|
echo $this->getJavascript();
|
|
?>
|
|
<ol class="breadcrumb small">
|
|
<li><a href="admin.php"><?php echo I18N::translate('Control panel'); ?></a></li>
|
|
<li><a href="admin_modules.php"><?php echo I18N::translate('Module administration'); ?></a></li>
|
|
<li class="active"><?php echo $controller->getPageTitle(); ?></li>
|
|
</ol>
|
|
<h2><?php echo $controller->getPageTitle(); ?></h2>
|
|
|
|
<form id="batch_update_form" class="form-horizontal" action="module.php" method="get">
|
|
<input type="hidden" name="mod" value="batch_update">
|
|
<input type="hidden" name="mod_action" value="admin_batch_update">
|
|
<input type="hidden" name="xref" value="' . $this->xref . '">
|
|
<input type="hidden" name="action" value=""><?php // will be set by javascript for next update ?>
|
|
<input type="hidden" name="data" value=""><?php // will be set by javascript for next update ?>
|
|
<div class="form-group">
|
|
<label class="control-label col-sm-3"><?php echo I18N::translate('Family tree') ?></label>
|
|
<div class="col-sm-9">
|
|
<?php echo FunctionsEdit::selectEditControl('ged', Tree::getNameList(), '', $WT_TREE->getName(), 'class="form-control" onchange="reset_reload();"') ?>
|
|
</div>
|
|
</div>
|
|
<div class="form-group">
|
|
<label class="control-label col-sm-3"><?php echo I18N::translate('Batch update') ?></label>
|
|
<div class="col-sm-9">
|
|
<select class="form-control" name="plugin" onchange="reset_reload();">
|
|
<?php if (!$this->plugin): ?>
|
|
<option value="" selected></option>
|
|
<?php endif; ?>
|
|
<?php foreach ($this->plugins as $class => $plugin): ?>
|
|
<option value="<?php echo $class ?>" <?php echo $this->plugin == $class ? 'selected' : ''; ?>><?php echo $plugin->getName(); ?></option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<?php if ($this->PLUGIN): ?>
|
|
<p class="small text-muted"><?php echo $this->PLUGIN->getDescription() ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
</div>
|
|
|
|
<?php if (!Auth::user()->getPreference('auto_accept')): ?>
|
|
<div class="alert alert-danger">
|
|
<?php echo I18N::translate('Your user account does not have “automatically accept changes” enabled. You will only be able to change one record at a time.'); ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
|
|
<?php // If a plugin is selected, display the details ?>
|
|
<?php if ($this->PLUGIN): ?>
|
|
<?php echo $this->PLUGIN->getOptionsForm(); ?>
|
|
<?php if (substr($this->action, -4) == '_all'): ?>
|
|
<?php // Reset - otherwise we might "undo all changes", which refreshes the ?>
|
|
<?php // page, which makes them all again! ?>
|
|
<script>reset_reload();</script>
|
|
<?php else: ?>
|
|
<hr>
|
|
<div id="batch_update2" class="col-sm-12">
|
|
<?php if ($this->curr_xref): ?>
|
|
<?php // Create an object, so we can get the latest version of the name. ?>
|
|
<?php $this->record = GedcomRecord::getInstance($this->curr_xref, $WT_TREE); ?>
|
|
<div class="form-group">
|
|
<?php echo self::createSubmitButton(I18N::translate('previous'), $this->prev_xref) ?>
|
|
<?php echo self::createSubmitButton(I18N::translate('next'), $this->next_xref) ?>
|
|
</div>
|
|
<div class="form-group">
|
|
<a class="lead" href="<?php echo $this->record->getHtmlUrl(); ?>"><?php echo $this->record->getFullName(); ?></a>
|
|
<?php echo $this->PLUGIN->getActionPreview($this->record); ?>
|
|
</div>
|
|
<div class="form-group">
|
|
<?php echo implode(' ', $this->PLUGIN->getActionButtons($this->curr_xref, $this->record)); ?>
|
|
</div>
|
|
<?php else: ?>
|
|
<div class="alert alert-info"><?php echo I18N::translate('Nothing found.'); ?></div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php endif; ?>
|
|
<?php endif; ?>
|
|
</form>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Find the next record that needs to be updated.
|
|
*
|
|
* @param string $xref
|
|
*
|
|
* @return string|null
|
|
*/
|
|
private function findNextXref($xref) {
|
|
foreach (array_keys($this->all_xrefs) as $key) {
|
|
if ($key > $xref) {
|
|
$record = self::getLatestRecord($key, $this->all_xrefs[$key]);
|
|
if ($this->PLUGIN->doesRecordNeedUpdate($key, $record)) {
|
|
return $key;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Find the previous record that needs to be updated.
|
|
*
|
|
* @param string $xref
|
|
*
|
|
* @return string|null
|
|
*/
|
|
private function findPrevXref($xref) {
|
|
foreach (array_reverse(array_keys($this->all_xrefs)) as $key) {
|
|
if ($key < $xref) {
|
|
$record = self::getLatestRecord($key, $this->all_xrefs[$key]);
|
|
if ($this->PLUGIN->doesRecordNeedUpdate($key, $record)) {
|
|
return $key;
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Generate a list of all XREFs.
|
|
*/
|
|
private function getAllXrefs() {
|
|
global $WT_TREE;
|
|
|
|
$sql = array();
|
|
$vars = array();
|
|
foreach ($this->PLUGIN->getRecordTypesToUpdate() as $type) {
|
|
switch ($type) {
|
|
case 'INDI':
|
|
$sql[] = "SELECT i_id, 'INDI' FROM `##individuals` WHERE i_file=?";
|
|
$vars[] = $WT_TREE->getTreeId();
|
|
break;
|
|
case 'FAM':
|
|
$sql[] = "SELECT f_id, 'FAM' FROM `##families` WHERE f_file=?";
|
|
$vars[] = $WT_TREE->getTreeId();
|
|
break;
|
|
case 'SOUR':
|
|
$sql[] = "SELECT s_id, 'SOUR' FROM `##sources` WHERE s_file=?";
|
|
$vars[] = $WT_TREE->getTreeId();
|
|
break;
|
|
case 'OBJE':
|
|
$sql[] = "SELECT m_id, 'OBJE' FROM `##media` WHERE m_file=?";
|
|
$vars[] = $WT_TREE->getTreeId();
|
|
break;
|
|
default:
|
|
$sql[] = "SELECT o_id, ? FROM `##other` WHERE o_type=? AND o_file=?";
|
|
$vars[] = $type;
|
|
$vars[] = $type;
|
|
$vars[] = $WT_TREE->getTreeId();
|
|
break;
|
|
}
|
|
}
|
|
$this->all_xrefs =
|
|
Database::prepare(implode(' UNION ', $sql) . ' ORDER BY 1 ASC')
|
|
->execute($vars)
|
|
->fetchAssoc();
|
|
}
|
|
|
|
/**
|
|
* Scan the plugin folder for a list of plugins
|
|
*
|
|
* @return BatchUpdateBasePlugin[]
|
|
*/
|
|
private function getPluginList() {
|
|
$plugins = array();
|
|
$dir_handle = opendir(__DIR__ . '/BatchUpdate');
|
|
while (($file = readdir($dir_handle)) !== false) {
|
|
if (substr($file, -10) == 'Plugin.php' && $file !== 'BatchUpdateBasePlugin.php') {
|
|
$class = '\Fisharebest\Webtrees\Module\BatchUpdate\\' . basename($file, '.php');
|
|
$plugins[$class] = new $class;
|
|
}
|
|
}
|
|
closedir($dir_handle);
|
|
|
|
return $plugins;
|
|
}
|
|
|
|
/**
|
|
* Javascript that gets included on every page
|
|
*
|
|
* @return string
|
|
*/
|
|
private function getJavascript() {
|
|
return
|
|
'<script>' .
|
|
'function reset_reload() {' .
|
|
' var bu_form=document.getElementById("batch_update_form");' .
|
|
' bu_form.xref.value="";' .
|
|
' bu_form.action.value="";' .
|
|
' bu_form.data.value="";' .
|
|
' bu_form.submit();' .
|
|
'}</script>';
|
|
}
|
|
|
|
/**
|
|
* Create a submit button for our form
|
|
*
|
|
* @param string $text
|
|
* @param string $xref
|
|
* @param string $action
|
|
* @param string $data
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function createSubmitButton($text, $xref, $action = '', $data = '') {
|
|
return
|
|
'<input class="btn btn-primary" type="submit" value="' . $text . '" onclick="' .
|
|
'this.form.xref.value=\'' . Filter::escapeHtml($xref) . '\';' .
|
|
'this.form.action.value=\'' . Filter::escapeHtml($action) . '\';' .
|
|
'this.form.data.value=\'' . Filter::escapeHtml($data) . '\';' .
|
|
'return true;"' .
|
|
($xref ? '' : ' disabled') . '>';
|
|
}
|
|
|
|
/**
|
|
* Get the current view of a record, allowing for pending changes
|
|
*
|
|
* @param string $xref
|
|
* @param string $type
|
|
*
|
|
* @return string
|
|
*/
|
|
public static function getLatestRecord($xref, $type) {
|
|
global $WT_TREE;
|
|
|
|
switch ($type) {
|
|
case 'INDI':
|
|
return Individual::getInstance($xref, $WT_TREE)->getGedcom();
|
|
case 'FAM':
|
|
return Family::getInstance($xref, $WT_TREE)->getGedcom();
|
|
case 'SOUR':
|
|
return Source::getInstance($xref, $WT_TREE)->getGedcom();
|
|
case 'REPO':
|
|
return Repository::getInstance($xref, $WT_TREE)->getGedcom();
|
|
case 'OBJE':
|
|
return Media::getInstance($xref, $WT_TREE)->getGedcom();
|
|
case 'NOTE':
|
|
return Note::getInstance($xref, $WT_TREE)->getGedcom();
|
|
default:
|
|
return GedcomRecord::getInstance($xref, $WT_TREE)->getGedcom();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* The URL to a page where the user can modify the configuration of this module.
|
|
* These links are displayed in the admin page menu.
|
|
*
|
|
* @return string
|
|
*/
|
|
public function getConfigLink() {
|
|
return 'module.php?mod=' . $this->getName() . '&mod_action=admin_batch_update';
|
|
}
|
|
|
|
}
|