Commit | Line | Data |
---|---|---|
6855525e JL |
1 | <?php |
2 | /* | |
3 | * Copyright (C) 2003-2004 Polytechnique.org | |
4 | * http://opensource.polytechnique.org/ | |
5 | * | |
6 | * This program is free software; you can redistribute it and/or modify | |
7 | * it under the terms of the GNU General Public License as published by | |
8 | * the Free Software Foundation; either version 2 of the License, or | |
9 | * (at your option) any later version. | |
10 | * | |
11 | * This program is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | * GNU General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU General Public License | |
17 | * along with this program; if not, write to the Free Software | |
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
19 | */ | |
20 | ||
21 | require_once 'Barrel/Page.php'; | |
22 | require_once 'Barrel/Options.php'; | |
23 | require_once 'diogenes/diogenes.flagset.inc.php'; | |
24 | ||
25 | ||
26 | /** This class describes a Diogenes Barrel. | |
27 | */ | |
28 | class Diogenes_Barrel | |
29 | { | |
30 | /** The barrel's alias. */ | |
31 | var $alias; | |
32 | ||
33 | /** The database table holding the menus */ | |
34 | var $table_menu; | |
35 | ||
36 | /** The database table holding the pages */ | |
37 | var $table_page; | |
38 | ||
39 | /** The site's flags. */ | |
40 | var $flags; | |
41 | ||
42 | /** The site's options. */ | |
43 | var $options; | |
44 | ||
45 | /** Cache of the homepage ID */ | |
46 | var $homepage; | |
47 | ||
48 | /** Handle to the spool */ | |
49 | var $spool; | |
50 | ||
51 | /** If the barrel is running on a virtualhost. */ | |
52 | var $vhost; | |
53 | ||
54 | /** Cache of tree */ | |
55 | var $treeCache; | |
56 | ||
57 | /** File containing the tree cache. */ | |
58 | var $treeCacheFile; | |
59 | ||
60 | /** Cache of the plugins */ | |
61 | var $pluginsCache; | |
62 | ||
63 | /** File containing the plugin cache. */ | |
64 | var $pluginsCacheFile; | |
65 | ||
66 | ||
67 | /** Construct a Diogenes Barrel. | |
68 | * | |
69 | * @param $alias | |
70 | */ | |
71 | function Diogenes_Barrel($alias) | |
72 | { | |
73 | global $globals; | |
74 | $webdav = ''; | |
75 | ||
76 | // Retrieve site-wide info from database | |
77 | $res = $globals->db->query("select alias,vhost,flags from diogenes_site where alias='$alias'"); | |
78 | if (!list($this->alias,$this->vhost,$flags) = mysql_fetch_row($res)) { | |
79 | return; | |
80 | } | |
81 | mysql_free_result($res); | |
82 | ||
83 | $this->table_menu = "{$this->alias}_menu"; | |
84 | $this->table_page = "{$this->alias}_page"; | |
85 | $this->treeCacheFile = $globals->spoolroot."/diogenes_c/". $this->alias.".tree"; | |
86 | $this->pluginsCacheFile = $globals->plugins->cacheFile($this->alias); | |
87 | ||
88 | $this->flags = new flagset($flags); | |
89 | $this->options = new Diogenes_Barrel_Options($this->alias); | |
cb8988c6 | 90 | $this->spool = new Diogenes_VCS_Spool($this,$this->alias); |
6855525e JL |
91 | |
92 | $this->readTree(); | |
93 | } | |
94 | ||
95 | ||
96 | /** Create a new Diogenes barrel. This creates the database, RCS and | |
97 | * spool entries for the new barrel. | |
98 | * | |
99 | * @param $alias | |
100 | * @param $caller | |
101 | */ | |
102 | function create($alias, &$caller) | |
103 | { | |
104 | global $globals; | |
105 | ||
106 | /* sanity check */ | |
107 | if (!preg_match("/^[a-zA-Z0-9_]+$/",$alias) or | |
108 | in_array($alias, $globals->invalidaliases)) | |
109 | { | |
110 | $caller->info("Invalid barrel name!"); | |
111 | return; | |
112 | } | |
113 | ||
114 | $res = $globals->db->query("select alias from diogenes_site where alias='$alias'"); | |
115 | if (mysql_num_rows($res) > 0) { | |
116 | $caller->info("Entry '{$alias}' already exists in table 'diogenes_site'!"); | |
117 | return; | |
118 | } | |
119 | ||
120 | if (file_exists("{$globals->rcsroot}/$alias")) { | |
121 | $caller->info("Directory '{$globals->rcsroot}/$alias' already exists!"); | |
122 | return; | |
123 | } | |
124 | ||
125 | if (!is_dir($globals->rcsroot) || !is_writable($globals->rcsroot)) { | |
126 | $caller->info("Directory '{$globals->rcsroot}' is not writable!"); | |
127 | return; | |
128 | } | |
129 | ||
130 | /* log this event */ | |
131 | $caller->log("barrel_create","$alias:*"); | |
132 | ||
133 | /* create DB entry */ | |
134 | $globals->db->query("insert into diogenes_site set alias='$alias'"); | |
135 | ||
136 | $globals->db->query("CREATE TABLE {$alias}_menu (" | |
137 | . "MID int(10) unsigned NOT NULL auto_increment," | |
138 | . "MIDpere int(10) unsigned NOT NULL," | |
139 | . "ordre int(10) unsigned NOT NULL," | |
140 | . "title tinytext NOT NULL," | |
141 | . "link text NOT NULL," | |
142 | . "PID int(10) unsigned NOT NULL," | |
143 | . "PRIMARY KEY (MID)" | |
144 | . ") TYPE=MyISAM;"); | |
145 | ||
146 | $globals->db->query("CREATE TABLE {$alias}_page (" | |
147 | . "PID int(10) unsigned NOT NULL auto_increment," | |
148 | . "parent INT( 10 ) UNSIGNED NOT NULL default '0'," | |
149 | . "location tinytext NOT NULL," | |
150 | . "title tinytext NOT NULL," | |
151 | . "status tinyint(1) unsigned NOT NULL default '0'," | |
152 | . "perms enum('public','auth','user','admin','forbidden') NOT NULL default 'public'," | |
153 | . "wperms enum('public','auth','user','admin','forbidden') NOT NULL default 'admin'," | |
154 | . "template varchar(255) NOT NULL," | |
155 | . "PRIMARY KEY (PID)" | |
156 | . ") TYPE=MyISAM;"); | |
157 | ||
158 | /* set the barrel's title */ | |
159 | $opt = new Diogenes_Barrel_Options($alias); | |
160 | $opt->updateOption('title',$alias); | |
161 | ||
162 | /* create entry for the homepage */ | |
163 | $globals->db->query("insert into {$alias}_page set location='temp'"); | |
164 | $homepage = mysql_insert_id(); | |
165 | $globals->db->query("update {$alias}_page set location='',title='Home',perms='public' where PID='$homepage'"); | |
166 | ||
aa2b3c61 | 167 | /* create home page */ |
6855525e JL |
168 | $rcs = new $globals->rcs($caller,$alias,$_SESSION['session']->username,true); |
169 | $rcs->newdir("",$homepage); | |
170 | $rcs->commit($homepage,$globals->htmlfile,""); | |
aa2b3c61 JL |
171 | |
172 | /* copy CSS template */ | |
173 | $def_css = file_get_contents("{$globals->root}/styles/{$globals->barrel_style_sheet}.css"); | |
174 | $rcs->commit($homepage,$globals->cssfile, $def_css); | |
6855525e JL |
175 | } |
176 | ||
177 | ||
178 | /** Destroy a Diogenes barrel. This removes the related database, RCS | |
179 | * and spool entries. | |
180 | * | |
181 | * @param $alias | |
182 | * @param $caller | |
183 | */ | |
184 | function destroy($alias, &$caller) { | |
185 | global $globals; | |
186 | ||
187 | /** Sanity check */ | |
188 | if (!$alias) { | |
189 | $caller->info("Empty alias supplied!"); | |
190 | return; | |
191 | } | |
192 | ||
193 | /* log this event */ | |
194 | $caller->log("barrel_delete","$alias:*"); | |
195 | ||
196 | system(escapeshellcmd("rm -rf ".escapeshellarg("{$globals->spoolroot}/$alias"))); | |
197 | system(escapeshellcmd("rm -rf ".escapeshellarg("{$globals->rcsroot}/$alias"))); | |
198 | system(escapeshellcmd("rm -f ".escapeshellarg("{$globals->spoolroot}/diogenes_c/$alias.tree"))); | |
199 | system(escapeshellcmd("rm -f ".escapeshellarg($globals->plugins->cacheFile($alias)))); | |
200 | $globals->db->query("drop table {$alias}_menu"); | |
201 | $globals->db->query("drop table {$alias}_page"); | |
202 | $globals->db->query("delete from diogenes_perm where alias='$alias'"); | |
203 | $globals->db->query("delete from diogenes_site where alias='$alias'"); | |
204 | $globals->db->query("delete from diogenes_option where barrel='$alias'"); | |
205 | $globals->db->query("delete from diogenes_plugin where barrel='$alias'"); | |
206 | } | |
207 | ||
208 | ||
209 | /** Return the location corresponding to a given page ID | |
210 | * | |
211 | * @param $PID | |
212 | */ | |
213 | function getLocation($PID) | |
214 | { | |
215 | return array_search($PID, $this->treeCache); | |
216 | } | |
217 | ||
218 | ||
219 | ||
220 | /** Return all the barrel's pages. | |
221 | */ | |
222 | function getPages() | |
223 | { | |
224 | global $globals; | |
225 | $bpages = array(); | |
226 | ||
227 | $res = $globals->db->query("select * from {$this->table_page}"); | |
228 | while ($props = mysql_fetch_assoc($res)) { | |
229 | $bpages[$props['PID']] = new Diogenes_Barrel_Page($this, $props); | |
230 | } | |
231 | mysql_free_result($res); | |
232 | return $bpages; | |
233 | } | |
234 | ||
235 | ||
236 | /** Return the page ID matching a given directory location | |
237 | * | |
238 | * @param $dir | |
239 | */ | |
240 | function getPID($dir) | |
241 | { | |
242 | if (isset($this->treeCache[$dir])) | |
243 | return $this->treeCache[$dir]; | |
244 | else | |
245 | return; | |
246 | } | |
247 | ||
248 | ||
249 | /** List the plugins that are active in a given context | |
250 | * | |
251 | * @param $page | |
252 | */ | |
253 | function getPlugins($page = 0) | |
254 | { | |
255 | $plugins = array(); | |
256 | foreach ($this->pluginsCache as $plug) | |
257 | { | |
258 | if ($plug['page'] == $page) | |
259 | { | |
260 | array_push($plugins, $plug); | |
261 | } | |
262 | } | |
263 | return $plugins; | |
264 | } | |
265 | ||
266 | ||
267 | /** Check whether the barrel has a given flag | |
268 | * | |
269 | * @param $flag | |
270 | */ | |
271 | function hasFlag($flag) | |
272 | { | |
273 | return $this->flags->hasFlag($flag); | |
274 | } | |
275 | ||
fcc3110e JL |
276 | |
277 | /** Create a page with the given path, and return its PID. | |
278 | * | |
279 | * @param $path | |
a511b644 | 280 | * @param $caller |
fcc3110e JL |
281 | */ |
282 | function makePath($path, &$caller) | |
283 | { | |
284 | $pathbits = split("/", $path); | |
285 | $curpath = ''; | |
286 | $curpid = $this->getPID($curpath);; | |
287 | foreach ($pathbits as $pathbit) | |
288 | { | |
289 | $newpath = ($curpath ? "$curpath/" : "") . $pathbit; | |
290 | $newpid = $this->getPID($newpath); | |
291 | if (!$newpid) | |
292 | { | |
293 | $tpage = new Diogenes_Barrel_Page($this, array('parent' => $curpid, 'location' => $pathbit)); | |
294 | $tpage->toDb(0, $caller); | |
295 | $newpid = $this->getPID($newpath); | |
296 | } | |
297 | $curpath = $newpath; | |
298 | $curpid = $newpid; | |
299 | } | |
300 | return $curpid; | |
301 | } | |
302 | ||
303 | ||
a511b644 JL |
304 | /** Recursively delete a given path. |
305 | * | |
306 | * @param $path | |
307 | * @param $caller | |
308 | */ | |
309 | function rmPath($path, &$caller) | |
310 | { | |
311 | global $globals; | |
312 | ||
d0b659f7 JL |
313 | if (!$path) { |
314 | $caller->info("rmPath: will not delete from root!"); | |
315 | return false; | |
316 | } | |
a511b644 JL |
317 | $curpid = $this->getPID($path); |
318 | if (!$curpid) { | |
319 | $caller->info("rmPath: could not find '$path'"); | |
320 | return false; | |
321 | } | |
322 | ||
323 | // lookup children | |
324 | $res = $globals->db->query("select PID from {$this->table_page} where parent=$curpid"); | |
325 | $children = array(); | |
326 | while (list($child) = mysql_fetch_row($res)) | |
327 | array_push($children, $child); | |
328 | mysql_free_result($res); | |
329 | ||
330 | // recurse into children | |
331 | foreach ($children as $child) | |
332 | { | |
333 | $childpath = $this->getLocation($child); | |
334 | if ($childpath) { | |
335 | if (!$this->rmPath($childpath, $caller)) | |
336 | return false; | |
337 | } | |
338 | } | |
339 | ||
340 | // delete this page | |
341 | return Diogenes_Barrel_Page::delete($this, $curpid, $caller); | |
342 | } | |
343 | ||
6855525e JL |
344 | /** Compile the directory tree |
345 | */ | |
346 | function compileTree() | |
347 | { | |
348 | global $globals; | |
349 | ||
350 | if (!$fp = fopen($this->treeCacheFile, "w")) { | |
351 | trigger_error("failed to open '{$this->treeCacheFile}' for writing", E_USER_ERROR); | |
352 | return; | |
353 | } | |
354 | ||
355 | // load all the pages | |
356 | $res = $globals->db->query("select * from {$this->table_page}"); | |
357 | $tpages = array(); | |
358 | while ($props = mysql_fetch_assoc($res)) | |
359 | { | |
360 | $tpage = new Diogenes_Barrel_Page($this, $props); | |
361 | $tpages[$props['PID']] = $tpage; | |
362 | if (!strlen($props['location'])) | |
363 | { | |
364 | $homepage = $props['PID']; | |
365 | } | |
366 | } | |
367 | ||
368 | // recursively build the tree, starting at the homepage | |
369 | $str = $this->compilePageTree($tpages, $homepage, ''); | |
370 | fputs($fp, $str); | |
371 | fclose($fp); | |
372 | } | |
373 | ||
374 | ||
375 | /** Compile a single page | |
376 | */ | |
377 | function compilePageTree(&$tpages, $PID, $ploc) | |
378 | { | |
379 | global $globals; | |
380 | ||
381 | $cpage = $tpages[$PID]; | |
382 | $ploc = ($ploc ? "$ploc/" : "") . $cpage->props['location']; | |
383 | ||
384 | // add this page | |
385 | $out = "$ploc\t$PID\t".$cpage->props['parent']."\n"; | |
386 | ||
387 | // add children | |
388 | $res = $globals->db->query("select PID from {$this->table_page} where parent='$PID'"); | |
389 | while (list($child) = mysql_fetch_row($res)) | |
390 | { | |
391 | $out .= $this->compilePageTree($tpages, $child, $ploc); | |
392 | } | |
393 | mysql_free_result($res); | |
394 | return $out; | |
395 | } | |
396 | ||
397 | ||
398 | /** Load all plugins for the specified page. | |
399 | * | |
400 | * @param $bpage | |
401 | */ | |
402 | function loadPlugins(&$bpage) | |
403 | { | |
404 | global $globals; | |
405 | ||
406 | $plugins = $this->getPlugins($bpage->props['PID']); | |
407 | ||
408 | $loaded = array(); | |
409 | foreach ($plugins as $plugentry) | |
410 | { | |
411 | $loaded[$plugentry['plugin']] =& $globals->plugins->load($plugentry); | |
412 | } | |
413 | return $loaded; | |
414 | } | |
415 | ||
416 | ||
417 | /** Read the compiled plugin cache | |
418 | */ | |
419 | function readPlugins() | |
420 | { | |
421 | global $globals; | |
422 | ||
423 | $this->pluginsCache = $globals->plugins->readCache($this->pluginsCacheFile, $this->alias); | |
424 | } | |
425 | ||
426 | ||
427 | /** Read the compiled directory tree | |
428 | */ | |
429 | function readTree() | |
430 | { | |
431 | global $globals; | |
432 | ||
433 | // if the tree cache does not exits, try to init it | |
434 | if (!file_exists($this->treeCacheFile)) { | |
435 | $this->compileTree(); | |
436 | } | |
437 | ||
438 | if (!$fp = fopen($this->treeCacheFile, "r")) { | |
439 | trigger_error("failed to open '{$this->treeCacheFile}' for reading", E_USER_ERROR); | |
440 | return; | |
441 | } | |
442 | ||
443 | $locations = array(); | |
444 | while ($line = fgets($fp)) | |
445 | { | |
446 | $line = substr($line, 0, -1); | |
447 | $bits = explode("\t", $line); | |
448 | list($loc, $pid, $parent) = $bits; | |
449 | $locations[$loc] = $pid; | |
450 | } | |
451 | fclose($fp); | |
452 | ||
453 | $this->treeCache = $locations; | |
454 | } | |
455 | ||
456 | } |