simplify SQL for authorisation
[diogenes.git] / include / diogenes.barrel.inc.php
1 <?php
2 /*
3 * Copyright (C) 2003-2005 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
22 require_once 'diogenes.page.inc.php';
23 require_once 'Barrel.php';
24 require_once 'Barrel/Menu.php';
25
26 /** This class is used to display a page of a Diogenes barrel,
27 * that is an RCS-managed website with a virtual directory
28 * structure.
29 */
30 class DiogenesBarrel extends DiogenesPage
31 {
32 // barrel definition info
33
34 /** The database table holding the menus */
35 var $table_menu;
36
37 /** The barrel's alias. */
38 var $alias;
39
40 /** The Diogenes_Barrel representing the barrel */
41 var $barrel;
42
43 // context info
44 /** A Diogenes_Barrel_Page representing the current page */
45 var $curpage;
46
47 /** Information about the current location */
48 var $pathinfo;
49
50 /** Can the current user edit this page? */
51 var $canedit = false;
52
53
54 /** Constructs a Smarty-derived object to display contents within a barrel.
55 *
56 * @param $override_pathinfo
57 */
58 function DiogenesBarrel($override_pathinfo = null)
59 {
60 global $globals;
61
62 // call parent constructor
63 $this->DiogenesPage();
64
65 // break down PATH_INFO into site and location components
66 $mypathinfo = $override_pathinfo ? $override_pathinfo : $_SERVER['PATH_INFO'];
67 $this->pathinfo = $this->parsePathInfo($mypathinfo);
68 if (!$this->pathinfo)
69 $this->kill404("Invalid location specified!");
70
71 // Retrieve site-wide info from database
72 $this->barrel = new Diogenes_Barrel($this->pathinfo['alias']);
73 if (!$this->barrel->alias)
74 $this->kill404("Unknown barrel requested : {$this->pathinfo['alias']}");
75
76 // Legacy
77 $this->alias = $this->barrel->alias;
78 $this->table_menu = $this->barrel->table_menu;
79
80 // Build page head
81 $this->makeHead();
82
83 // Check the requested page exists
84 $tdir = $this->pathinfo['dir'];
85 if ($tdir != 'admin')
86 {
87 if (!$this->pathinfo['PID'] = $this->barrel->getPID($tdir))
88 {
89 $this->kill404("Unknown location specified '$tdir'!");
90 }
91 }
92 }
93
94 /** Check the user has the right permissions.
95 * Read the user's permissions for the current site from database.
96 *
97 * @param level the required permissions level
98 */
99 function checkPerms($level) {
100 global $globals;
101
102 if ($level != "public")
103 $_SESSION['session']->doAuth($this);
104
105 $_SESSION['session']->setBarrelPerms($this->alias);
106
107 if (!$_SESSION['session']->hasPerms($level))
108 $this->kill(__("You are not authorized to view this page!"), 403);
109 }
110
111
112 /** Read the contents for the current location.
113 */
114 function doContent()
115 {
116 global $globals;
117
118 // Retrieve information specific to the current page
119
120 // enable directory index
121 $file = $this->pathinfo['file'] ? $this->pathinfo['file'] : $globals->htmlfile;
122
123 // read from Db
124 if (!$bpage = Diogenes_Barrel_Page::fromDb($this->barrel, $this->pathinfo['PID']))
125 {
126 $this->kill404("Directory not found : '{$this->pathinfo['dir']}' ({$this->pathinfo['PID']}) !");
127 }
128 $this->curpage =& $bpage;
129
130 // check the permissions for the current location
131 if (!$this->pathinfo['file'] || $bpage->props['perms'] != 'public' || isset($_REQUEST['rev'])) {
132 $this->startSession();
133
134 // handle login/logout requests
135 if (isset($_REQUEST['dologout']))
136 $this->doLogout();
137 if (isset($_REQUEST['doauth']))
138 $this->checkPerms('auth');
139
140 $this->checkPerms($bpage->props['perms']);
141
142 // can we edit this page?
143 $this->canedit = $_SESSION['session']->hasPerms($bpage->props['wperms']);
144 }
145
146 // now we can display the page
147 // check the location is valid
148 if (!$this->barrel->spool->checkPath($bpage->props['PID'],$file,false))
149 $this->kill404("Malformed location!");
150
151 // check that the page is 'live'
152 switch ($bpage->props['status']) {
153 case 0:
154 break;
155 case 1:
156 $this->assign('page_content', "<p>".__("This page is currently under construction.")."<p>");
157 $this->display('');
158 exit;
159 default:
160 $this->assign('page_content', "<p>".__("This page is currently unavailable.")."<p>");
161 $this->display('');
162 exit;
163 }
164
165 // if necessary, do a checkout
166 if (isset($_REQUEST['rev'])) {
167 $rcs = $this->getRcs();
168 $path = $rcs->checkout($bpage->props['PID'],$file,$_REQUEST['rev'],System::mktemp("-d"));
169 } else {
170 $path = $this->barrel->spool->spoolPath($bpage->props['PID'],$file);
171 }
172
173 if (!is_file($path))
174 $this->kill404("File not found : $path!");
175
176 if (!$this->pathinfo['file']) {
177 // this is a page, display it within header/footer framework
178 $this->doPage($path, $bpage);
179 } else {
180 // otherwise, we send back the raw file
181 $type = get_mime_type($path);
182 if (is_mime_multipart($type)) {
183 $boundary = get_mime_boundary($path);
184 if ($boundary) $type = "$type; boundary=\"$boundary\"";
185 }
186 header("Content-Type:$type");
187 header("Content-Length:".filesize($path));
188 header("Last-modified:".gmdate("D, d M Y H:i:s T", filemtime($path)));
189 readfile($path);
190 }
191
192 }
193
194
195 /** Display a page within the header/footer framework.
196 *
197 * @param path the path of the file
198 * @param bpage a Diogenes_Barrel_Page representing the current page
199 */
200 function doPage($path, $bpage)
201 {
202 global $globals;
203
204 $this->assign('page',stripslashes($bpage->props['title']));
205
206 // load plugins
207 $this->barrel->readPlugins();
208 $active_plugins = $this->barrel->loadPlugins($bpage);
209
210 // search for rendering pluging
211 $render_plugin = '';
212 foreach ($active_plugins as $plugname => $plugobj) {
213 if (is_object($plugobj) && ($plugobj->type == "render")) {
214 $render_plugin = $plugobj;
215 }
216 }
217
218 // source page or pass it to a rendering plugin
219 if (is_object($render_plugin)) {
220 $content = $render_plugin->render($path);
221 } else {
222 $content = file_get_contents($path);
223 }
224
225 // apply plugin filtering
226 foreach ($active_plugins as $plugname => $plugobj) {
227 if (is_object($plugobj) && ($plugobj->type == "filter")) {
228 $content = $plugobj->filter($content);
229 }
230 }
231 $this->assign('page_content', $content);
232
233 parent::display('', $this->getTemplate($bpage->props['template']));
234 }
235
236
237 /** Return an RCS handle. */
238 function getRcs()
239 {
240 global $globals;
241 return new $globals->rcs($this,$this->alias,$_SESSION['session']->username);
242 }
243
244
245 /** Returns the master template for the current context.
246 *
247 * @param template
248 */
249 function getTemplate($template = '')
250 {
251 if ($template)
252 {
253 // we have a page-specific template, get its full path
254 $tpl = $this->templatePath($template);
255 } else if ($this->barrel->options->template) {
256 // we have default site template, get is full path
257 $tpl = $this->templatePath($this->barrel->options->template);
258 } else {
259 // fall back on the system-wide default template
260 $tpl = parent::getTemplate();
261 }
262 return $tpl;
263 }
264
265
266 /** Returns the available master templates. */
267 function getTemplates()
268 {
269 // the system-wide templates
270 $templates = parent::getTemplates();
271 $bbarrel =& $this->barrel;
272
273 // lookup templates in the template directory
274 if ($bbarrel->hasFlag('tpl') && $bbarrel->options->template_dir) {
275 $dir = $bbarrel->spool->spoolPath($bbarrel->options->template_dir);
276 $files = System::find($dir.' -maxdepth 1 -name *.tpl');
277 foreach ($files as $file)
278 $templates["barrel:".basename($file)] = "[barrel] ".basename($file);
279 }
280 return $templates;
281 }
282
283
284 /** Is the user an administrator for the current barrel ? */
285 function isAdmin() {
286 return isset($_SESSION['session']) && $_SESSION['session']->hasPerms('admin');
287 }
288
289
290 /** Build the page's "head" tag.
291 */
292 function makeHead() {
293 global $globals;
294 $bbarrel =& $this->barrel;
295
296 // site name
297 $this->assign('site', stripslashes($bbarrel->options->title));
298
299 // meta
300 array_push($this->head, '<meta name="description" content="'.stripslashes($bbarrel->options->description).'" />');
301 array_push($this->head, '<meta name="keywords" content="'.stripslashes($bbarrel->options->keywords).'" />');
302
303 // stylesheets
304 $this->sheets = array();
305 array_push($this->sheets, $this->url("common.css"));
306 if ($bbarrel->options->menu_style == 1 || $bbarrel->options->menu_style == 2)
307 array_push($this->sheets, $this->url("phplayersmenu/{$bbarrel->options->menu_theme}/style.css"));
308 array_push($this->sheets, $this->urlSite("", $globals->cssfile));
309
310 // add stylesheets to head
311 foreach ($this->sheets as $mysheet) {
312 array_push($this->head, '<link rel="stylesheet" href="'.$mysheet.'" type="text/css" />');
313 }
314 // favicon
315 if ($bbarrel->options->favicon)
316 array_push($this->head, '<link rel="icon" href="'.$this->urlSite("", $bbarrel->options->favicon).'" type="image/png" />');
317
318 // RSS feed
319 if ($bbarrel->options->feed_enable)
320 array_push($this->head, '<link rel="alternate" type="application/rss+xml" title="'.stripslashes($bbarrel->options->title).'" href="'.$this->urlSite("admin", "rss").'" />');
321 }
322
323
324 /** Build the barrel's menu.
325 */
326 function makeMenu() {
327 global $globals;
328 $bbarrel =& $this->barrel;
329
330 // menu style & theme
331 $this->assign('menustyle', $bbarrel->options->menu_style);
332 $this->assign('menutheme', $bbarrel->options->menu_theme);
333
334 $PID = $this->curpage->props['PID'];
335
336 // build the Diogenes part of the menu
337 if (!$bbarrel->options->menu_hide_diogenes) {
338 array_push($this->menu,array(0,__("Home"),$this->urlSite(""), 1));
339 if ($this->isLogged()) {
340 array_push($this->menu, array(1,__("Logout"), "?dologout=1") );
341 array_push($this->menu, array(1,__("Preferences"), $this->urlSite("admin", "prefs")));
342 } else {
343 array_push($this->menu, array(1,__("Login"), "?doauth=1") );
344 }
345
346 if ($this->isAdmin()) {
347 array_push($this->menu, array(1, __("Administration"), $this->urlSite("admin")));
348 if ($PID)
349 array_push($this->menu, array(1, __("Page properties"), $this->urlSite("admin", "pages?dir=$PID")));
350 } elseif ($this->canedit && $PID) {
351 array_push($this->menu, array(0, __("Edit this page"), "", 1));
352 array_push($this->menu, array(1, __("Raw editor"), $this->urlSite("admin", "edit?dir=$PID&amp;file={$globals->htmlfile}")));
353 array_push($this->menu, array(1, __("HTML editor"), $this->urlSite("admin" , "compose?dir=$PID&amp;file={$globals->htmlfile}")));
354 }
355 }
356
357 // if this is an error page, we need to bail out here
358 if (!isset($this->table_menu))
359 return;
360
361 // add the user-defined part of the menu
362 $bmenu = new Diogenes_Barrel_Menu($this->dbh, $this->table_menu);
363 $this->menu = array_merge($this->menu, $bmenu->makeMenu($PID, $this->barrel->options->menu_min_level, array($this, 'urlSiteByPid')));
364 }
365
366
367 /**
368 * Break down a PATH_INFO into site, page id and file
369 * Directories *must* be accessed with a final slash.
370 *
371 * @param path the path to parse
372 */
373 function parsePathInfo($path) {
374 if (empty($path) || !preg_match("/^\/([^\/]+)\/((.+)\/)?([^\/]*)$/",$path,$asplit))
375 return false;
376
377 $split['alias'] = $asplit[1];
378 $split['dir'] = isset($asplit[3]) ? $asplit[3] : "";
379 $split['file'] = isset($asplit[4]) ? $asplit[4] : "";
380 return $split;
381 }
382
383
384 /** Return the current URI.
385 */
386 function script_uri()
387 {
388 if ($this->barrel->vhost)
389 return preg_replace("/^(.*)\/site(\.php)?\/{$this->alias}\/(.*)/", "/\$3",$_SERVER['REQUEST_URI']);
390 else
391 return $_SERVER['REQUEST_URI'];
392 }
393
394
395 /** Returns the path to a given template. */
396 function templatePath($template)
397 {
398 global $globals;
399
400 $bits = split(":", $template);
401 switch ($bits[0]) {
402 case "global":
403 $path = $globals->template_dir."/". $bits[1];
404 break;
405 case "barrel":
406 $path = $this->barrel->spool->spoolPath($this->barrel->options->template_dir, $bits[1]);
407 break;
408 default:
409 $path = parent::templatePath($template);
410 }
411 return $path;
412 }
413
414
415 /** Returns the URL to one of the barrel's pages relative to
416 * the current location.
417 *
418 * @param dir
419 * @param file
420 */
421 function urlSite($dir, $file = '') {
422 global $page;
423 $tosite = strlen($this->pathinfo['dir']) ? str_repeat("../",1+substr_count($this->pathinfo['dir'],"/")) : '';
424 $url = $tosite . (strlen($dir) ? "$dir/" : "") . $file;
425 return strlen($url) ? $url : "./";
426 }
427
428
429 /** Returns the URL to one of the barrel's pages relative to
430 * the current location.
431 *
432 * @param dir
433 * @param file
434 */
435 function urlSiteByPid($PID, $file = '')
436 {
437 return $this->urlSite($this->barrel->getLocation($PID), $file);
438 }
439
440 }
441
442 ?>