link api from web interface, make single note fetching work, redo note storage username
[grauphel.git] / lib / notestorage.php
1 <?php
2 /**
3  * Part of grauphel
4  *
5  * PHP version 5
6  *
7  * @category  Tools
8  * @package   Grauphel
9  * @author    Christian Weiske <cweiske@cweiske.de>
10  * @copyright 2014 Christian Weiske
11  * @license   http://www.gnu.org/licenses/agpl.html GNU AGPL v3
12  * @link      http://cweiske.de/grauphel.htm
13  */
14 namespace OCA\Grauphel\Lib;
15
16 /**
17  * Flat file storage for notes
18  *
19  * @category  Tools
20  * @package   Grauphel
21  * @author    Christian Weiske <cweiske@cweiske.de>
22  * @copyright 2014 Christian Weiske
23  * @license   http://www.gnu.org/licenses/agpl.html GNU AGPL v3
24  * @version   Release: @package_version@
25  * @link      http://cweiske.de/grauphel.htm
26  */
27 class NoteStorage
28 {
29     protected $urlGen;
30     protected $username;
31
32     public function __construct($urlGen)
33     {
34         $this->urlGen   = $urlGen;
35     }
36
37     public function setUsername($username)
38     {
39         $this->username = $username;
40     }
41
42     /**
43      * Create a new sync data object for fresh users.
44      * Used by loadSyncData()
45      *
46      * @return SyncData New synchronization statistics
47      */
48     protected function getNewSyncData()
49     {
50         $syncdata = new SyncData();
51         $syncdata->initNew($this->username);
52         return $syncdata;
53     }
54
55     public function getTags()
56     {
57     }
58
59     /**
60      * Updates the given $note object with data from $noteUpdate.
61      * Sets the last-sync-revision to $syncRevision
62      *
63      * @param object  $note         Original note object
64      * @param object  $noteUpdate   Update note object from a PUT to the API
65      * @param integer $syncRevision Current sync revision number
66      *
67      * @return void
68      */
69     public function update($note, $noteUpdate, $syncRevision)
70     {
71         static $updateFields = array(
72             'create-date',
73             'last-change-date',
74             'last-metadata-change-date',
75             'note-content',
76             'note-content-version',
77             'open-on-startup',
78             'pinned',
79             'tags',
80             'title',
81         );
82
83         $changed = array();
84         foreach ($updateFields as $field) {
85             $changed[$field] = false;
86             if (isset($noteUpdate->$field)) {
87                 if ($note->$field != $noteUpdate->$field) {
88                     $note->$field = $noteUpdate->$field;
89                     $changed[$field] = true;
90                 }
91             }
92         }
93
94         if (!isset($noteUpdate->{'last-change-date'})
95             && ($changed['title'] || $changed['note-content'])
96         ) {
97             //no idea how to get the microseconds in there
98             $note->{'last-change-date'} = date('c');
99         }
100
101         if (!isset($noteUpdate->{'last-metadata-change-date'})) {
102             //no idea how to get the microseconds in there
103             $note->{'last-metadata-change-date'} = date('c');
104         }
105
106         if (isset($noteUpdate->{'node-content'})
107             && $note->{'note-content-version'} == 0
108         ) {
109             $note->{'note-content-version'} = 0.3;
110         }
111
112         $note->{'last-sync-revision'} = $syncRevision;
113     }
114
115     /**
116      * Loads synchronization data for the given user.
117      * Creates fresh sync data if there are none for the user.
118      *
119      * @return SyncData Synchronization statistics (revision, sync guid)
120      */
121     public function loadSyncData()
122     {
123         $row = \OC_DB::executeAudited(
124             'SELECT * FROM `*PREFIX*grauphel_syncdata`'
125             . ' WHERE `syncdata_user` = ?',
126             array($this->username)
127         )->fetchRow();
128
129         if ($row === false) {
130             $syncdata = $this->getNewSyncData($this->username);
131             $this->saveSyncData($this->username, $syncdata);
132         } else {
133             $syncdata = new SyncData();
134             $syncdata->latestSyncRevision = (int) $row['syncdata_latest_sync_revision'];
135             $syncdata->currentSyncGuid    = $row['syncdata_current_sync_guid'];
136         }
137
138         return $syncdata;
139     }
140
141     /**
142      * Save synchronization data for the given user.
143      *
144      * @param SyncData $syncdata Synchronization data object
145      *
146      * @return void
147      */
148     public function saveSyncData(SyncData $syncdata)
149     {
150         $row = \OC_DB::executeAudited(
151             'SELECT * FROM `*PREFIX*grauphel_syncdata`'
152             . ' WHERE `syncdata_user` = ?',
153             array($this->username)
154         )->fetchRow();
155
156         if ($row === false) {
157             //INSERT
158             $sql = 'INSERT INTO `*PREFIX*grauphel_syncdata`'
159                 . '(`syncdata_user`, `syncdata_latest_sync_revision`, `syncdata_current_sync_guid`)'
160                 . ' VALUES(?, ?, ?)';
161             $params = array(
162                 $this->username,
163                 $syncdata->latestSyncRevision,
164                 $syncdata->currentSyncGuid
165             );
166         } else {
167             //UPDATE
168             $data = array(
169                 'syncdata_latest_sync_revision' => $syncdata->latestSyncRevision,
170                 'syncdata_current_sync_guid'    => $syncdata->currentSyncGuid,
171             );
172             $sql = 'UPDATE `*PREFIX*grauphel_syncdata` SET'
173                 . ' `' . implode('` = ?, `', array_keys($data)) . '` = ?'
174                 . ' WHERE `syncdata_user` = ?';
175             $params = array_values($data);
176             $params[] = $this->username;
177         }
178         \OC_DB::executeAudited($sql, $params);
179     }
180
181     /**
182      * Load a note from the storage.
183      *
184      * @param string  $guid      Note identifier
185      * @param boolean $createNew Create a new note if it does not exist
186      *
187      * @return object Note object, NULL if !$createNew and note does not exist
188      */
189     public function load($guid, $createNew = true)
190     {
191         $row = \OC_DB::executeAudited(
192             'SELECT * FROM `*PREFIX*grauphel_notes`'
193             . ' WHERE `note_user` = ? AND `note_guid` = ?',
194             array($this->username, $guid)
195         )->fetchRow();
196
197         if ($row === false) {
198             if (!$createNew) {
199                 return null;
200             }
201             return (object) array(
202                 'guid' => $guid,
203
204                 'create-date'               => null,
205                 'last-change-date'          => null,
206                 'last-metadata-change-date' => null,
207
208                 'title'                => null,
209                 'note-content'         => null,
210                 'note-content-version' => 0.3,
211
212                 'open-on-startup' => false,
213                 'pinned'          => false,
214                 'tags'            => array(),
215             );
216         }
217         
218         return $this->noteFromRow($row);
219     }
220
221     /**
222      * Save a note into storage.
223      *
224      * @param object $note Note to save
225      *
226      * @return void
227      */
228     public function save($note)
229     {
230         $row = \OC_DB::executeAudited(
231             'SELECT * FROM `*PREFIX*grauphel_notes`'
232             . ' WHERE `note_user` = ? AND `note_guid` = ?',
233             array($this->username, $note->guid)
234         )->fetchRow();
235
236         $data = $this->rowFromNote($note);
237         if ($row === false) {
238             //INSERT
239             $data['note_user'] = $this->username;
240             $sql = 'INSERT INTO `*PREFIX*grauphel_notes`'
241                 . ' (`' . implode('`, `', array_keys($data)) . '`)'
242                 . ' VALUES(' . implode(', ', array_fill(0, count($data), '?')) . ')';
243             $params = array_values($data);
244         } else {
245             //UPDATE
246             $sql = 'UPDATE `*PREFIX*grauphel_notes` SET '
247                 . '`' . implode('` = ?, `', array_keys($data)) . '` = ?'
248                 . ' WHERE `note_user` = ? AND `note_guid` = ?';
249             $params = array_values($data);
250             $params[] = $this->username;
251             $params[] = $note->guid;
252         }
253         \OC_DB::executeAudited($sql, $params);
254     }
255
256     /**
257      * Delete a note from storage.
258      *
259      * @param object $guid ID of the note
260      *
261      * @return void
262      */
263     public function delete($guid)
264     {
265         \OC_DB::executeAudited(
266             'DELETE FROM `*PREFIX*grauphel_notes`'
267             . ' WHERE `note_user` = ? AND `note_guid` = ?',
268             array($this->username, $guid)
269         );
270     }
271
272     /**
273      * Load notes for the given user in short form.
274      * Optionally only those changed after $since revision
275      *
276      * @param integer $since Revision number after which the notes changed
277      *
278      * @return array Array of short note objects
279      */
280     public function loadNotesOverview($since = null)
281     {
282         $result = \OC_DB::executeAudited(
283             'SELECT `note_guid`, `note_title`, `note_last_sync_revision`'
284             . ' FROM `*PREFIX*grauphel_notes`'
285             . ' WHERE note_user = ?',
286             array($this->username)
287         );
288
289         $notes = array();
290         while ($row = $result->fetchRow()) {
291             if ($since !== null && $row['note_last_sync_revision'] <= $since) {
292                 continue;
293             }
294             $notes[] = array(
295                 'guid' => $row['note_guid'],
296                 'ref'  => array(
297                     'api-ref' => $this->urlGen->getAbsoluteURL(
298                         $this->urlGen->linkToRoute(
299                             'grauphel.api.note',
300                             array(
301                                 'username' => $this->username,
302                                 'guid' => $row['note_guid']
303                             )
304                         )
305                     ),
306                     'href' => null,//FIXME
307                 ),
308                 'title' => $row['note_title'],
309             );
310         }
311
312         return $notes;
313     }
314
315     /**
316      * Load notes for the given user in full form.
317      * Optionally only those changed after $since revision
318      *
319      * @param integer $since Revision number after which the notes changed
320      *
321      * @return array Array of full note objects
322      */
323     public function loadNotesFull($since = null)
324     {
325         $result = \OC_DB::executeAudited(
326             'SELECT * FROM `*PREFIX*grauphel_notes`'
327             . ' WHERE note_user = ?',
328             array($this->username)
329         );
330
331         $notes = array();
332         while ($row = $result->fetchRow()) {
333             if ($since !== null && $row['note_last_sync_revision'] <= $since) {
334                 continue;
335             }
336             $notes[] = $this->noteFromRow($row);
337         }
338
339         return $notes;
340     }
341
342     protected function noteFromRow($row)
343     {
344         return (object) array(
345             'guid'  => $row['note_guid'],
346
347             'create-date'               => $row['note_create_date'],
348             'last-change-date'          => $row['note_last_change_date'],
349             'last-metadata-change-date' => $row['note_last_metadata_change_date'],
350
351             'title'                => $row['note_title'],
352             'note-content'         => $row['note_content'],
353             'note-content-version' => $row['note_content_version'],
354
355             'open-on-startup' => (bool) $row['note_open_on_startup'],
356             'pinned'          => (bool) $row['note_pinned'],
357             'tags'            => json_decode($row['note_tags']),
358
359             'last-sync-revision' => (int) $row['note_last_sync_revision'],
360         );
361     }
362
363     protected function rowFromNote($note)
364     {
365         return array(
366             'note_guid'  => $note->guid,
367             'note_title' => $note->title,
368
369             'note_content'         => $note->{'note-content'},
370             'note_content_version' => $note->{'note-content-version'},
371
372             'note_create_date'               => $note->{'create-date'},
373             'note_last_change_date'          => $note->{'last-change-date'},
374             'note_last_metadata_change_date' => $note->{'last-metadata-change-date'},
375             
376             'note_open_on_startup' => $note->{'open-on-startup'},
377             'note_pinned'          => $note->pinned,
378             'note_tags'            => json_encode($note->tags),
379
380             'note_last_sync_revision' => $note->{'last-sync-revision'},
381         );
382     }
383 }
384 ?>