mirror of
https://github.com/wallabag/wallabag.git
synced 2025-02-15 18:25:15 +00:00
Merge pull request #3208 from wallabag/is-public
Add ability to filter public entries & use it in the API
This commit is contained in:
commit
977ac0a1d6
19 changed files with 165 additions and 6 deletions
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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">
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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');
|
||||
|
|
Loading…
Reference in a new issue