]> git.immae.eu Git - github/shaarli/Shaarli.git/commitdiff
Add a button to set links as sticky
authorArthurHoaro <arthur@hoa.ro>
Tue, 22 May 2018 20:44:38 +0000 (22:44 +0200)
committerArthurHoaro <arthur@hoa.ro>
Sat, 6 Oct 2018 10:55:05 +0000 (12:55 +0200)
Meaning that they always appear on top of all links

Fixes #186

12 files changed:
application/LinkDB.php
application/Router.php
application/Updater.php
assets/default/scss/shaarli.scss
index.php
tests/FeedBuilderTest.php
tests/LinkDBTest.php
tests/NetscapeBookmarkUtils/BookmarkExportTest.php
tests/Updater/UpdaterTest.php
tests/api/controllers/links/GetLinksTest.php
tests/utils/ReferenceLinkDB.php
tpl/default/linklist.html

index cd0f29671f9b199c213b4333e8eeab23eedcadb7..cdd68cfb1bec88e8dffd526e0c8c6a433933344a 100644 (file)
@@ -537,6 +537,9 @@ You use the community supported version of the original Shaarli project, by Seba
         $order = $order === 'ASC' ? -1 : 1;
         // Reorder array by dates.
         usort($this->links, function($a, $b) use ($order) {
+            if (isset($a['sticky']) && isset($b['sticky']) && $a['sticky'] !== $b['sticky']) {
+                return $a['sticky'] ? -1 : 1;
+            }
             return $a['created'] < $b['created'] ? 1 * $order : -1 * $order;
         });
 
index bf86b884db07243a215c86748d5f97cc9c1b811c..beb3165b49e128e1a8cb5f60bbb0427fa3a80b5e 100644 (file)
@@ -37,6 +37,8 @@ class Router
 
     public static $PAGE_DELETELINK = 'delete_link';
 
+    public static $PAGE_PINLINK = 'pin';
+
     public static $PAGE_EXPORT = 'export';
 
     public static $PAGE_IMPORT = 'import';
@@ -146,6 +148,10 @@ class Router
             return self::$PAGE_DELETELINK;
         }
 
+        if (startsWith($query, 'do='. self::$PAGE_PINLINK)) {
+            return self::$PAGE_PINLINK;
+        }
+
         if (startsWith($query, 'do='. self::$PAGE_EXPORT)) {
             return self::$PAGE_EXPORT;
         }
index 480bff8267956ad82e12d3a4169e7b09f60ee135..5dde47cb0164c4fe397689f8e7e57a6d1b096d04 100644 (file)
@@ -517,6 +517,26 @@ class Updater
 
         return true;
     }
