]> git.immae.eu Git - github/wallabag/wallabag.git/commitdiff
Merge pull request #356 from inthepoche/tags
authorNicolas Lœuillet <nicolas.loeuillet@gmail.com>
Thu, 12 Dec 2013 09:48:24 +0000 (01:48 -0800)
committerNicolas Lœuillet <nicolas.loeuillet@gmail.com>
Thu, 12 Dec 2013 09:48:24 +0000 (01:48 -0800)
Tags feature

14 files changed:
inc/poche/Database.class.php
inc/poche/Poche.class.php
inc/poche/Tools.class.php
index.php
install/mysql.sql
install/poche.sqlite
install/postgres.sql
themes/default/_menu.twig
themes/default/css/style.css
themes/default/edit-tags.twig [new file with mode: 0644]
themes/default/img/default/rss.png [new file with mode: 0644]
themes/default/tag.twig [new file with mode: 0644]
themes/default/tags.twig [new file with mode: 0644]
themes/default/view.twig

index c233eda16cf17df37ed5fb01831e950eca46ef80..d95b9b8101c08903bd4dfa80875697aca957b9db 100644 (file)
@@ -249,4 +249,75 @@ class Database {
     public function getLastId($column = '') {
         return $this->getHandle()->lastInsertId($column);
     }
+
+    public function retrieveAllTags() {
+        $sql = "SELECT * FROM tags";
+        $query = $this->executeQuery($sql, array());
+        $tags = $query->fetchAll();
+
+        return $tags;
+    }
+
+    public function retrieveTag($id) {
+        $tag  = NULL;
+        $sql    = "SELECT * FROM tags WHERE id=?";
+        $params = array(intval($id));
+        $query  = $this->executeQuery($sql, $params);
+        $tag  = $query->fetchAll();
+
+        return isset($tag[0]) ? $tag[0] : null;
+    }
+
+    public function retrieveEntriesByTag($tag_id) {
+        $sql = 
+            "SELECT * FROM entries
+            LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id
+            WHERE tags_entries.tag_id = ?";
+        $query = $this->executeQuery($sql, array($tag_id));
+        $entries = $query->fetchAll();
+
+        return $entries;
+    }
+
+    public function retrieveTagsByEntry($entry_id) {
+        $sql = 
+            "SELECT * FROM tags
+            LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id
+            WHERE tags_entries.entry_id = ?";
+        $query = $this->executeQuery($sql, array($entry_id));
+        $tags = $query->fetchAll();
+
+        return $tags;
+    }
+
+    public function removeTagForEntry($entry_id, $tag_id) {
+        $sql_action     = "DELETE FROM tags_entries WHERE tag_id=? AND entry_id=?";
+        $params_action  = array($tag_id, $entry_id);
+        $query          = $this->executeQuery($sql_action, $params_action);
+        return $query;
+    }
+
+    public function retrieveTagByValue($value) {
+        $tag  = NULL;
+        $sql    = "SELECT * FROM tags WHERE value=?";
+        $params = array($value);
+        $query  = $this->executeQuery($sql, $params);
+        $tag  = $query->fetchAll();
+
+        return isset($tag[0]) ? $tag[0] : null;
+    }
+
+    public function createTag($value) {
+        $sql_action = 'INSERT INTO tags ( value ) VALUES (?)';
+        $params_action = array($value);
+        $query = $this->executeQuery($sql_action, $params_action);
+        return $query;
+    }
+
+    public function setTagToEntry($tag_id, $entry_id) {
+        $sql_action = 'INSERT INTO tags_entries ( tag_id, entry_id ) VALUES (?, ?)';
+        $params_action = array($tag_id, $entry_id);
+        $query = $this->executeQuery($sql_action, $params_action);
+        return $query;
+    }
 }
index d45d0c406b60ba6da378de12595a76e61637f8d7..d415dd03b6cd3820a7a1a62a041027657eeccd7d 100644 (file)
@@ -397,6 +397,36 @@ class Poche
                     Tools::redirect();
                 }
                 break;
+            case 'add_tag' :
+                $tags = explode(',', $_POST['value']);
+                $entry_id = $_POST['entry_id'];
+                foreach($tags as $key => $tag_value) {
+                    $value = trim($tag_value);
+                    $tag = $this->store->retrieveTagByValue($value);
+
+                    if (is_null($tag)) {
+                        # we create the tag
+                        $tag = $this->store->createTag($value);
+                        $sequence = '';
+                        if (STORAGE == 'postgres') {
+                            $sequence = 'tags_id_seq';
+                        }
+                        $tag_id = $this->store->getLastId($sequence);
+                    }
+                    else {
+                        $tag_id = $tag['id'];
+                    }
+
+                    # we assign the tag to the article
+                    $this->store->setTagToEntry($tag_id, $entry_id);
+                }
+                Tools::redirect();
+                break;
+            case 'remove_tag' :
+                $tag_id = $_GET['tag_id'];
+                $this->store->removeTagForEntry($id, $tag_id);
+                Tools::redirect();
+                break;
             default:
                 break;
         }
