Merge pull request #3208 from wallabag/is-public

Add ability to filter public entries & use it in the API
This commit is contained in:
Nicolas Lœuillet 2017-06-12 10:26:01 +02:00 committed by GitHub
commit 977ac0a1d6
19 changed files with 165 additions and 6 deletions

View file

@ -77,6 +77,7 @@ class EntryRestController extends WallabagRestController
* {"name"="perPage", "dataType"="integer", "required"=false, "format"="default'30'", "description"="results per page."},
* {"name"="tags", "dataType"="string", "required"=false, "format"="api,rest", "description"="a list of tags url encoded. Will returns entries that matches ALL tags."},
* {"name"="since", "dataType"="integer", "required"=false, "format"="default '0'", "description"="The timestamp since when you want entries updated."},
* {"name"="public", "dataType"="integer", "required"=false, "format"="1 or 0, all entries by default", "description"="filter by entries with a public link"},
* }
* )
*
@ -88,6 +89,7 @@ class EntryRestController extends WallabagRestController
$isArchived = (null === $request->query->get('archive')) ? null : (bool) $request->query->get('archive');
$isStarred = (null === $request->query->get('starred')) ? null : (bool) $request->query->get('starred');
$isPublic = (null === $request->query->get('public')) ? null : (bool) $request->query->get('public');
$sort = $request->query->get('sort', 'created');
$order = $request->query->get('order', 'desc');
$page = (int) $request->query->get('page', 1);
@ -96,9 +98,16 @@ class EntryRestController extends WallabagRestController
$since = $request->query->get('since', 0);
/** @var \Pagerfanta\Pagerfanta $pager */
$pager = $this->getDoctrine()
->getRepository('WallabagCoreBundle:Entry')
->findEntries($this->getUser()->getId(), $isArchived, $isStarred, $sort, $order, $since, $tags);
$pager = $this->get('wallabag_core.entry_repository')->findEntries(
$this->getUser()->getId(),
$isArchived,
$isStarred,
$isPublic,
$sort,
$order,
$since,
$tags
);
$pager->setMaxPerPage($perPage);
$pager->setCurrentPage($page);
@ -111,6 +120,7 @@ class EntryRestController extends WallabagRestController
[
'archive' => $isArchived,
'starred' => $isStarred,
'public' => $isPublic,
'sort' => $sort,
'order' => $order,
'page' => $page,
@ -289,6 +299,7 @@ class EntryRestController extends WallabagRestController
* {"name"="preview_picture", "dataType"="string", "required"=false, "description"="Preview picture of the entry"},
* {"name"="published_at", "dataType"="datetime|integer", "format"="YYYY-MM-DDTHH:II:SS+TZ or a timestamp", "required"=false, "description"="Published date of the entry"},
* {"name"="authors", "dataType"="string", "format"="Name Firstname,author2,author3", "required"=false, "description"="Authors of the entry"},
* {"name"="public", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="will generate a public link for the entry"},
* }
* )
*
@ -332,6 +343,7 @@ class EntryRestController extends WallabagRestController
* {"name"="preview_picture", "dataType"="string", "required"=false, "description"="Preview picture of the entry"},
* {"name"="published_at", "dataType"="datetime|integer", "format"="YYYY-MM-DDTHH:II:SS+TZ or a timestamp", "required"=false, "description"="Published date of the entry"},
* {"name"="authors", "dataType"="string", "format"="Name Firstname,author2,author3", "required"=false, "description"="Authors of the entry"},
* {"name"="public", "dataType"="integer", "required"=false, "format"="1 or 0", "description"="will generate a public link for the entry"},
* }
* )
*
@ -623,6 +635,7 @@ class EntryRestController extends WallabagRestController
$tags = $request->request->get('tags', []);
$isArchived = $request->request->get('archive');
$isStarred = $request->request->get('starred');
$isPublic = $request->request->get('public');
$content = $request->request->get('content');
$language = $request->request->get('language');
$picture = $request->request->get('preview_picture');
@ -666,6 +679,14 @@ class EntryRestController extends WallabagRestController
$this->get('wallabag_core.tags_assigner')->assignTagsToEntry($entry, $tags);
}
if (!is_null($isPublic)) {
if (true === (bool) $isPublic && null === $entry->getUid()) {
$entry->generateUid();
} elseif (false === (bool) $isPublic) {
$entry->cleanUid();
}
}
$em = $this->getDoctrine()->getManager();
$em->persist($entry);
$em->flush();

