Skip to content

Commit

Permalink
version 2.1.0
Browse files Browse the repository at this point in the history
* Unterstützung für Slices
* Refactoring
* Bugfixing
  • Loading branch information
Hirbod Mirjavadi committed Mar 19, 2017
1 parent b8982f1 commit 31db007
Show file tree
Hide file tree
Showing 7 changed files with 157 additions and 66 deletions.
9 changes: 6 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# undo
Mit diesem AddOn kann ein gelöschter Artikel oder eine gelöschte Kategorie wiederhergestellt werden. Das Wiederherstellen funktioniert nur einen einzigen Pageload lang. Sobald die Seite oder ein neuer Tab geladen wird, ist ein Revert nicht mehr möglich (soll nur vor versehentlichem Löschen schützen).
Mit diesem AddOn kann ein gelöschter Artikel, Slice oder eine gelöschte Kategorie wiederhergestellt werden. Das Wiederherstellen funktioniert nur einen einzigen Pageload lang. Sobald die Seite oder ein neuer Tab geladen wird, ist ein Revert nicht mehr möglich (soll nur vor versehentlichem Löschen schützen).

![Screenshot](https://raw.githubusercontent.com/FriendsOfREDAXO/undo/assets/screenshot.png)

Changelog
------------
Version 2.0.4
* Sprachfix
Version 2.1.0
* Unterstützung für Slices
* Refactoring
* Bugfixing

Version 2.0.2
* Auto-Repair Funktion, wenn der Core oder ein AddOn die rex_article oder rex_article_slice verändert _(Das AddOn muss nicht mehr neu installiert werden.)_
Expand Down Expand Up @@ -35,6 +37,7 @@ Voraussetzungen
------------

* REDAXO >= 5.3.0
* structure AddOn

ToDo
-----
Expand Down
140 changes: 80 additions & 60 deletions boot.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,13 @@
rex_perm::register('undo[]');

// Check for vars in url
$mode = rex_request('mode', 'string', false);
$mode = rex_request('undo_mode', 'string', false);
$aid = rex_request('aid', 'int', false);
$article_id = rex_request('article_id', 'int', false);
$category_id = rex_request('category_id', 'int', false);
$slice_restore_id = rex_request('slice_restore_id', 'int', false);
$type = rex_request('type', 'string', '');
$ctype = rex_request('ctype', 'int', 1);
$deleteQueue = true;

/*
Expand All @@ -24,22 +27,26 @@
// Listen on EP to save a tmp state
rex_extension::register('ART_PRE_DELETED', function (rex_extension_point $ep) {
$content = $ep->getParams();
$ART = rex_sql::factory();

try {
$ART->setQuery('INSERT INTO '.rex::getTablePrefix().'article_undo SELECT * FROM '.rex::getTablePrefix().'article where id=?', [$content['id']]);
$ART->setQuery('INSERT INTO '.rex::getTablePrefix().'article_slice_undo SELECT * FROM '.rex::getTablePrefix().'article_slice where article_id=?', [$content['id']]);
undo::saveArticle($content['id']);
} catch (Exception $e) {
/* Table was changed, we need to reinstall it */
$ART->setQuery('DROP TABLE IF EXISTS '.rex::getTable('article_undo'));
$ART->setQuery('DROP TABLE IF EXISTS '.rex::getTable('article_slice_undo'));
if (undo::fixTables()) {
undo::saveArticle($content['id']);
}
}

});

$ART->setQuery('CREATE TABLE IF NOT EXISTS '.rex::getTable('article_undo').' LIKE '.rex::getTable('article'));
$ART->setQuery('CREATE TABLE IF NOT EXISTS '.rex::getTable('article_slice_undo').' LIKE '.rex::getTable('article_slice'));
rex_extension::register('SLICE_DELETE', function (rex_extension_point $ep) {
$content = $ep->getParams();

// Retry last insert undo action
$ART->setQuery('INSERT INTO '.rex::getTablePrefix().'article_undo SELECT * FROM '.rex::getTablePrefix().'article where id=?', [$content['id']]);
$ART->setQuery('INSERT INTO '.rex::getTablePrefix().'article_slice_undo SELECT * FROM '.rex::getTablePrefix().'article_slice where article_id=?', [$content['id']]);
try {
undo::saveSlice($content['slice_id']);
} catch (Exception $e) {
if (undo::fixTables()) {
undo::saveSlice($content['slice_id']);
}
}

});
Expand All @@ -49,67 +56,85 @@
$content = $ep->getParams();
$deleteQueue = false;