+
+    /**
+     * Set sticky = false on all links
+     *
+     * @return bool true if the update is successful, false otherwise.
+     */
+    public function updateMethodSetSticky()
+    {
+        foreach ($this->linkDB as $key => $link) {
+            if (isset($link['sticky'])) {
+                return true;
+            }
+            $link['sticky'] = false;
+            $this->linkDB[$key] = $link;
+        }
+
+        $this->linkDB->save($this->conf->get('resource.page_cache'));
+
+        return true;
+    }
 }
 
 /**
index b8578ea6869855b907c5d89ae963e938ecb864a0..037183ddd249cf17e49ecb55c34876abc1a400d0 100644 (file)
@@ -755,6 +755,14 @@ body,
   font-size: 1.3em;
 }
 
+.pin-link {
+    font-size: 1.3em;
+}
+
+.pinned-link {
+    color: #0b5ea6 !important;
+}
+
 .linklist-item-description {
   position: relative;
   padding: 0 10px;
@@ -848,6 +856,10 @@ body,
   margin: 0 7px;
 }
 
+.ctrl-delete {
+    margin: 0 7px 0 0;
+}
+
 // 64em -> lg
 @media screen and (max-width: 64em) {
   .linklist-item-infos-url {
index 0ef3363354e54f69a958092fafaf5d7ba619855f..b702bd133bc7023c7f9c5d63396754a80f272d51 100644 (file)
--- a/index.php
+++ b/index.php
@@ -1353,6 +1353,25 @@ function renderPage($conf, $pluginManager, $LINKSDB, $history, $sessionManager,
         exit;
     }
 
+    if ($targetPage == Router::$PAGE_PINLINK) {
+        if (! isset($_GET['id']) || empty($LINKSDB[$_GET['id']])) {
+            // FIXME! Use a proper error system.
+            $msg = t('Invalid link ID provided');
+            echo '<script>alert("'. $msg .'");document.location=\''. index_url($_SERVER) .'\';</script>';
+            exit;
+        }
+        if (! $sessionManager->checkToken($_GET['token'])) {
+            die('Wrong token.');
+        }
+
+        $link = $LINKSDB[$_GET['id']];
+        $link['sticky'] = ! $link['sticky'];
+        $LINKSDB[(int) $_GET['id']] = $link;
+        $LINKSDB->save($conf->get('resource.page_cache'));
+        header('Location: '.index_url($_SERVER));
+        exit;
+    }
+
     if ($targetPage == Router::$PAGE_EXPORT) {
         // Export links as a Netscape Bookmarks file
 
index a590306db54524e8fc4a98a6d5a2d8e023c3d4ee..4ca58e5a3b514bf20f21a4597c3d49fb927c1378 100644 (file)
@@ -82,8 +82,8 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase
         $this->assertFalse($data['usepermalinks']);
         $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
 
-        // Test first link (note link)
-        $link = reset($data['links']);
+        // Test first not pinned link (note link)
+        $link = $data['links'][array_keys($data['links'])[2]];
         $this->assertEquals(41, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
         $this->assertEquals('http://host.tld/?WDWyig', $link['guid']);
@@ -119,7 +119,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase
         $data = $feedBuilder->buildData();
         $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
         $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['last_update']);
-        $link = reset($data['links']);
+        $link = $data['links'][array_keys($data['links'])[2]];
         $this->assertRegExp('/2015-03-10T11:46:51\+\d{2}:\d{2}/', $link['pub_iso_date']);
         $this->assertRegExp('/2016-08-03T09:30:33\+\d{2}:\d{2}/', $data['links'][8]['up_iso_date']);
     }
@@ -148,13 +148,13 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase
     public function testBuildDataCount()
     {
         $criteria = array(
-            'nb' => '1',
+            'nb' => '3',
         );
         $feedBuilder = new FeedBuilder(self::$linkDB, FeedBuilder::$FEED_ATOM, self::$serverInfo, $criteria, false);
         $feedBuilder->setLocale(self::$LOCALE);
         $data = $feedBuilder->buildData();
-        $this->assertEquals(1, count($data['links']));
-        $link = array_shift($data['links']);
+        $this->assertEquals(3, count($data['links']));
+        $link = $data['links'][array_keys($data['links'])[2]];
         $this->assertEquals(41, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
     }
@@ -171,7 +171,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase
         $this->assertEquals(ReferenceLinkDB::$NB_LINKS_TOTAL, count($data['links']));
         $this->assertTrue($data['usepermalinks']);
         // First link is a permalink
-        $link = array_shift($data['links']);
+        $link = $data['links'][array_keys($data['links'])[2]];
         $this->assertEquals(41, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114651'), $link['created']);
         $this->assertEquals('http://host.tld/?WDWyig', $link['guid']);
@@ -179,7 +179,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase
         $this->assertContains('Direct link', $link['description']);
         $this->assertContains('http://host.tld/?WDWyig', $link['description']);
         // Second link is a direct link
-        $link = array_shift($data['links']);
+        $link = $data['links'][array_keys($data['links'])[3]];
         $this->assertEquals(8, $link['id']);
         $this->assertEquals(DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20150310_114633'), $link['created']);
         $this->assertEquals('http://host.tld/?RttfEw', $link['guid']);
@@ -237,7 +237,7 @@ class FeedBuilderTest extends PHPUnit_Framework_TestCase
         );
 
         // Test first link (note link)
-        $link = array_shift($data['links']);
+        $link = $data['links'][array_keys($data['links'])[2]];
         $this->assertEquals('http://host.tld:8080/~user/shaarli/?WDWyig', $link['guid']);
         $this->assertEquals('http://host.tld:8080/~user/shaarli/?WDWyig', $link['url']);
         $this->assertContains('http://host.tld:8080/~user/shaarli/?addtag=hashtag', $link['description']);
index 3b9808782fba646c9ec1440b844d46310b05cbcd..fcab76f609b8366a1f2d657fc1aaa76ab0386519 100644 (file)
@@ -239,12 +239,12 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
     public function testDays()
     {
         $this->assertEquals(
-            array('20100310', '20121206', '20130614', '20150310'),
+            array('20100309', '20100310', '20121206', '20121207', '20130614', '20150310'),
             self::$publicLinkDB->days()
         );
 
         $this->assertEquals(
-            array('20100310', '20121206', '20130614', '20141125', '20150310'),
+            array('20100309', '20100310', '20121206', '20121207', '20130614', '20141125', '20150310'),
             self::$privateLinkDB->days()
         );
     }
@@ -475,13 +475,15 @@ class LinkDBTest extends PHPUnit_Framework_TestCase
     public function testReorderLinksDesc()
     {
         self::$privateLinkDB->reorder('ASC');
-        $linkIds = array(42, 4, 9, 1, 0, 7, 6, 8, 41);
+        $stickyIds = [11, 10];
+        $standardIds = [42, 4, 9, 1, 0, 7, 6, 8, 41];
+        $linkIds = array_merge($stickyIds, $standardIds);
         $cpt = 0;
         foreach (self::$privateLinkDB as $key => $value) {
             $this->assertEquals($linkIds[$cpt++], $key);
         }
         self::$privateLinkDB->reorder('DESC');
-        $linkIds = array_reverse($linkIds);
+        $linkIds = array_merge(array_reverse($stickyIds), array_reverse($standardIds));
         $cpt = 0;
         foreach (self::$privateLinkDB as $key => $value) {
             $this->assertEquals($linkIds[$cpt++], $key);
index 6a47bbb97acac26996766c7cf9c30f8738fc069c..77fbd5f38795ee6bf8d1761e1a00da77922be9ae 100644 (file)
@@ -110,7 +110,7 @@ class BookmarkExportTest extends PHPUnit_Framework_TestCase
         $links = NetscapeBookmarkUtils::filterAndFormat(self::$linkDb, 'public', false, '');
         $this->assertEquals(
             '?WDWyig',
-            $links[0]['url']
+            $links[2]['url']
         );
     }
 
@@ -128,7 +128,7 @@ class BookmarkExportTest extends PHPUnit_Framework_TestCase
         );
         $this->assertEquals(
             $indexUrl . '?WDWyig',
-            $links[0]['url']
+            $links[2]['url']
         );
     }
 }
index cacee2d2da25b247e8f5084a1192fe09640693f4..870f169a703d4b459a5c90006f2699a49768c908 100644 (file)
@@ -688,6 +688,7 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
     }
 
     /**
+<<<<<<< HEAD
      * Test updateMethodWebThumbnailer with thumbnails enabled.
      */
     public function testUpdateMethodWebThumbnailerEnabled()