@@ -430,6 +460,31 @@ class Poche
                 );
                 Tools::logm('config view');
                 break;
+            case 'edit-tags':
+                # tags
+                $tags = $this->store->retrieveTagsByEntry($id);
+                $tpl_vars = array(
+                    'entry_id' => $id,
+                    'tags' => $tags,
+                );
+                break;
+            case 'tag':
+                $entries = $this->store->retrieveEntriesByTag($id);
+                $tag = $this->store->retrieveTag($id);
+                $tpl_vars = array(
+                    'tag' => $tag,
+                    'entries' => $entries,
+                );
+                break;
+            case 'tags':
+                $token = $this->user->getConfigValue('token');
+                $tags = $this->store->retrieveAllTags();
+                $tpl_vars = array(
+                    'token' => $token,
+                    'user_id' => $this->user->getId(),
+                    'tags' => $tags,
+                );
+                break;
             case 'view':
                 $entry = $this->store->retrieveOneById($id, $this->user->getId());
                 if ($entry != NULL) {
@@ -443,12 +498,16 @@ class Poche
 
                     # flattr checking
                     $flattr = new FlattrItem();
-                    $flattr->checkItem($entry['url'],$entry['id']);
+                    $flattr->checkItem($entry['url'], $entry['id']);
+
+                    # tags
+                    $tags = $this->store->retrieveTagsByEntry($entry['id']);
 
                     $tpl_vars = array(
-                    'entry' => $entry,
-                    'content' => $content,
-                    'flattr' => $flattr
+                        'entry' => $entry,
+                        'content' => $content,
+                        'flattr' => $flattr,
+                        'tags' => $tags
                     );
                 }
                 else {
@@ -859,9 +918,9 @@ class Poche
         $_SESSION['poche_user']->setConfig($currentConfig);
     }
 
