mirror of
https://github.com/wallabag/wallabag.git
synced 2024-12-24 00:20:28 +00:00
Merge pull request #1386 from wallabag/v2-refactor
WIP – Fixing things around 💨
This commit is contained in:
commit
109d67dbb1
16 changed files with 190 additions and 298 deletions
|
@ -51,6 +51,7 @@ twig:
|
|||
form:
|
||||
resources:
|
||||
- LexikFormFilterBundle:Form:form_div_layout.html.twig
|
||||
|
||||
# Assetic Configuration
|
||||
assetic:
|
||||
debug: "%kernel.debug%"
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
},
|
||||
{
|
||||
"name": "Jérémy Benoist",
|
||||
"homepage": "http://www.j0k3r.net",
|
||||
"role": "Developer"
|
||||
}
|
||||
],
|
||||
|
|
|
@ -170,6 +170,31 @@ class WallabagRestControllerTest extends WebTestCase
|
|||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$client->request('GET', '/api/entries', array('star' => 1, 'sort' => 'updated'), array(), $headers);
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
||||
$content = json_decode($client->getResponse()->getContent(), true);
|
||||
|
||||
$this->assertGreaterThanOrEqual(1, count($content));
|
||||
$this->assertNotEmpty($content['_embedded']['items']);
|
||||
$this->assertGreaterThanOrEqual(1, $content['total']);
|
||||
$this->assertEquals(1, $content['page']);
|
||||
$this->assertGreaterThanOrEqual(1, $content['pages']);
|
||||
|
||||
$this->assertTrue(
|
||||
$client->getResponse()->headers->contains(
|
||||
'Content-Type',
|
||||
'application/json'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public function testGetArchiveEntries()
|
||||
{
|
||||
$client = $this->createClient();
|
||||
$headers = $this->generateHeaders('admin', 'mypassword');
|
||||
|
||||
$client->request('GET', '/api/entries', array('archive' => 1), array(), $headers);
|
||||
|
||||
$this->assertEquals(200, $client->getResponse()->getStatusCode());
|
||||
|
|
|
@ -113,34 +113,7 @@ class EntryController extends Controller
|
|||
*/
|
||||
public function showUnreadAction(Request $request, $page)
|
||||
{
|
||||
$form = $this->get('form.factory')->create(new EntryFilterType());
|
||||
|
||||
$filterBuilder = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findUnreadByUser($this->getUser()->getId());
|
||||
|
||||
if ($request->query->has($form->getName())) {
|
||||
// manually bind values from the request
|
||||
$form->submit($request->query->get($form->getName()));
|
||||
|
||||
// build the query from the given form object
|
||||
$this->get('lexik_form_filter.query_builder_updater')->addFilterConditions($form, $filterBuilder);
|
||||
}
|
||||
|
||||
$pagerAdapter = new DoctrineORMAdapter($filterBuilder->getQuery());
|
||||
$entries = new Pagerfanta($pagerAdapter);
|
||||
|
||||
$entries->setMaxPerPage($this->getUser()->getConfig()->getItemsPerPage());
|
||||
$entries->setCurrentPage($page);
|
||||
|
||||
return $this->render(
|
||||
'WallabagCoreBundle:Entry:entries.html.twig',
|
||||
array(
|
||||
'form' => $form->createView(),
|
||||
'entries' => $entries,
|
||||
'currentPage' => $page,
|
||||
)
|
||||
);
|
||||
return $this->showEntries('unread', $request, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -155,34 +128,7 @@ class EntryController extends Controller
|
|||
*/
|
||||
public function showArchiveAction(Request $request, $page)
|
||||
{
|
||||
$form = $this->get('form.factory')->create(new EntryFilterType());
|
||||
|
||||
$filterBuilder = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findArchiveByUser($this->getUser()->getId());
|
||||
|
||||
if ($request->query->has($form->getName())) {
|
||||
// manually bind values from the request
|
||||
$form->submit($request->query->get($form->getName()));
|
||||
|
||||
// build the query from the given form object
|
||||
$this->get('lexik_form_filter.query_builder_updater')->addFilterConditions($form, $filterBuilder);
|
||||
}
|
||||
|
||||
$pagerAdapter = new DoctrineORMAdapter($filterBuilder->getQuery());
|
||||
$entries = new Pagerfanta($pagerAdapter);
|
||||
|
||||
$entries->setMaxPerPage($this->getUser()->getConfig()->getItemsPerPage());
|
||||
$entries->setCurrentPage($page);
|
||||
|
||||
return $this->render(
|
||||
'WallabagCoreBundle:Entry:entries.html.twig',
|
||||
array(
|
||||
'form' => $form->createView(),
|
||||
'entries' => $entries,
|
||||
'currentPage' => $page,
|
||||
)
|
||||
);
|
||||
return $this->showEntries('archive', $request, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -197,11 +143,64 @@ class EntryController extends Controller
|
|||
*/
|
||||
public function showStarredAction(Request $request, $page)
|
||||
{
|
||||
return $this->showEntries('starred', $request, $page);
|
||||
}
|
||||
|
||||
/**
|
||||
* Global method to retrieve entries depending on the given type
|
||||
* It returns the response to be send.
|
||||
*
|
||||
* @param string $type Entries type: unread, starred or archive
|
||||
* @param Request $request
|
||||
* @param int $page
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
private function showEntries($type, Request $request, $page)
|
||||
{
|
||||
$repository = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry');
|
||||
|
||||
switch ($type) {
|
||||
case 'starred':
|
||||
$qb = $repository->getBuilderForStarredByUser($this->getUser()->getId());
|
||||
break;
|
||||
|
||||
case 'archive':
|
||||
$qb = $repository->getBuilderForArchiveByUser($this->getUser()->getId());
|
||||
break;
|
||||
|
||||
case 'unread':
|
||||
$qb = $repository->getBuilderForUnreadByUser($this->getUser()->getId());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Type "%s" is not implemented.', $type));
|
||||
}
|
||||
|
||||
$form = $this->get('form.factory')->create(new EntryFilterType());
|
||||
|
||||
$filterBuilder = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findStarredByUser($this->getUser()->getId());
|
||||
if ($request->query->has($form->getName())) {
|
||||
// manually bind values from the request
|
||||
$form->submit($request->query->get($form->getName()));
|
||||
|
||||
// build the query from the given form object
|
||||
$this->get('lexik_form_filter.query_builder_updater')->addFilterConditions($form, $qb);
|
||||
}
|
||||
|
||||
$pagerAdapter = new DoctrineORMAdapter($qb->getQuery());
|
||||
$entries = new Pagerfanta($pagerAdapter);
|
||||
|
||||
$entries->setMaxPerPage($this->getUser()->getConfig()->getItemsPerPage());
|
||||
$entries->setCurrentPage($page);
|
||||
|
||||
return $this->render(
|
||||
'WallabagCoreBundle:Entry:entries.html.twig',
|
||||
array(
|
||||
'form' => $form->createView(),
|
||||
'entries' => $entries,
|
||||
'currentPage' => $page,
|
||||
)
|
||||
);
|
||||
|
||||
if ($request->query->has($form->getName())) {
|
||||
// manually bind values from the request
|
||||
|
|
|
@ -22,22 +22,7 @@ class RssController extends Controller
|
|||
*/
|
||||
public function showUnreadAction(User $user)
|
||||
{
|
||||
$qb = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findUnreadByUser(
|
||||
$user->getId()
|
||||
);
|
||||
|
||||
$pagerAdapter = new DoctrineORMAdapter($qb->getQuery());
|
||||
$entries = new Pagerfanta($pagerAdapter);
|
||||
|
||||
$perPage = $user->getConfig()->getRssLimit() ?: $this->container->getParameter('rss_limit');
|
||||
$entries->setMaxPerPage($perPage);
|
||||
|
||||
return $this->render('WallabagCoreBundle:Entry:entries.xml.twig', array(
|
||||
'type' => 'unread',
|
||||
'entries' => $entries,
|
||||
));
|
||||
return $this->showEntries('unread', $user);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -50,22 +35,7 @@ class RssController extends Controller
|
|||
*/
|
||||
public function showArchiveAction(User $user)
|
||||
{
|
||||
$qb = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findArchiveByUser(
|
||||
$user->getId()
|
||||
);
|
||||
|
||||
$pagerAdapter = new DoctrineORMAdapter($qb->getQuery());
|
||||
$entries = new Pagerfanta($pagerAdapter);
|
||||
|
||||
$perPage = $user->getConfig()->getRssLimit() ?: $this->container->getParameter('rss_limit');
|
||||
$entries->setMaxPerPage($perPage);
|
||||
|
||||
return $this->render('WallabagCoreBundle:Entry:entries.xml.twig', array(
|
||||
'type' => 'archive',
|
||||
'entries' => $entries,
|
||||
));
|
||||
return $this->showEntries('archive', $user);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -78,11 +48,38 @@ class RssController extends Controller
|
|||
*/
|
||||
public function showStarredAction(User $user)
|
||||
{
|
||||
$qb = $this->getDoctrine()
|
||||
->getRepository('WallabagCoreBundle:Entry')
|
||||
->findStarredByUser(
|
||||
$user->getId()
|
||||
);
|
||||
return $this->showEntries('starred', $user);
|
||||
}
|
||||
|
||||
/**
|
||||
* Global method to retrieve entries depending on the given type
|
||||
* It returns the response to be send.
|
||||
*
|
||||
* @param string $type Entries type: unread, starred or archive
|
||||
* @param User $user
|
||||
*
|
||||
* @return \Symfony\Component\HttpFoundation\Response
|
||||
*/
|
||||
private function showEntries($type, User $user)
|
||||
{
|
||||
$repository = $this->getDoctrine()->getRepository('WallabagCoreBundle:Entry');
|
||||
|
||||
switch ($type) {
|
||||
case 'starred':
|
||||
$qb = $repository->getBuilderForStarredByUser($user->getId());
|
||||
break;
|
||||
|
||||
case 'archive':
|
||||
$qb = $repository->getBuilderForArchiveByUser($user->getId());
|
||||
break;
|
||||
|
||||
case 'unread':
|
||||
$qb = $repository->getBuilderForUnreadByUser($user->getId());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new \InvalidArgumentException(sprintf('Type "%s" is not implemented.', $type));
|
||||
}
|
||||
|
||||
$pagerAdapter = new DoctrineORMAdapter($qb->getQuery());
|
||||
$entries = new Pagerfanta($pagerAdapter);
|
||||
|
@ -91,7 +88,7 @@ class RssController extends Controller
|
|||
$entries->setMaxPerPage($perPage);
|
||||
|
||||
return $this->render('WallabagCoreBundle:Entry:entries.xml.twig', array(
|
||||
'type' => 'starred',
|
||||
'type' => $type,
|
||||
'entries' => $entries,
|
||||
));
|
||||
}
|
||||
|
|
|
@ -28,12 +28,4 @@ class StaticController extends Controller
|
|||
array()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @Route("/", name="homepage")
|
||||
*/
|
||||
public function apiAction()
|
||||
{
|
||||
return $this->redirect($this->generateUrl('nelmio_api_doc_index'));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use Doctrine\ORM\Mapping as ORM;
|
|||
use Symfony\Component\Validator\Constraints as Assert;
|
||||
use Hateoas\Configuration\Annotation as Hateoas;
|
||||
use JMS\Serializer\Annotation\XmlRoot;
|
||||
use Wallabag\CoreBundle\Helper\Tools;
|
||||
use Wallabag\CoreBundle\Tools\Utils;
|
||||
|
||||
/**
|
||||
* Entry.
|
||||
|
@ -265,7 +265,7 @@ class Entry
|
|||
public function setContent($content)
|
||||
{
|
||||
$this->content = $content;
|
||||
$this->readingTime = Tools::getReadingTime($content);
|
||||
$this->readingTime = Utils::getReadingTime($content);
|
||||
$this->domainName = parse_url($this->url, PHP_URL_HOST);
|
||||
|
||||
return $this;
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Helper;
|
||||
|
||||
class Entry
|
||||
{
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Wallabag\CoreBundle\Helper;
|
||||
|
||||
final class Tools
|
||||
{
|
||||
/**
|
||||
* Download a file (typically, for downloading pictures on web server).
|
||||
*
|
||||
* @param $url
|
||||
*
|
||||
* @return bool|mixed|string
|
||||
*/
|
||||
public static function getFile($url)
|
||||
{
|
||||
$timeout = 15;
|
||||
$useragent = 'Mozilla/5.0 (Windows NT 5.1; rv:18.0) Gecko/20100101 Firefox/18.0';
|
||||
|
||||
if (in_array('curl', get_loaded_extensions())) {
|
||||
# Fetch feed from URL
|
||||
$curl = curl_init();
|
||||
curl_setopt($curl, CURLOPT_URL, $url);
|
||||
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
|
||||
if (!ini_get('open_basedir') && !ini_get('safe_mode')) {
|
||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
|
||||
}
|
||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($curl, CURLOPT_HEADER, false);
|
||||
|
||||
# for ssl, do not verified certificate
|
||||
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
|
||||
curl_setopt($curl, CURLOPT_AUTOREFERER, true);
|
||||
|
||||
# FeedBurner requires a proper USER-AGENT...
|
||||
curl_setopt($curl, CURL_HTTP_VERSION_1_1, true);
|
||||
curl_setopt($curl, CURLOPT_ENCODING, 'gzip, deflate');
|
||||
curl_setopt($curl, CURLOPT_USERAGENT, $useragent);
|
||||
|
||||
$data = curl_exec($curl);
|
||||
$httpcode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
|
||||
$httpcodeOK = isset($httpcode) and ($httpcode == 200 or $httpcode == 301);
|
||||
curl_close($curl);
|
||||
} else {
|
||||
# create http context and add timeout and user-agent
|
||||
$context = stream_context_create(
|
||||
array(
|
||||
'http' => array(
|
||||
'timeout' => $timeout,
|
||||
'header' => 'User-Agent: '.$useragent,
|
||||
'follow_location' => true,
|
||||
),
|
||||
'ssl' => array(
|
||||
'verify_peer' => false,
|
||||
'allow_self_signed' => true,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
# only download page lesser than 4MB
|
||||
$data = @file_get_contents($url, false, $context, -1, 4000000);
|
||||
|
||||
if (isset($http_response_header) and isset($http_response_header[0])) {
|
||||
$httpcodeOK = isset($http_response_header) and isset($http_response_header[0]) and ((strpos($http_response_header[0], '200 OK') !== false) or (strpos($http_response_header[0], '301 Moved Permanently') !== false));
|
||||
}
|
||||
}
|
||||
|
||||
# if response is not empty and response is OK
|
||||
if (isset($data) and isset($httpcodeOK) and $httpcodeOK) {
|
||||
# take charset of page and get it
|
||||
preg_match('#<meta .*charset=.*>#Usi', $data, $meta);
|
||||
|
||||
# if meta tag is found
|
||||
if (!empty($meta[0])) {
|
||||
preg_match('#charset="?(.*)"#si', $meta[0], $encoding);
|
||||
# if charset is found set it otherwise, set it to utf-8
|
||||
$html_charset = (!empty($encoding[1])) ? strtolower($encoding[1]) : 'utf-8';
|
||||
if (empty($encoding[1])) {
|
||||
$encoding[1] = 'utf-8';
|
||||
}
|
||||
} else {
|
||||
$html_charset = 'utf-8';
|
||||
$encoding[1] = '';
|
||||
}
|
||||
|
||||
# replace charset of url to charset of page
|
||||
$data = str_replace('charset='.$encoding[1], 'charset='.$html_charset, $data);
|
||||
|
||||
return $data;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a URL by using a salt.
|
||||
*
|
||||
* @param $string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function encodeString($string)
|
||||
{
|
||||
return sha1($string.SALT);
|
||||
}
|
||||
|
||||
public static function generateToken()
|
||||
{
|
||||
if (ini_get('open_basedir') === '') {
|
||||
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
|
||||
// alternative to /dev/urandom for Windows
|
||||
$token = substr(base64_encode(uniqid(mt_rand(), true)), 0, 20);
|
||||
} else {
|
||||
$token = substr(base64_encode(file_get_contents('/dev/urandom', false, null, 0, 20)), 0, 15);
|
||||
}
|
||||
} else {
|
||||
$token = substr(base64_encode(uniqid(mt_rand(), true)), 0, 20);
|
||||
}
|
||||
|
||||
return str_replace('+', '', $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given text, we calculate reading time for an article.
|
||||
*
|
||||
* @param $text
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function getReadingTime($text)
|
||||
{
|
||||
return floor(str_word_count(strip_tags($text)) / 200);
|
||||
}
|
||||
}
|
|
@ -8,6 +8,22 @@ use Pagerfanta\Pagerfanta;
|
|||
|
||||
class EntryRepository extends EntityRepository
|
||||
{
|
||||
/**
|
||||
* Return a query builder to used by other getBuilderFor* method.
|
||||
*
|
||||
* @param int $userId
|
||||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
private function getBuilderByUser($userId)
|
||||
{
|
||||
return $this->createQueryBuilder('e')
|
||||
->leftJoin('e.user', 'u')
|
||||
->andWhere('u.id = :userId')->setParameter('userId', $userId)
|
||||
->orderBy('e.id', 'desc')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves unread entries for a user.
|
||||
*
|
||||
|
@ -15,13 +31,12 @@ class EntryRepository extends EntityRepository
|
|||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function findUnreadByUser($userId)
|
||||
public function getBuilderForUnreadByUser($userId)
|
||||
{
|
||||
return $this->createQueryBuilder('e')
|
||||
->leftJoin('e.user', 'u')
|
||||
->where('e.isArchived = false')
|
||||
->andWhere('u.id =:userId')->setParameter('userId', $userId)
|
||||
->orderBy('e.id', 'desc');
|
||||
return $this
|
||||
->getBuilderByUser($userId)
|
||||
->andWhere('e.isArchived = false')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -31,13 +46,12 @@ class EntryRepository extends EntityRepository
|
|||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function findArchiveByUser($userId)
|
||||
public function getBuilderForArchiveByUser($userId)
|
||||
{
|
||||
return $this->createQueryBuilder('e')
|
||||
->leftJoin('e.user', 'u')
|
||||
->where('e.isArchived = true')
|
||||
->andWhere('u.id =:userId')->setParameter('userId', $userId)
|
||||
->orderBy('e.id', 'desc');
|
||||
return $this
|
||||
->getBuilderByUser($userId)
|
||||
->andWhere('e.isArchived = true')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -47,13 +61,12 @@ class EntryRepository extends EntityRepository
|
|||
*
|
||||
* @return QueryBuilder
|
||||
*/
|
||||
public function findStarredByUser($userId)
|
||||
public function getBuilderForStarredByUser($userId)
|
||||
{
|
||||
return $this->createQueryBuilder('e')
|
||||
->leftJoin('e.user', 'u')
|
||||
->where('e.isStarred = true')
|
||||
->andWhere('u.id =:userId')->setParameter('userId', $userId)
|
||||
->orderBy('e.id', 'desc');
|
||||
return $this
|
||||
->getBuilderByUser($userId)
|
||||
->andWhere('e.isStarred = true')
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
entry:
|
||||
resource: "@WallabagCoreBundle/Controller/EntryController.php"
|
||||
type: annotation
|
||||
|
||||
config:
|
||||
resource: "@WallabagCoreBundle/Controller/ConfigController.php"
|
||||
type: annotation
|
|
@ -3,38 +3,34 @@
|
|||
{% block title %}{% trans %}About{% endtrans %}{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<h2>{% trans %}About wallabag{% endtrans %}</h2>
|
||||
<h2>{% trans %}Who is behind wallabag{% endtrans %}</h2>
|
||||
|
||||
<dl>
|
||||
<dt>{% trans %}Developed by{% endtrans %}</dt>
|
||||
<dd><a href="mailto:nicolas@loeuillet.org">Nicolas Lœuillet</a> — <a href="http://cdetc.fr">{% trans %}website{% endtrans %}</a></dd>
|
||||
<dd>Thomas Citharel — <a href="https://tcit.fr">{% trans %}website{% endtrans %}</a></dd>
|
||||
<dd>Jérémy Benoist — <a href="http://www.j0k3r.net">{% trans %}website{% endtrans %}</a></dd>
|
||||
|
||||
<dt>{% trans %}And many others contributors ♥{% endtrans %} <a href="https://github.com/wallabag/wallabag/graphs/contributors">{% trans %}on Github{% endtrans %}</a></dt>
|
||||
|
||||
<dt>{% trans %}Project website{% endtrans %}</dt>
|
||||
<dd><a href="https://www.wallabag.org">https://www.wallabag.org</a></dd>
|
||||
|
||||
<dt>{% trans %}Main developer{% endtrans %}</dt>
|
||||
<dd><a href="mailto:nicolas@loeuillet.org">Nicolas Lœuillet</a> — <a href="http://cdetc.fr">{% trans %}website{% endtrans %}</a></dd>
|
||||
<dt>{% trans %}License{% endtrans %}: <a href="http://en.wikipedia.org/wiki/MIT_License">MIT</a></dt>
|
||||
|
||||
<dt>{% trans %}Contributors ♥:{% endtrans %}</dt>
|
||||
<dd><a href="https://github.com/wallabag/wallabag/graphs/contributors">{% trans %}on Github{% endtrans %}</a></dd>
|
||||
|
||||
<dt>{% trans %}Bug reports{% endtrans %}</dt>
|
||||
<dd><a href="https://support.wallabag.org">{% trans %}On our support website{% endtrans %}</a> {% trans %}or{% endtrans %} <a href="https://github.com/wallabag/wallabag/issues">{% trans %}on Github{% endtrans %}</a></dd>
|
||||
|
||||
<dt>{% trans %}License{% endtrans %}</dt>
|
||||
<dd><a href="http://en.wikipedia.org/wiki/MIT_License">MIT</a></dd>
|
||||
|
||||
<dt>{% trans %}Version{% endtrans %}</dt>
|
||||
<dd>{{ version }}</dd>
|
||||
<dt>{% trans %}Version{% endtrans %}: {{ version }}</dt>
|
||||
</dl>
|
||||
|
||||
<p>{% trans %}wallabag is a read-it-later application: you can save a web page by keeping only content. Elements like ads or menus are deleted.{% endtrans %}</p>
|
||||
|
||||
<h2>{% trans %}Getting help{% endtrans %}</h2>
|
||||
|
||||
<dl>
|
||||
<dt>{% trans %}Documentation{% endtrans %}</dt>
|
||||
<dd><a href="https://doc.wallabag.org/">Online documentation</a></dd>
|
||||
<dd><a href="https://doc.wallabag.org/en">english</a></dd>
|
||||
<dd><a href="https://doc.wallabag.org/fr">français</a></dd>
|
||||
<dd><a href="https://doc.wallabag.org/de">deutsch</a></dd>
|
||||
|
||||
<dt>{% trans %}Support{% endtrans %}</dt>
|
||||
<dd><a href="http://support.wallabag.org/">http://support.wallabag.org/</a></dd>
|
||||
<dt>{% trans %}Bug reports{% endtrans %}</dt>
|
||||
<dd><a href="https://support.wallabag.org">{% trans %}On our support website{% endtrans %}</a> {% trans %}or{% endtrans %} <a href="https://github.com/wallabag/wallabag/issues">{% trans %}on Github{% endtrans %}</a></dd>
|
||||
</dl>
|
||||
|
||||
<h2>{% trans %}Helping wallabag{% endtrans %}</h2>
|
||||
|
@ -42,8 +38,10 @@
|
|||
<p>{% trans %}wallabag is free and opensource. You can help us:{% endtrans %}</p>
|
||||
|
||||
<dl>
|
||||
<dt><a href="{{ paypal_url }}">{% trans %}via Paypal{% endtrans %}</a></dt>
|
||||
<dt>{% trans %}wallabag is free and opensource. You can help us:{% endtrans %}</dt>
|
||||
<dd>by contributing to the project: <a href="https://github.com/wallabag/wallabag/issues/1254">an issue lists all our needs</a></dd>
|
||||
<dd><a href="{{ paypal_url }}">{% trans %}via Paypal{% endtrans %}</a></dd>
|
||||
|
||||
<dt><a href="{{ flattr_url }}">{% trans %}via Flattr{% endtrans %}</a></dt>
|
||||
<dd><a href="{{ flattr_url }}">{% trans %}via Flattr{% endtrans %}</a></dd>
|
||||
</dl>
|
||||
{% endblock %}
|
||||
|
|
|
@ -71,7 +71,7 @@
|
|||
<li><a href="{{ path('unread') }}">{% trans %}unread{% endtrans %}</a></li>
|
||||
<li><a href="{{ path('starred') }}">{% trans %}favorites{% endtrans %}</a></li>
|
||||
<li><a href="{{ path('archive') }}"}>{% trans %}archive{% endtrans %}</a></li>
|
||||
<li><a href="{{ path ('tag') }}">{% trans %}tags{% endtrans %}</a></li>
|
||||
<li><a href="{{ path('tag') }}">{% trans %}tags{% endtrans %}</a></li>
|
||||
<li><a href="{{ path('new') }}">{% trans %}save a link{% endtrans %}</a></li>
|
||||
<li style="position: relative;"><a href="javascript: void(null);" id="search">{% trans %}search{% endtrans %}</a>
|
||||
<div id="search-form" class="messages info popup-form">
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<dt>{% trans %}Developed by{% endtrans %}</dt>
|
||||
<dd><a href="mailto:nicolas@loeuillet.org">Nicolas Lœuillet</a> — <a href="http://cdetc.fr">{% trans %}website{% endtrans %}</a></dd>
|
||||
<dd>Thomas Citharel — <a href="https://tcit.fr">{% trans %}website{% endtrans %}</a></dd>
|
||||
<dd>Jérémy Besnoit — <a href="http://wildtrip.net">{% trans %}website{% endtrans %}</a></dd>
|
||||
<dd>Jérémy Benoist — <a href="http://www.j0k3r.net">{% trans %}website{% endtrans %}</a></dd>
|
||||
<dt>{% trans %}And many others contributors ♥{% endtrans %} <a href="https://github.com/wallabag/wallabag/graphs/contributors">{% trans %}on Github{% endtrans %}</a></dt>
|
||||
<dt>{% trans %}Project website{% endtrans %}</dt>
|
||||
<dd><a href="https://www.wallabag.org">https://www.wallabag.org</a></dd>
|
||||
|
|
|
@ -55,9 +55,9 @@
|
|||
</div>
|
||||
<div class="input-field nav-panel-buttom">
|
||||
<ul>
|
||||
<li class="bold"><a class="waves-effect" href="{{ path('new') }}" id="nav-btn-add"><i class="mdi-content-add"></i></a></li>
|
||||
<li><a class="waves-effect" href="javascript: void(null);" id="nav-btn-search"><i class="mdi-action-search"></i></a>
|
||||
<li id="button_filters"><a href="#" data-activates="filters" class="nav-panel-menu button-collapse-right"><i class="mdi-content-filter-list"></i></a></li>
|
||||
<li class="bold"><a title="{% trans %}Add a new entry{% endtrans %}" class="waves-effect" href="{{ path('new') }}" id="nav-btn-add"><i class="mdi-content-add"></i></a></li>
|
||||
<li><a title="{% trans %}Search{% endtrans %}" class="waves-effect" href="javascript: void(null);" id="nav-btn-search"><i class="mdi-action-search"></i></a>
|
||||
<li id="button_filters"><a title="{% trans %}Filter entries{% endtrans %}" href="#" data-activates="filters" class="nav-panel-menu button-collapse-right"><i class="mdi-content-filter-list"></i></a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<form method="get" action="index.php">
|
||||
|
|
|
@ -25,4 +25,17 @@ class Utils
|
|||
// remove character which can broken the url
|
||||
return str_replace(array('+', '/'), '', $token);
|
||||
}
|
||||
|
||||
/**
|
||||
* For a given text, we calculate reading time for an article
|
||||
* based on 200 words per minute.
|
||||
*
|
||||
* @param $text
|
||||
*
|
||||
* @return float
|
||||
*/
|
||||
public static function getReadingTime($text)
|
||||
{
|
||||
return floor(str_word_count(strip_tags($text)) / 200);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue