diff options
author | ArthurHoaro <arthur@hoa.ro> | 2017-01-16 12:31:08 +0100 |
---|---|---|
committer | ArthurHoaro <arthur@hoa.ro> | 2017-03-21 20:29:20 +0100 |
commit | 4306b184c4471825f916d895b047ed03fdf58985 (patch) | |
tree | ae4ffd760d74e58bf469f743076aecf838f634f2 /application | |
parent | b2306b0c783365e3f8110ae25bc93f2630b8b2c8 (diff) | |
download | Shaarli-4306b184c4471825f916d895b047ed03fdf58985.tar.gz Shaarli-4306b184c4471825f916d895b047ed03fdf58985.tar.zst Shaarli-4306b184c4471825f916d895b047ed03fdf58985.zip |
History mechanism
Use case: rest API service
* saved by default in data/history
* same format as datastore.php
* traced events:
* save/edit/delete link
* change settings or plugins settings
* rename tag
Diffstat (limited to 'application')
-rw-r--r-- | application/History.php | 183 | ||||
-rw-r--r-- | application/NetscapeBookmarkUtils.php | 5 | ||||
-rw-r--r-- | application/config/ConfigManager.php | 1 |
3 files changed, 188 insertions, 1 deletions
diff --git a/application/History.php b/application/History.php new file mode 100644 index 00000000..c06067df --- /dev/null +++ b/application/History.php | |||
@@ -0,0 +1,183 @@ | |||
1 | <?php | ||
2 | |||
3 | /** | ||
4 | * Class History | ||
5 | * | ||
6 | * Handle the history file tracing events in Shaarli. | ||
7 | * The history is stored as JSON in a file set by 'resource.history' setting. | ||
8 | * | ||
9 | * Available data: | ||
10 | * - event: event key | ||
11 | * - datetime: event date, in ISO8601 format. | ||
12 | * - id: event item identifier (currently only link IDs). | ||
13 | * | ||
14 | * Available event keys: | ||
15 | * - CREATED: new link | ||
16 | * - UPDATED: link updated | ||
17 | * - DELETED: link deleted | ||
18 | * - SETTINGS: the settings have been updated through the UI. | ||
19 | * | ||
20 | * Note: new events are put at the beginning of the file and history array. | ||
21 | */ | ||
22 | class History | ||
23 | { | ||
24 | /** | ||
25 | * @var string Action key: a new link has been created. | ||
26 | */ | ||
27 | const CREATED = 'CREATED'; | ||
28 | |||
29 | /** | ||
30 | * @var string Action key: a link has been updated. | ||
31 | */ | ||
32 | const UPDATED = 'UPDATED'; | ||
33 | |||
34 | /** | ||
35 | * @var string Action key: a link has been deleted. | ||
36 | */ | ||
37 | const DELETED = 'DELETED'; | ||
38 | |||
39 | /** | ||
40 | * @var string Action key: settings have been updated. | ||
41 | */ | ||
42 | const SETTINGS = 'SETTINGS'; | ||
43 | |||
44 | /** | ||
45 | * @var string History file path. | ||
46 | */ | ||
47 | protected $historyFilePath; | ||
48 | |||
49 | /** | ||
50 | * @var array History data. | ||
51 | */ | ||
52 | protected $history; | ||
53 | |||
54 | /** | ||
55 | * @var int History retention time in seconds (1 month). | ||
56 | */ | ||
57 | protected $retentionTime = 2678400; | ||
58 | |||
59 | /** | ||
60 | * History constructor. | ||
61 | * | ||
62 | * @param string $historyFilePath History file path. | ||
63 | * @param int $retentionTime History content rentention time in seconds. | ||
64 | * | ||
65 | * @throws Exception if something goes wrong. | ||
66 | */ | ||
67 | public function __construct($historyFilePath, $retentionTime = null) | ||
68 | { | ||
69 | $this->historyFilePath = $historyFilePath; | ||
70 | if ($retentionTime !== null) { | ||
71 | $this->retentionTime = $retentionTime; | ||
72 | } | ||
73 | $this->check(); | ||
74 | $this->read(); | ||
75 | } | ||
76 | |||
77 | /** | ||
78 | * Add Event: new link. | ||
79 | * | ||
80 | * @param array $link Link data. | ||
81 | */ | ||
82 | public function addLink($link) | ||
83 | { | ||
84 | $this->addEvent(self::CREATED, $link['id']); | ||
85 | } | ||
86 | |||
87 | /** | ||
88 | * Add Event: update existing link. | ||
89 | * | ||
90 | * @param array $link Link data. | ||
91 | */ | ||
92 | public function updateLink($link) | ||
93 | { | ||
94 | $this->addEvent(self::UPDATED, $link['id']); | ||
95 | } | ||
96 | |||
97 | /** | ||
98 | * Add Event: delete existing link. | ||
99 | * | ||
100 | * @param array $link Link data. | ||
101 | */ | ||
102 | public function deleteLink($link) | ||
103 | { | ||
104 | $this->addEvent(self::DELETED, $link['id']); | ||
105 | } | ||
106 | |||
107 | /** | ||
108 | * Add Event: settings updated. | ||
109 | */ | ||
110 | public function updateSettings() | ||
111 | { | ||
112 | $this->addEvent(self::SETTINGS); | ||
113 | } | ||
114 | |||
115 | /** | ||
116 | * Save a new event and write it in the history file. | ||
117 | * | ||
118 | * @param string $status Event key, should be defined as constant. | ||
119 | * @param mixed $id Event item identifier (e.g. link ID). | ||
120 | */ | ||
121 | protected function addEvent($status, $id = null) | ||
122 | { | ||
123 | $item = [ | ||
124 | 'event' => $status, | ||
125 | 'datetime' => (new DateTime())->format(DateTime::ATOM), | ||
126 | 'id' => $id !== null ? $id : '', | ||
127 | ]; | ||
128 | $this->history = array_merge([$item], $this->history); | ||
129 | $this->write(); | ||
130 | } | ||
131 | |||
132 | /** | ||
133 | * Check that the history file is writable. | ||
134 | * Create the file if it doesn't exist. | ||
135 | * | ||
136 | * @throws Exception if it isn't writable. | ||
137 | */ | ||
138 | protected function check() | ||
139 | { | ||
140 | if (! is_file($this->historyFilePath)) { | ||
141 | FileUtils::writeFlatDB($this->historyFilePath, []); | ||
142 | } | ||
143 | |||
144 | if (! is_writable($this->historyFilePath)) { | ||
145 | throw new Exception('History file isn\'t readable or writable'); | ||
146 | } | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * Read JSON history file. | ||
151 | */ | ||
152 | protected function read() | ||
153 | { | ||
154 | $this->history = FileUtils::readFlatDB($this->historyFilePath, []); | ||
155 | if ($this->history === false) { | ||
156 | throw new Exception('Could not parse history file'); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | /** | ||
161 | * Write JSON history file and delete old entries. | ||
162 | */ | ||
163 | protected function write() | ||
164 | { | ||
165 | $comparaison = new DateTime('-'. $this->retentionTime . ' seconds'); | ||
166 | foreach ($this->history as $key => $value) { | ||
167 | if (DateTime::createFromFormat(DateTime::ATOM, $value['datetime']) < $comparaison) { | ||
168 | unset($this->history[$key]); | ||
169 | } | ||
170 | } | ||
171 | FileUtils::writeFlatDB($this->historyFilePath, array_values($this->history)); | ||
172 | } | ||
173 | |||
174 | /** | ||
175 | * Get the History. | ||
176 | * | ||
177 | * @return array | ||
178 | */ | ||
179 | public function getHistory() | ||
180 | { | ||
181 | return $this->history; | ||
182 | } | ||
183 | } | ||
diff --git a/application/NetscapeBookmarkUtils.php b/application/NetscapeBookmarkUtils.php index ab346f81..bbfde138 100644 --- a/application/NetscapeBookmarkUtils.php +++ b/application/NetscapeBookmarkUtils.php | |||
@@ -95,10 +95,11 @@ class NetscapeBookmarkUtils | |||
95 | * @param array $files Server $_FILES parameters | 95 | * @param array $files Server $_FILES parameters |
96 | * @param LinkDB $linkDb Loaded LinkDB instance | 96 | * @param LinkDB $linkDb Loaded LinkDB instance |
97 | * @param ConfigManager $conf instance | 97 | * @param ConfigManager $conf instance |
98 | * @param History $history History instance | ||
98 | * | 99 | * |
99 | * @return string Summary of the bookmark import status | 100 | * @return string Summary of the bookmark import status |
100 | */ | 101 | */ |
101 | public static function import($post, $files, $linkDb, $conf) | 102 | public static function import($post, $files, $linkDb, $conf, $history) |
102 | { | 103 | { |
103 | $filename = $files['filetoupload']['name']; | 104 | $filename = $files['filetoupload']['name']; |
104 | $filesize = $files['filetoupload']['size']; | 105 | $filesize = $files['filetoupload']['size']; |
@@ -182,6 +183,7 @@ class NetscapeBookmarkUtils | |||
182 | $linkDb[$existingLink['id']] = $newLink; | 183 | $linkDb[$existingLink['id']] = $newLink; |
183 | $importCount++; | 184 | $importCount++; |
184 | $overwriteCount++; | 185 | $overwriteCount++; |
186 | $history->updateLink($newLink); | ||
185 | continue; | 187 | continue; |
186 | } | 188 | } |
187 | 189 | ||
@@ -193,6 +195,7 @@ class NetscapeBookmarkUtils | |||
193 | $newLink['shorturl'] = link_small_hash($newLink['created'], $newLink['id']); | 195 | $newLink['shorturl'] = link_small_hash($newLink['created'], $newLink['id']); |
194 | $linkDb[$newLink['id']] = $newLink; | 196 | $linkDb[$newLink['id']] = $newLink; |
195 | $importCount++; | 197 | $importCount++; |
198 | $history->addLink($newLink); | ||
196 | } | 199 | } |
197 | 200 | ||
198 | $linkDb->save($conf->get('resource.page_cache')); | 201 | $linkDb->save($conf->get('resource.page_cache')); |
diff --git a/application/config/ConfigManager.php b/application/config/ConfigManager.php index 7bfbfc72..86a917fb 100644 --- a/application/config/ConfigManager.php +++ b/application/config/ConfigManager.php | |||
@@ -301,6 +301,7 @@ class ConfigManager | |||
301 | $this->setEmpty('resource.updates', 'data/updates.txt'); | 301 | $this->setEmpty('resource.updates', 'data/updates.txt'); |
302 | $this->setEmpty('resource.log', 'data/log.txt'); | 302 | $this->setEmpty('resource.log', 'data/log.txt'); |
303 | $this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt'); | 303 | $this->setEmpty('resource.update_check', 'data/lastupdatecheck.txt'); |
304 | $this->setEmpty('resource.history', 'data/history.php'); | ||
304 | $this->setEmpty('resource.raintpl_tpl', 'tpl/'); | 305 | $this->setEmpty('resource.raintpl_tpl', 'tpl/'); |
305 | $this->setEmpty('resource.theme', 'default'); | 306 | $this->setEmpty('resource.theme', 'default'); |
306 | $this->setEmpty('resource.raintpl_tmp', 'tmp/'); | 307 | $this->setEmpty('resource.raintpl_tmp', 'tmp/'); |