Allow to remove all archived entries

Since we still support fucking SQLite, we need to retrieve all tags & annotations for archived entries before deleting them.

Signed-off-by: Thomas Citharel <tcit@tcit.fr>
This commit is contained in:
Thomas Citharel 2017-03-30 16:24:59 +02:00 committed by Nicolas Lœuillet
parent fa884b30ba
commit 6da1aebc94
18 changed files with 205 additions and 1 deletions

View file

@ -122,4 +122,20 @@ class AnnotationRepository extends EntityRepository
->setParameter('userId', $userId)
->execute();
}
/**
* Find all annotations related to archived entries
*
* @param $userId
* @return mixed
*/
public function findAllByArchivedEntriesAndUserId($userId)
{
return $this->createQueryBuilder('a')
->leftJoin('a.entry', 'e')
->where('a.user = :userid')->setParameter(':userid', $userId)
->andWhere('e.isArchived = true')
->getQuery()
->getResult();
}
}

View file

@ -248,7 +248,7 @@ class ConfigController extends Controller
break;
case 'entries':
// SQLite doesn't care about cascading remove, so we need to manually remove associated stuf
// SQLite doesn't care about cascading remove, so we need to manually remove associated stuff
// otherwise they won't be removed ...
if ($this->get('doctrine')->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) {
$this->getDoctrine()->getRepository('WallabagAnnotationBundle:Annotation')->removeAllByUserId($this->getUser()->getId());
@ -260,6 +260,19 @@ class ConfigController extends Controller
$this->getDoctrine()
->getRepository('WallabagCoreBundle:Entry')
->removeAllByUserId($this->getUser()->getId());
break;
case 'archived':
if ($this->get('doctrine')->getConnection()->getDriver() instanceof \Doctrine\DBAL\Driver\PDOSqlite\Driver) {
$this->removeAnnotationsForArchivedByUserId($this->getUser()->getId());
}
// manually remove tags to avoid orphan tag
$this->removeTagsForArchivedByUserId($this->getUser()->getId());
$this->getDoctrine()
->getRepository('WallabagCoreBundle:Entry')
->removeArchivedByUserId($this->getUser()->getId());
break;
}
$this->get('session')->getFlashBag()->add(
@ -299,6 +312,50 @@ class ConfigController extends Controller
$em->flush();
}
/**
* Remove all tags for a given user and cleanup orphan tags.
*
* @param int $userId
*/
private function removeTagsForArchivedByUserId($userId)
{
$tags = $this->getDoctrine()->getRepository('WallabagCoreBundle:Tag')->findTagsForArchivedArticles($userId);
if (empty($tags)) {
return;
}
$this->getDoctrine()
->getRepository('WallabagCoreBundle:Entry')
->removeTags($userId, $tags);
// cleanup orphan tags
$em = $this->getDoctrine()->getManager();
foreach ($tags as $tag) {
if (count($tag->getEntries()) === 0) {
$em->remove($tag);
}
}
$em->flush();
}
private function removeAnnotationsForArchivedByUserId($userId)
{
$em = $this->getDoctrine()->getManager();
$archivedEntriesAnnotations = $this->getDoctrine()
->getRepository('WallabagAnnotationBundle:Annotation')
->findAllByArchivedEntriesAndUserId($userId);
foreach ($archivedEntriesAnnotations as $archivedEntriesAnnotation) {
$em->remove($archivedEntriesAnnotation);
}
$em->flush();
}
/**
* Validate that a rule can be edited/deleted by the current user.
*

View file

@ -371,4 +371,12 @@ class EntryRepository extends EntityRepository
->setParameter('userId', $userId)
->execute();
}
public function removeArchivedByUserId($userId)
{
$this->getEntityManager()
->createQuery('DELETE FROM Wallabag\CoreBundle\Entity\Entry e WHERE e.user = :userId AND e.isArchived = TRUE')
->setParameter('userId', $userId)
->execute();
}
}

View file

@ -76,4 +76,24 @@ class TagRepository extends EntityRepository
->getQuery()
->getSingleResult();
}
public function findTagsForArchivedArticles($userId)
{
$ids = $this->createQueryBuilder('t')
->select('t.id')
->leftJoin('t.entries', 'e')
->where('e.user = :userId')->setParameter('userId', $userId)
->andWhere('e.isArchived = true')
->groupBy('t.id')
->orderBy('t.slug')
->getQuery()
->getArrayResult();
$tags = [];
foreach ($ids as $id) {
$tags[] = $this->find($id);
}
return $tags;
}
}

View file

@ -110,6 +110,7 @@ config:
# annotations: Remove ALL annotations
# tags: Remove ALL tags
# entries: Remove ALL entries
# archived: Remove ALL archived entries
# confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
form_password:
# description: "You can change your password here. Your new password should by at least 8 characters long."
@ -528,6 +529,7 @@ flashes:
# annotations_reset: Annotations reset
# tags_reset: Tags reset
# entries_reset: Entries reset
# archived_reset: Archived entries deleted
entry:
notice:
# entry_already_saved: 'Entry already saved on %date%'

View file

@ -110,6 +110,7 @@ config:
annotations: Entferne ALLE Annotationen
tags: Entferne ALLE Tags
entries: Entferne ALLE Einträge
# archived: Remove ALL archived entries
confirm: Bist du wirklich sicher? (DIES KANN NICHT RÜCKGÄNGIG GEMACHT WERDEN)
form_password:
description: "Hier kannst du dein Kennwort ändern. Dieses sollte mindestens acht Zeichen enthalten."
@ -528,6 +529,7 @@ flashes:
annotations_reset: Anmerkungen zurücksetzen
tags_reset: Tags zurücksetzen
entries_reset: Einträge zurücksetzen
# archived_reset: Archived entries deleted
entry:
notice:
entry_already_saved: 'Eintrag bereits am %date% gespeichert'

View file

@ -110,6 +110,7 @@ config:
annotations: Remove ALL annotations
tags: Remove ALL tags
entries: Remove ALL entries
archived: Remove ALL archived entries
confirm: Are you really sure? (THIS CAN'T BE UNDONE)
form_password:
description: "You can change your password here. Your new password should by at least 8 characters long."
@ -528,6 +529,7 @@ flashes:
annotations_reset: Annotations reset
tags_reset: Tags reset
entries_reset: Entries reset
archived_reset: Archived entries deleted
entry:
notice:
entry_already_saved: 'Entry already saved on %date%'

View file

@ -110,6 +110,7 @@ config:
annotations: Eliminar TODAS las anotaciones
tags: Eliminar TODAS las etiquetas
entries: Eliminar TODOS los artículos
# archived: Remove ALL archived entries
confirm: ¿Estás completamente seguro? (NO SE PUEDE DESHACER)
form_password:
description: "Puedes cambiar la contraseña aquí. Tu nueva contraseña debe tener al menos 8 caracteres."
@ -528,6 +529,7 @@ flashes:
annotations_reset: Anotaciones reiniciadas
tags_reset: Etiquetas reiniciadas
entries_reset: Artículos reiniciados
# archived_reset: Archived entries deleted
entry:
notice:
entry_already_saved: 'Artículo ya guardado el %fecha%'

View file

@ -110,6 +110,7 @@ config:
# annotations: Remove ALL annotations
# tags: Remove ALL tags
# entries: Remove ALL entries
# archived: Remove ALL archived entries
# confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
form_password:
# description: "You can change your password here. Your new password should by at least 8 characters long."
@ -528,6 +529,7 @@ flashes:
# annotations_reset: Annotations reset
# tags_reset: Tags reset
# entries_reset: Entries reset
# archived_reset: Archived entries deleted
entry:
notice:
entry_already_saved: 'این مقاله در تاریخ %date% ذخیره شده بود'

View file

@ -110,6 +110,7 @@ config:
annotations: Supprimer TOUTES les annotations
tags: Supprimer TOUS les tags
entries: Supprimer TOUS les articles
archived: Supprimer TOUS les articles archivés
confirm: Êtes-vous vraiment vraiment sûr ? (C'EST IRRÉVERSIBLE)
form_password:
description: "Vous pouvez changer ici votre mot de passe. Le mot de passe doit contenir au moins 8 caractères."
@ -528,6 +529,7 @@ flashes:
annotations_reset: Annotations supprimées
tags_reset: Tags supprimés
entries_reset: Articles supprimés
archived_reset: Articles archivés supprimés
entry:
notice:
entry_already_saved: "Article déjà sauvegardé le %date%"

View file

@ -110,6 +110,7 @@ config:
# annotations: Remove ALL annotations
# tags: Remove ALL tags
# entries: Remove ALL entries
# archived: Remove ALL archived entries
# confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
form_password:
# description: "You can change your password here. Your new password should by at least 8 characters long."
@ -528,6 +529,7 @@ flashes:
# annotations_reset: Annotations reset
# tags_reset: Tags reset
# entries_reset: Entries reset
# archived_reset: Archived entries deleted
entry:
notice:
entry_already_saved: 'Contenuto già salvato in data %date%'

View file

@ -110,6 +110,7 @@ config:
annotations: Levar TOTAS las anotacions
tags: Levar TOTAS las etiquetas
entries: Levar TOTES los articles
# archived: Remove ALL archived entries
confirm: Sètz vertadièrament segur ? (ES IRREVERSIBLE)
form_password:
description: "Podètz cambiar vòstre senhal aquí. Vòstre senhal deu èsser long d'almens 8 caractèrs."
@ -528,6 +529,7 @@ flashes:
annotations_reset: Anotacions levadas
tags_reset: Etiquetas levadas
entries_reset: Articles levats
# archived_reset: Archived entries deleted
entry:
notice:
entry_already_saved: 'Article ja salvargardat lo %date%'

View file

@ -110,6 +110,7 @@ config:
annotations: Usuń WSZYSTKIE adnotacje
tags: Usuń WSZYSTKIE tagi
entries: usuń WSZYTSTKIE wpisy
# archived: Remove ALL archived entries
confirm: Jesteś pewien? (tej operacji NIE MOŻNA cofnąć)
form_password:
description: "Tutaj możesz zmienić swoje hasło. Twoje nowe hasło powinno mieć conajmniej 8 znaków."
@ -528,6 +529,7 @@ flashes:
annotations_reset: Zresetuj adnotacje
tags_reset: Zresetuj tagi
entries_reset: Zresetuj wpisy
# archived_reset: Archived entries deleted
entry:
notice:
entry_already_saved: 'Wpis już został dodany %date%'

View file

@ -110,6 +110,7 @@ config:
# annotations: Remove ALL annotations
# tags: Remove ALL tags
# entries: Remove ALL entries
# archived: Remove ALL archived entries
# confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
form_password:
# description: "You can change your password here. Your new password should by at least 8 characters long."
@ -528,6 +529,7 @@ flashes:
# annotations_reset: Annotations reset
# tags_reset: Tags reset
# entries_reset: Entries reset
# archived_reset: Archived entries deleted
entry:
notice:
entry_already_saved: 'Entrada já foi salva em %date%'

View file

@ -110,6 +110,7 @@ config:
# annotations: Remove ALL annotations
# tags: Remove ALL tags
# entries: Remove ALL entries
# archived: Remove ALL archived entries
# confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
form_password:
# description: "You can change your password here. Your new password should by at least 8 characters long."
@ -528,6 +529,7 @@ flashes:
# annotations_reset: Annotations reset
# tags_reset: Tags reset
# entries_reset: Entries reset
# archived_reset: Archived entries deleted
entry:
notice:
# entry_already_saved: 'Entry already saved on %date%'

View file

@ -110,6 +110,7 @@ config:
# annotations: Remove ALL annotations
# tags: Remove ALL tags
# entries: Remove ALL entries
# archived: Remove ALL archived entries
# confirm: Are you really really sure? (THIS CAN'T BE UNDONE)
form_password:
# description: "You can change your password here. Your new password should by at least 8 characters long."
@ -528,6 +529,7 @@ flashes:
# annotations_reset: Annotations reset
# tags_reset: Tags reset
# entries_reset: Entries reset
# archived_reset: Archived entries deleted
entry:
notice:
entry_already_saved: 'Entry already saved on %date%'

View file

@ -229,6 +229,9 @@
<a href="{{ path('config_reset', { type: 'tags'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
{{ 'config.reset.tags'|trans }}
</a>
<a href="{{ path('config_reset', { type: 'archived'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
{{ 'config.reset.archived'|trans }}
</a>
<a href="{{ path('config_reset', { type: 'entries'}) }}" onclick="return confirm('{{ 'config.reset.confirm'|trans|escape('js') }}')" class="waves-effect waves-light btn red">
{{ 'config.reset.entries'|trans }}
</a>

View file

@ -803,6 +803,82 @@ class ConfigControllerTest extends WallabagCoreTestCase
$this->assertEquals(0, $entryReset, 'Entries were reset');
}
public function testResetArchivedEntries()
{
$this->logInAs('empty');
$client = $this->getClient();
$em = $client->getContainer()->get('doctrine.orm.entity_manager');
$user = static::$kernel->getContainer()->get('security.token_storage')->getToken()->getUser();
$tag = new Tag();
$tag->setLabel('super');
$em->persist($tag);
$entry = new Entry($user);
$entry->setUrl('http://www.lemonde.fr/europe/article/2016/10/01/pour-le-psoe-chaque-election-s-est-transformee-en-une-agonie_5006476_3214.html');
$entry->setContent('Youhou');
$entry->setTitle('Youhou');
$entry->addTag($tag);
$em->persist($entry);
$annotation = new Annotation($user);
$annotation->setText('annotated');
$annotation->setQuote('annotated');
$annotation->setRanges([]);
$annotation->setEntry($entry);
$em->persist($annotation);
$tagArchived = new Tag();
$tagArchived->setLabel('super');
$em->persist($tagArchived);
$entryArchived = new Entry($user);
$entryArchived->setUrl('http://www.lemonde.fr/europe/article/2016/10/01/pour-le-psoe-chaque-election-s-est-transformee-en-une-agonie_5006476_3214.html');
$entryArchived->setContent('Youhou');
$entryArchived->setTitle('Youhou');
$entryArchived->addTag($tagArchived);
$entryArchived->setArchived(true);
$em->persist($entryArchived);
$annotationArchived = new Annotation($user);
$annotationArchived->setText('annotated');
$annotationArchived->setQuote('annotated');
$annotationArchived->setRanges([]);
$annotationArchived->setEntry($entryArchived);
$em->persist($annotationArchived);
$em->flush();
$crawler = $client->request('GET', '/config#set3');
$this->assertEquals(200, $client->getResponse()->getStatusCode());
$crawler = $client->click($crawler->selectLink('config.reset.archived')->link());
$this->assertEquals(302, $client->getResponse()->getStatusCode());
$this->assertContains('flashes.config.notice.archived_reset', $client->getContainer()->get('session')->getFlashBag()->get('notice')[0]);
$entryReset = $em
->getRepository('WallabagCoreBundle:Entry')
->countAllEntriesByUsername($user->getId());
$this->assertEquals(1, $entryReset, 'Entries were reset');
$tagReset = $em
->getRepository('WallabagCoreBundle:Tag')
->countAllTags($user->getId());
$this->assertEquals(1, $tagReset, 'Tags were reset');
$annotationsReset = $em
->getRepository('WallabagAnnotationBundle:Annotation')
->findAnnotationsByPageId($annotationArchived->getId(), $user->getId());
$this->assertEmpty($annotationsReset, 'Annotations were reset');
}
public function testResetEntriesCascade()
{
$this->logInAs('empty');