View file

@ -684,6 +684,21 @@ class Entry
$this->uid = null;
}
/**
* Used in the entries filter so it's more explicit for the end user than the uid.
* Also used in the API.
*
* @VirtualProperty
* @SerializedName("is_public")
* @Groups({"entries_for_user"})
*
* @return bool
*/
public function isPublic()
{
return null !== $this->uid;
}
/**
* @return string
*/

View file

@ -150,6 +150,20 @@ class EntryFilterType extends AbstractType
},
'label' => 'entry.filters.preview_picture_label',
])
->add('isPublic', CheckboxFilterType::class, [
'apply_filter' => function (QueryInterface $filterQuery, $field, $values) {
if (false === $values['value']) {
return;
}
// is_public isn't a real field
// we should use the "uid" field to determine if the entry has been made public
$expression = $filterQuery->getExpr()->isNotNull($values['alias'].'.uid');
return $filterQuery->createCondition($expression);
},
'label' => 'entry.filters.is_public_label',
])
->add('language', ChoiceFilterType::class, [
'choices' => array_flip($this->repository->findDistinctLanguageByUser($this->user->getId())),
'label' => 'entry.filters.language_label',

View file

@ -135,6 +135,7 @@ class EntryRepository extends EntityRepository
* @param int $userId
* @param bool $isArchived
* @param bool $isStarred
* @param bool $isPublic
* @param string $sort
* @param string $order
* @param int $since
@ -142,18 +143,22 @@ class EntryRepository extends EntityRepository
*
* @return array
*/
public function findEntries($userId, $isArchived = null, $isStarred = null, $sort = 'created', $order = 'ASC', $since = 0, $tags = '')
public function findEntries($userId, $isArchived = null, $isStarred = null, $isPublic = null, $sort = 'created', $order = 'ASC', $since = 0, $tags = '')
{
$qb = $this->createQueryBuilder('e')
->leftJoin('e.tags', 't')
->where('e.user =:userId')->setParameter('userId', $userId);
if (null !== $isArchived) {
$qb->andWhere('e.isArchived =:isArchived')->setParameter('isArchived', (bool) $isArchived);
$qb->andWhere('e.isArchived = :isArchived')->setParameter('isArchived', (bool) $isArchived);
}
if (null !== $isStarred) {
$qb->andWhere('e.isStarred =:isStarred')->setParameter('isStarred', (bool) $isStarred);
$qb->andWhere('e.isStarred = :isStarred')->setParameter('isStarred', (bool) $isStarred);
}
if (null !== $isPublic) {
$qb->andWhere('e.uid IS '.(true === $isPublic ? 'NOT' : '').' NULL');
}
if ($since > 0) {

View file

@ -186,6 +186,8 @@ entry:
unread_label: 'Ulæst'
preview_picture_label: 'Har et vist billede'
preview_picture_help: 'Forhåndsvis billede'
# is_public_label: 'Has a public link'
# is_public_help: 'Public link'
language_label: 'Sprog'
# http_status_label: 'HTTP status'
reading_time:

View file

@ -187,6 +187,8 @@ entry:
unread_label: 'Ungelesene'
preview_picture_label: 'Vorschaubild vorhanden'
preview_picture_help: 'Vorschaubild'
# is_public_label: 'Has a public link'
# is_public_help: 'Public link'
language_label: 'Sprache'
http_status_label: 'HTTP-Status'
reading_time:

View file

@ -187,6 +187,8 @@ entry:
unread_label: 'Unread'
preview_picture_label: 'Has a preview picture'
preview_picture_help: 'Preview picture'
is_public_label: 'Has a public link'
is_public_help: 'Public link'
language_label: 'Language'
http_status_label: 'HTTP status'
reading_time:

View file

@ -187,6 +187,8 @@ entry:
unread_label: 'Sin leer'
preview_picture_label: 'Tiene imagen de previsualización'
preview_picture_help: 'Imagen de previsualización'
# is_public_label: 'Has a public link'
# is_public_help: 'Public link'
language_label: 'Idioma'
http_status_label: 'Código de estado HTTP'
reading_time:

View file

@ -187,6 +187,8 @@ entry:
unread_label: 'خوانده‌نشده'
preview_picture_label: 'دارای عکس پیش‌نمایش'
preview_picture_help: 'پیش‌نمایش عکس'
# is_public_label: 'Has a public link'
# is_public_help: 'Public link'
language_label: 'زبان'
# http_status_label: 'HTTP status'
reading_time:

View file

@ -187,6 +187,8 @@ entry:
unread_label: "Non lus"
preview_picture_label: "A une photo"
preview_picture_help: "Photo"
is_public_label: 'A un lien public'
is_public_help: 'Lien public'
language_label: "Langue"
http_status_label: "Statut HTTP"
reading_time:

View file

@ -187,6 +187,8 @@ entry:
# unread_label: 'Unread'
preview_picture_label: "Ha un'immagine di anteprima"
preview_picture_help: 'Immagine di anteprima'
# is_public_label: 'Has a public link'
# is_public_help: 'Public link'
language_label: 'Lingua'
# http_status_label: 'HTTP status'
reading_time:

View file

@ -187,6 +187,8 @@ entry:
unread_label: 'Pas legits'
preview_picture_label: 'A un imatge'
preview_picture_help: 'Imatge'
# is_public_label: 'Has a public link'
# is_public_help: 'Public link'
language_label: 'Lenga'
http_status_label: 'Estatut HTTP'
reading_time:

View file

@ -187,6 +187,8 @@ entry:
unread_label: 'Nieprzeczytane'
preview_picture_label: 'Posiada podgląd obrazu'
preview_picture_help: 'Podgląd obrazu'
# is_public_label: 'Has a public link'
# is_public_help: 'Public link'
language_label: 'Język'
http_status_label: 'Status HTTP'
reading_time:

View file

@ -187,6 +187,8 @@ entry:
unread_label: 'Não Lido'
preview_picture_label: 'Possui uma imagem de preview'
preview_picture_help: 'Imagem de preview'
# is_public_label: 'Has a public link'
# is_public_help: 'Public link'
language_label: 'Idioma'
# http_status_label: 'HTTP status'
reading_time:

View file

@ -187,6 +187,8 @@ entry:
unread_label: 'Necitite'
preview_picture_label: 'Are o imagine de previzualizare'
preview_picture_help: 'Previzualizare imagine'
# is_public_label: 'Has a public link'
# is_public_help: 'Public link'
language_label: 'Limbă'
# http_status_label: 'HTTP status'
reading_time:

View file

@ -127,6 +127,11 @@
{{ form_widget(form.previewPicture) }}
{{ form_label(form.previewPicture) }}
</div>
<div class="input-field">
{{ form_widget(form.isPublic) }}
{{ form_label(form.isPublic) }}
</div>
</div>
<div id="filter-language" class="filter-group">

View file

@ -102,6 +102,15 @@
{{ form_label(form.previewPicture) }}
</div>
<div class="col s12">
<label>{{ 'entry.filters.is_public_help'|trans }}</label>
</div>
<div class="input-field col s12 with-checkbox">
{{ form_widget(form.isPublic) }}
{{ form_label(form.isPublic) }}
</div>
<div class="col s12">
{{ form_label(form.language) }}
</div>
@ -121,10 +130,12 @@
<div class="col s12">
{{ form_label(form.readingTime) }}
</div>
<div class="input-field col s6">
{{ form_widget(form.readingTime.left_number, {'type': 'number'}) }}
<label for="entry_filter_readingTime_left_number">{{ 'entry.filters.reading_time.from'|trans }}</label>
</div>
<div class="input-field col s6">
{{ form_widget(form.readingTime.right_number, {'type': 'number'}) }}
<label for="entry_filter_readingTime_right_number">{{ 'entry.filters.reading_time.to'|trans }}</label>

View file

@ -128,6 +128,7 @@ class EntryRestControllerTest extends WallabagApiTestCase
'perPage' => 2,
'tags' => 'foo',
'since' => 1443274283,
'public' => 0,
]);
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
@ -154,6 +155,53 @@ class EntryRestControllerTest extends WallabagApiTestCase
$this->assertContains('order=asc', $content['_links'][$link]['href']);
$this->assertContains('tags=foo', $content['_links'][$link]['href']);
$this->assertContains('since=1443274283', $content['_links'][$link]['href']);
$this->assertContains('public=0', $content['_links'][$link]['href']);
}
$this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
}
public function testGetEntriesPublicOnly()
{
$entry = $this->client->getContainer()
->get('doctrine.orm.entity_manager')
->getRepository('WallabagCoreBundle:Entry')
->findOneByUser(1);
if (!$entry) {
$this->markTestSkipped('No content found in db.');
}
// generate at least one public entry
$entry->generateUid();
$em = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$em->persist($entry);
$em->flush();
$this->client->request('GET', '/api/entries', [
'public' => 1,
]);
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
$content = json_decode($this->client->getResponse()->getContent(), true);
$this->assertGreaterThanOrEqual(1, count($content));
$this->assertArrayHasKey('items', $content['_embedded']);
$this->assertGreaterThanOrEqual(1, $content['total']);
$this->assertEquals(1, $content['page']);
$this->assertEquals(30, $content['limit']);
$this->assertGreaterThanOrEqual(1, $content['pages']);
$this->assertArrayHasKey('_links', $content);
$this->assertArrayHasKey('self', $content['_links']);
$this->assertArrayHasKey('first', $content['_links']);
$this->assertArrayHasKey('last', $content['_links']);
foreach (['self', 'first', 'last'] as $link) {
$this->assertArrayHasKey('href', $content['_links'][$link]);
$this->assertContains('public=1', $content['_links'][$link]['href']);
}
$this->assertEquals('application/json', $this->client->getResponse()->headers->get('Content-Type'));
@ -348,6 +396,7 @@ class EntryRestControllerTest extends WallabagApiTestCase
'language' => 'de',
'published_at' => '2016-09-08T11:55:58+0200',
'authors' => 'bob,helen',
'public' => 1,
]);
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
@ -367,6 +416,7 @@ class EntryRestControllerTest extends WallabagApiTestCase
$this->assertCount(2, $content['published_by']);
$this->assertContains('bob', $content['published_by']);
$this->assertContains('helen', $content['published_by']);
$this->assertTrue($content['is_public'], 'A public link has been generated for that entry');
}
public function testPostSameEntry()
@ -481,6 +531,7 @@ class EntryRestControllerTest extends WallabagApiTestCase
'preview_picture' => 'http://preview.io/picture.jpg',
'authors' => 'bob,sponge',
'content' => 'awesome',
'public' => 0,
]);
$this->assertEquals(200, $this->client->getResponse()->getStatusCode());
@ -497,6 +548,7 @@ class EntryRestControllerTest extends WallabagApiTestCase
$this->assertContains('sponge', $content['published_by']);
$this->assertContains('bob', $content['published_by']);
$this->assertEquals('awesome', $content['content']);
$this->assertFalse($content['is_public'], 'Entry is no more shared');
}
public function testPatchEntryWithoutQuotes()

View file

@ -860,6 +860,20 @@ class EntryControllerTest extends WallabagCoreTestCase
$this->assertCount(1, $crawler->filter('div[class=entry]'));
}
public function testFilterOnIsPublic()
{
$this->logInAs('admin');
$this->useTheme('baggy');
$client = $this->getClient();
$crawler = $client->request('GET', '/unread/list');
$form = $crawler->filter('button[id=submit-filter]')->form();
$form['entry_filter[isPublic]']->tick();
$crawler = $client->submit($form);
$this->assertCount(0, $crawler->filter('div[class=entry]'));
}
public function testPreviewPictureFilter()
{
$this->logInAs('admin');