@@ -732,4 +733,64 @@ $GLOBALS[\'privateLinkByDefault\'] = true;';
         $this->assertEquals(53, $this->conf->get('thumbnails.height'));
         $this->assertTrue(empty($_SESSION['warnings']));
     }
+
+    /**
+     * Test updateMethodSetSticky().
+     */
+    public function testUpdateStickyValid()
+    {
+        $blank = [
+            'id' => 1,
+            'url' => 'z',
+            'title' => '',
+            'description' => '',
+            'tags' => '',
+            'created' => new DateTime(),
+        ];
+        $links = [
+            1 => ['id' => 1] + $blank,
+            2 => ['id' => 2] + $blank,
+        ];
+        $refDB = new ReferenceLinkDB();
+        $refDB->setLinks($links);
+        $refDB->write(self::$testDatastore);
+        $linkDB = new LinkDB(self::$testDatastore, true, false);
+
+        $updater = new Updater(array(), $linkDB, $this->conf, true);
+        $this->assertTrue($updater->updateMethodSetSticky());
+
+        $linkDB = new LinkDB(self::$testDatastore, true, false);
+        foreach ($linkDB as $link) {
+            $this->assertFalse($link['sticky']);
+        }
+    }
+
+    /**
+     * Test updateMethodSetSticky().
+     */
+    public function testUpdateStickyNothingToDo()
+    {
+        $blank = [
+            'id' => 1,
+            'url' => 'z',
+            'title' => '',
+            'description' => '',
+            'tags' => '',
+            'created' => new DateTime(),
+        ];
+        $links = [
+            1 => ['id' => 1, 'sticky' => true] + $blank,
+            2 => ['id' => 2] + $blank,
+        ];
+        $refDB = new ReferenceLinkDB();
+        $refDB->setLinks($links);
+        $refDB->write(self::$testDatastore);
+        $linkDB = new LinkDB(self::$testDatastore, true, false);
+
+        $updater = new Updater(array(), $linkDB, $this->conf, true);
+        $this->assertTrue($updater->updateMethodSetSticky());
+
+        $linkDB = new LinkDB(self::$testDatastore, true, false);
+        $this->assertTrue($linkDB[1]['sticky']);
+    }
 }
