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); | |
90 | $this->spool = new DiogenesSpool($this,$this->alias); | |
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 | |
280 | */ | |
281 | function makePath($path, &$caller) | |
282 | { | |
283 | $pathbits = split("/", $path); | |
284 | $curpath = ''; | |
285 | $curpid = $this->getPID($curpath);; | |
286 | foreach ($pathbits as $pathbit) | |
287 | { | |
288 | $newpath = ($curpath ? "$curpath/" : "") . $pathbit; | |
289 | $newpid = $this->getPID($newpath); | |
290 | if (!$newpid) | |
291 | { | |
292 | $tpage = new Diogenes_Barrel_Page($this, array('parent' => $curpid, 'location' => $pathbit)); | |
293 | $tpage->toDb(0, $caller); | |
294 | $newpid = $this->getPID($newpath); | |
295 | } | |
296 | $curpath = $newpath; | |
297 | $curpid = $newpid; | |
298 | } | |
299 | return $curpid; | |
300 | } | |
301 | ||
302 | ||
6855525e JL |
303 | /** Compile the directory tree |
304 | */ | |
305 | function compileTree() | |
306 | { | |
307 | global $globals; | |
308 | ||
309 | if (!$fp = fopen($this->treeCacheFile, "w")) { | |
310 | trigger_error("failed to open '{$this->treeCacheFile}' for writing", E_USER_ERROR); | |
311 | return; | |
312 | } | |
313 | ||
314 | // load all the pages | |
315 | $res = $globals->db->query("select * from {$this->table_page}"); | |
316 | $tpages = array(); | |
317 | while ($props = mysql_fetch_assoc($res)) | |
318 | { | |
319 | $tpage = new Diogenes_Barrel_Page($this, $props); | |
320 | $tpages[$props['PID']] = $tpage; | |
321 | if (!strlen($props['location'])) | |
322 | { | |
323 | $homepage = $props['PID']; | |
324 | } | |
325 | } | |
326 | ||
327 | // recursively build the tree, starting at the homepage | |
328 | $str = $this->compilePageTree($tpages, $homepage, ''); | |
329 | fputs($fp, $str); | |
330 | fclose($fp); | |
331 | } | |
332 | ||
333 | ||
334 | /** Compile a single page | |
335 | */ | |
336 | function compilePageTree(&$tpages, $PID, $ploc) | |
337 | { | |
338 | global $globals; | |
339 | ||
340 | $cpage = $tpages[$PID]; | |
341 | $ploc = ($ploc ? "$ploc/" : "") . $cpage->props['location']; | |
342 | ||
343 | // add this page | |
344 | $out = "$ploc\t$PID\t".$cpage->props['parent']."\n"; | |
345 | ||
346 | // add children | |
347 | $res = $globals->db->query("select PID from {$this->table_page} where parent='$PID'"); | |
348 | while (list($child) = mysql_fetch_row($res)) | |
349 | { | |
350 | $out .= $this->compilePageTree($tpages, $child, $ploc); | |
351 | } | |
352 | mysql_free_result($res); | |
353 | return $out; | |
354 | } | |
355 | ||
356 | ||
357 | /** Load all plugins for the specified page. | |
358 | * | |
359 | * @param $bpage | |
360 | */ | |
361 | function loadPlugins(&$bpage) | |
362 | { | |
363 | global $globals; | |
364 | ||
365 | $plugins = $this->getPlugins($bpage->props['PID']); | |
366 | ||
367 | $loaded = array(); | |
368 | foreach ($plugins as $plugentry) | |
369 | { | |
370 | $loaded[$plugentry['plugin']] =& $globals->plugins->load($plugentry); | |
371 | } | |
372 | return $loaded; | |
373 | } | |
374 | ||
375 | ||
376 | /** Read the compiled plugin cache | |
377 | */ | |
378 | function readPlugins() | |
379 | { | |
380 | global $globals; | |
381 | ||
382 | $this->pluginsCache = $globals->plugins->readCache($this->pluginsCacheFile, $this->alias); | |
383 | } | |
384 | ||
385 | ||
386 | /** Read the compiled directory tree | |
387 | */ | |
388 | function readTree() | |
389 | { | |
390 | global $globals; | |
391 | ||
392 | // if the tree cache does not exits, try to init it | |
393 | if (!file_exists($this->treeCacheFile)) { | |
394 | $this->compileTree(); | |
395 | } | |
396 | ||
397 | if (!$fp = fopen($this->treeCacheFile, "r")) { | |
398 | trigger_error("failed to open '{$this->treeCacheFile}' for reading", E_USER_ERROR); | |
399 | return; | |
400 | } | |
401 | ||
402 | $locations = array(); | |
403 | while ($line = fgets($fp)) | |
404 | { | |
405 | $line = substr($line, 0, -1); | |
406 | $bits = explode("\t", $line); | |
407 | list($loc, $pid, $parent) = $bits; | |
408 | $locations[$loc] = $pid; | |
409 | } | |
410 | fclose($fp); | |
411 | ||
412 | $this->treeCache = $locations; | |
413 | } | |
414 | ||
415 | } |