return rex_i18n::msg('article_deleted')." <a href='?page=structure&mode=undo&type=art&category_id=".$category_id.'&aid='.$content['id'].'&clang='.rex_clang::getCurrentId()."'>".rex_i18n::msg('undo_undo_action').'</a>.';
return rex_i18n::msg('article_deleted')." <a href='?page=structure&undo_mode=undo&type=art&category_id=".$category_id.'&aid='.$content['id'].'&clang='.rex_clang::getCurrentId()."'>".rex_i18n::msg('undo_undo_action').'</a>.';
});

// output message with undo-link for slices
rex_extension::register('SLICE_DELETED', function (rex_extension_point $ep) use (&$deleteQueue, $category_id) {
$content = $ep->getParams();
$deleteQueue = false;

return rex_i18n::msg('block_deleted')." <a href='?page=content/edit&undo_mode=undo&pjax=false&mode=edit&type=slice&category_id=".$category_id.'&article_id='.$content['article_id'].'&slice_restore_id='.$content['slice_id'].'&ctype='.$content['ctype'].'&clang='.rex_clang::getCurrentId()."'>".rex_i18n::msg('undo_undo_action').'</a>.';
});

// output message with undo-link for categories
rex_extension::register('CAT_DELETED', function (rex_extension_point $ep) use (&$deleteQueue, $category_id) {
$content = $ep->getParams();
$deleteQueue = false;

return rex_i18n::msg('category_deleted')." <a href='?page=structure&mode=undo&type=cat&category_id=".$category_id.'&aid='.$content['id'].'&clang='.rex_clang::getCurrentId()."'>".rex_i18n::msg('undo_undo_action').'</a>.';
return rex_i18n::msg('category_deleted')." <a href='?page=structure&undo_mode=undo&type=cat&category_id=".$category_id.'&aid='.$content['id'].'&clang='.rex_clang::getCurrentId()."'>".rex_i18n::msg('undo_undo_action').'</a>.';
});