index d22ed3bfe97fe8d98054f1eff9e9e3597573e5a9..64f027743787d22fd7ad9a700145c4e6563ba6e7 100644 (file)
@@ -95,7 +95,7 @@ class GetLinksTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals($this->refDB->countLinks(), count($data));
 
         // Check order
-        $order = [41, 8, 6, 7, 0, 1, 9, 4, 42];
+        $order = [10, 11, 41, 8, 6, 7, 0, 1, 9, 4, 42];
         $cpt = 0;
         foreach ($data as $link) {
             $this->assertEquals(self::NB_FIELDS_LINK, count($link));
@@ -103,7 +103,7 @@ class GetLinksTest extends \PHPUnit_Framework_TestCase
         }
 
         // Check first element fields
-        $first = $data[0];
+        $first = $data[2];
         $this->assertEquals('http://domain.tld/?WDWyig', $first['url']);
         $this->assertEquals('WDWyig', $first['shorturl']);
         $this->assertEquals('Link title: @website', $first['title']);
@@ -120,7 +120,7 @@ class GetLinksTest extends \PHPUnit_Framework_TestCase
         $this->assertEmpty($first['updated']);
 
         // Multi tags
-        $link = $data[1];
+        $link = $data[3];
         $this->assertEquals(7, count($link['tags']));
 
         // Update date
@@ -138,7 +138,7 @@ class GetLinksTest extends \PHPUnit_Framework_TestCase
     {
         $env = Environment::mock([
             'REQUEST_METHOD' => 'GET',
-            'QUERY_STRING' => 'offset=1&limit=1'
+            'QUERY_STRING' => 'offset=3&limit=1'
         ]);
         $request = Request::createFromEnvironment($env);
         $response = $this->controller->getLinks($request, new Response());
@@ -164,7 +164,7 @@ class GetLinksTest extends \PHPUnit_Framework_TestCase
         $data = json_decode((string) $response->getBody(), true);
         $this->assertEquals($this->refDB->countLinks(), count($data));
         // Check order
-        $order = [41, 8, 6, 7, 0, 1, 9, 4, 42];
+        $order = [10, 11, 41, 8, 6, 7, 0, 1, 9, 4, 42];
         $cpt = 0;
         foreach ($data as $link) {
             $this->assertEquals(self::NB_FIELDS_LINK, count($link));
@@ -205,7 +205,8 @@ class GetLinksTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals(200, $response->getStatusCode());
         $data = json_decode((string)$response->getBody(), true);
         $this->assertEquals($this->refDB->countLinks(), count($data));
-        $this->assertEquals(41, $data[0]['id']);
+        $this->assertEquals(10, $data[0]['id']);
+        $this->assertEquals(41, $data[2]['id']);
         $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
     }
 
@@ -243,7 +244,8 @@ class GetLinksTest extends \PHPUnit_Framework_TestCase
         $this->assertEquals(200, $response->getStatusCode());
         $data = json_decode((string)$response->getBody(), true);
         $this->assertEquals($this->refDB->countPublicLinks(), count($data));
-        $this->assertEquals(41, $data[0]['id']);
+        $this->assertEquals(10, $data[0]['id']);
+        $this->assertEquals(41, $data[2]['id']);
         $this->assertEquals(self::NB_FIELDS_LINK, count($data[0]));
     }
 
