diff options
-rwxr-xr-x[-rw-r--r--] | inc/3rdparty/libraries/feedwriter/FeedWriter.php | 168 | ||||
-rwxr-xr-x | inc/poche/Database.class.php | 96 | ||||
-rwxr-xr-x | inc/poche/Poche.class.php | 317 | ||||
-rwxr-xr-x | inc/poche/Tools.class.php | 8 | ||||
-rwxr-xr-x | inc/poche/config.inc.php.new | 14 | ||||
-rwxr-xr-x[-rw-r--r--] | index.php | 5 | ||||
-rwxr-xr-x[-rw-r--r--] | themes/baggy/config.twig | 27 | ||||
-rwxr-xr-x | themes/baggy/css/main.css | 7 | ||||
-rwxr-xr-x[-rw-r--r--] | themes/baggy/layout.twig | 3 | ||||
-rwxr-xr-x | themes/default/_import.twig | 15 | ||||
-rwxr-xr-x[-rw-r--r--] | themes/default/config.twig | 25 | ||||
-rwxr-xr-x | themes/default/home.twig | 5 |
12 files changed, 384 insertions, 306 deletions
diff --git a/inc/3rdparty/libraries/feedwriter/FeedWriter.php b/inc/3rdparty/libraries/feedwriter/FeedWriter.php index adb2526c..5d16e765 100644..100755 --- a/inc/3rdparty/libraries/feedwriter/FeedWriter.php +++ b/inc/3rdparty/libraries/feedwriter/FeedWriter.php | |||
@@ -9,9 +9,9 @@ define('JSONP', 3, true); | |||
9 | * Genarate RSS2 or JSON (original: RSS 1.0, RSS2.0 and ATOM Feed) | 9 | * Genarate RSS2 or JSON (original: RSS 1.0, RSS2.0 and ATOM Feed) |
10 | * | 10 | * |
11 | * Modified for FiveFilters.org's Full-Text RSS project | 11 | * Modified for FiveFilters.org's Full-Text RSS project |
12 | * to allow for inclusion of hubs, JSON output. | 12 | * to allow for inclusion of hubs, JSON output. |
13 | * Stripped RSS1 and ATOM support. | 13 | * Stripped RSS1 and ATOM support. |
14 | * | 14 | * |
15 | * @package UnivarselFeedWriter | 15 | * @package UnivarselFeedWriter |
16 | * @author Anis uddin Ahmad <anisniit@gmail.com> | 16 | * @author Anis uddin Ahmad <anisniit@gmail.com> |
17 | * @link http://www.ajaxray.com/projects/rss | 17 | * @link http://www.ajaxray.com/projects/rss |
@@ -26,32 +26,32 @@ define('JSONP', 3, true); | |||
26 | private $CDATAEncoding = array(); // The tag names which have to encoded as CDATA | 26 | private $CDATAEncoding = array(); // The tag names which have to encoded as CDATA |
27 | private $xsl = null; // stylesheet to render RSS (used by Chrome) | 27 | private $xsl = null; // stylesheet to render RSS (used by Chrome) |
28 | private $json = null; // JSON object | 28 | private $json = null; // JSON object |
29 | 29 | ||
30 | private $version = null; | 30 | private $version = null; |
31 | 31 | ||
32 | /** | 32 | /** |
33 | * Constructor | 33 | * Constructor |
34 | * | 34 | * |
35 | * @param constant the version constant (RSS2 or JSON). | 35 | * @param constant the version constant (RSS2 or JSON). |
36 | */ | 36 | */ |
37 | function __construct($version = RSS2) | 37 | function __construct($version = RSS2) |
38 | { | 38 | { |
39 | $this->version = $version; | 39 | $this->version = $version; |
40 | 40 | ||
41 | // Setting default value for assential channel elements | 41 | // Setting default value for assential channel elements |
42 | $this->channels['title'] = $version . ' Feed'; | 42 | $this->channels['title'] = $version . ' Feed'; |
43 | $this->channels['link'] = 'http://www.ajaxray.com/blog'; | 43 | $this->channels['link'] = 'http://www.ajaxray.com/blog'; |
44 | 44 | ||
45 | //Tag names to encode in CDATA | 45 | //Tag names to encode in CDATA |
46 | $this->CDATAEncoding = array('description', 'content:encoded', 'content', 'subtitle', 'summary'); | 46 | $this->CDATAEncoding = array('description', 'content:encoded', 'content', 'subtitle', 'summary'); |
47 | } | 47 | } |
48 | 48 | ||
49 | public function setFormat($format) { | 49 | public function setFormat($format) { |
50 | $this->version = $format; | 50 | $this->version = $format; |
51 | } | 51 | } |
52 | 52 | ||
53 | // Start # public functions --------------------------------------------- | 53 | // Start # public functions --------------------------------------------- |
54 | 54 | ||
55 | /** | 55 | /** |
56 | * Set a channel element | 56 | * Set a channel element |
57 | * @access public | 57 | * @access public |
@@ -63,11 +63,11 @@ define('JSONP', 3, true); | |||
63 | { | 63 | { |
64 | $this->channels[$elementName] = $content ; | 64 | $this->channels[$elementName] = $content ; |
65 | } | 65 | } |
66 | 66 | ||
67 | /** | 67 | /** |
68 | * Set multiple channel elements from an array. Array elements | 68 | * Set multiple channel elements from an array. Array elements |
69 | * should be 'channelName' => 'channelContent' format. | 69 | * should be 'channelName' => 'channelContent' format. |
70 | * | 70 | * |
71 | * @access public | 71 | * @access public |
72 | * @param array array of channels | 72 | * @param array array of channels |
73 | * @return void | 73 | * @return void |
@@ -75,30 +75,30 @@ define('JSONP', 3, true); | |||
75 | public function setChannelElementsFromArray($elementArray) | 75 | public function setChannelElementsFromArray($elementArray) |
76 | { | 76 | { |
77 | if(! is_array($elementArray)) return; | 77 | if(! is_array($elementArray)) return; |
78 | foreach ($elementArray as $elementName => $content) | 78 | foreach ($elementArray as $elementName => $content) |
79 | { | 79 | { |
80 | $this->setChannelElement($elementName, $content); | 80 | $this->setChannelElement($elementName, $content); |
81 | } | 81 | } |
82 | } | 82 | } |
83 | 83 | ||
84 | /** | 84 | /** |
85 | * Genarate the actual RSS/JSON file | 85 | * Genarate the actual RSS/JSON file |
86 | * | 86 | * |
87 | * @access public | 87 | * @access public |
88 | * @return void | 88 | * @return void |
89 | */ | 89 | */ |
90 | public function genarateFeed() | 90 | public function genarateFeed() |
91 | { | 91 | { |
92 | if ($this->version == RSS2) { | 92 | if ($this->version == RSS2) { |
93 | header('Content-type: text/xml; charset=UTF-8'); | 93 | // header('Content-type: text/xml; charset=UTF-8'); |
94 | // this line prevents Chrome 20 from prompting download | 94 | // this line prevents Chrome 20 from prompting download |
95 | // used by Google: https://news.google.com/news/feeds?ned=us&topic=b&output=rss | 95 | // used by Google: https://news.google.com/news/feeds?ned=us&topic=b&output=rss |
96 | header('X-content-type-options: nosniff'); | 96 | // header('X-content-type-options: nosniff'); |
97 | } elseif ($this->version == JSON) { | 97 | } elseif ($this->version == JSON) { |
98 | header('Content-type: application/json; charset=UTF-8'); | 98 | // header('Content-type: application/json; charset=UTF-8'); |
99 | $this->json = new stdClass(); | 99 | $this->json = new stdClass(); |
100 | } elseif ($this->version == JSONP) { | 100 | } elseif ($this->version == JSONP) { |
101 | header('Content-type: application/javascript; charset=UTF-8'); | 101 | // header('Content-type: application/javascript; charset=UTF-8'); |
102 | $this->json = new stdClass(); | 102 | $this->json = new stdClass(); |
103 | } | 103 | } |
104 | $this->printHead(); | 104 | $this->printHead(); |
@@ -109,10 +109,10 @@ define('JSONP', 3, true); | |||
109 | echo json_encode($this->json); | 109 | echo json_encode($this->json); |
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | /** | 113 | /** |
114 | * Create a new FeedItem. | 114 | * Create a new FeedItem. |
115 | * | 115 | * |
116 | * @access public | 116 | * @access public |
117 | * @return object instance of FeedItem class | 117 | * @return object instance of FeedItem class |
118 | */ | 118 | */ |
@@ -121,24 +121,24 @@ define('JSONP', 3, true); | |||
121 | $Item = new FeedItem($this->version); | 121 | $Item = new FeedItem($this->version); |
122 | return $Item; | 122 | return $Item; |
123 | } | 123 | } |
124 | 124 | ||
125 | /** | 125 | /** |
126 | * Add a FeedItem to the main class | 126 | * Add a FeedItem to the main class |
127 | * | 127 | * |
128 | * @access public | 128 | * @access public |
129 | * @param object instance of FeedItem class | 129 | * @param object instance of FeedItem class |
130 | * @return void | 130 | * @return void |
131 | */ | 131 | */ |
132 | public function addItem($feedItem) | 132 | public function addItem($feedItem) |
133 | { | 133 | { |
134 | $this->items[] = $feedItem; | 134 | $this->items[] = $feedItem; |
135 | } | 135 | } |
136 | 136 | ||
137 | // Wrapper functions ------------------------------------------------------------------- | 137 | // Wrapper functions ------------------------------------------------------------------- |
138 | 138 | ||
139 | /** | 139 | /** |
140 | * Set the 'title' channel element | 140 | * Set the 'title' channel element |
141 | * | 141 | * |
142 | * @access public | 142 | * @access public |
143 | * @param srting value of 'title' channel tag | 143 | * @param srting value of 'title' channel tag |
144 | * @return void | 144 | * @return void |
@@ -147,59 +147,59 @@ define('JSONP', 3, true); | |||
147 | { | 147 | { |
148 | $this->setChannelElement('title', $title); | 148 | $this->setChannelElement('title', $title); |
149 | } | 149 | } |
150 | 150 | ||
151 | /** | 151 | /** |
152 | * Add a hub to the channel element | 152 | * Add a hub to the channel element |
153 | * | 153 | * |
154 | * @access public | 154 | * @access public |
155 | * @param string URL | 155 | * @param string URL |
156 | * @return void | 156 | * @return void |
157 | */ | 157 | */ |
158 | public function addHub($hub) | 158 | public function addHub($hub) |
159 | { | 159 | { |
160 | $this->hubs[] = $hub; | 160 | $this->hubs[] = $hub; |
161 | } | 161 | } |
162 | 162 | ||
163 | /** | 163 | /** |
164 | * Set XSL URL | 164 | * Set XSL URL |
165 | * | 165 | * |
166 | * @access public | 166 | * @access public |
167 | * @param string URL | 167 | * @param string URL |
168 | * @return void | 168 | * @return void |
169 | */ | 169 | */ |
170 | public function setXsl($xsl) | 170 | public function setXsl($xsl) |
171 | { | 171 | { |
172 | $this->xsl = $xsl; | 172 | $this->xsl = $xsl; |
173 | } | 173 | } |
174 | 174 | ||
175 | /** | 175 | /** |
176 | * Set self URL | 176 | * Set self URL |
177 | * | 177 | * |
178 | * @access public | 178 | * @access public |
179 | * @param string URL | 179 | * @param string URL |
180 | * @return void | 180 | * @return void |
181 | */ | 181 | */ |
182 | public function setSelf($self) | 182 | public function setSelf($self) |
183 | { | 183 | { |
184 | $this->self = $self; | 184 | $this->self = $self; |
185 | } | 185 | } |
186 | 186 | ||
187 | /** | 187 | /** |
188 | * Set the 'description' channel element | 188 | * Set the 'description' channel element |
189 | * | 189 | * |
190 | * @access public | 190 | * @access public |
191 | * @param srting value of 'description' channel tag | 191 | * @param srting value of 'description' channel tag |
192 | * @return void | 192 | * @return void |
193 | */ | 193 | */ |
194 | public function setDescription($desciption) | 194 | public function setDescription($desciption) |
195 | { | 195 | { |
196 | $tag = ($this->version == ATOM)? 'subtitle' : 'description'; | 196 | $tag = ($this->version == ATOM)? 'subtitle' : 'description'; |
197 | $this->setChannelElement($tag, $desciption); | 197 | $this->setChannelElement($tag, $desciption); |
198 | } | 198 | } |
199 | 199 | ||
200 | /** | 200 | /** |
201 | * Set the 'link' channel element | 201 | * Set the 'link' channel element |
202 | * | 202 | * |
203 | * @access public | 203 | * @access public |
204 | * @param srting value of 'link' channel tag | 204 | * @param srting value of 'link' channel tag |
205 | * @return void | 205 | * @return void |
@@ -208,10 +208,10 @@ define('JSONP', 3, true); | |||
208 | { | 208 | { |
209 | $this->setChannelElement('link', $link); | 209 | $this->setChannelElement('link', $link); |
210 | } | 210 | } |
211 | 211 | ||
212 | /** | 212 | /** |
213 | * Set the 'image' channel element | 213 | * Set the 'image' channel element |
214 | * | 214 | * |
215 | * @access public | 215 | * @access public |
216 | * @param srting title of image | 216 | * @param srting title of image |
217 | * @param srting link url of the imahe | 217 | * @param srting link url of the imahe |
@@ -222,14 +222,14 @@ define('JSONP', 3, true); | |||
222 | { | 222 | { |
223 | $this->setChannelElement('image', array('title'=>$title, 'link'=>$link, 'url'=>$url)); | 223 | $this->setChannelElement('image', array('title'=>$title, 'link'=>$link, 'url'=>$url)); |
224 | } | 224 | } |
225 | 225 | ||
226 | // End # public functions ---------------------------------------------- | 226 | // End # public functions ---------------------------------------------- |
227 | 227 | ||
228 | // Start # private functions ---------------------------------------------- | 228 | // Start # private functions ---------------------------------------------- |
229 | 229 | ||
230 | /** | 230 | /** |
231 | * Prints the xml and rss namespace | 231 | * Prints the xml and rss namespace |
232 | * | 232 | * |
233 | * @access private | 233 | * @access private |
234 | * @return void | 234 | * @return void |
235 | */ | 235 | */ |
@@ -247,10 +247,10 @@ define('JSONP', 3, true); | |||
247 | $this->json->rss = array('@attributes' => array('version' => '2.0')); | 247 | $this->json->rss = array('@attributes' => array('version' => '2.0')); |
248 | } | 248 | } |
249 | } | 249 | } |
250 | 250 | ||
251 | /** | 251 | /** |
252 | * Closes the open tags at the end of file | 252 | * Closes the open tags at the end of file |
253 | * | 253 | * |
254 | * @access private | 254 | * @access private |
255 | * @return void | 255 | * @return void |
256 | */ | 256 | */ |
@@ -258,14 +258,14 @@ define('JSONP', 3, true); | |||
258 | { | 258 | { |
259 | if ($this->version == RSS2) | 259 | if ($this->version == RSS2) |
260 | { | 260 | { |
261 | echo '</channel>',PHP_EOL,'</rss>'; | 261 | echo '</channel>',PHP_EOL,'</rss>'; |
262 | } | 262 | } |
263 | // do nothing for JSON | 263 | // do nothing for JSON |
264 | } | 264 | } |
265 | 265 | ||
266 | /** | 266 | /** |
267 | * Creates a single node as xml format | 267 | * Creates a single node as xml format |
268 | * | 268 | * |
269 | * @access private | 269 | * @access private |
270 | * @param string name of the tag | 270 | * @param string name of the tag |
271 | * @param mixed tag value as string or array of nested tags in 'tagName' => 'tagValue' format | 271 | * @param mixed tag value as string or array of nested tags in 'tagName' => 'tagValue' format |
@@ -273,22 +273,22 @@ define('JSONP', 3, true); | |||
273 | * @return string formatted xml tag | 273 | * @return string formatted xml tag |
274 | */ | 274 | */ |
275 | private function makeNode($tagName, $tagContent, $attributes = null) | 275 | private function makeNode($tagName, $tagContent, $attributes = null) |
276 | { | 276 | { |
277 | if ($this->version == RSS2) | 277 | if ($this->version == RSS2) |
278 | { | 278 | { |
279 | $nodeText = ''; | 279 | $nodeText = ''; |
280 | $attrText = ''; | 280 | $attrText = ''; |
281 | if (is_array($attributes)) | 281 | if (is_array($attributes)) |
282 | { | 282 | { |
283 | foreach ($attributes as $key => $value) | 283 | foreach ($attributes as $key => $value) |
284 | { | 284 | { |
285 | $attrText .= " $key=\"$value\" "; | 285 | $attrText .= " $key=\"$value\" "; |
286 | } | 286 | } |
287 | } | 287 | } |
288 | $nodeText .= "<{$tagName}{$attrText}>"; | 288 | $nodeText .= "<{$tagName}{$attrText}>"; |
289 | if (is_array($tagContent)) | 289 | if (is_array($tagContent)) |
290 | { | 290 | { |
291 | foreach ($tagContent as $key => $value) | 291 | foreach ($tagContent as $key => $value) |
292 | { | 292 | { |
293 | $nodeText .= $this->makeNode($key, $value); | 293 | $nodeText .= $this->makeNode($key, $value); |
294 | } | 294 | } |
@@ -297,7 +297,7 @@ define('JSONP', 3, true); | |||
297 | { | 297 | { |
298 | //$nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : htmlentities($tagContent); | 298 | //$nodeText .= (in_array($tagName, $this->CDATAEncoding))? $tagContent : htmlentities($tagContent); |
299 | $nodeText .= htmlspecialchars($tagContent); | 299 | $nodeText .= htmlspecialchars($tagContent); |
300 | } | 300 | } |
301 | //$nodeText .= (in_array($tagName, $this->CDATAEncoding))? "]]></$tagName>" : "</$tagName>"; | 301 | //$nodeText .= (in_array($tagName, $this->CDATAEncoding))? "]]></$tagName>" : "</$tagName>"; |
302 | $nodeText .= "</$tagName>"; | 302 | $nodeText .= "</$tagName>"; |
303 | return $nodeText . PHP_EOL; | 303 | return $nodeText . PHP_EOL; |
@@ -321,7 +321,7 @@ define('JSONP', 3, true); | |||
321 | } | 321 | } |
322 | return ''; // should not get here | 322 | return ''; // should not get here |
323 | } | 323 | } |
324 | 324 | ||
325 | private function json_keys(array $array) { | 325 | private function json_keys(array $array) { |
326 | $new = array(); | 326 | $new = array(); |
327 | foreach ($array as $key => $val) { | 327 | foreach ($array as $key => $val) { |
@@ -334,7 +334,7 @@ define('JSONP', 3, true); | |||
334 | } | 334 | } |
335 | return $new; | 335 | return $new; |
336 | } | 336 | } |
337 | 337 | ||
338 | /** | 338 | /** |
339 | * @desc Print channels | 339 | * @desc Print channels |
340 | * @access private | 340 | * @access private |
@@ -344,7 +344,7 @@ define('JSONP', 3, true); | |||
344 | { | 344 | { |
345 | //Start channel tag | 345 | //Start channel tag |
346 | if ($this->version == RSS2) { | 346 | if ($this->version == RSS2) { |
347 | echo '<channel>' . PHP_EOL; | 347 | echo '<channel>' . PHP_EOL; |
348 | // add hubs | 348 | // add hubs |
349 | foreach ($this->hubs as $hub) { | 349 | foreach ($this->hubs as $hub) { |
350 | //echo $this->makeNode('link', '', array('rel'=>'hub', 'href'=>$hub, 'xmlns'=>'http://www.w3.org/2005/Atom')); | 350 | //echo $this->makeNode('link', '', array('rel'=>'hub', 'href'=>$hub, 'xmlns'=>'http://www.w3.org/2005/Atom')); |
@@ -356,7 +356,7 @@ define('JSONP', 3, true); | |||
356 | echo '<link rel="self" href="'.htmlspecialchars($this->self).'" xmlns="http://www.w3.org/2005/Atom" />' . PHP_EOL; | 356 | echo '<link rel="self" href="'.htmlspecialchars($this->self).'" xmlns="http://www.w3.org/2005/Atom" />' . PHP_EOL; |
357 | } | 357 | } |
358 | //Print Items of channel | 358 | //Print Items of channel |
359 | foreach ($this->channels as $key => $value) | 359 | foreach ($this->channels as $key => $value) |
360 | { | 360 | { |
361 | echo $this->makeNode($key, $value); | 361 | echo $this->makeNode($key, $value); |
362 | } | 362 | } |
@@ -364,26 +364,26 @@ define('JSONP', 3, true); | |||
364 | $this->json->rss['channel'] = (object)$this->json_keys($this->channels); | 364 | $this->json->rss['channel'] = (object)$this->json_keys($this->channels); |
365 | } | 365 | } |
366 | } | 366 | } |
367 | 367 | ||
368 | /** | 368 | /** |
369 | * Prints formatted feed items | 369 | * Prints formatted feed items |
370 | * | 370 | * |
371 | * @access private | 371 | * @access private |
372 | * @return void | 372 | * @return void |
373 | */ | 373 | */ |
374 | private function printItems() | 374 | private function printItems() |
375 | { | 375 | { |
376 | foreach ($this->items as $item) { | 376 | foreach ($this->items as $item) { |
377 | $itemElements = $item->getElements(); | 377 | $itemElements = $item->getElements(); |
378 | 378 | ||
379 | echo $this->startItem(); | 379 | echo $this->startItem(); |
380 | 380 | ||
381 | if ($this->version == JSON || $this->version == JSONP) { | 381 | if ($this->version == JSON || $this->version == JSONP) { |
382 | $json_item = array(); | 382 | $json_item = array(); |
383 | } | 383 | } |
384 | 384 | ||
385 | foreach ($itemElements as $thisElement) { | 385 | foreach ($itemElements as $thisElement) { |
386 | foreach ($thisElement as $instance) { | 386 | foreach ($thisElement as $instance) { |
387 | if ($this->version == RSS2) { | 387 | if ($this->version == RSS2) { |
388 | echo $this->makeNode($instance['name'], $instance['content'], $instance['attributes']); | 388 | echo $this->makeNode($instance['name'], $instance['content'], $instance['attributes']); |
389 | } elseif ($this->version == JSON || $this->version == JSONP) { | 389 | } elseif ($this->version == JSON || $this->version == JSONP) { |
@@ -406,10 +406,10 @@ define('JSONP', 3, true); | |||
406 | } | 406 | } |
407 | } | 407 | } |
408 | } | 408 | } |
409 | 409 | ||
410 | /** | 410 | /** |
411 | * Make the starting tag of channels | 411 | * Make the starting tag of channels |
412 | * | 412 | * |
413 | * @access private | 413 | * @access private |
414 | * @return void | 414 | * @return void |
415 | */ | 415 | */ |
@@ -417,14 +417,14 @@ define('JSONP', 3, true); | |||
417 | { | 417 | { |
418 | if ($this->version == RSS2) | 418 | if ($this->version == RSS2) |
419 | { | 419 | { |
420 | echo '<item>' . PHP_EOL; | 420 | echo '<item>' . PHP_EOL; |
421 | } | 421 | } |
422 | // nothing for JSON | 422 | // nothing for JSON |
423 | } | 423 | } |
424 | 424 | ||
425 | /** | 425 | /** |
426 | * Closes feed item tag | 426 | * Closes feed item tag |
427 | * | 427 | * |
428 | * @access private | 428 | * @access private |
429 | * @return void | 429 | * @return void |
430 | */ | 430 | */ |
@@ -432,10 +432,10 @@ define('JSONP', 3, true); | |||
432 | { | 432 | { |
433 | if ($this->version == RSS2) | 433 | if ($this->version == RSS2) |
434 | { | 434 | { |
435 | echo '</item>' . PHP_EOL; | 435 | echo '</item>' . PHP_EOL; |
436 | } | 436 | } |
437 | // nothing for JSON | 437 | // nothing for JSON |
438 | } | 438 | } |
439 | 439 | ||
440 | // End # private functions ---------------------------------------------- | 440 | // End # private functions ---------------------------------------------- |
441 | } \ No newline at end of file | 441 | } \ No newline at end of file |
diff --git a/inc/poche/Database.class.php b/inc/poche/Database.class.php index 2257f281..6244df88 100755 --- a/inc/poche/Database.class.php +++ b/inc/poche/Database.class.php | |||
@@ -18,7 +18,7 @@ class Database { | |||
18 | 'default' => 'ORDER BY entries.id' | 18 | 'default' => 'ORDER BY entries.id' |
19 | ); | 19 | ); |
20 | 20 | ||
21 | function __construct() | 21 | function __construct() |
22 | { | 22 | { |
23 | switch (STORAGE) { | 23 | switch (STORAGE) { |
24 | case 'sqlite': | 24 | case 'sqlite': |
@@ -27,11 +27,11 @@ class Database { | |||
27 | break; | 27 | break; |
28 | case 'mysql': | 28 | case 'mysql': |
29 | $db_path = 'mysql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB; | 29 | $db_path = 'mysql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB; |
30 | $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); | 30 | $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); |
31 | break; | 31 | break; |
32 | case 'postgres': | 32 | case 'postgres': |
33 | $db_path = 'pgsql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB; | 33 | $db_path = 'pgsql:host=' . STORAGE_SERVER . ';dbname=' . STORAGE_DB; |
34 | $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); | 34 | $this->handle = new PDO($db_path, STORAGE_USER, STORAGE_PASSWORD); |
35 | break; | 35 | break; |
36 | } | 36 | } |
37 | 37 | ||
@@ -51,7 +51,7 @@ class Database { | |||
51 | } | 51 | } |
52 | $hasAdmin = count($query->fetchAll()); | 52 | $hasAdmin = count($query->fetchAll()); |
53 | 53 | ||
54 | if ($hasAdmin == 0) | 54 | if ($hasAdmin == 0) |
55 | return false; | 55 | return false; |
56 | 56 | ||
57 | return true; | 57 | return true; |
@@ -140,7 +140,7 @@ class Database { | |||
140 | $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)'; | 140 | $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)'; |
141 | $params = array($id_user, 'language', LANG); | 141 | $params = array($id_user, 'language', LANG); |
142 | $query = $this->executeQuery($sql, $params); | 142 | $query = $this->executeQuery($sql, $params); |
143 | 143 | ||
144 | $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)'; | 144 | $sql = 'INSERT INTO users_config ( user_id, name, value ) VALUES (?, ?, ?)'; |
145 | $params = array($id_user, 'theme', DEFAULT_THEME); | 145 | $params = array($id_user, 'theme', DEFAULT_THEME); |
146 | $query = $this->executeQuery($sql, $params); | 146 | $query = $this->executeQuery($sql, $params); |
@@ -153,7 +153,7 @@ class Database { | |||
153 | $query = $this->executeQuery($sql, array($id)); | 153 | $query = $this->executeQuery($sql, array($id)); |
154 | $result = $query->fetchAll(); | 154 | $result = $query->fetchAll(); |
155 | $user_config = array(); | 155 | $user_config = array(); |
156 | 156 | ||
157 | foreach ($result as $key => $value) { | 157 | foreach ($result as $key => $value) { |
158 | $user_config[$value['name']] = $value['value']; | 158 | $user_config[$value['name']] = $value['value']; |
159 | } | 159 | } |
@@ -201,10 +201,10 @@ class Database { | |||
201 | $params_update = array($password, $userId); | 201 | $params_update = array($password, $userId); |
202 | $query = $this->executeQuery($sql_update, $params_update); | 202 | $query = $this->executeQuery($sql_update, $params_update); |
203 | } | 203 | } |
204 | 204 | ||
205 | public function updateUserConfig($userId, $key, $value) { | 205 | public function updateUserConfig($userId, $key, $value) { |
206 | $config = $this->getConfigUser($userId); | 206 | $config = $this->getConfigUser($userId); |
207 | 207 | ||
208 | if (! isset($config[$key])) { | 208 | if (! isset($config[$key])) { |
209 | $sql = "INSERT INTO users_config (value, user_id, name) VALUES (?, ?, ?)"; | 209 | $sql = "INSERT INTO users_config (value, user_id, name) VALUES (?, ?, ?)"; |
210 | } | 210 | } |
@@ -252,8 +252,16 @@ class Database { | |||
252 | return $entries; | 252 | return $entries; |
253 | } | 253 | } |
254 | 254 | ||
255 | public function retrieveUnfetchedEntriesCount($user_id) { | ||
256 | $sql = "SELECT count(*) FROM entries WHERE (content = '' OR content IS NULL) AND user_id=?"; | ||
257 | $query = $this->executeQuery($sql, array($user_id)); | ||
258 | list($count) = $query->fetch(); | ||
259 | |||
260 | return $count; | ||
261 | } | ||
262 | |||
255 | public function retrieveAll($user_id) { | 263 | public function retrieveAll($user_id) { |
256 | $sql = "SELECT * FROM entries WHERE content <> '' AND user_id=? ORDER BY id"; | 264 | $sql = "SELECT * FROM entries WHERE user_id=? ORDER BY id"; |
257 | $query = $this->executeQuery($sql, array($user_id)); | 265 | $query = $this->executeQuery($sql, array($user_id)); |
258 | $entries = $query->fetchAll(); | 266 | $entries = $query->fetchAll(); |
259 | 267 | ||
@@ -272,7 +280,7 @@ class Database { | |||
272 | 280 | ||
273 | public function retrieveOneByURL($url, $user_id) { | 281 | public function retrieveOneByURL($url, $user_id) { |
274 | $entry = NULL; | 282 | $entry = NULL; |
275 | $sql = "SELECT * FROM entries WHERE content <> '' AND url=? AND user_id=?"; | 283 | $sql = "SELECT * FROM entries WHERE url=? AND user_id=?"; |
276 | $params = array($url, $user_id); | 284 | $params = array($url, $user_id); |
277 | $query = $this->executeQuery($sql, $params); | 285 | $query = $this->executeQuery($sql, $params); |
278 | $entry = $query->fetchAll(); | 286 | $entry = $query->fetchAll(); |
@@ -289,22 +297,21 @@ class Database { | |||
289 | public function getEntriesByView($view, $user_id, $limit = '', $tag_id = 0) { | 297 | public function getEntriesByView($view, $user_id, $limit = '', $tag_id = 0) { |
290 | switch ($view) { | 298 | switch ($view) { |
291 | case 'archive': | 299 | case 'archive': |
292 | $sql = "SELECT * FROM entries WHERE content <> '' AND user_id=? AND is_read=? "; | 300 | $sql = "SELECT * FROM entries WHERE user_id=? AND is_read=? "; |
293 | $params = array($user_id, 1); | 301 | $params = array($user_id, 1); |
294 | break; | 302 | break; |
295 | case 'fav' : | 303 | case 'fav' : |
296 | $sql = "SELECT * FROM entries WHERE content <> '' AND user_id=? AND is_fav=? "; | 304 | $sql = "SELECT * FROM entries WHERE user_id=? AND is_fav=? "; |
297 | $params = array($user_id, 1); | 305 | $params = array($user_id, 1); |
298 | break; | 306 | break; |
299 | case 'tag' : | 307 | case 'tag' : |
300 | $sql = "SELECT entries.* FROM entries | 308 | $sql = "SELECT entries.* FROM entries |
301 | LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id | 309 | LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id |
302 | WHERE entries.content <> '' AND | 310 | WHERE entries.user_id=? AND tags_entries.tag_id = ? "; |
303 | entries.user_id=? AND tags_entries.tag_id = ? "; | ||
304 | $params = array($user_id, $tag_id); | 311 | $params = array($user_id, $tag_id); |
305 | break; | 312 | break; |
306 | default: | 313 | default: |
307 | $sql = "SELECT * FROM entries WHERE content <> '' AND user_id=? AND is_read=? "; | 314 | $sql = "SELECT * FROM entries WHERE user_id=? AND is_read=? "; |
308 | $params = array($user_id, 0); | 315 | $params = array($user_id, 0); |
309 | break; | 316 | break; |
310 | } | 317 | } |
@@ -320,22 +327,21 @@ class Database { | |||
320 | public function getEntriesByViewCount($view, $user_id, $tag_id = 0) { | 327 | public function getEntriesByViewCount($view, $user_id, $tag_id = 0) { |
321 | switch ($view) { | 328 | switch ($view) { |
322 | case 'archive': | 329 | case 'archive': |
323 | $sql = "SELECT count(*) FROM entries WHERE content <> '' AND user_id=? AND is_read=? "; | 330 | $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_read=? "; |
324 | $params = array($user_id, 1); | 331 | $params = array($user_id, 1); |
325 | break; | 332 | break; |
326 | case 'fav' : | 333 | case 'fav' : |
327 | $sql = "SELECT count(*) FROM entries WHERE content <> '' AND user_id=? AND is_fav=? "; | 334 | $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_fav=? "; |
328 | $params = array($user_id, 1); | 335 | $params = array($user_id, 1); |
329 | break; | 336 | break; |
330 | case 'tag' : | 337 | case 'tag' : |
331 | $sql = "SELECT count(*) FROM entries | 338 | $sql = "SELECT count(*) FROM entries |
332 | LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id | 339 | LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id |
333 | WHERE entries.content <> '' AND | 340 | WHERE entries.user_id=? AND tags_entries.tag_id = ? "; |
334 | entries.user_id=? AND tags_entries.tag_id = ? "; | ||
335 | $params = array($user_id, $tag_id); | 341 | $params = array($user_id, $tag_id); |
336 | break; | 342 | break; |
337 | default: | 343 | default: |
338 | $sql = "SELECT count(*) FROM entries WHERE content <> '' AND user_id=? AND is_read=? "; | 344 | $sql = "SELECT count(*) FROM entries WHERE user_id=? AND is_read=? "; |
339 | $params = array($user_id, 0); | 345 | $params = array($user_id, 0); |
340 | break; | 346 | break; |
341 | } | 347 | } |
@@ -353,11 +359,24 @@ class Database { | |||
353 | return $query; | 359 | return $query; |
354 | } | 360 | } |
355 | 361 | ||
356 | public function add($url, $title, $content, $user_id) { | 362 | /** |
357 | $sql_action = 'INSERT INTO entries ( url, title, content, user_id ) VALUES (?, ?, ?, ?)'; | 363 | * |
358 | $params_action = array($url, $title, $content, $user_id); | 364 | * @param string $url |
359 | $query = $this->executeQuery($sql_action, $params_action); | 365 | * @param string $title |
360 | return $query; | 366 | * @param string $content |
367 | * @param integer $user_id | ||
368 | * @return integer $id of inserted record | ||
369 | */ | ||
370 | public function add($url, $title, $content, $user_id, $isFavorite=0, $isRead=0) { | ||
371 | $sql_action = 'INSERT INTO entries ( url, title, content, user_id, is_fav, is_read ) VALUES (?, ?, ?, ?, ?, ?)'; | ||
372 | $params_action = array($url, $title, $content, $user_id, $isFavorite, $isRead); | ||
373 | if ( !$this->executeQuery($sql_action, $params_action) ) { | ||
374 | $id = null; | ||
375 | } | ||
376 | else { | ||
377 | $id = intval($this->getLastId( (STORAGE == 'postgres') ? 'users_id_seq' : '' )); | ||
378 | } | ||
379 | return $id; | ||
361 | } | 380 | } |
362 | 381 | ||
363 | public function deleteById($id, $user_id) { | 382 | public function deleteById($id, $user_id) { |
@@ -389,20 +408,20 @@ class Database { | |||
389 | return $this->getHandle()->lastInsertId($column); | 408 | return $this->getHandle()->lastInsertId($column); |
390 | } | 409 | } |
391 | 410 | ||
392 | public function search($term,$id,$limit = ''){ | 411 | public function search($term, $user_id, $limit = '') { |
393 | $search = '%'.$term.'%'; | 412 | $search = '%'.$term.'%'; |
394 | $sql_action = ("SELECT * FROM entries WHERE user_id=? AND (content LIKE ? OR title LIKE ? OR url LIKE ?) "); //searches in content, title and URL | 413 | $sql_action = "SELECT * FROM entries WHERE user_id=? AND (content LIKE ? OR title LIKE ? OR url LIKE ?) "; //searches in content, title and URL |
395 | $sql_action .= $this->getEntriesOrder().' ' . $limit; | 414 | $sql_action .= $this->getEntriesOrder().' ' . $limit; |
396 | $params_action = array($id,$search,$search,$search); | 415 | $params_action = array($user_id, $search, $search, $search); |
397 | $query = $this->executeQuery($sql_action, $params_action); | 416 | $query = $this->executeQuery($sql_action, $params_action); |
398 | return $query->fetchAll(); | 417 | return $query->fetchAll(); |
399 | } | 418 | } |
400 | 419 | ||
401 | public function retrieveAllTags($user_id, $term = null) { | 420 | public function retrieveAllTags($user_id, $term = null) { |
402 | $sql = "SELECT DISTINCT tags.*, count(entries.id) AS entriescount FROM tags | 421 | $sql = "SELECT DISTINCT tags.*, count(entries.id) AS entriescount FROM tags |
403 | LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id | 422 | LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id |
404 | LEFT JOIN entries ON tags_entries.entry_id=entries.id | 423 | LEFT JOIN entries ON tags_entries.entry_id=entries.id |
405 | WHERE entries.content <> '' AND entries.user_id=? | 424 | WHERE entries.user_id=? |
406 | ". (($term) ? "AND lower(tags.value) LIKE ?" : '') ." | 425 | ". (($term) ? "AND lower(tags.value) LIKE ?" : '') ." |
407 | GROUP BY tags.id, tags.value | 426 | GROUP BY tags.id, tags.value |
408 | ORDER BY tags.value"; | 427 | ORDER BY tags.value"; |
@@ -417,7 +436,7 @@ class Database { | |||
417 | $sql = "SELECT DISTINCT tags.* FROM tags | 436 | $sql = "SELECT DISTINCT tags.* FROM tags |
418 | LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id | 437 | LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id |
419 | LEFT JOIN entries ON tags_entries.entry_id=entries.id | 438 | LEFT JOIN entries ON tags_entries.entry_id=entries.id |
420 | WHERE entries.content <> '' AND tags.id=? AND entries.user_id=?"; | 439 | WHERE tags.id=? AND entries.user_id=?"; |
421 | $params = array(intval($id), $user_id); | 440 | $params = array(intval($id), $user_id); |
422 | $query = $this->executeQuery($sql, $params); | 441 | $query = $this->executeQuery($sql, $params); |
423 | $tag = $query->fetchAll(); | 442 | $tag = $query->fetchAll(); |
@@ -426,11 +445,10 @@ class Database { | |||
426 | } | 445 | } |
427 | 446 | ||
428 | public function retrieveEntriesByTag($tag_id, $user_id) { | 447 | public function retrieveEntriesByTag($tag_id, $user_id) { |
429 | $sql = | 448 | $sql = |
430 | "SELECT entries.* FROM entries | 449 | "SELECT entries.* FROM entries |
431 | LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id | 450 | LEFT JOIN tags_entries ON tags_entries.entry_id=entries.id |
432 | WHERE entries.content <> '' AND | 451 | WHERE tags_entries.tag_id = ? AND entries.user_id=?"; |
433 | tags_entries.tag_id = ? AND entries.user_id=?"; | ||
434 | $query = $this->executeQuery($sql, array($tag_id, $user_id)); | 452 | $query = $this->executeQuery($sql, array($tag_id, $user_id)); |
435 | $entries = $query->fetchAll(); | 453 | $entries = $query->fetchAll(); |
436 | 454 | ||
@@ -438,7 +456,7 @@ class Database { | |||
438 | } | 456 | } |
439 | 457 | ||
440 | public function retrieveTagsByEntry($entry_id) { | 458 | public function retrieveTagsByEntry($entry_id) { |
441 | $sql = | 459 | $sql = |
442 | "SELECT tags.* FROM tags | 460 | "SELECT tags.* FROM tags |
443 | LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id | 461 | LEFT JOIN tags_entries ON tags_entries.tag_id=tags.id |
444 | WHERE tags_entries.entry_id = ?"; | 462 | WHERE tags_entries.entry_id = ?"; |
diff --git a/inc/poche/Poche.class.php b/inc/poche/Poche.class.php index 42a2dd9a..ee3b2ac2 100755 --- a/inc/poche/Poche.class.php +++ b/inc/poche/Poche.class.php | |||
@@ -18,7 +18,7 @@ class Poche | |||
18 | public $tpl; | 18 | public $tpl; |
19 | public $messages; | 19 | public $messages; |
20 | public $pagination; | 20 | public $pagination; |
21 | 21 | ||
22 | private $currentTheme = ''; | 22 | private $currentTheme = ''; |
23 | private $currentLanguage = ''; | 23 | private $currentLanguage = ''; |
24 | private $notInstalledMessage = array(); | 24 | private $notInstalledMessage = array(); |
@@ -42,11 +42,11 @@ class Poche | |||
42 | if ($this->configFileIsAvailable()) { | 42 | if ($this->configFileIsAvailable()) { |
43 | $this->init(); | 43 | $this->init(); |
44 | } | 44 | } |
45 | 45 | ||
46 | if ($this->themeIsInstalled()) { | 46 | if ($this->themeIsInstalled()) { |
47 | $this->initTpl(); | 47 | $this->initTpl(); |
48 | } | 48 | } |
49 | 49 | ||
50 | if ($this->systemIsInstalled()) { | 50 | if ($this->systemIsInstalled()) { |
51 | $this->store = new Database(); | 51 | $this->store = new Database(); |
52 | $this->messages = new Messages(); | 52 | $this->messages = new Messages(); |
@@ -57,8 +57,8 @@ class Poche | |||
57 | $this->store->checkTags(); | 57 | $this->store->checkTags(); |
58 | } | 58 | } |
59 | } | 59 | } |
60 | 60 | ||
61 | private function init() | 61 | private function init() |
62 | { | 62 | { |
63 | Tools::initPhp(); | 63 | Tools::initPhp(); |
64 | 64 | ||
@@ -74,28 +74,28 @@ class Poche | |||
74 | $language = $this->user->getConfigValue('language'); | 74 | $language = $this->user->getConfigValue('language'); |
75 | putenv('LC_ALL=' . $language); | 75 | putenv('LC_ALL=' . $language); |
76 | setlocale(LC_ALL, $language); | 76 | setlocale(LC_ALL, $language); |
77 | bindtextdomain($language, LOCALE); | 77 | bindtextdomain($language, LOCALE); |
78 | textdomain($language); | 78 | textdomain($language); |
79 | 79 | ||
80 | # Pagination | 80 | # Pagination |
81 | $this->pagination = new Paginator($this->user->getConfigValue('pager'), 'p'); | 81 | $this->pagination = new Paginator($this->user->getConfigValue('pager'), 'p'); |
82 | 82 | ||
83 | # Set up theme | 83 | # Set up theme |
84 | $themeDirectory = $this->user->getConfigValue('theme'); | 84 | $themeDirectory = $this->user->getConfigValue('theme'); |
85 | 85 | ||
86 | if ($themeDirectory === false) { | 86 | if ($themeDirectory === false) { |
87 | $themeDirectory = DEFAULT_THEME; | 87 | $themeDirectory = DEFAULT_THEME; |
88 | } | 88 | } |
89 | 89 | ||
90 | $this->currentTheme = $themeDirectory; | 90 | $this->currentTheme = $themeDirectory; |
91 | 91 | ||
92 | # Set up language | 92 | # Set up language |
93 | $languageDirectory = $this->user->getConfigValue('language'); | 93 | $languageDirectory = $this->user->getConfigValue('language'); |
94 | 94 | ||
95 | if ($languageDirectory === false) { | 95 | if ($languageDirectory === false) { |
96 | $languageDirectory = DEFAULT_THEME; | 96 | $languageDirectory = DEFAULT_THEME; |
97 | } | 97 | } |
98 | 98 | ||
99 | $this->currentLanguage = $languageDirectory; | 99 | $this->currentLanguage = $languageDirectory; |
100 | } | 100 | } |
101 | 101 | ||
@@ -108,7 +108,7 @@ class Poche | |||
108 | 108 | ||
109 | return true; | 109 | return true; |
110 | } | 110 | } |
111 | 111 | ||
112 | public function themeIsInstalled() { | 112 | public function themeIsInstalled() { |
113 | $passTheme = TRUE; | 113 | $passTheme = TRUE; |
114 | # Twig is an absolute requirement for Poche to function. Abort immediately if the Composer installer hasn't been run yet | 114 | # Twig is an absolute requirement for Poche to function. Abort immediately if the Composer installer hasn't been run yet |
@@ -123,27 +123,27 @@ class Poche | |||
123 | self::$canRenderTemplates = false; | 123 | self::$canRenderTemplates = false; |
124 | 124 | ||
125 | $passTheme = FALSE; | 125 | $passTheme = FALSE; |
126 | } | 126 | } |
127 | 127 | ||
128 | # Check if the selected theme and its requirements are present | 128 | # Check if the selected theme and its requirements are present |
129 | $theme = $this->getTheme(); | 129 | $theme = $this->getTheme(); |
130 | 130 | ||
131 | if ($theme != '' && ! is_dir(THEME . '/' . $theme)) { | 131 | if ($theme != '' && ! is_dir(THEME . '/' . $theme)) { |
132 | $this->notInstalledMessage[] = 'The currently selected theme (' . $theme . ') does not seem to be properly installed (Missing directory: ' . THEME . '/' . $theme . ')'; | 132 | $this->notInstalledMessage[] = 'The currently selected theme (' . $theme . ') does not seem to be properly installed (Missing directory: ' . THEME . '/' . $theme . ')'; |
133 | 133 | ||
134 | self::$canRenderTemplates = false; | 134 | self::$canRenderTemplates = false; |
135 | 135 | ||
136 | $passTheme = FALSE; | 136 | $passTheme = FALSE; |
137 | } | 137 | } |
138 | 138 | ||
139 | $themeInfo = $this->getThemeInfo($theme); | 139 | $themeInfo = $this->getThemeInfo($theme); |
140 | if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) { | 140 | if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) { |
141 | foreach ($themeInfo['requirements'] as $requiredTheme) { | 141 | foreach ($themeInfo['requirements'] as $requiredTheme) { |
142 | if (! is_dir(THEME . '/' . $requiredTheme)) { | 142 | if (! is_dir(THEME . '/' . $requiredTheme)) { |
143 | $this->notInstalledMessage[] = 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')'; | 143 | $this->notInstalledMessage[] = 'The required "' . $requiredTheme . '" theme is missing for the current theme (' . $theme . ')'; |
144 | 144 | ||
145 | self::$canRenderTemplates = false; | 145 | self::$canRenderTemplates = false; |
146 | 146 | ||
147 | $passTheme = FALSE; | 147 | $passTheme = FALSE; |
148 | } | 148 | } |
149 | } | 149 | } |
@@ -153,21 +153,21 @@ class Poche | |||
153 | return FALSE; | 153 | return FALSE; |
154 | } | 154 | } |
155 | 155 | ||
156 | 156 | ||
157 | return true; | 157 | return true; |
158 | } | 158 | } |
159 | 159 | ||
160 | /** | 160 | /** |
161 | * all checks before installation. | 161 | * all checks before installation. |
162 | * @todo move HTML to template | 162 | * @todo move HTML to template |
163 | * @return boolean | 163 | * @return boolean |
164 | */ | 164 | */ |
165 | public function systemIsInstalled() | 165 | public function systemIsInstalled() |
166 | { | 166 | { |
167 | $msg = TRUE; | 167 | $msg = TRUE; |
168 | 168 | ||
169 | $configSalt = defined('SALT') ? constant('SALT') : ''; | 169 | $configSalt = defined('SALT') ? constant('SALT') : ''; |
170 | 170 | ||
171 | if (empty($configSalt)) { | 171 | if (empty($configSalt)) { |
172 | $this->notInstalledMessage[] = 'You have not yet filled in the SALT value in the config.inc.php file.'; | 172 | $this->notInstalledMessage[] = 'You have not yet filled in the SALT value in the config.inc.php file.'; |
173 | $msg = FALSE; | 173 | $msg = FALSE; |
@@ -193,7 +193,7 @@ class Poche | |||
193 | 193 | ||
194 | return true; | 194 | return true; |
195 | } | 195 | } |
196 | 196 | ||
197 | public function getNotInstalledMessage() { | 197 | public function getNotInstalledMessage() { |
198 | return $this->notInstalledMessage; | 198 | return $this->notInstalledMessage; |
199 | } | 199 | } |
@@ -202,7 +202,7 @@ class Poche | |||
202 | { | 202 | { |
203 | $loaderChain = new Twig_Loader_Chain(); | 203 | $loaderChain = new Twig_Loader_Chain(); |
204 | $theme = $this->getTheme(); | 204 | $theme = $this->getTheme(); |
205 | 205 | ||
206 | # add the current theme as first to the loader chain so Twig will look there first for overridden template files | 206 | # add the current theme as first to the loader chain so Twig will look there first for overridden template files |
207 | try { | 207 | try { |
208 | $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $theme)); | 208 | $loaderChain->addLoader(new Twig_Loader_Filesystem(THEME . '/' . $theme)); |
@@ -210,7 +210,7 @@ class Poche | |||
210 | # @todo isInstalled() should catch this, inject Twig later | 210 | # @todo isInstalled() should catch this, inject Twig later |
211 | die('The currently selected theme (' . $theme . ') does not seem to be properly installed (' . THEME . '/' . $theme .' is missing)'); | 211 | die('The currently selected theme (' . $theme . ') does not seem to be properly installed (' . THEME . '/' . $theme .' is missing)'); |
212 | } | 212 | } |
213 | 213 | ||
214 | # add all required themes to the loader chain | 214 | # add all required themes to the loader chain |
215 | $themeInfo = $this->getThemeInfo($theme); | 215 | $themeInfo = $this->getThemeInfo($theme); |
216 | if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) { | 216 | if (isset($themeInfo['requirements']) && is_array($themeInfo['requirements'])) { |
@@ -223,16 +223,16 @@ class Poche | |||
223 | } | 223 | } |
224 | } | 224 | } |
225 | } | 225 | } |
226 | 226 | ||
227 | if (DEBUG_POCHE) { | 227 | if (DEBUG_POCHE) { |
228 | $twigParams = array(); | 228 | $twigParams = array(); |
229 | } else { | 229 | } else { |
230 | $twigParams = array('cache' => CACHE); | 230 | $twigParams = array('cache' => CACHE); |
231 | } | 231 | } |
232 | 232 | ||
233 | $this->tpl = new Twig_Environment($loaderChain, $twigParams); | 233 | $this->tpl = new Twig_Environment($loaderChain, $twigParams); |
234 | $this->tpl->addExtension(new Twig_Extensions_Extension_I18n()); | 234 | $this->tpl->addExtension(new Twig_Extensions_Extension_I18n()); |
235 | 235 | ||
236 | # filter to display domain name of an url | 236 | # filter to display domain name of an url |
237 | $filter = new Twig_SimpleFilter('getDomain', 'Tools::getDomain'); | 237 | $filter = new Twig_SimpleFilter('getDomain', 'Tools::getDomain'); |
238 | $this->tpl->addFilter($filter); | 238 | $this->tpl->addFilter($filter); |
@@ -251,7 +251,7 @@ class Poche | |||
251 | 'poche_url' => Tools::getPocheUrl() | 251 | 'poche_url' => Tools::getPocheUrl() |
252 | )); | 252 | )); |
253 | if (isset($_GET['install'])) { | 253 | if (isset($_GET['install'])) { |
254 | if (($_POST['password'] == $_POST['password_repeat']) | 254 | if (($_POST['password'] == $_POST['password_repeat']) |
255 | && $_POST['password'] != "" && $_POST['login'] != "") { | 255 | && $_POST['password'] != "" && $_POST['login'] != "") { |
256 | # let's rock, install poche baby ! | 256 | # let's rock, install poche baby ! |
257 | if ($this->store->install($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login']))) | 257 | if ($this->store->install($_POST['login'], Tools::encodeString($_POST['password'] . $_POST['login']))) |
@@ -268,7 +268,7 @@ class Poche | |||
268 | } | 268 | } |
269 | exit(); | 269 | exit(); |
270 | } | 270 | } |
271 | 271 | ||
272 | public function getTheme() { | 272 | public function getTheme() { |
273 | return $this->currentTheme; | 273 | return $this->currentTheme; |
274 | } | 274 | } |
@@ -293,7 +293,7 @@ class Poche | |||
293 | if (is_file($themeIniFile) && is_readable($themeIniFile)) { | 293 | if (is_file($themeIniFile) && is_readable($themeIniFile)) { |
294 | $themeInfo = parse_ini_file($themeIniFile); | 294 | $themeInfo = parse_ini_file($themeIniFile); |
295 | } | 295 | } |
296 | 296 | ||
297 | if ($themeInfo === false) { | 297 | if ($themeInfo === false) { |
298 | $themeInfo = array(); | 298 | $themeInfo = array(); |
299 | } | 299 | } |
@@ -304,7 +304,7 @@ class Poche | |||
304 | 304 | ||
305 | return $themeInfo; | 305 | return $themeInfo; |
306 | } | 306 | } |
307 | 307 | ||
308 | public function getInstalledThemes() { | 308 | public function getInstalledThemes() { |
309 | $handle = opendir(THEME); | 309 | $handle = opendir(THEME); |
310 | $themes = array(); | 310 | $themes = array(); |
@@ -331,28 +331,28 @@ class Poche | |||
331 | public function getInstalledLanguages() { | 331 | public function getInstalledLanguages() { |
332 | $handle = opendir(LOCALE); | 332 | $handle = opendir(LOCALE); |
333 | $languages = array(); | 333 | $languages = array(); |
334 | 334 | ||
335 | while (($language = readdir($handle)) !== false) { | 335 | while (($language = readdir($handle)) !== false) { |
336 | # Languages are stored in a directory, so all directory names are languages | 336 | # Languages are stored in a directory, so all directory names are languages |
337 | # @todo move language installation data to database | 337 | # @todo move language installation data to database |
338 | if (! is_dir(LOCALE . '/' . $language) || in_array($language, array('..', '.', 'tools'))) { | 338 | if (! is_dir(LOCALE . '/' . $language) || in_array($language, array('..', '.', 'tools'))) { |
339 | continue; | 339 | continue; |
340 | } | 340 | } |
341 | 341 | ||
342 | $current = false; | 342 | $current = false; |
343 | 343 | ||
344 | if ($language === $this->getLanguage()) { | 344 | if ($language === $this->getLanguage()) { |
345 | $current = true; | 345 | $current = true; |
346 | } | 346 | } |
347 | 347 | ||
348 | $languages[] = array('name' => (isset($this->language_names[$language]) ? $this->language_names[$language] : $language), 'value' => $language, 'current' => $current); | 348 | $languages[] = array('name' => (isset($this->language_names[$language]) ? $this->language_names[$language] : $language), 'value' => $language, 'current' => $current); |
349 | } | 349 | } |
350 | 350 | ||
351 | return $languages; | 351 | return $languages; |
352 | } | 352 | } |
353 | 353 | ||
354 | public function getDefaultConfig() | 354 | public function getDefaultConfig() |
355 | { | 355 | { |
356 | return array( | 356 | return array( |
357 | 'pager' => PAGINATION, | 357 | 'pager' => PAGINATION, |
358 | 'language' => LANG, | 358 | 'language' => LANG, |
@@ -385,19 +385,15 @@ class Poche | |||
385 | $body = ''; | 385 | $body = ''; |
386 | } | 386 | } |
387 | 387 | ||
388 | //search for possible duplicate if not in import mode | 388 | //search for possible duplicate |
389 | $duplicate = NULL; | 389 | $duplicate = NULL; |
390 | if (!$import) { | 390 | if (!$import) { |
391 | $duplicate = $this->store->retrieveOneByURL($url->getUrl(), $this->user->getId()); | 391 | $duplicate = $this->store->retrieveOneByURL($url->getUrl(), $this->user->getId()); |
392 | } | 392 | } |
393 | 393 | ||
394 | if ($this->store->add($url->getUrl(), $title, $body, $this->user->getId())) { | 394 | $last_id = $this->store->add($url->getUrl(), $title, $body, $this->user->getId()); |
395 | if ( $last_id && !$import ) { | ||
395 | Tools::logm('add link ' . $url->getUrl()); | 396 | Tools::logm('add link ' . $url->getUrl()); |
396 | $sequence = ''; | ||
397 | if (STORAGE == 'postgres') { | ||
398 | $sequence = 'entries_id_seq'; | ||
399 | } | ||
400 | $last_id = $this->store->getLastId($sequence); | ||
401 | if (DOWNLOAD_PICTURES) { | 397 | if (DOWNLOAD_PICTURES) { |
402 | $content = filtre_picture($body, $url->getUrl(), $last_id); | 398 | $content = filtre_picture($body, $url->getUrl(), $last_id); |
403 | Tools::logm('updating content article'); | 399 | Tools::logm('updating content article'); |
@@ -417,9 +413,7 @@ class Poche | |||
417 | } | 413 | } |
418 | } | 414 | } |
419 | 415 | ||
420 | if (!$import) { | 416 | $this->messages->add('s', _('the link has been added successfully')); |
421 | $this->messages->add('s', _('the link has been added successfully')); | ||
422 | } | ||
423 | } | 417 | } |
424 | else { | 418 | else { |
425 | if (!$import) { | 419 | if (!$import) { |
@@ -603,20 +597,19 @@ class Poche | |||
603 | 'tags' => $tags, | 597 | 'tags' => $tags, |
604 | ); | 598 | ); |
605 | break; | 599 | break; |
606 | 600 | case 'search': | |
607 | case 'search': | 601 | if (isset($_GET['search'])) { |
608 | if (isset($_GET['search'])){ | 602 | $search = filter_var($_GET['search'], FILTER_SANITIZE_STRING); |
609 | $search = filter_var($_GET['search'], FILTER_SANITIZE_STRING); | 603 | $tpl_vars['entries'] = $this->store->search($search, $this->user->getId()); |
610 | $tpl_vars['entries'] = $this->store->search($search,$this->user->getId()); | 604 | $count = count($tpl_vars['entries']); |
611 | $count = count($tpl_vars['entries']); | 605 | $this->pagination->set_total($count); |
612 | $this->pagination->set_total($count); | 606 | $page_links = str_replace(array('previous', 'next'), array(_('previous'), _('next')), |
613 | $page_links = str_replace(array('previous', 'next'), array(_('previous'), _('next')), | 607 | $this->pagination->page_links('?view=' . $view . '?search=' . $search . '&sort=' . $_SESSION['sort'] . '&' )); |
614 | $this->pagination->page_links('?view=' . $view . '?search=' . $search . '&sort=' . $_SESSION['sort'] . '&' )); | 608 | $tpl_vars['page_links'] = $page_links; |
615 | $tpl_vars['page_links'] = $page_links; | 609 | $tpl_vars['nb_results'] = $count; |
616 | $tpl_vars['nb_results'] = $count; | 610 | $tpl_vars['search_term'] = $search; |
617 | $tpl_vars['search_term'] = $search; | 611 | } |
618 | } | 612 | break; |
619 | break; | ||
620 | case 'view': | 613 | case 'view': |
621 | $entry = $this->store->retrieveOneById($id, $this->user->getId()); | 614 | $entry = $this->store->retrieveOneById($id, $this->user->getId()); |
622 | if ($entry != NULL) { | 615 | if ($entry != NULL) { |
@@ -653,7 +646,7 @@ class Poche | |||
653 | 'nb_results' => '', | 646 | 'nb_results' => '', |
654 | 'listmode' => (isset($_COOKIE['listmode']) ? true : false), | 647 | 'listmode' => (isset($_COOKIE['listmode']) ? true : false), |
655 | ); | 648 | ); |
656 | 649 | ||
657 | //if id is given - we retrive entries by tag: id is tag id | 650 | //if id is given - we retrive entries by tag: id is tag id |
658 | if ($id) { | 651 | if ($id) { |
659 | $tpl_vars['tag'] = $this->store->retrieveTag($id, $this->user->getId()); | 652 | $tpl_vars['tag'] = $this->store->retrieveTag($id, $this->user->getId()); |
@@ -678,8 +671,8 @@ class Poche | |||
678 | } | 671 | } |
679 | 672 | ||
680 | /** | 673 | /** |
681 | * update the password of the current user. | 674 | * update the password of the current user. |
682 | * if MODE_DEMO is TRUE, the password can't be updated. | 675 | * if MODE_DEMO is TRUE, the password can't be updated. |
683 | * @todo add the return value | 676 | * @todo add the return value |
684 | * @todo set the new password in function header like this updatePassword($newPassword) | 677 | * @todo set the new password in function header like this updatePassword($newPassword) |
685 | * @return boolean | 678 | * @return boolean |
@@ -707,44 +700,44 @@ class Poche | |||
707 | } | 700 | } |
708 | } | 701 | } |
709 | } | 702 | } |
710 | 703 | ||
711 | public function updateTheme() | 704 | public function updateTheme() |
712 | { | 705 | { |
713 | # no data | 706 | # no data |
714 | if (empty($_POST['theme'])) { | 707 | if (empty($_POST['theme'])) { |
715 | } | 708 | } |
716 | 709 | ||
717 | # we are not going to change it to the current theme... | 710 | # we are not going to change it to the current theme... |
718 | if ($_POST['theme'] == $this->getTheme()) { | 711 | if ($_POST['theme'] == $this->getTheme()) { |
719 | $this->messages->add('w', _('still using the "' . $this->getTheme() . '" theme!')); | 712 | $this->messages->add('w', _('still using the "' . $this->getTheme() . '" theme!')); |
720 | Tools::redirect('?view=config'); | 713 | Tools::redirect('?view=config'); |
721 | } | 714 | } |
722 | 715 | ||
723 | $themes = $this->getInstalledThemes(); | 716 | $themes = $this->getInstalledThemes(); |
724 | $actualTheme = false; | 717 | $actualTheme = false; |
725 | 718 | ||
726 | foreach (array_keys($themes) as $theme) { | 719 | foreach (array_keys($themes) as $theme) { |
727 | if ($theme == $_POST['theme']) { | 720 | if ($theme == $_POST['theme']) { |
728 | $actualTheme = true; | 721 | $actualTheme = true; |
729 | break; | 722 | break; |
730 | } | 723 | } |
731 | } | 724 | } |
732 | 725 | ||
733 | if (! $actualTheme) { | 726 | if (! $actualTheme) { |
734 | $this->messages->add('e', _('that theme does not seem to be installed')); | 727 | $this->messages->add('e', _('that theme does not seem to be installed')); |
735 | Tools::redirect('?view=config'); | 728 | Tools::redirect('?view=config'); |
736 | } | 729 | } |
737 | 730 | ||
738 | $this->store->updateUserConfig($this->user->getId(), 'theme', $_POST['theme']); | 731 | $this->store->updateUserConfig($this->user->getId(), 'theme', $_POST['theme']); |
739 | $this->messages->add('s', _('you have changed your theme preferences')); | 732 | $this->messages->add('s', _('you have changed your theme preferences')); |
740 | 733 | ||
741 | $currentConfig = $_SESSION['poche_user']->config; | 734 | $currentConfig = $_SESSION['poche_user']->config; |
742 | $currentConfig['theme'] = $_POST['theme']; | 735 | $currentConfig['theme'] = $_POST['theme']; |
743 | 736 | ||
744 | $_SESSION['poche_user']->setConfig($currentConfig); | 737 | $_SESSION['poche_user']->setConfig($currentConfig); |
745 | 738 | ||
746 | $this->emptyCache(); | 739 | $this->emptyCache(); |
747 | 740 | ||
748 | Tools::redirect('?view=config'); | 741 | Tools::redirect('?view=config'); |
749 | } | 742 | } |
750 | 743 | ||
@@ -753,40 +746,40 @@ class Poche | |||
753 | # no data | 746 | # no data |
754 | if (empty($_POST['language'])) { | 747 | if (empty($_POST['language'])) { |
755 | } | 748 | } |
756 | 749 | ||
757 | # we are not going to change it to the current language... | 750 | # we are not going to change it to the current language... |
758 | if ($_POST['language'] == $this->getLanguage()) { | 751 | if ($_POST['language'] == $this->getLanguage()) { |
759 | $this->messages->add('w', _('still using the "' . $this->getLanguage() . '" language!')); | 752 | $this->messages->add('w', _('still using the "' . $this->getLanguage() . '" language!')); |
760 | Tools::redirect('?view=config'); | 753 | Tools::redirect('?view=config'); |
761 | } | 754 | } |
762 | 755 | ||
763 | $languages = $this->getInstalledLanguages(); | 756 | $languages = $this->getInstalledLanguages(); |
764 | $actualLanguage = false; | 757 | $actualLanguage = false; |
765 | 758 | ||
766 | foreach ($languages as $language) { | 759 | foreach ($languages as $language) { |
767 | if ($language['value'] == $_POST['language']) { | 760 | if ($language['value'] == $_POST['language']) { |
768 | $actualLanguage = true; | 761 | $actualLanguage = true; |
769 | break; | 762 | break; |
770 | } | 763 | } |
771 | } | 764 | } |
772 | 765 | ||
773 | if (! $actualLanguage) { | 766 | if (! $actualLanguage) { |
774 | $this->messages->add('e', _('that language does not seem to be installed')); | 767 | $this->messages->add('e', _('that language does not seem to be installed')); |
775 | Tools::redirect('?view=config'); | 768 | Tools::redirect('?view=config'); |
776 | } | 769 | } |
777 | 770 | ||
778 | $this->store->updateUserConfig($this->user->getId(), 'language', $_POST['language']); | 771 | $this->store->updateUserConfig($this->user->getId(), 'language', $_POST['language']); |
779 | $this->messages->add('s', _('you have changed your language preferences')); | 772 | $this->messages->add('s', _('you have changed your language preferences')); |
780 | 773 | ||
781 | $currentConfig = $_SESSION['poche_user']->config; | 774 | $currentConfig = $_SESSION['poche_user']->config; |
782 | $currentConfig['language'] = $_POST['language']; | 775 | $currentConfig['language'] = $_POST['language']; |
783 | 776 | ||
784 | $_SESSION['poche_user']->setConfig($currentConfig); | 777 | $_SESSION['poche_user']->setConfig($currentConfig); |
785 | 778 | ||
786 | $this->emptyCache(); | 779 | $this->emptyCache(); |
787 | 780 | ||
788 | Tools::redirect('?view=config'); | 781 | Tools::redirect('?view=config'); |
789 | } | 782 | } |
790 | /** | 783 | /** |
791 | * get credentials from differents sources | 784 | * get credentials from differents sources |
792 | * it redirects the user to the $referer link | 785 | * it redirects the user to the $referer link |
@@ -841,7 +834,7 @@ class Poche | |||
841 | /** | 834 | /** |
842 | * log out the poche user. It cleans the session. | 835 | * log out the poche user. It cleans the session. |
843 | * @todo add the return value | 836 | * @todo add the return value |
844 | * @return boolean | 837 | * @return boolean |
845 | */ | 838 | */ |
846 | public function logout() | 839 | public function logout() |
847 | { | 840 | { |
@@ -897,7 +890,7 @@ class Poche | |||
897 | * import from Pocket. poche needs a ./ril_export.html file | 890 | * import from Pocket. poche needs a ./ril_export.html file |
898 | * @todo add the return value | 891 | * @todo add the return value |
899 | * @param string $targetFile the file used for importing | 892 | * @param string $targetFile the file used for importing |
900 | * @return boolean | 893 | * @return boolean |
901 | */ | 894 | */ |
902 | private function importFromPocket($targetFile) | 895 | private function importFromPocket($targetFile) |
903 | { | 896 | { |
@@ -928,7 +921,7 @@ class Poche | |||
928 | $this->action('add_tag',$url,$last_id,true,false,$tags); | 921 | $this->action('add_tag',$url,$last_id,true,false,$tags); |
929 | } | 922 | } |
930 | } | 923 | } |
931 | 924 | ||
932 | # the second <ul> is for read links | 925 | # the second <ul> is for read links |
933 | $read = 1; | 926 | $read = 1; |
934 | } | 927 | } |
@@ -943,7 +936,7 @@ class Poche | |||
943 | * import from Readability. poche needs a ./readability file | 936 | * import from Readability. poche needs a ./readability file |
944 | * @todo add the return value | 937 | * @todo add the return value |
945 | * @param string $targetFile the file used for importing | 938 | * @param string $targetFile the file used for importing |
946 | * @return boolean | 939 | * @return boolean |
947 | */ | 940 | */ |
948 | private function importFromReadability($targetFile) | 941 | private function importFromReadability($targetFile) |
949 | { | 942 | { |
@@ -1000,7 +993,7 @@ class Poche | |||
1000 | /** | 993 | /** |
1001 | * import from Poche exported file | 994 | * import from Poche exported file |
1002 | * @param string $targetFile the file used for importing | 995 | * @param string $targetFile the file used for importing |
1003 | * @return boolean | 996 | * @return boolean |
1004 | */ | 997 | */ |
1005 | private function importFromPoche($targetFile) | 998 | private function importFromPoche($targetFile) |
1006 | { | 999 | { |
@@ -1020,12 +1013,12 @@ class Poche | |||
1020 | $url = new Url(base64_encode($value['url'])); | 1013 | $url = new Url(base64_encode($value['url'])); |
1021 | $favorite = ($value['is_fav'] == -1); | 1014 | $favorite = ($value['is_fav'] == -1); |
1022 | $archive = ($value['is_read'] == -1); | 1015 | $archive = ($value['is_read'] == -1); |
1023 | 1016 | ||
1024 | # we can add the url | 1017 | # we can add the url |
1025 | if (!is_null($url) && $url->isCorrect()) { | 1018 | if (!is_null($url) && $url->isCorrect()) { |
1026 | 1019 | ||
1027 | $this->action('add', $url, 0, TRUE); | 1020 | $this->action('add', $url, 0, TRUE); |
1028 | 1021 | ||
1029 | $count++; | 1022 | $count++; |
1030 | if ($favorite) { | 1023 | if ($favorite) { |
1031 | $last_id = $this->store->getLastId($sequence); | 1024 | $last_id = $this->store->getLastId($sequence); |
@@ -1036,7 +1029,7 @@ class Poche | |||
1036 | $this->action('toggle_archive', $url, $last_id, TRUE); | 1029 | $this->action('toggle_archive', $url, $last_id, TRUE); |
1037 | } | 1030 | } |
1038 | } | 1031 | } |
1039 | 1032 | ||
1040 | } | 1033 | } |
1041 | 1034 | ||
1042 | unlink($targetFile); | 1035 | unlink($targetFile); |
@@ -1047,37 +1040,115 @@ class Poche | |||
1047 | 1040 | ||
1048 | /** | 1041 | /** |
1049 | * import datas into your poche | 1042 | * import datas into your poche |
1050 | * @param string $from name of the service to import : pocket, instapaper or readability | 1043 | * @return boolean |
1051 | * @todo add the return value | ||
1052 | * @return boolean | ||
1053 | */ | 1044 | */ |
1054 | public function import($from) | 1045 | public function import() { |
1055 | { | 1046 | |
1056 | $providers = array( | 1047 | if ( isset($_FILES['file']) ) { |
1057 | 'pocket' => 'importFromPocket', | 1048 | // assume, that file is in json format |
1058 | 'readability' => 'importFromReadability', | 1049 | $str_data = file_get_contents($_FILES['file']['tmp_name']); |
1059 | 'instapaper' => 'importFromInstapaper', | 1050 | $data = json_decode($str_data, true); |
1060 | 'poche' => 'importFromPoche', | 1051 | |
1061 | ); | 1052 | if ( $data === null ) { |
1062 | 1053 | //not json - assume html | |
1063 | if (! isset($providers[$from])) { | 1054 | $html = new simple_html_dom(); |
1064 | $this->messages->add('e', _('Unknown import provider.')); | 1055 | $html->load_file($_FILES['file']['tmp_name']); |
1065 | Tools::redirect(); | 1056 | $data = array(); |
1057 | $read = 0; | ||
1058 | foreach (array('ol','ul') as $list) { | ||
1059 | foreach ($html->find($list) as $ul) { | ||
1060 | foreach ($ul->find('li') as $li) { | ||
1061 | $tmpEntry = array(); | ||
1062 | $a = $li->find('a'); | ||
1063 | $tmpEntry['url'] = $a[0]->href; | ||
1064 | $tmpEntry['tags'] = $a[0]->tags; | ||
1065 | $tmpEntry['is_read'] = $read; | ||
1066 | if ($tmpEntry['url']) { | ||
1067 | $data[] = $tmpEntry; | ||
1068 | } | ||
1069 | } | ||
1070 | # the second <ol/ul> is for read links | ||
1071 | $read = ((sizeof($data) && $read)?0:1); | ||
1072 | } | ||
1073 | } | ||
1066 | } | 1074 | } |
1067 | 1075 | ||
1068 | $targetFile = CACHE . '/' . constant(strtoupper($from) . '_FILE'); | 1076 | $i = 0; //counter for articles inserted |
1069 | 1077 | foreach ($data as $record) { | |
1070 | if (! file_exists($targetFile)) { | 1078 | //echo '<pre>'; |
1071 | $this->messages->add('e', _('Could not find required "' . $targetFile . '" import file.')); | 1079 | //var_dump($record); |
1072 | Tools::redirect(); | 1080 | // foreach ($record as $key=>$val) { |
1081 | // echo "\n=================\n$i: $key: $val\n"; | ||
1082 | // } | ||
1083 | // exit; | ||
1084 | |||
1085 | $url = trim($record['url']); | ||
1086 | if ( $url ) { | ||
1087 | $title = (isset($record['title']) ? $record['title'] : _('Untitled - Import - ').'</a> <a href="./?import">'._('click to finish import').'</a><a>'); | ||
1088 | $body = (isset($record['content']) ? $record['content'] : ''); | ||
1089 | $isRead = (isset($record['is_read']) ? intval($record['is_read']) : 0); | ||
1090 | $isFavorite = (isset($record['is_fav']) ? intval($record['is_fav']) : 0); | ||
1091 | //insert new record | ||
1092 | $id = $this->store->add($url, $title, $body, $this->user->getId(), $isFavorite, $isRead); | ||
1093 | if ( $id ) { | ||
1094 | //increment no of records inserted | ||
1095 | $i++; | ||
1096 | if ( isset($record['tags']) && trim($record['tags']) ) { | ||
1097 | //@TODO: set tags | ||
1098 | |||
1099 | } | ||
1100 | } | ||
1101 | } | ||
1102 | } | ||
1103 | |||
1104 | if ( $i > 0 ) { | ||
1105 | $this->messages->add('s', _('Articles inserted: ').$i._('. Please note, that some may be marked as "read".')); | ||
1073 | } | 1106 | } |
1074 | 1107 | } | |
1075 | $this->$providers[$from]($targetFile); | 1108 | //file parsing finished here |
1109 | |||
1110 | //now download article contents if any | ||
1111 | |||
1112 | //check if we need to download any content | ||
1113 | $recordsDownloadRequired = $this->store->retrieveUnfetchedEntriesCount($this->user->getId()); | ||
1114 | if ( $recordsDownloadRequired == 0 ) { | ||
1115 | //nothing to download | ||
1116 | $this->messages->add('s', _('Import finished.')); | ||
1117 | Tools::redirect(); | ||
1118 | } | ||
1119 | else { | ||
1120 | //if just inserted - don't download anything, download will start in next reload | ||
1121 | if ( !isset($_FILES['file']) ) { | ||
1122 | //download next batch | ||
1123 | $items = $this->store->retrieveUnfetchedEntries($this->user->getId(), IMPORT_LIMIT); | ||
1124 | |||
1125 | $config = HTMLPurifier_Config::createDefault(); | ||
1126 | $config->set('Cache.SerializerPath', CACHE); | ||
1127 | $purifier = new HTMLPurifier($config); | ||
1128 | |||
1129 | foreach ($items as $item) { | ||
1130 | $url = new Url(base64_encode($item['url'])); | ||
1131 | $content = Tools::getPageContent($url); | ||
1132 | |||
1133 | $title = (($content['rss']['channel']['item']['title'] != '') ? $content['rss']['channel']['item']['title'] : _('Untitled')); | ||
1134 | $body = (($content['rss']['channel']['item']['description'] != '') ? $content['rss']['channel']['item']['description'] : _('Undefined')); | ||
1135 | |||
1136 | //clean content to prevent xss attack | ||
1137 | $title = $purifier->purify($title); | ||
1138 | $body = $purifier->purify($body); | ||
1139 | |||
1140 | $this->store->updateContentAndTitle($item['id'], $title, $body, $this->user->getId()); | ||
1141 | } | ||
1142 | |||
1143 | } | ||
1144 | } | ||
1145 | |||
1146 | return array('includeImport'=>true, 'import'=>array('recordsDownloadRequired'=>$recordsDownloadRequired, 'recordsUnderDownload'=> IMPORT_LIMIT, 'delay'=> IMPORT_DELAY * 1000) ); | ||
1076 | } | 1147 | } |
1077 | 1148 | ||
1078 | public function uploadFile() { | 1149 | public function uploadFile() { |
1079 | if(isset($_FILES['file'])) | 1150 | if (isset($_FILES['file'])) |
1080 | { | 1151 | { |
1081 | $dir = CACHE . '/'; | 1152 | $dir = CACHE . '/'; |
1082 | $file = basename($_FILES['file']['name']); | 1153 | $file = basename($_FILES['file']['name']); |
1083 | if(move_uploaded_file($_FILES['file']['tmp_name'], $dir . $file)) { | 1154 | if(move_uploaded_file($_FILES['file']['tmp_name'], $dir . $file)) { |
@@ -1087,7 +1158,7 @@ class Poche | |||
1087 | $this->messages->add('e', _('Error while importing file. Do you have access to upload it?')); | 1158 | $this->messages->add('e', _('Error while importing file. Do you have access to upload it?')); |
1088 | } | 1159 | } |
1089 | } | 1160 | } |
1090 | 1161 | ||
1091 | Tools::redirect('?view=config'); | 1162 | Tools::redirect('?view=config'); |
1092 | } | 1163 | } |
1093 | 1164 | ||
@@ -1099,7 +1170,7 @@ class Poche | |||
1099 | { | 1170 | { |
1100 | $filename = "wallabag-export-".$this->user->getId()."-".date("Y-m-d").".json"; | 1171 | $filename = "wallabag-export-".$this->user->getId()."-".date("Y-m-d").".json"; |
1101 | header('Content-Disposition: attachment; filename='.$filename); | 1172 | header('Content-Disposition: attachment; filename='.$filename); |
1102 | 1173 | ||
1103 | $entries = $this->store->retrieveAll($this->user->getId()); | 1174 | $entries = $this->store->retrieveAll($this->user->getId()); |
1104 | echo $this->tpl->render('export.twig', array( | 1175 | echo $this->tpl->render('export.twig', array( |
1105 | 'export' => Tools::renderJson($entries), | 1176 | 'export' => Tools::renderJson($entries), |
diff --git a/inc/poche/Tools.class.php b/inc/poche/Tools.class.php index ad451fc6..a130e94b 100755 --- a/inc/poche/Tools.class.php +++ b/inc/poche/Tools.class.php | |||
@@ -7,7 +7,7 @@ | |||
7 | * @copyright 2013 | 7 | * @copyright 2013 |
8 | * @license http://www.wtfpl.net/ see COPYING file | 8 | * @license http://www.wtfpl.net/ see COPYING file |
9 | */ | 9 | */ |
10 | 10 | ||
11 | class Tools | 11 | class Tools |
12 | { | 12 | { |
13 | public static function initPhp() | 13 | public static function initPhp() |
@@ -42,7 +42,7 @@ class Tools | |||
42 | && (strtolower($_SERVER['HTTPS']) == 'on')) | 42 | && (strtolower($_SERVER['HTTPS']) == 'on')) |
43 | || (isset($_SERVER["SERVER_PORT"]) | 43 | || (isset($_SERVER["SERVER_PORT"]) |
44 | && $_SERVER["SERVER_PORT"] == '443') // HTTPS detection. | 44 | && $_SERVER["SERVER_PORT"] == '443') // HTTPS detection. |
45 | || (isset($_SERVER["SERVER_PORT"]) //Custom HTTPS port detection | 45 | || (isset($_SERVER["SERVER_PORT"]) //Custom HTTPS port detection |
46 | && $_SERVER["SERVER_PORT"] == SSL_PORT) | 46 | && $_SERVER["SERVER_PORT"] == SSL_PORT) |
47 | || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) | 47 | || (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) |
48 | && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'); | 48 | && $_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'); |
@@ -148,7 +148,7 @@ class Tools | |||
148 | ); | 148 | ); |
149 | 149 | ||
150 | # only download page lesser than 4MB | 150 | # only download page lesser than 4MB |
151 | $data = @file_get_contents($url, false, $context, -1, 4000000); | 151 | $data = @file_get_contents($url, false, $context, -1, 4000000); |
152 | 152 | ||
153 | if (isset($http_response_header) and isset($http_response_header[0])) { | 153 | if (isset($http_response_header) and isset($http_response_header[0])) { |
154 | $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)); | 154 | $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)); |
@@ -200,7 +200,7 @@ class Tools | |||
200 | } | 200 | } |
201 | } | 201 | } |
202 | 202 | ||
203 | public static function encodeString($string) | 203 | public static function encodeString($string) |
204 | { | 204 | { |
205 | return sha1($string . SALT); | 205 | return sha1($string . SALT); |
206 | } | 206 | } |
diff --git a/inc/poche/config.inc.php.new b/inc/poche/config.inc.php.new index 8d52497b..83b3c4c0 100755 --- a/inc/poche/config.inc.php.new +++ b/inc/poche/config.inc.php.new | |||
@@ -52,12 +52,8 @@ define ('CACHE', ROOT . '/cache'); | |||
52 | 52 | ||
53 | define ('PAGINATION', '10'); | 53 | define ('PAGINATION', '10'); |
54 | 54 | ||
55 | define ('POCKET_FILE', '/ril_export.html'); | 55 | //limit for download of articles during import |
56 | define ('READABILITY_FILE', '/readability'); | 56 | define ('IMPORT_LIMIT', 5); |
57 | define ('INSTAPAPER_FILE', '/instapaper-export.html'); | 57 | //delay between downloads (in sec) |
58 | define ('POCHE_FILE', '/poche-export'); | 58 | define ('IMPORT_DELAY', 5); |
59 | 59 | ||
60 | define ('IMPORT_POCKET_FILE', ROOT . POCKET_FILE); | ||
61 | define ('IMPORT_READABILITY_FILE', ROOT . READABILITY_FILE); | ||
62 | define ('IMPORT_INSTAPAPER_FILE', ROOT . INSTAPAPER_FILE); | ||
63 | define ('IMPORT_POCHE_FILE', ROOT . POCHE_FILE); \ No newline at end of file | ||
@@ -40,7 +40,7 @@ $tpl_vars = array( | |||
40 | 40 | ||
41 | if (! empty($notInstalledMessage)) { | 41 | if (! empty($notInstalledMessage)) { |
42 | if (! Poche::$canRenderTemplates || ! Poche::$configFileAvailable) { | 42 | if (! Poche::$canRenderTemplates || ! Poche::$configFileAvailable) { |
43 | # We cannot use Twig to display the error message | 43 | # We cannot use Twig to display the error message |
44 | echo '<h1>Errors</h1><ol>'; | 44 | echo '<h1>Errors</h1><ol>'; |
45 | foreach ($notInstalledMessage as $message) { | 45 | foreach ($notInstalledMessage as $message) { |
46 | echo '<li>' . $message . '</li>'; | 46 | echo '<li>' . $message . '</li>'; |
@@ -67,7 +67,8 @@ if (isset($_GET['login'])) { | |||
67 | # Update password | 67 | # Update password |
68 | $poche->updatePassword(); | 68 | $poche->updatePassword(); |
69 | } elseif (isset($_GET['import'])) { | 69 | } elseif (isset($_GET['import'])) { |
70 | $import = $poche->import($_GET['from']); | 70 | $import = $poche->import(); |
71 | $tpl_vars = array_merge($tpl_vars, $import); | ||
71 | } elseif (isset($_GET['download'])) { | 72 | } elseif (isset($_GET['download'])) { |
72 | Tools::download_db(); | 73 | Tools::download_db(); |
73 | } elseif (isset($_GET['empty-cache'])) { | 74 | } elseif (isset($_GET['empty-cache'])) { |
diff --git a/themes/baggy/config.twig b/themes/baggy/config.twig index a13af0c8..fc7890ec 100644..100755 --- a/themes/baggy/config.twig +++ b/themes/baggy/config.twig | |||
@@ -105,37 +105,20 @@ | |||
105 | {% endif %} | 105 | {% endif %} |
106 | 106 | ||
107 | <h2>{% trans "Import" %}</h2> | 107 | <h2>{% trans "Import" %}</h2> |
108 | <p>{% trans "Importing from other services can be quite long, and webservers default configuration often prevents long scripts execution time, so it must be done in multiple parts." %}</p> | 108 | <p>{% trans "You can import your Pocket, Readability, Instapaper, Wallabag or any data in appropriate json or html format." %}</p> |
109 | <p>1. {% trans "First, select the export file on your computer and upload it." %}</p> | 109 | <p>{% trans "Please select export file on your computer:" %}</p> |
110 | <form method="post" action="?uploadfile" name="uploadfile" enctype="multipart/form-data"> | 110 | <form method="post" action="?import" name="uploadfile" enctype="multipart/form-data"> |
111 | <fieldset class="w500p"> | 111 | <fieldset class="w500p"> |
112 | <div class="row"> | 112 | <div class="row"> |
113 | <label class="col w150p" for="file">{% trans "File:" %}</label> | 113 | <label class="col w150p" for="file">{% trans "File:" %}</label> |
114 | <input class="col" type="file" id="file" name="file" tabindex="4"> | 114 | <input class="col" type="file" id="file" name="file" tabindex="4"> |
115 | </div> | 115 | </div> |
116 | <div class="row mts txtcenter"> | 116 | <div class="row mts txtcenter"> |
117 | <button class="bouton" type="submit" tabindex="4">{% trans "Upload" %}</button> | 117 | <button class="bouton" type="submit" tabindex="4">{% trans "Import" %}</button> |
118 | </div> | 118 | </div> |
119 | </fieldset> | 119 | </fieldset> |
120 | <input type="hidden" name="MAX_FILE_SIZE" value="1048576"> | ||
121 | <input type="hidden" name="returnurl" value="{{ referer }}"> | ||
122 | </form> | 120 | </form> |
123 | <p>2. {% trans "Then, click on the right link below." %}</p> | 121 | |
124 | <ul> | ||
125 | <li><a href="./?import&from=pocket">{% trans "Import from Pocket" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('POCKET_FILE')) }}</li> | ||
126 | <li><a href="./?import&from=readability">{% trans "Import from Readability" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('READABILITY_FILE')) }}</li> | ||
127 | <li><a href="./?import&from=instapaper">{% trans "Import from Instapaper" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('INSTAPAPER_FILE')) }}</li> | ||
128 | <li><a href="./?import&from=poche">{% trans "Import from wallabag" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('POCHE_FILE')) }}</li> | ||
129 | </ul> | ||
130 | |||
131 | {% if token == '' %} | ||
132 | <p>{% trans "3. Your feed token is currently empty and must first be generated to fetch content. Click <a href='?feed&action=generate'>here to generate it</a>." %}</p> | ||
133 | {% else %} | ||
134 | <p>3. {% trans "Finally, you have to fetch content for imported items." %} <a href="cron.php?limit=10&user-id={{ user_id }}&token={{token}}" target="_blank">{% trans "Click here" %}</a> {% trans "to fetch content for 10 articles" %}.</p> | ||
135 | <p>{% trans "If you have console access to your server, you can also create a cron task:" %}</p> | ||
136 | <pre><code>0 */4 * * * cd /path/to/wallabag && php cron.php --limit=10 --user-id={{user_id}} --token={{token}} >/dev/null 2>&1</code></pre> | ||
137 | {% endif %} | ||
138 | |||
139 | <h2>{% trans "Export your wallabag data" %}</h2> | 122 | <h2>{% trans "Export your wallabag data" %}</h2> |
140 | {% if constant('STORAGE') == 'sqlite' %} | 123 | {% if constant('STORAGE') == 'sqlite' %} |
141 | <p><a href="?download" target="_blank">{% trans "Click here" %}</a> {% trans "to download your database." %}</p>{% endif %} | 124 | <p><a href="?download" target="_blank">{% trans "Click here" %}</a> {% trans "to download your database." %}</p>{% endif %} |
diff --git a/themes/baggy/css/main.css b/themes/baggy/css/main.css index 6e328ba1..9a45544b 100755 --- a/themes/baggy/css/main.css +++ b/themes/baggy/css/main.css | |||
@@ -777,7 +777,7 @@ margin-top:1em; | |||
777 | } | 777 | } |
778 | 778 | ||
779 | .warning { | 779 | .warning { |
780 | font-size: 3em; | 780 | /* font-size: 3em; |
781 | color: #999; | 781 | color: #999; |
782 | font-style: italic; | 782 | font-style: italic; |
783 | position: absolute; | 783 | position: absolute; |
@@ -786,7 +786,10 @@ margin-top:1em; | |||
786 | width: 100%; | 786 | width: 100%; |
787 | text-align: center; | 787 | text-align: center; |
788 | padding-right: 5%; | 788 | padding-right: 5%; |
789 | margin-top: -2em; | 789 | margin-top: -2em;*/ |
790 | font-weight: bold; | ||
791 | display: block; | ||
792 | width: 100%; | ||
790 | } | 793 | } |
791 | 794 | ||
792 | /* ========================================================================== | 795 | /* ========================================================================== |
diff --git a/themes/baggy/layout.twig b/themes/baggy/layout.twig index dfebc3ea..8de12749 100644..100755 --- a/themes/baggy/layout.twig +++ b/themes/baggy/layout.twig | |||
@@ -21,6 +21,9 @@ | |||
21 | {% block precontent %}{% endblock %} | 21 | {% block precontent %}{% endblock %} |
22 | {% block messages %} | 22 | {% block messages %} |
23 | {% include '_messages.twig' %} | 23 | {% include '_messages.twig' %} |
24 | {% if includeImport %} | ||
25 | {% include '_import.twig' %} | ||
26 | {% endif %} | ||
24 | {% endblock %} | 27 | {% endblock %} |
25 | <div id="content" class="w600p center"> | 28 | <div id="content" class="w600p center"> |
26 | {% block content %}{% endblock %} | 29 | {% block content %}{% endblock %} |
diff --git a/themes/default/_import.twig b/themes/default/_import.twig new file mode 100755 index 00000000..926696c1 --- /dev/null +++ b/themes/default/_import.twig | |||
@@ -0,0 +1,15 @@ | |||
1 | <script type="text/javascript"> | ||
2 | <!-- | ||
3 | $(document).ready(function() { | ||
4 | $("body").css("cursor", "wait"); | ||
5 | |||
6 | setTimeout(function(){ | ||
7 | window.location = '/?import'; | ||
8 | }, {{ import.delay }} ); | ||
9 | }); | ||
10 | //--> | ||
11 | </script> | ||
12 | <div class="messages warning"> | ||
13 | <p>{% trans "Download required for " %} {{ import.recordsDownloadRequired }} {% trans "records" %}.</p> | ||
14 | <p>{% trans "Downloading next " %} {{ import.recordsUnderDownload }} {% trans "articles, please wait" %}...</p> | ||
15 | </div> | ||
diff --git a/themes/default/config.twig b/themes/default/config.twig index 5d20e0ea..7ccd0b36 100644..100755 --- a/themes/default/config.twig +++ b/themes/default/config.twig | |||
@@ -104,36 +104,19 @@ | |||
104 | {% endif %} | 104 | {% endif %} |
105 | 105 | ||
106 | <h2>{% trans "Import" %}</h2> | 106 | <h2>{% trans "Import" %}</h2> |
107 | <p>{% trans "Importing from other services can be quite long, and webservers default configuration often prevents long scripts execution time, so it must be done in multiple parts." %}</p> | 107 | <p>{% trans "You can import your Pocket, Readability, Instapaper, Wallabag or any data in appropriate json or html format." %}</p> |
108 | <p>1. {% trans "First, select the export file on your computer and upload it." %}</p> | 108 | <p>{% trans "Please select export file on your computer:" %}</p> |
109 | <form method="post" action="?uploadfile" name="uploadfile" enctype="multipart/form-data"> | 109 | <form method="post" action="?import" name="uploadfile" enctype="multipart/form-data"> |
110 | <fieldset class="w500p"> | 110 | <fieldset class="w500p"> |
111 | <div class="row"> | 111 | <div class="row"> |
112 | <label class="col w150p" for="file">{% trans "File:" %}</label> | 112 | <label class="col w150p" for="file">{% trans "File:" %}</label> |
113 | <input class="col" type="file" id="file" name="file" tabindex="4"> | 113 | <input class="col" type="file" id="file" name="file" tabindex="4"> |
114 | </div> | 114 | </div> |
115 | <div class="row mts txtcenter"> | 115 | <div class="row mts txtcenter"> |
116 | <button class="bouton" type="submit" tabindex="4">{% trans "Upload" %}</button> | 116 | <button class="bouton" type="submit" tabindex="4">{% trans "Import" %}</button> |
117 | </div> | 117 | </div> |
118 | </fieldset> | 118 | </fieldset> |
119 | <input type="hidden" name="MAX_FILE_SIZE" value="1048576"> | ||
120 | <input type="hidden" name="returnurl" value="{{ referer }}"> | ||
121 | </form> | 119 | </form> |
122 | <p>2. {% trans "Then, click on the right link below." %}</p> | ||
123 | <ul> | ||
124 | <li><a href="./?import&from=pocket">{% trans "Import from Pocket" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('POCKET_FILE')) }}</li> | ||
125 | <li><a href="./?import&from=readability">{% trans "Import from Readability" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('READABILITY_FILE')) }}</li> | ||
126 | <li><a href="./?import&from=instapaper">{% trans "Import from Instapaper" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('INSTAPAPER_FILE')) }}</li> | ||
127 | <li><a href="./?import&from=poche">{% trans "Import from wallabag" %}</a> {{ '(after uploaded %s file)'|trans|format(constant('POCHE_FILE')) }}</li> | ||
128 | </ul> | ||
129 | |||
130 | {% if token == '' %} | ||
131 | <p>{% trans "3. Your feed token is currently empty and must first be generated to fetch content. Click <a href='?feed&action=generate'>here to generate it</a>." %}</p> | ||
132 | {% else %} | ||
133 | <p>3. {% trans "Finally, you have to fetch content for imported items." %} <a href="cron.php?limit=10&user-id={{ user_id }}&token={{token}}" target="_blank">{% trans "Click here" %}</a> {% trans "to fetch content for 10 articles" %}.</p> | ||
134 | <p>{% trans "If you have console access to your server, you can also create a cron task:" %}</p> | ||
135 | <pre><code>0 */4 * * * cd /path/to/wallabag && php cron.php --limit=10 --user-id={{user_id}} --token={{token}} >/dev/null 2>&1</code></pre> | ||
136 | {% endif %} | ||
137 | 120 | ||
138 | <h2>{% trans "Export your wallabag data" %}</h2> | 121 | <h2>{% trans "Export your wallabag data" %}</h2> |
139 | {% if constant('STORAGE') == 'sqlite' %} | 122 | {% if constant('STORAGE') == 'sqlite' %} |
diff --git a/themes/default/home.twig b/themes/default/home.twig index 7bee883b..d6cb98e8 100755 --- a/themes/default/home.twig +++ b/themes/default/home.twig | |||
@@ -16,6 +16,11 @@ | |||
16 | {% include '_sorting.twig' %} | 16 | {% include '_sorting.twig' %} |
17 | {% endblock %} | 17 | {% endblock %} |
18 | {% block content %} | 18 | {% block content %} |
19 | |||
20 | {% if includeImport %} | ||
21 | {% include '_import.twig' %} | ||
22 | {% endif %} | ||
23 | |||
19 | {% if tag %} | 24 | {% if tag %} |
20 | <h3>{% trans "Tag" %}: <b>{{ tag.value }}</b></h3> | 25 | <h3>{% trans "Tag" %}: <b>{{ tag.value }}</b></h3> |
21 | {% endif %} | 26 | {% endif %} |