Feature to Revert Tag changes by IP address.
Allows you to revert all edits made by a specific ip during a specified timeframe.
This commit is contained in:
parent
0b03f91f1c
commit
daf51d5477
@ -1,8 +1,8 @@
|
|||||||
<?php
|
<?php
|
||||||
/*
|
/*
|
||||||
* Name: Tag History
|
* Name: Tag History
|
||||||
* Author: Bzchan <bzchan@animemahou.com>
|
* Author: Bzchan <bzchan@animemahou.com>, modified by jgen <jgen.tech@gmail.com>
|
||||||
* Description: Keep a record of tag changes
|
* Description: Keep a record of tag changes, and allows you to revert changes.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class Tag_History implements Extension {
|
class Tag_History implements Extension {
|
||||||
@ -20,8 +20,44 @@ class Tag_History implements Extension {
|
|||||||
$this->install();
|
$this->install();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($event instanceof PageRequestEvent) && $event->page_matches("tag_history"))
|
if(($event instanceof AdminBuildingEvent))
|
||||||
|
{
|
||||||
|
if(isset($_POST['revert_ip']) && $user->is_admin() && $user->check_auth_token())
|
||||||
|
{
|
||||||
|
$revert_ip = filter_var($_POST['revert_ip'], FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE);
|
||||||
|
|
||||||
|
if ($revert_ip === false) {
|
||||||
|
// invalid ip given.
|
||||||
|
$this->theme->display_admin_block('Invalid IP');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_POST['revert_date']) && !empty($_POST['revert_date'])) {
|
||||||
|
if (isValidDate($_POST['revert_date'])){
|
||||||
|
$revert_date = addslashes($_POST['revert_date']); // addslashes is really unnecessary since we just checked if valid, but better safe.
|
||||||
|
} else {
|
||||||
|
$this->theme->display_admin_block('Invalid Date');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$revert_date = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
set_time_limit(0); // reverting changes can take a long time, disable php's timelimit if possible.
|
||||||
|
|
||||||
|
// Call the revert function.
|
||||||
|
$this->process_revert_all_changes_by_ip($revert_ip, $revert_date);
|
||||||
|
// output results
|
||||||
|
$this->theme->display_revert_ip_results();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$this->theme->display_admin_block(); // add a block to the admin panel
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($event instanceof PageRequestEvent) && ($event->page_matches("tag_history")))
|
||||||
{
|
{
|
||||||
if($event->get_arg(0) == "revert")
|
if($event->get_arg(0) == "revert")
|
||||||
{
|
{
|
||||||
@ -40,6 +76,7 @@ class Tag_History implements Extension {
|
|||||||
$this->theme->display_global_page($page, $this->get_global_tag_history());
|
$this->theme->display_global_page($page, $this->get_global_tag_history());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(($event instanceof DisplayingImageEvent))
|
if(($event instanceof DisplayingImageEvent))
|
||||||
{
|
{
|
||||||
// handle displaying a link on the view page
|
// handle displaying a link on the view page
|
||||||
@ -107,7 +144,7 @@ class Tag_History implements Extension {
|
|||||||
{
|
{
|
||||||
global $page;
|
global $page;
|
||||||
// check for the nothing case
|
// check for the nothing case
|
||||||
if($revert_id=="nothing")
|
if(empty($revert_id) || $revert_id=="nothing")
|
||||||
{
|
{
|
||||||
// tried to set it too the same thing so ignore it (might be a bot)
|
// tried to set it too the same thing so ignore it (might be a bot)
|
||||||
// go back to the index page with you
|
// go back to the index page with you
|
||||||
@ -121,7 +158,7 @@ class Tag_History implements Extension {
|
|||||||
// lets get this revert id assuming it exists
|
// lets get this revert id assuming it exists
|
||||||
$result = $this->get_tag_history_from_revert($revert_id);
|
$result = $this->get_tag_history_from_revert($revert_id);
|
||||||
|
|
||||||
if($result==null)
|
if(empty($result))
|
||||||
{
|
{
|
||||||
// there is no history entry with that id so either the image was deleted
|
// there is no history entry with that id so either the image was deleted
|
||||||
// while the user was viewing the history, someone is playing with form
|
// while the user was viewing the history, someone is playing with form
|
||||||
@ -135,13 +172,43 @@ class Tag_History implements Extension {
|
|||||||
$stored_image_id = $result['image_id'];
|
$stored_image_id = $result['image_id'];
|
||||||
$stored_tags = $result['tags'];
|
$stored_tags = $result['tags'];
|
||||||
|
|
||||||
log_debug("tag_history", "Reverting tags of $stored_image_id to [$stored_tags]");
|
log_debug("tag_history", 'Reverting tags of Image #'.$stored_image_id.' to ['.$stored_tags.']');
|
||||||
// all should be ok so we can revert by firing the SetUserTags event.
|
// all should be ok so we can revert by firing the SetUserTags event.
|
||||||
send_event(new TagSetEvent(Image::by_id($stored_image_id), $stored_tags));
|
send_event(new TagSetEvent(Image::by_id($stored_image_id), $stored_tags));
|
||||||
|
|
||||||
// all should be done now so redirect the user back to the image
|
// all should be done now so redirect the user back to the image
|
||||||
$page->set_mode("redirect");
|
$page->set_mode("redirect");
|
||||||
$page->set_redirect(make_link("post/view/$stored_image_id"));
|
$page->set_redirect(make_link('post/view/'.$stored_image_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This function is used by process_revert_all_changes_by_ip()
|
||||||
|
* to just revert an image's tag history.
|
||||||
|
*/
|
||||||
|
private function process_revert_request_only($revert_id)
|
||||||
|
{
|
||||||
|
if(empty($revert_id)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$id = (int) $revert_id;
|
||||||
|
$result = $this->get_tag_history_from_revert($id);
|
||||||
|
|
||||||
|
if(empty($result)) {
|
||||||
|
// there is no history entry with that id so either the image was deleted
|
||||||
|
// while the user was viewing the history, or something messed up
|
||||||
|
/* calling die() is probably not a good idea, we should throw an Exception */
|
||||||
|
die('Error: No tag history with specified id ('.$id.') was found in the database.'."\n\n".
|
||||||
|
'Perhaps the image was deleted while processing this request.');
|
||||||
|
}
|
||||||
|
|
||||||
|
// lets get the values out of the result
|
||||||
|
$stored_result_id = $result['id'];
|
||||||
|
$stored_image_id = $result['image_id'];
|
||||||
|
$stored_tags = $result['tags'];
|
||||||
|
|
||||||
|
log_debug("tag_history", 'Reverting tags of Image #'.$stored_image_id.' to ['.$stored_tags.']');
|
||||||
|
// all should be ok so we can revert by firing the SetUserTags event.
|
||||||
|
send_event(new TagSetEvent(Image::by_id($stored_image_id), $stored_tags));
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get_tag_history_from_revert($revert_id)
|
public function get_tag_history_from_revert($revert_id)
|
||||||
@ -192,16 +259,54 @@ class Tag_History implements Extension {
|
|||||||
return ($row ? $row : array());
|
return ($row ? $row : array());
|
||||||
}
|
}
|
||||||
|
|
||||||
public function process_revert_all_changes_by_ip($ip)
|
/*
|
||||||
|
* This function attempts to revert all changes by a given IP within an (optional) timeframe.
|
||||||
|
*/
|
||||||
|
public function process_revert_all_changes_by_ip($ip, $date=null)
|
||||||
{
|
{
|
||||||
global $database;
|
global $database;
|
||||||
/*
|
$date_select = '';
|
||||||
|
|
||||||
SELECT * FROM `tag_histories` WHERE image_id IN
|
if (!empty($date)) {
|
||||||
( select image_id from `tag_histories` where user_ip="216.240.14.185" and date_set >= 2011-10-23)
|
$date_select = 'and date_set >= '.$date;
|
||||||
ORDER BY image_id, date_set
|
} else {
|
||||||
|
$date = 'forever';
|
||||||
|
}
|
||||||
|
|
||||||
*/
|
log_info("tag_history", 'Attempting to revert edits by ip='.$ip.' (from '.$date.' to now).');
|
||||||
|
|
||||||
|
// Get all the images that the given IP has changed tags on (within the timeframe) that were last editied by the given IP
|
||||||
|
$result = $database->get_all('
|
||||||
|
SELECT t1.image_id FROM tag_histories t1 LEFT JOIN tag_histories t2
|
||||||
|
ON (t1.image_id = t2.image_id AND t1.date_set < t2.date_set)
|
||||||
|
WHERE t2.image_id IS NULL AND t1.user_ip="'.$ip.'" AND t1.image_id IN
|
||||||
|
( select image_id from `tag_histories` where user_ip="'.$ip.'" '.$date_select.')
|
||||||
|
ORDER BY t1.image_id;');
|
||||||
|
|
||||||
|
if (empty($result)) {
|
||||||
|
log_info("tag_history", 'Nothing to revert! for ip='.$ip.' (from '.$date.' to now).');
|
||||||
|
$this->theme->add_status('Nothing to Revert','Nothing to revert for ip='.$ip.' (from '.$date.' to now)');
|
||||||
|
return; // nothing to do.
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0 ; $i < count($result) ; $i++)
|
||||||
|
{
|
||||||
|
$image_id = (int) $result[$i]['image_id'];
|
||||||
|
|
||||||
|
// Get the first tag history that was done before the given IP edit
|
||||||
|
$row = $database->get_row('
|
||||||
|
SELECT id,tags FROM `tag_histories` WHERE image_id="'.$image_id.'" AND user_ip!="'.$ip.'" '.$date_select.' ORDER BY date_set DESC LIMIT 1');
|
||||||
|
|
||||||
|
if (empty($row)) {
|
||||||
|
// we can not revert this image based on the date restriction.
|
||||||
|
// Output a message perhaps?
|
||||||
|
} else {
|
||||||
|
$id = (int) $row['id'];
|
||||||
|
$this->process_revert_request_only($id);
|
||||||
|
$this->theme->add_status('Reverted Change','Reverted Image #'.$image_id.' to Tag History #'.$id.' ('.$row['tags'].')');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
log_info("tag_history", 'Reverted '.count($result).' edits by ip='.$ip.' (from '.$date.' to now).');
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -232,6 +337,7 @@ ORDER BY image_id, date_set
|
|||||||
// if the image has no history, make one with the old tags
|
// if the image has no history, make one with the old tags
|
||||||
$entries = $database->get_one("SELECT COUNT(*) FROM tag_histories WHERE image_id = ?", array($image->id));
|
$entries = $database->get_one("SELECT COUNT(*) FROM tag_histories WHERE image_id = ?", array($image->id));
|
||||||
if($entries == 0){
|
if($entries == 0){
|
||||||
|
/* these two queries could probably be combined */
|
||||||
$database->execute("
|
$database->execute("
|
||||||
INSERT INTO tag_histories(image_id, tags, user_id, user_ip, date_set)
|
INSERT INTO tag_histories(image_id, tags, user_id, user_ip, date_set)
|
||||||
VALUES (?, ?, ?, ?, now())",
|
VALUES (?, ?, ?, ?, now())",
|
||||||
|
@ -1,6 +1,12 @@
|
|||||||
<?php
|
<?php
|
||||||
|
/*
|
||||||
|
* Name: Tag History
|
||||||
|
* Author: Bzchan <bzchan@animemahou.com>, modified by jgen <jgen.tech@gmail.com>
|
||||||
|
*/
|
||||||
|
|
||||||
class Tag_HistoryTheme extends Themelet {
|
class Tag_HistoryTheme extends Themelet {
|
||||||
|
var $messages = array();
|
||||||
|
|
||||||
public function display_history_page(Page $page, $image_id, $history) {
|
public function display_history_page(Page $page, $image_id, $history) {
|
||||||
global $user;
|
global $user;
|
||||||
$start_string = "
|
$start_string = "
|
||||||
@ -22,11 +28,12 @@ class Tag_HistoryTheme extends Themelet {
|
|||||||
$setter .= " / " . $fields['user_ip'];
|
$setter .= " / " . $fields['user_ip'];
|
||||||
}
|
}
|
||||||
$selected = ($n == 2) ? " checked" : "";
|
$selected = ($n == 2) ? " checked" : "";
|
||||||
$history_list .= "
|
$history_list .= '
|
||||||
<li>
|
<li>
|
||||||
<input type='radio' name='revert' id='$current_id' value='$current_id'$selected>
|
<input type="radio" name="revert" id="'.$current_id.'" value="'.$current_id.'"$selected>
|
||||||
<label for='$current_id'>$current_tags (Set by $setter)</label>
|
<label for="'.$current_id.'">'.$current_tags.' (Set by '.$setter.')</label>
|
||||||
</li>\n";
|
</li>
|
||||||
|
';
|
||||||
}
|
}
|
||||||
|
|
||||||
$end_string = "
|
$end_string = "
|
||||||
@ -37,8 +44,8 @@ class Tag_HistoryTheme extends Themelet {
|
|||||||
";
|
";
|
||||||
$history_html = $start_string . $history_list . $end_string;
|
$history_html = $start_string . $history_list . $end_string;
|
||||||
|
|
||||||
$page->set_title("Image $image_id Tag History");
|
$page->set_title('Image '.$image_id.' Tag History');
|
||||||
$page->set_heading("Tag History: $image_id");
|
$page->set_heading('Tag History: '.$image_id);
|
||||||
$page->add_block(new NavBlock());
|
$page->add_block(new NavBlock());
|
||||||
$page->add_block(new Block("Tag History", $history_html, "main", 10));
|
$page->add_block(new Block("Tag History", $history_html, "main", 10));
|
||||||
}
|
}
|
||||||
@ -68,13 +75,13 @@ class Tag_HistoryTheme extends Themelet {
|
|||||||
if($user->is_admin()) {
|
if($user->is_admin()) {
|
||||||
$setter .= " / " . $fields['user_ip'];
|
$setter .= " / " . $fields['user_ip'];
|
||||||
}
|
}
|
||||||
$history_list .= "
|
$history_list .= '
|
||||||
<li>
|
<li>
|
||||||
<input type='radio' name='revert' value='$current_id'>
|
<input type="radio" name="revert" value="'.$current_id.'">
|
||||||
<a href='".make_link("post/view/$image_id")."'>$image_id</a>:
|
<a href="'.make_link('post/view/'.$image_id).'">'.$image_id.'</a>:
|
||||||
$current_tags (Set by $setter)
|
'.$current_tags.' (Set by '.$setter.')
|
||||||
</li>
|
</li>
|
||||||
";
|
';
|
||||||
}
|
}
|
||||||
|
|
||||||
$history_html = $start_string . $history_list . $end_string;
|
$history_html = $start_string . $history_list . $end_string;
|
||||||
@ -85,8 +92,46 @@ class Tag_HistoryTheme extends Themelet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function display_history_link(Page $page, $image_id) {
|
public function display_history_link(Page $page, $image_id) {
|
||||||
$link = "<a href='".make_link("tag_history/$image_id")."'>Tag History</a>\n";
|
$link = '<a href="'.make_link('tag_history/'.$image_id).'">Tag History</a>';
|
||||||
$page->add_block(new Block(null, $link, "main", 5));
|
$page->add_block(new Block(null, $link, "main", 5));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add a section to the admin page.
|
||||||
|
*/
|
||||||
|
public function display_admin_block($validation_msg='') {
|
||||||
|
global $page;
|
||||||
|
|
||||||
|
if (!empty($validation_msg)) {
|
||||||
|
$validation_msg = '<br><b>'. $validation_msg .'</b>';
|
||||||
|
}
|
||||||
|
|
||||||
|
$html = '
|
||||||
|
Revert tag changes/edit by a specific IP address.<br>
|
||||||
|
You can restrict the time frame to revert these edits as well.
|
||||||
|
<br>(Date format: 2011-10-23)
|
||||||
|
'.$validation_msg.'
|
||||||
|
|
||||||
|
<br><br>'.make_form(make_link("admin/revert_ip"),'POST',false,'revert_ip_form')."
|
||||||
|
IP Address: <input type='text' id='revert_ip' name='revert_ip' size='15'><br>
|
||||||
|
Date range: <input type='text' id='revert_date' name='revert_date' size='15'><br><br>
|
||||||
|
<input type='submit' value='Revert' onclick='return confirm(\"Revert all edits by this IP?\");'>
|
||||||
|
</form><br>
|
||||||
|
";
|
||||||
|
$page->add_block(new Block("Revert By IP", $html));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Show a standard page for results to be put into
|
||||||
|
*/
|
||||||
|
public function display_revert_ip_results() {
|
||||||
|
global $page;
|
||||||
|
$html = implode($this->messages, "\n");
|
||||||
|
$page->add_block(new Block("Revert by IP", $html));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function add_status($title, $body) {
|
||||||
|
$this->messages[] = '<p><b>'. $title .'</b><br>'. $body .'</p>';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
|
@ -134,6 +134,38 @@ function autodate($date, $html=true) {
|
|||||||
return ($html ? "<time datetime='$cpu'>$hum</time>" : $hum);
|
return ($html ? "<time datetime='$cpu'>$hum</time>" : $hum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given string is a valid date-time. ( Format: yyyy-mm-dd hh:mm:ss )
|
||||||
|
*
|
||||||
|
* @retval boolean
|
||||||
|
*/
|
||||||
|
function isValidDateTime($dateTime)
|
||||||
|
{
|
||||||
|
if (preg_match("/^(\d{4})-(\d{2})-(\d{2}) ([01][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$/", $dateTime, $matches)) {
|
||||||
|
if (checkdate($matches[2], $matches[3], $matches[1])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a given string is a valid date. ( Format: yyyy-mm-dd )
|
||||||
|
*
|
||||||
|
* @retval boolean
|
||||||
|
*/
|
||||||
|
function isValidDate($date)
|
||||||
|
{
|
||||||
|
if (preg_match("/^(\d{4})-(\d{2})-(\d{2})$/", $date, $matches)) {
|
||||||
|
// checkdate wants (month, day, year)
|
||||||
|
if (checkdate($matches[2], $matches[3], $matches[1])) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a pluraliser if necessary
|
* Return a pluraliser if necessary
|
||||||
|
Loading…
x
Reference in New Issue
Block a user