// undo magic if link was clicked
if ($mode == 'undo') {

// we need to register late, or we wont be able to triggr ART_UPDATED / CAT_UPDATED
rex_extension::register('PACKAGES_INCLUDED', function (rex_extension_point $ep) use ($mode, $aid, $category_id, $type) {
rex_extension::register('PACKAGES_INCLUDED', function (rex_extension_point $ep) use ($mode, $aid, $category_id, $type, $slice_restore_id, $ctype, $article_id) {

$outputMsg = '';

$sql = rex_sql::factory();
//$sql->setDebug();
$elements = $sql->getArray('SELECT name,catname,parent_id,catpriority,priority,status,clang_id,template_id FROM '.rex::getTablePrefix().'article_undo where id=?', [$aid]);

if ($sql->getRows()) {
$i = 1;
foreach ($elements as $e) {
$parent_id = $e['parent_id'];
$template_id = $e['template_id'];
$status = $e['status'];

$artpriority = $e['priority'];
$artname = $e['name'];

$catname = $e['catname'];
$catpriority = $e['catpriority'];

$clang = $e['clang_id'];

$ART = rex_sql::factory();
$ART->setQuery('INSERT INTO '.rex::getTablePrefix().'article SELECT * FROM '.rex::getTablePrefix().'article_undo where id=? and clang_id=?', [$aid, $clang]);
// slices just need to get inserted once
if ($counter === 1) {
$ART->setQuery('INSERT INTO '.rex::getTablePrefix().'article_slice SELECT * FROM '.rex::getTablePrefix().'article_slice_undo where article_id=?', [$aid]);
}

switch ($type) {
case 'cat':
$outputMsg = rex_i18n::msg('undo_category_restored');
rex_category_service::newCatPrio($parent_id, $clang, $catpriority, 0);
rex_category_service::editCategory($aid, $clang, array('catpriority' => $catpriority, 'catname' => $catname));
break;

default:
$outputMsg = rex_i18n::msg('undo_article_restored');
rex_article_service::newArtPrio($category_id, $clang, $artpriority, 0);
rex_article_service::editArticle($aid, $clang, array('name' => $artname, 'template_id' => $template_id, 'priority' => $artpriority, 'status' => $status));
break;
if ($type == 'cat' || $type == 'art') {
$sql = rex_sql::factory();
$elements = $sql->getArray('SELECT name,catname,parent_id,catpriority,priority,status,clang_id,template_id FROM '.rex::getTable('article_undo').' where id=?', [$aid]);

if ($sql->getRows()) {
$i = 1;
foreach ($elements as $e) {
$parent_id = $e['parent_id'];
$template_id = $e['template_id'];
$status = $e['status'];

$artpriority = $e['priority'];
$artname = $e['name'];

$catname = $e['catname'];
$catpriority = $e['catpriority'];

$clang = $e['clang_id'];

$ART = rex_sql::factory();
$ART->setQuery('INSERT INTO '.rex::getTable('article').' SELECT * FROM '.rex::getTable('article_undo').' where id=? and clang_id=?', [$aid, $clang]);
// slices just need to get inserted once
if ($i === 1) {
$ART->setQuery('INSERT INTO '.rex::getTable('article_slice').' SELECT * FROM '.rex::getTable('article_slice_undo').' where article_id=?', [$aid]);
}

switch ($type) {
case 'cat':
$outputMsg = rex_i18n::msg('undo_category_restored');
rex_category_service::newCatPrio($parent_id, $clang, $catpriority, 0);
rex_category_service::editCategory($aid, $clang, array('catpriority' => $catpriority, 'catname' => $catname));
break;

default:
$outputMsg = rex_i18n::msg('undo_article_restored');
rex_article_service::newArtPrio($category_id, $clang, $artpriority, 0);
rex_article_service::editArticle($aid, $clang, array('name' => $artname, 'template_id' => $template_id, 'priority' => $artpriority, 'status' => $status));
break;
}
++$i;
}
++$i;
}
} elseif ($type == 'slice') {
$outputMsg = rex_i18n::msg('undo_slice_restored');
$slice = rex_sql::factory();
$slice->setQuery('INSERT INTO '.rex::getTable('article_slice').' SELECT * FROM '.rex::getTable('article_slice_undo').' WHERE id=?', [$slice_restore_id]);
undo::fixSlicePrio($article_id, $ctype);
rex_article_cache::delete($article_id, rex_clang::getCurrentId());
undo::deleteQueue();
}

if ($outputMsg) {
rex_extension::register('PAGE_TITLE', function (rex_extension_point $ep) use ($outputMsg) {
return rex_view::success($outputMsg);
});
Expand All @@ -119,12 +144,7 @@
} else {
/* Undo-Action will only last for one page reload */
if ($deleteQueue) {
$ART = rex_sql::factory();
$ART->setQuery('SELECT id FROM '.rex::getTablePrefix().'article_undo LIMIT 1');
if ($ART->getRows()) {
$ART->setQuery('DELETE FROM '.rex::getTablePrefix().'article_undo');
$ART->setQuery('DELETE FROM '.rex::getTablePrefix().'article_slice_undo');
}
undo::deleteQueue();
}
}
}
1 change: 1 addition & 0 deletions lang/de_de.lang
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
undo_undo_action = Rückgängig machen
undo_article_restored = Artikel wurde wiederhergestellt!
undo_category_restored = Kategorie wurde wiederhergestellt!
undo_slice_restored = Block wurde wiederhergestellt!


# Benennung für die Addonrechte, sichtbar innerhalb der REDAXO-Administration unter Benutzer > Rollen > Allgemein
Expand Down
2 changes: 1 addition & 1 deletion lang/en_gb.lang
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
undo_undo_action = Undo
undo_article_restored = Article has been restored!
undo_category_restored = Category has been restored!

undo_slice_restored = Block has been restored!

# Benennung für die Addonrechte, sichtbar innerhalb der REDAXO-Administration unter Benutzer > Rollen > Allgemein

Expand Down
1 change: 1 addition & 0 deletions lang/fr_fr.lang
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
undo_undo_action = Undo
undo_article_restored = Le produit a été récupéré!
undo_category_restored = Catégorie a été restauré!
undo_slice_restored = Bloc a été restauré!


# Benennung für die Addonrechte, sichtbar innerhalb der REDAXO-Administration unter Benutzer > Rollen > Allgemein
Expand Down
66 changes: 66 additions & 0 deletions lib/undo.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

/**
* undo Addon.
*
* @author Friends Of REDAXO
*
* @var rex_addon
*/
class undo
{
/* will also save categories, as it's in the same table */
public static function saveArticle($id)
{
$art = rex_sql::factory();
$art->setQuery('INSERT INTO '.rex::getTable('article_undo').' SELECT * FROM '.rex::getTable('article').' WHERE id=?', [$id]);
$art->setQuery('INSERT INTO '.rex::getTable('article_slice_undo').' SELECT * FROM '.rex::getTable('article_slice').' WHERE article_id=?', [$id]);
}

public static function deleteQueue()
{
$art = rex_sql::factory();
$art->setQuery('SELECT id FROM '.rex::getTable('article_undo').' LIMIT 1');
$slice = rex_sql::factory();
$slice->setQuery('SELECT id FROM '.rex::getTable('article_slice_undo').' LIMIT 1');

if ($art->getRows() || $slice->getRows()) {
$art->setQuery('DELETE FROM '.rex::getTable('article_undo'));

This comment has been minimized.

Copy link
@staabm

staabm Jul 3, 2018

Member

wird hier bewusst die komplette article undo historie gelöscht, nicht nur die zu einem speziellen Artikel o.ä.?

warum passieren vorher die selects auf ID, wenn das ergebnis daraus nirgends verwendet wird?

This comment has been minimized.

Copy link
@hirbod

hirbod Jul 4, 2018

Contributor

Ja, einfach nur der Einfachheit halber. Die Table wird eh immer nur für einen Datensatz benötigt und beim nächsten Pagereload gelöscht. Ich habe bewusst nicht TRUNCATE genutzt, da es zu Locks kam bzw das Ladeverhalten dadurch beeinträchtigt wurde. Der SELECT ist nur dafür da, um zu prüfen, ob es einen Datensatz gibt.

Bin offen für Verbesserungsvorschläge

This comment has been minimized.

Copy link
@staabm

staabm Jul 4, 2018

Member

Hmm d.h. 2 user gleizeitig können sich das undo aktuell gegenseitig „kaputt“ machen?

This comment has been minimized.

Copy link
@hirbod

hirbod Jul 4, 2018

Contributor

Theoretisch ja, an diesen Zustand habe ich bei der Entwicklung auch gedacht, aber keine Lösung für entwickelt, da mir die Zeit gefehlt hatte.

$art->setQuery('DELETE FROM '.rex::getTable('article_slice_undo'));
}
}

public static function fixSlicePrio($article_id, $ctype, $slice_revision = 0)
{
dump($article_id);
dump($ctype);
rex_sql_util::organizePriorities(
rex::getTable('article_slice'),
'priority',
'article_id='.(int) $article_id.' AND clang_id='.(int) rex_clang::getCurrentId().' AND ctype_id='.(int) $ctype.' AND revision='.(int) $slice_revision,
'priority, updatedate DESC'
);
}

public static function saveSlice($id)
{
$slice = rex_sql::factory();
$slice->setQuery('INSERT INTO '.rex::getTable('article_slice_undo').' SELECT * FROM '.rex::getTable('article_slice').' WHERE id=? AND clang_id=?', [$id, rex_clang::getCurrentId()]);
}

public static function fixTables()
{
try {
$art = rex_sql::factory();
$art->setQuery('DROP TABLE IF EXISTS '.rex::getTable('article_undo'));
$art->setQuery('DROP TABLE IF EXISTS '.rex::getTable('article_slice_undo'));

$art->setQuery('CREATE TABLE IF NOT EXISTS '.rex::getTable('article_undo').' LIKE '.rex::getTable('article'));
$art->setQuery('CREATE TABLE IF NOT EXISTS '.rex::getTable('article_slice_undo').' LIKE '.rex::getTable('article_slice'));

return true;
} catch (Exception $e) {
return false;
}
}
}
4 changes: 2 additions & 2 deletions package.yml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package: undo
version: '2.0.4'
author: FriendsOfREDAXO
version: '2.1.0'
author: Friends Of REDAXO
supportpage: github.com/FriendsOfREDAXO/undo

requires:
Expand Down

0 comments on commit 31db007

Please sign in to comment.