]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - plugins/Bookmark/Bookmark.php
f9bc71447eee79df3cc7c1539be7eed6b189c55d
[quix0rs-gnu-social.git] / plugins / Bookmark / Bookmark.php
1 <?php
2 /**
3  * Data class to mark notices as bookmarks
4  *
5  * PHP version 5
6  *
7  * @category Data
8  * @package  StatusNet
9  * @author   Evan Prodromou <evan@status.net>
10  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
11  * @link     http://status.net/
12  *
13  * StatusNet - the distributed open-source microblogging tool
14  * Copyright (C) 2009, StatusNet, Inc.
15  *
16  * This program is free software: you can redistribute it and/or modify
17  * it under the terms of the GNU Affero General Public License as published by
18  * the Free Software Foundation, either version 3 of the License, or
19  * (at your option) any later version.
20  *
21  * This program is distributed in the hope that it will be useful,
22  * but WITHOUT ANY WARRANTY; without even the implied warranty of
23  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the
24  * GNU Affero General Public License for more details.
25  *
26  * You should have received a copy of the GNU Affero General Public License
27  * along with this program. If not, see <http://www.gnu.org/licenses/>.
28  */
29
30 if (!defined('STATUSNET')) {
31     exit(1);
32 }
33
34 /**
35  * For storing the fact that a notice is a bookmark
36  *
37  * @category Bookmark
38  * @package  StatusNet
39  * @author   Evan Prodromou <evan@status.net>
40  * @license  http://www.fsf.org/licensing/licenses/agpl.html AGPLv3
41  * @link     http://status.net/
42  *
43  * @see      DB_DataObject
44  */
45 class Bookmark extends Managed_DataObject
46 {
47     public $__table = 'bookmark'; // table name
48     public $id;          // char(36) primary_key not_null
49     public $profile_id;  // int(4) not_null
50     public $url;         // varchar(255) not_null
51     public $title;       // varchar(255)
52     public $description; // text
53     public $uri;         // varchar(255)
54     public $created;     // datetime
55
56     /**
57      * Get an instance by compound key
58      *
59      * This is a utility method to get a single instance with a given set of
60      * key-value pairs. Usually used for the primary key for a compound key; thus
61      * the name.
62      *
63      * @param array $kv array of key-value mappings
64      *
65      * @return Bookmark object found, or null for no hits
66      *
67      */
68     function pkeyGet($kv)
69     {
70         return Memcached_DataObject::pkeyGet('Bookmark', $kv);
71     }
72
73     /**
74      * return table definition for DB_DataObject
75      *
76      * DB_DataObject needs to know something about the table to manipulate
77      * instances. This method provides all the DB_DataObject needs to know.
78      *
79      * @return array array of column definitions
80      */
81     function table()
82     {
83         return array('id' => DB_DATAOBJECT_STR + DB_DATAOBJECT_NOTNULL,
84                      'profile_id' => DB_DATAOBJECT_INT + DB_DATAOBJECT_NOTNULL,
85                      'url' => DB_DATAOBJECT_STR,
86                      'title' => DB_DATAOBJECT_STR,
87                      'description' => DB_DATAOBJECT_STR,
88                      'uri' => DB_DATAOBJECT_STR,
89                      'created' => DB_DATAOBJECT_STR + DB_DATAOBJECT_DATE +
90                      DB_DATAOBJECT_TIME + DB_DATAOBJECT_NOTNULL);
91     }
92
93     /**
94      * return key definitions for DB_DataObject
95      *
96      * @return array list of key field names
97      */
98     function keys()
99     {
100         return array_keys($this->keyTypes());
101     }
102
103     /**
104      * return key definitions for Memcached_DataObject
105      *
106      * @return array associative array of key definitions
107      */
108     function keyTypes()
109     {
110         return array('id' => 'K',
111                      'uri' => 'U');
112     }
113
114     /**
115      * Magic formula for non-autoincrementing integer primary keys
116      *
117      * @return array magic three-false array that stops auto-incrementing.
118      */
119     function sequenceKey()
120     {
121         return array(false, false, false);
122     }
123
124     /**
125      * Get a bookmark based on a notice
126      *
127      * @param Notice $notice Notice to check for
128      *
129      * @return Bookmark found bookmark or null
130      */
131     static function getByNotice($notice)
132     {
133         return self::staticGet('uri', $notice->uri);
134     }
135
136     /**
137      * Get the bookmark that a user made for an URL
138      *
139      * @param Profile $profile Profile to check for
140      * @param string  $url     URL to check for
141      *
142      * @return Bookmark bookmark found or null
143      */
144     static function getByURL($profile, $url)
145     {
146         $nb = new Bookmark();
147
148         $nb->profile_id = $profile->id;
149         $nb->url        = $url;
150
151         if ($nb->find(true)) {
152             return $nb;
153         } else {
154             return null;
155         }
156     }
157
158     /**
159      * Save a new notice bookmark
160      *
161      * @param Profile $profile     To save the bookmark for
162      * @param string  $title       Title of the bookmark
163      * @param string  $url         URL of the bookmark
164      * @param mixed   $rawtags     array of tags or string
165      * @param string  $description Description of the bookmark
166      * @param array   $options     Options for the Notice::saveNew()
167      *
168      * @return Notice saved notice
169      */
170     static function saveNew($profile, $title, $url, $rawtags, $description,
171                             $options=null)
172     {
173         $nb = self::getByURL($profile, $url);
174
175         if (!empty($nb)) {
176             // TRANS: Client exception thrown when trying to save a new bookmark that already exists.
177             throw new ClientException(_m('Bookmark already exists.'));
178         }
179
180         if (empty($options)) {
181             $options = array();
182         }
183
184         if (array_key_exists('uri', $options)) {
185             $other = Bookmark::staticGet('uri', $options['uri']);
186             if (!empty($other)) {
187                 // TRANS: Client exception thrown when trying to save a new bookmark that already exists.
188                 throw new ClientException(_m('Bookmark already exists.'));
189             }
190         }
191
192         if (is_string($rawtags)) {
193             if (empty($rawtags)) {
194                 $rawtags = array();
195             } else {
196                 $rawtags = preg_split('/[\s,]+/', $rawtags);
197             }
198         }
199
200         $nb = new Bookmark();
201
202         $nb->id          = UUID::gen();
203         $nb->profile_id  = $profile->id;
204         $nb->url         = $url;
205         $nb->title       = $title;
206         $nb->description = $description;
207
208         if (array_key_exists('created', $options)) {
209             $nb->created = $options['created'];
210         } else {
211             $nb->created = common_sql_now();
212         }
213
214         if (array_key_exists('uri', $options)) {
215             $nb->uri = $options['uri'];
216         } else {
217             // FIXME: hacks to work around router bugs in
218             // queue daemons
219
220             $r = Router::get();
221
222             $path = $r->build('showbookmark',
223                               array('id' => $nb->id));
224
225             if (empty($path)) {
226                 $nb->uri = common_path('bookmark/'.$nb->id, false, false);
227             } else {
228                 $nb->uri = common_local_url('showbookmark',
229                                             array('id' => $nb->id),
230                                             null,
231                                             null,
232                                             false);
233             }
234         }
235
236         $nb->insert();
237
238         $tags    = array();
239         $replies = array();
240
241         // filter "for:nickname" tags
242
243         foreach ($rawtags as $tag) {
244             if (strtolower(mb_substr($tag, 0, 4)) == 'for:') {
245                 // skip if done by caller
246                 if (!array_key_exists('replies', $options)) {
247                     $nickname = mb_substr($tag, 4);
248                     $other    = common_relative_profile($profile,
249                                                         $nickname);
250                     if (!empty($other)) {
251                         $replies[] = $other->getUri();
252                     }
253                 }
254             } else {
255                 $tags[] = common_canonical_tag($tag);
256             }
257         }
258
259         $hashtags = array();
260         $taglinks = array();
261
262         foreach ($tags as $tag) {
263             $hashtags[] = '#'.$tag;
264             $attrs      = array('href' => Notice_tag::url($tag),
265                                 'rel'  => $tag,
266                                 'class' => 'tag');
267             $taglinks[] = XMLStringer::estring('a', $attrs, $tag);
268         }
269
270         // Use user's preferences for short URLs, if possible
271
272         try {
273             $user = User::staticGet('id', $profile->id);
274
275             $shortUrl = File_redirection::makeShort($url,
276                                                     empty($user) ? null : $user);
277         } catch (Exception $e) {
278             // Don't let this stop us.
279             $shortUrl = $url;
280         }
281
282         // TRANS: Bookmark content.
283         // TRANS: %1$s is a title, %2$s is a short URL, %3$s is the bookmark description,
284         // TRANS: %4$s is space separated list of hash tags.
285         $content = sprintf(_m('"%1$s" %2$s %3$s %4$s'),
286                            $title,
287                            $shortUrl,
288                            $description,
289                            implode(' ', $hashtags));
290
291         // TRANS: Rendered bookmark content.
292         // TRANS: %1$s is a URL, %2$s the bookmark title, %3$s is the bookmark description,
293         // TRANS: %4$s is space separated list of hash tags.
294         $rendered = sprintf(_m('<span class="xfolkentry">'.
295                               '<a class="taggedlink" href="%1$s">%2$s</a> '.
296                               '<span class="description">%3$s</span> '.
297                               '<span class="meta">%4$s</span>'.
298                               '</span>'),
299                             htmlspecialchars($url),
300                             htmlspecialchars($title),
301                             htmlspecialchars($description),
302                             implode(' ', $taglinks));
303
304         $options = array_merge(array('urls' => array($url),
305                                      'rendered' => $rendered,
306                                      'tags' => $tags,
307                                      'replies' => $replies,
308                                      'object_type' => ActivityObject::BOOKMARK),
309                                $options);
310
311         if (!array_key_exists('uri', $options)) {
312             $options['uri'] = $nb->uri;
313         }
314
315         try {
316             $saved = Notice::saveNew($profile->id,
317                                      $content,
318                                      array_key_exists('source', $options) ?
319                                      $options['source'] : 'web',
320                                      $options);
321         } catch (Exception $e) {
322             $nb->delete();
323             throw $e;
324         }
325
326         if (empty($saved)) {
327             $nb->delete();
328         }
329
330         return $saved;
331     }
332 }