-    public function generateFeeds($token, $user_id, $type = 'home')
+    public function generateFeeds($token, $user_id, $tag_id, $type = 'home')
     {
-        $allowed_types = array('home', 'fav', 'archive');
+        $allowed_types = array('home', 'fav', 'archive', 'tag');
         $config = $this->store->getConfigUser($user_id);
 
         if (!in_array($type, $allowed_types) ||
@@ -876,7 +935,13 @@ class Poche
         $feed->setChannelElement('updated', date(DATE_RSS , time()));
         $feed->setChannelElement('author', 'poche');
 
-        $entries = $this->store->getEntriesByView($type, $user_id);
+        if ($type == 'tag') {
+            $entries = $this->store->retrieveEntriesByTag($tag_id);
+        }
+        else {
+            $entries = $this->store->getEntriesByView($type, $user_id);
+        }
+
         if (count($entries) > 0) {
             foreach ($entries as $entry) {
                 $newItem = $feed->createNewItem();
index 9d8e1fd655175e81b243523829988cc0018b619e..6391658259bea3aeecd3e18c15fa0a157233a605 100644 (file)
@@ -88,39 +88,16 @@ class Tools
 
     public static function getTplFile($view)
     {
-        $default_tpl = 'home.twig';
-        
-        switch ($view) {
-            case 'install':
-                $tpl_file = 'install.twig';
-                break;
-            case 'import';
-                $tpl_file = 'import.twig';
-                break;
-            case 'export':
-                $tpl_file = 'export.twig';
-                break;
-            case 'config':
-                $tpl_file = 'config.twig';
-                break;
-            case 'view':
-                $tpl_file = 'view.twig';
-                break;
-            
-            case 'login':
-                $tpl_file = 'login.twig';
-                break;
-                
-            case 'error':
-                $tpl_file = 'error.twig';
-                break;
-                
-            default:
-                $tpl_file = $default_tpl;
-                break;
+        $views = array(
+            'install', 'import', 'export', 'config', 'tags',
+            'edit-tags', 'view', 'login', 'error', 'tag'
+            );
+
+        if (in_array($view, $views)) {
+            return $view . '.twig';
         }
-        
-        return $tpl_file;
+
+        return 'home.twig';
     }
 
     public static function getFile($url)
index d2b363b0342bb044e44595abc89dacc60fe618dd..145da772f5ca28238e993dc79340518e2822d583 100644 (file)
--- a/index.php
+++ b/index.php
@@ -77,7 +77,8 @@ if (isset($_GET['login'])) {
         $poche->generateToken();
     }
     else {
-        $poche->generateFeeds($_GET['token'], $_GET['user_id'], $_GET['type']);
+        $tag_id = (isset($_GET['tag_id']) ? intval($_GET['tag_id']) : 0);
+        $poche->generateFeeds($_GET['token'], $_GET['user_id'], $tag_id, $_GET['type']);
     }
 }
 
index 9b01e32cf7200110fe91b6dce8ca457bf4db411b..66c4bb31274ff14dc4466a749c811b3ce1abad56 100644 (file)
@@ -31,4 +31,19 @@ CREATE TABLE IF NOT EXISTS `users_config` (
   `name` varchar(255) NOT NULL,
   `value` varchar(255) NOT NULL,
   PRIMARY KEY (`id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
+
+CREATE TABLE tags (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `value` varchar(255) NOT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
+
+CREATE TABLE tags_entries (
+  `id` int(11) NOT NULL AUTO_INCREMENT,
+  `entry_id` int(11) NOT NULL,
+  `tag_id` int(11) NOT NULL,
+  FOREIGN KEY(entry_id) REFERENCES entries(id) ON DELETE CASCADE,
+  FOREIGN KEY(tag_id) REFERENCES tags(id) ON DELETE CASCADE,
+  PRIMARY KEY (`id`)
 ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
\ No newline at end of file
index 7abf1f62ddbed441a90d283e9236a9bb3011ae84..b911f2720a34def149c1154bf75f591080a5dbe5 100755 (executable)
Binary files a/install/poche.sqlite and b/install/poche.sqlite differ
index 9e0e82763058cc483423b65a7a7b5c80fd5f5273..fe8f559ca29c31925a69b88d0d2cab5d815f117a 100644 (file)
@@ -27,4 +27,15 @@ CREATE TABLE users_config (
     user_id integer NOT NULL,
     name varchar(255) NOT NULL,
     value varchar(255) NOT NULL
-);
\ No newline at end of file
+);
+
+CREATE TABLE tags (
+  id bigserial primary key,
+  value varchar(255) NOT NULL
+);
+
+CREATE TABLE tags_entries (
+  id bigserial primary key,
+  entry_id integer NOT NULL,
+  tag_id integer NOT NULL
+)
\ No newline at end of file
index 699d6a0c93411d46d9b04b8fbfe6c1dc18ca7370..02bec1dcdbf94d99050d4cb68188e1c43d125ad0 100644 (file)
@@ -2,6 +2,7 @@
                 <li><a href="./" {% if view == 'home' %}class="current"{% endif %}>{% trans "home" %}</a></li>
                 <li><a href="./?view=fav" {% if view == 'fav' %}class="current"{% endif %}>{% trans "favorites" %}</a></li>
                 <li><a href="./?view=archive" {% if view == 'archive' %}class="current"{% endif %}>{% trans "archive" %}</a></li>
+                <li><a href="./?view=tags" {% if view == 'tags' %}class="current"{% endif %}>{% trans "tags" %}</a></li>
                 <li><a href="./?view=config" {% if view == 'config' %}class="current"{% endif %}>{% trans "config" %}</a></li>
                 <li><a href="./?logout" title="{% trans "logout" %}">{% trans "logout" %}</a></li>
             </ul>
\ No newline at end of file
index 670eb50f4966581e6d0ffca4110343a11ce639e5..2088ee2ee9c5b97522dcaeab9150ccae590e0018 100644 (file)
@@ -176,6 +176,12 @@ a:visited {
     text-decoration: none;
 }
 
+#article .tags {
+    font-size: 0.8em;
+    color: #888;
+    padding-bottom: 5px;
+}
+
 .backhome {
     display: inline;
 }
diff --git a/themes/default/edit-tags.twig b/themes/default/edit-tags.twig
new file mode 100644 (file)
index 0000000..7116bba
--- /dev/null
@@ -0,0 +1,20 @@
+{% extends "layout.twig" %}
+{% block title %}edit tags{% endblock %}
+{% block menu %}
+{% include '_menu.twig' %}
+{% endblock %}
+{% block content %}
+{% if tags is empty %}
+no tags
+{% endif %}
+<ul>
+{% for tag in tags %}<li>{{ tag.value }} <a href="./?action=remove_tag&amp;tag_id={{ tag.id }}&amp;id={{ entry_id }}">✘</a></li>{% endfor %}
+</ul>
+<form method="post" action="./?action=add_tag">
+    <label for="value">New tags: </label><input type="text" id="value" name="value" required="required" />
+    <p>{% trans "you can type several tags, separated by comma" %}</p>
+    <input type="hidden" name="entry_id" value="{{ entry_id }}" />
+    <input type="submit" value="add tags" />
+</form>
+<a href="./?view=view&id={{ entry_id }}">{% trans "back to the article" %}</a>
+{% endblock %}
\ No newline at end of file
diff --git a/themes/default/img/default/rss.png b/themes/default/img/default/rss.png
new file mode 100644 (file)
index 0000000..21bad1a
Binary files /dev/null and b/themes/default/img/default/rss.png differ
diff --git a/themes/default/tag.twig b/themes/default/tag.twig
new file mode 100644 (file)
index 0000000..364c7cd
--- /dev/null
@@ -0,0 +1,33 @@
+{% extends "layout.twig" %}
+{% block title %}tag {% endblock %}
+{% block menu %}
+{% include '_menu.twig' %}
+{% endblock %}
+{% block content %}
+    <h3>{% trans "Tag" %} {{ tag.value }}</h3>
+    {% if entries is empty %}
+    <div class="messages warning"><p>{% trans "No link available here!" %}</p></div>
+    {% else %}
+        {% block pager %}
+            {% if nb_results > 1 %}
+        <div class="results">
+            <div class="nb-results">{{ nb_results }} {% trans "results" %}</div>
+                {{ page_links | raw }}
+        </div>
+            {% endif %}
+        {% endblock %}
+        {% for entry in entries %}
+    <div id="entry-{{ entry.id|e }}" class="entrie">
+        <h2><a href="index.php?view=view&amp;id={{ entry.id|e }}">{{ entry.title|raw }}</a></h2>
+        <ul class="tools">
+            <li><a title="{% trans "toggle mark as read" %}" class="tool {% if entry.is_read == 0 %}archive-off{% else %}archive{% endif %}" href="./?action=toggle_archive&amp;id={{ entry.id|e }}"><span>{% trans "toggle mark as read" %}</span></a></li>
+            <li><a title="{% trans "toggle favorite" %}" class="tool {% if entry.is_fav == 0 %}fav-off{% else %}fav{% endif %}" href="./?action=toggle_fav&amp;id={{ entry.id|e }}"><span>{% trans "toggle favorite" %}</span></a></li>
+            <li><a title="{% trans "delete" %}" class="tool delete" href="./?action=delete&amp;id={{ entry.id|e }}"><span>{% trans "delete" %}</span></a></li>
+            <li><a href="{{ entry.url|e }}" target="_blank" title="{% trans "original" %} : {{ entry.title|e }}" class="tool link"><span>{{ entry.url | e | getDomain }}</span></a></li>
+            <li><a target="_blank" title="{% trans "estimated reading time:" %} {{ entry.content| getReadingTime }} min" class="reading-time"><span>{{ entry.content| getReadingTime }} min</span></a></li>
+        </ul>
+        <p>{{ entry.content|striptags|slice(0, 300) }}...</p>
+    </div>
+        {% endfor %}
+    {% endif %}
+{% endblock %}
\ No newline at end of file
diff --git a/themes/default/tags.twig b/themes/default/tags.twig
new file mode 100644 (file)
index 0000000..cff6b1d
--- /dev/null
@@ -0,0 +1,8 @@
+{% extends "layout.twig" %}
+{% block title %}tags{% endblock %}
+{% block menu %}
+{% include '_menu.twig' %}
+{% endblock %}
+{% block content %}
+{% for tag in tags %}<a href="./?view=tag&amp;id={{ tag.id }}">{{ tag.value }}</a> {% if token != '' %}<a href="?feed&amp;type=tag&amp;user_id={{ user_id }}&amp;tag_id={{ tag.id }}&amp;token={{ token }}" target="_blank"><img src="{{ poche_url }}/themes/{{ theme }}/img/{{ theme }}/rss.png" /></a>{% endif %} {% endfor %}
+{% endblock %}
\ No newline at end of file
index 1e54ae384e84e00482a949f89359ef5b6bfadc98..64672b617752a0d60dcf74d13d51d9933d289c04 100644 (file)
@@ -20,6 +20,9 @@
             <header class="mbm">
                 <h1>{{ entry.title|raw }}</h1>
             </header>
+            <aside class="tags">
+                tags: {% for tag in tags %}<a href="./?view=tag&amp;id={{ tag.id }}">{{ tag.value }}</a> {% endfor %}<a href="./?view=edit-tags&amp;id={{ entry.id|e }}" title="{% trans "edit tags" %}">✎</a>
+            </aside>
             <article>
                 {{ content | raw }}
             </article>