1
0
Fork 0
mirror of https://github.com/wallabag/wallabag.git synced 2025-08-26 18:21:02 +00:00

Merge remote-tracking branch 'origin/master' into 2.2

This commit is contained in:
Jeremy Benoist 2016-10-11 21:01:30 +02:00
commit e4cf672ccf
No known key found for this signature in database
GPG key ID: BCA73962457ACC3C
74 changed files with 1595 additions and 1519 deletions

View file

@ -1,12 +1,12 @@
<?php
namespace Wallabag\CoreBundle\Controller;
namespace Wallabag\ApiBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Wallabag\ApiBundle\Entity\Client;
use Wallabag\CoreBundle\Form\Type\ClientType;
use Wallabag\ApiBundle\Form\Type\ClientType;
class DeveloperController extends Controller
{

View file

@ -27,7 +27,8 @@ class WallabagRestController extends FOSRestController
*
* @ApiDoc(
* parameters={
* {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="Url to check if it exists"}
* {"name"="url", "dataType"="string", "required"=true, "format"="An url", "description"="Url to check if it exists"},
* {"name"="urls", "dataType"="string", "required"=false, "format"="An array of urls (?urls[]=http...&urls[]=http...)", "description"="Urls (as an array) to check if it exists"}
* }
* )
*
@ -37,6 +38,25 @@ class WallabagRestController extends FOSRestController
{
$this->validateAuthentication();
$urls = $request->query->get('urls', []);
// handle multiple urls first
if (!empty($urls)) {
$results = [];
foreach ($urls as $url) {
$res = $this->getDoctrine()
->getRepository('WallabagCoreBundle:Entry')
->findByUrlAndUserId($url, $this->getUser()->getId());
$results[$url] = false === $res ? false : true;
}
$json = $this->get('serializer')->serialize($results, 'json');
return (new JsonResponse())->setJson($json);
}
// let's see if it is a simple url?
$url = $request->query->get('url', '');
if (empty($url)) {
@ -367,7 +387,7 @@ class WallabagRestController extends FOSRestController
$tags = $this->getDoctrine()
->getRepository('WallabagCoreBundle:Tag')
->findAllTagsWithEntries($this->getUser()->getId());
->findAllTags($this->getUser()->getId());
$json = $this->get('serializer')->serialize($tags, 'json');
@ -400,6 +420,8 @@ class WallabagRestController extends FOSRestController
->getRepository('WallabagCoreBundle:Entry')
->removeTag($this->getUser()->getId(), $tag);
$this->cleanOrphanTag($tag);
$json = $this->get('serializer')->serialize($tag, 'json');
return (new JsonResponse())->setJson($json);
@ -440,6 +462,8 @@ class WallabagRestController extends FOSRestController
->getRepository('WallabagCoreBundle:Entry')
->removeTags($this->getUser()->getId(), $tags);
$this->cleanOrphanTag($tags);
$json = $this->get('serializer')->serialize($tags, 'json');
return (new JsonResponse())->setJson($json);
@ -464,6 +488,8 @@ class WallabagRestController extends FOSRestController
->getRepository('WallabagCoreBundle:Entry')
->removeTag($this->getUser()->getId(), $tag);
$this->cleanOrphanTag($tag);
$json = $this->get('serializer')->serialize($tag, 'json');
return (new JsonResponse())->setJson($json);
@ -485,6 +511,28 @@ class WallabagRestController extends FOSRestController
return (new JsonResponse())->setJson($json);
}
/**
* Remove orphan tag in case no entries are associated to it.
*
* @param Tag|array $tags
*/
private function cleanOrphanTag($tags)
{
if (!is_array($tags)) {
$tags = [$tags];
}
$em = $this->getDoctrine()->getManager();
foreach ($tags as $tag) {
if (count($tag->getEntries()) === 0) {
$em->remove($tag);
}
}
$em->flush();
}
/**
* Validate that the first id is equal to the second one.
* If not, throw exception. It means a user try to access information from an other user.

View file

@ -19,7 +19,7 @@ class AccessToken extends BaseAccessToken
protected $id;
/**
* @ORM\ManyToOne(targetEntity="Client")
* @ORM\ManyToOne(targetEntity="Client", inversedBy="accessTokens")
* @ORM\JoinColumn(nullable=false)
*/
protected $client;

View file

@ -25,6 +25,16 @@ class Client extends BaseClient
*/
protected $name;
/**
* @ORM\OneToMany(targetEntity="RefreshToken", mappedBy="client", cascade={"remove"})
*/
protected $refreshTokens;
/**
* @ORM\OneToMany(targetEntity="AccessToken", mappedBy="client", cascade={"remove"})
*/
protected $accessTokens;
public function __construct()
{
parent::__construct();

View file

@ -19,7 +19,7 @@ class RefreshToken extends BaseRefreshToken
protected $id;
/**
* @ORM\ManyToOne(targetEntity="Client")
* @ORM\ManyToOne(targetEntity="Client", inversedBy="refreshTokens")
* @ORM\JoinColumn(nullable=false)
*/
protected $client;

View file

@ -1,6 +1,6 @@
<?php
namespace Wallabag\CoreBundle\Form\Type;
namespace Wallabag\ApiBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\CallbackTransformer;

View file

@ -9,7 +9,7 @@ use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Output\BufferedOutput;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\Question;
@ -97,7 +97,8 @@ class InstallCommand extends ContainerAwareCommand
try {
$this->getContainer()->get('doctrine')->getManager()->getConnection()->connect();
} catch (\Exception $e) {
if (false === strpos($e->getMessage(), 'Unknown database')) {
if (false === strpos($e->getMessage(), 'Unknown database')
&& false === strpos($e->getMessage(), 'database "'.$this->getContainer()->getParameter('database_name').'" does not exist')) {
$fulfilled = false;
$status = '<error>ERROR!</error>';
$help = 'Can\'t connect to the database: '.$e->getMessage();
@ -420,16 +421,18 @@ class InstallCommand extends ContainerAwareCommand
}
$this->getApplication()->setAutoExit(false);
$exitCode = $this->getApplication()->run(new ArrayInput($parameters), new NullOutput());
$output = new BufferedOutput();
$exitCode = $this->getApplication()->run(new ArrayInput($parameters), $output);
if (0 !== $exitCode) {
$this->getApplication()->setAutoExit(true);
$errorMessage = sprintf('The command "%s" terminated with an error code: %u.', $command, $exitCode);
$this->defaultOutput->writeln("<error>$errorMessage</error>");
$exception = new \Exception($errorMessage, $exitCode);
$this->defaultOutput->writeln('');
$this->defaultOutput->writeln('<error>The command "'.$command.'" generates some errors: </error>');
$this->defaultOutput->writeln($output->fetch());
throw $exception;
die();
}
// PDO does not always close the connection after Doctrine commands.

View file

@ -34,10 +34,13 @@ class TagAllCommand extends ContainerAwareCommand
}
$tagger = $this->getContainer()->get('wallabag_core.rule_based_tagger');
$output->write(sprintf('Tagging entries for user « <info>%s</info> »... ', $user->getUserName()));
$output->write(sprintf('Tagging entries for user « <comment>%s</comment> »... ', $user->getUserName()));
$entries = $tagger->tagAllForUser($user);
$output->writeln('<info>Done.</info>');
$output->write(sprintf('Persist entries ... ', $user->getUserName()));
$em = $this->getDoctrine()->getManager();
foreach ($entries as $entry) {
$em->persist($entry);

View file

@ -63,10 +63,12 @@ class TagController extends Controller
$entry->removeTag($tag);
$em = $this->getDoctrine()->getManager();
$em->flush();
if (count($tag->getEntries()) == 0) {
// remove orphan tag in case no entries are associated to it
if (count($tag->getEntries()) === 0) {
$em->remove($tag);
$em->flush();
}
$em->flush();
$redirectUrl = $this->get('wallabag_core.helper.redirect')->to($request->headers->get('referer'));
@ -84,10 +86,25 @@ class TagController extends Controller
{
$tags = $this->getDoctrine()
->getRepository('WallabagCoreBundle:Tag')
->findAllTagsWithEntries($this->getUser()->getId());
->findAllTags($this->getUser()->getId());
$flatTags = [];
foreach ($tags as $key => $tag) {
$nbEntries = $this->getDoctrine()
->getRepository('WallabagCoreBundle:Entry')
->countAllEntriesByUserIdAndTagId($this->getUser()->getId(), $tag['id']);
$flatTags[] = [
'id' => $tag['id'],
'label' => $tag['label'],
'slug' => $tag['slug'],
'nbEntries' => $nbEntries,
];
}
return $this->render('WallabagCoreBundle:Tag:tags.html.twig', [
'tags' => $tags,
'tags' => $flatTags,
]);
}

View file

@ -55,6 +55,7 @@ class RuleBasedTagger
{
$rules = $this->getRulesForUser($user);
$entries = [];
$tagsCache = [];
foreach ($rules as $rule) {
$qb = $this->entryRepository->getBuilderForAllByUser($user->getId());
@ -62,7 +63,12 @@ class RuleBasedTagger
foreach ($entries as $entry) {
foreach ($rule->getTags() as $label) {
$tag = $this->getTag($label);
// avoid new tag duplicate by manually caching them
if (!isset($tagsCache[$label])) {
$tagsCache[$label] = $this->getTag($label);
}
$tag = $tagsCache[$label];
$entry->addTag($tag);
}

View file

@ -309,4 +309,24 @@ class EntryRepository extends EntityRepository
return $qb->getQuery()->getSingleScalarResult();
}
/**
* Count all entries for a tag and a user.
*
* @param int $userId
* @param int $tagId
*
* @return int
*/
public function countAllEntriesByUserIdAndTagId($userId, $tagId)
{
$qb = $this->createQueryBuilder('e')
->select('count(e.id)')
->leftJoin('e.tags', 't')
->where('e.user=:userId')->setParameter('userId', $userId)
->andWhere('t.id=:tagId')->setParameter('tagId', $tagId)
;
return $qb->getQuery()->getSingleScalarResult();
}
}

View file

@ -33,19 +33,23 @@ class TagRepository extends EntityRepository
}
/**
* Find all tags with associated entries per user.
* Find all tags per user.
*
* @param int $userId
*
* @return array
*/
public function findAllTagsWithEntries($userId)
public function findAllTags($userId)
{
return $this->createQueryBuilder('t')
->select('t.slug', 't.label', 't.id')
->leftJoin('t.entries', 'e')
->where('e.user = :userId')->setParameter('userId', $userId)
->groupBy('t.slug')
->addGroupBy('t.label')
->addGroupBy('t.id')
->getQuery()
->getResult();
->getArrayResult();
}
/**

View file

@ -29,7 +29,7 @@ services:
arguments:
- "@doctrine"
wallabag_core.table_prefix_subscriber:
wallabag_core.subscriber.table_prefix:
class: Wallabag\CoreBundle\Subscriber\TablePrefixSubscriber
arguments:
- "%database_table_prefix%"

View file

@ -200,7 +200,7 @@ entry:
description: 'Vises artiklen forkert?'
edit_title: 'Rediger titel'
original_article: 'original'
# annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %nbAnnotations% annotations'
# annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations'
created_at: 'Oprettelsesdato'
new:
page_title: 'Gem ny artikel'

View file

@ -200,7 +200,7 @@ entry:
description: 'Erscheint dieser Artikel falsch?'
edit_title: 'Titel ändern'
original_article: 'original'
annotations_on_the_entry: '{0} Keine Anmerkungen|{1} Eine Anmerkung|]1,Inf[ %nbAnnotations% Anmerkungen'
annotations_on_the_entry: '{0} Keine Anmerkungen|{1} Eine Anmerkung|]1,Inf[ %count% Anmerkungen'
created_at: 'Erstellungsdatum'
new:
page_title: 'Neuen Artikel speichern'

View file

@ -200,7 +200,7 @@ entry:
description: 'Does this article appear wrong?'
edit_title: 'Edit title'
original_article: 'original'
annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %nbAnnotations% annotations'
annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations'
created_at: 'Creation date'
new:
page_title: 'Save new entry'

View file

@ -200,7 +200,7 @@ entry:
description: '¿Este artículo no se muestra bien?'
edit_title: 'Modificar el título'
original_article: 'original'
annotations_on_the_entry: '{0} Sin anotaciones|{1} Una anotación|]1,Inf[ %nbAnnotations% anotaciones'
annotations_on_the_entry: '{0} Sin anotaciones|{1} Una anotación|]1,Inf[ %count% anotaciones'
created_at: 'Fecha de creación'
new:
page_title: 'Guardar un nuevo artículo'

View file

@ -200,7 +200,7 @@ entry:
description: "Est-ce que cet article s'affiche mal ?"
edit_title: 'Modifier le titre'
original_article: 'original'
annotations_on_the_entry: '{0} Aucune annotation|{1} Une annotation|]1,Inf[ %nbAnnotations% annotations'
annotations_on_the_entry: '{0} Aucune annotation|{1} Une annotation|]1,Inf[ %count% annotations'
created_at: 'Date de création'
new:
page_title: 'Sauvegarder un nouvel article'

View file

@ -200,7 +200,7 @@ entry:
description: 'Questo contenuto viene visualizzato male?'
edit_title: 'Modifica titolo'
original_article: 'originale'
annotations_on_the_entry: '{0} Nessuna annotazione|{1} Una annotazione|]1,Inf[ %nbAnnotations% annotazioni'
annotations_on_the_entry: '{0} Nessuna annotazione|{1} Una annotazione|]1,Inf[ %count% annotazioni'
created_at: 'Data di creazione'
new:
page_title: 'Salva un nuovo contenuto'

View file

@ -200,7 +200,7 @@ entry:
description: "Marca mal la presentacion d'aqueste article ?"
edit_title: 'Modificar lo títol'
original_article: 'original'
annotations_on_the_entry: "{0} Pas cap d'anotacion|{1} Una anotacion|]1,Inf[ %nbAnnotations% anotacions"
annotations_on_the_entry: "{0} Pas cap d'anotacion|{1} Una anotacion|]1,Inf[ %count% anotacions"
created_at: 'Data de creacion'
new:
page_title: 'Enregistrar un novèl article'

View file

@ -200,7 +200,7 @@ entry:
description: 'Czy ten artykuł wygląda źle?'
edit_title: 'Edytuj tytuł'
original_article: 'oryginalny'
annotations_on_the_entry: '{0} Nie ma adnotacji |{1} Jedna adnotacja |]1,Inf[ %nbAnnotations% adnotacji'
annotations_on_the_entry: '{0} Nie ma adnotacji |{1} Jedna adnotacja |]1,Inf[ %count% adnotacji'
created_at: 'Czas stworzenia'
new:
page_title: 'Zapisz nowy wpis'

View file

@ -200,7 +200,7 @@ entry:
description: 'Îți pare ciudat articolul?'
edit_title: 'Editează titlul'
original_article: 'original'
# annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %nbAnnotations% annotations'
# annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations'
created_at: 'Data creării'
new:
page_title: 'Salvează un nou articol'

View file

@ -199,7 +199,7 @@ entry:
description: 'Bu makalede herhangi bir yanlışlık mı var?'
edit_title: 'Başlığı düzenle'
original_article: 'orijinal'
# annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %nbAnnotations% annotations'
# annotations_on_the_entry: '{0} No annotations|{1} One annotation|]1,Inf[ %count% annotations'
created_at: 'Oluşturulma tarihi'
new:
page_title: 'Yeni makaleyi kaydet'

View file

@ -54,7 +54,6 @@
{% endif %}
</i>
{% set nbAnnotations = entry.annotations | length %}
<span class="tool link"><i class="material-icons link">comment</i> {{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }}</span>
<aside class="tags">
<div class="card-entry-tags">

View file

@ -9,7 +9,7 @@
<ul>
{% for tag in tags %}
<li id="tag-{{ tag.id|e }}"><a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{tag.label}} ({{ tag.entries.getValues | length }})</a></li>
<li id="tag-{{ tag.id|e }}"><a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{tag.label}} ({{ tag.nbEntries | length }})</a></li>
{% endfor %}
</ul>

View file

@ -30,11 +30,16 @@
<meta property="og:title" content="{{ entry.title | raw }}" />
<meta property="og:type" content="article" />
<meta property="og:url" content="{{ app.request.uri }}" />
{% set picturePath = app.request.schemeAndHttpHost ~ asset('bundles/wallabagcore/themes/_global/img/logo-other_themes.png') %}
{% if entry.previewPicture is not null %}
<meta property="og:image" content="{{ entry.previewPicture }}" />
{% else %}
<meta property="og:image" content="{{ app.request.schemeAndHttpHost }}{{ asset('bundles/wallabagcore/themes/_global/img/logo-other_themes.png') }}" />
{% set picturePath = entry.previewPicture %}
{% endif %}
<meta property="og:image" content="{{ picturePath }}" />
<meta name="twitter:card" content="summary" />
<meta name="twitter:image" content="{{ picturePath }}" />
<meta name="twitter:site" content="@wallabagapp" />
<meta name="twitter:title" content="{{ entry.title | raw }}" />
<meta name="twitter:description" content="{{ entry.title | raw }}" />
</head>
<body>
<header>

View file

@ -1 +1 @@
<a id="bookmarklet" ondragend="this.click();" href="javascript:var url=location.href||url;var wllbg=window.open('{{ url('bookmarklet') }}?url=' + encodeURI(url),'_blank');wllbg.close();void(0);">bag it!</a>
<a id="bookmarklet" ondragend="this.click();" href="javascript:(function(){var url=location.href||url;var wllbg=window.open('{{ url('bookmarklet') }}?url=' + encodeURI(url),'_blank');})();">bag it!</a>

View file

@ -77,7 +77,7 @@
<div class="card-action">
<span class="bold">
<a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.list.original_article'|trans }}: {{ entry.title|e }} - {{ entry.domainName|removeWww }}" class="tool original grey-text"><span>{{ entry.domainName|removeWww|truncate(18) }}</span></a>
</bold>
</span>
<ul class="tools right">
<li>

View file

@ -225,7 +225,7 @@
<a href="{{ entry.url|e }}" target="_blank" title="{{ 'entry.view.original_article'|trans }} : {{ entry.title|e }}" class="tool">
<i class="material-icons link">link</i> <span class="link">{{ entry.domainName|removeWww }}</span>
</a>
<span class="tool"><i class="material-icons link">comment</i> <span class="link">{{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }}</span>
<span class="tool"><i class="material-icons link">comment</i></span> <span class="link">{{ 'entry.view.annotations_on_the_entry'|transchoice(entry.annotations | length) }}</span>
<div id="list">
{% for tag in entry.tags %}
<div class="chip">

View file

@ -6,12 +6,19 @@
<div class="results clearfix">
<div class="nb-results left">{{ 'tag.list.number_on_the_page'|transchoice(tags|length) }}</div>
</div>
<br />
<ul class="row data">
{% for tag in tags %}
<li id="tag-{{ tag.id|e }}" class="col l4 m6 s12"><a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{tag.label}} ({{ tag.entries.getValues | length }})</a></li>
{% endfor %}
</ul>
<div class="row">
<ul class="card-tag-labels">
{% for tag in tags %}
<li title="{{tag.label}} ({{ tag.nbEntries }})" id="tag-{{ tag.id }}" class="col l2 m2 s2">
<a href="{{ path('tag_entries', {'slug': tag.slug}) }}">{{tag.label}} ({{ tag.nbEntries }})</a>
</li>
{% endfor %}
</ul>
</div>
<div>
<a href="{{ path('untagged') }}">{{ 'tag.list.see_untagged_entries'|trans }}</a>
</div>

View file

@ -73,7 +73,7 @@
<a class="waves-effect" href="{{ path('howto') }}">{{ 'menu.left.howto'|trans }}</a>
</li>
<li class="bold">
<a class="waves-effect" class="icon icon-power" href="{{ path('fos_user_security_logout') }}">{{ 'menu.left.logout'|trans }}</a>
<a class="waves-effect icon icon-power" href="{{ path('fos_user_security_logout') }}">{{ 'menu.left.logout'|trans }}</a>
</li>
</ul>
<div class="nav-wrapper nav-panels">