@@ -413,8 +415,9 @@ class GetLinksTest extends \PHPUnit_Framework_TestCase
         $response = $this->controller->getLinks($request, new Response());
         $this->assertEquals(200, $response->getStatusCode());
         $data = json_decode((string) $response->getBody(), true);
-        $this->assertEquals(9, count($data));
-        $this->assertEquals(41, $data[0]['id']);
+        $this->assertEquals(\ReferenceLinkDB::$NB_LINKS_TOTAL, count($data));
+        $this->assertEquals(10, $data[0]['id']);
+        $this->assertEquals(41, $data[2]['id']);
 
         // wildcard: optional ('*' does not need to expand)
         $env = Environment::mock([
index e887aa78c2251747c46cf37fab4359c782b32b36..7426ad0783e49652872f4b9ca2db8e5951f5c21b 100644 (file)
@@ -4,7 +4,7 @@
  */
 class ReferenceLinkDB
 {
-    public static $NB_LINKS_TOTAL = 9;
+    public static $NB_LINKS_TOTAL = 11;
 
     private $_links = array();
     private $_publicCount = 0;
@@ -15,6 +15,32 @@ class ReferenceLinkDB
      */
     public function __construct()
     {
+        $this->addLink(
+            11,
+            'Pined older',
+            '?PCRizQ',
+            'This is an older pinned link',
+            0,
+            DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20100309_101010'),
+            '',
+            null,
+            'PCRizQ',
+            true
+        );
+
+        $this->addLink(
+            10,
+            'Pined',
+            '?0gCTjQ',
+            'This is a pinned link',
+            0,
+            DateTime::createFromFormat(LinkDB::LINK_DATE_FORMAT, '20121207_152312'),
+            '',
+            null,
+            '0gCTjQ',
+            true
+        );
+
         $this->addLink(
             41,
             'Link title: @website',
@@ -114,7 +140,17 @@ class ReferenceLinkDB
     /**
      * Adds a new link
      */
-    protected function addLink($id, $title, $url, $description, $private, $date, $tags, $updated = '', $shorturl = '')
+    protected function addLink(
+        $id,
+        $title,
+        $url,
+        $description,
+        $private,
+        $date,
+        $tags,
+        $updated = '',
+        $shorturl = '',
+        $pinned = false)
     {
         $link = array(
             'id' => $id,
@@ -126,6 +162,7 @@ class ReferenceLinkDB
             'created' => $date,
             'updated' => $updated,
             'shorturl' => $shorturl ? $shorturl : smallHash($date->format(LinkDB::LINK_DATE_FORMAT) . $id),
+            'sticky' => $pinned
         );
         $this->_links[$id] = $link;
 
@@ -165,6 +202,10 @@ class ReferenceLinkDB
         $order = $order === 'ASC' ? -1 : 1;
         // Reorder array by dates.
         usort($this->_links, function($a, $b) use ($order) {
+            if (isset($a['sticky']) && isset($b['sticky']) && $a['sticky'] !== $b['sticky']) {
+                return $a['sticky'] ? -1 : 1;
+            }
+
             return $a['created'] < $b['created'] ? 1 * $order : -1 * $order;
         });
     }
index 8ea2ce66194ef728581cd75f8c5a7dfa5cf157e8..aaa9bc747c912e3346d650aea3db6c4e7b651b94 100644 (file)
                         <i class="fa fa-trash"></i>
                       </a>
                     </span>
+                    <span class="linklist-item-infos-controls-item ctrl-pin">
+                      <a href="?do=pin&amp;id={$value.id}&amp;token={$token}"
+                         title="{$strDelete}" class="pin-link {if="$value.sticky"}pinned-link{/if} pure-u-0 pure-u-lg-visible">
+                        <i class="fa fa-thumb-tack"></i>
+                      </a>
+                    </span>
                   </div>
                 {/if}
                 <a href="?{$value.shorturl}" title="{$strPermalink}">