Release diogenes-0.9.22
[diogenes.git] / include / Barrel.php
CommitLineData
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
21require_once 'Barrel/Page.php';
22require_once 'Barrel/Options.php';
23require_once 'diogenes/diogenes.flagset.inc.php';
24
25
26/** This class describes a Diogenes Barrel.
27 */
28class 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}