Dotclear

source: inc/admin/lib.moduleslist.php @ 2216:91f485a16187

Revision 2216:91f485a16187, 27.9 KB checked in by Denis Jean-Chirstian <contact@…>, 12 years ago (diff)

Rename dcRepository to dcStore because of dotAddict used this name

Line 
1<?php
2# -- BEGIN LICENSE BLOCK ---------------------------------------
3#
4# This file is part of Dotclear 2.
5#
6# Copyright (c) 2003-2013 Olivier Meunier & Association Dotclear
7# Licensed under the GPL version 2.0 license.
8# See LICENSE file or
9# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
10#
11# -- END LICENSE BLOCK -----------------------------------------
12if (!defined('DC_ADMIN_CONTEXT')) { return; }
13
14class adminModulesList
15{
16     public $core;
17     public $modules;
18     public $store;
19
20     public static $allow_multi_install = false;
21     public static $distributed_modules = array();
22
23     protected $list_id = 'unknow';
24     protected $data = array();
25
26     protected $config_module = '';
27     protected $config_file = '';
28     protected $config_content = '';
29
30     protected $path = false;
31     protected $path_writable = false;
32     protected $path_pattern = false;
33
34     protected $page_url = 'plugins.php';
35     protected $page_qs = '?';
36     protected $page_tab = '';
37
38     public static $nav_indexes = 'abcdefghijklmnopqrstuvwxyz0123456789';
39     protected $nav_list = array();
40     protected $nav_special = 'other';
41
42     protected $sort_field = 'sname';
43     protected $sort_asc = true;
44
45     public function __construct(dcModules $modules, $modules_root, $xml_url)
46     {
47          $this->core = $modules->core;
48          $this->modules = $modules;
49          $this->store = new dcStore($modules, $xml_url);
50
51          $this->setPathInfo($modules_root);
52          $this->setNavSpecial(__('other'));
53     }
54
55     public function newList($list_id)
56     {
57          $this->data = array();
58          $this->page_tab = '';
59          $this->list_id = $list_id;
60
61          return $this;
62     }
63
64     protected function setPathInfo($root)
65     {
66          $paths = explode(PATH_SEPARATOR, $root);
67          $path = array_pop($paths);
68          unset($paths);
69
70          $this->path = $path;
71          if (is_dir($path) && is_writeable($path)) {
72               $this->path_writable = true;
73               $this->path_pattern = preg_quote($path,'!');
74          }
75
76          return $this;
77     }
78
79     public function getPath()
80     {
81          return $this->path;
82     }
83
84     public function isPathWritable()
85     {
86          return $this->path_writable;
87     }
88
89     public function isPathDeletable($root)
90     {
91          return $this->path_writable 
92               && preg_match('!^'.$this->path_pattern.'!', $root) 
93               && $this->core->auth->isSuperAdmin();
94     }
95
96     public function setPageURL($url)
97     {
98          $this->page_qs = strpos('?', $url) ? '&' : '?';
99          $this->page_url = $url;
100
101          return $this;
102     }
103
104     public function getPageURL($queries='', $with_tab=true)
105     {
106          return $this->page_url.
107               (!empty($queries) ? $this->page_qs : '').
108               (is_array($queries) ? http_build_query($queries) : $queries).
109               ($with_tab && !empty($this->page_tab) ? '#'.$this->page_tab : '');
110     }
111
112     public function setPageTab($tab)
113     {
114          $this->page_tab = $tab;
115
116          return $this;
117     }
118
119     public function getPageTab()
120     {
121          return $this->page_tab;
122     }
123
124     public function getSearchQuery()
125     {
126          $query = !empty($_REQUEST['m_search']) ? trim($_REQUEST['m_search']) : null;
127          return strlen($query) > 1 ? $query : null;
128     }
129
130     public function displaySearchForm()
131     {
132          $query = $this->getSearchQuery();
133
134          if (empty($this->data) && $query === null) {
135               return $this;
136          }
137
138          echo 
139          '<form action="'.$this->getPageURL().'" method="get" class="fieldset">'.
140          '<p><label for="m_search" class="classic">'.__('Search in repository:').'&nbsp;</label><br />'.
141          form::field(array('m_search','m_search'), 30, 255, html::escapeHTML($query)).
142          '<input type="submit" value="'.__('Search').'" /> ';
143          if ($query) { echo ' <a href="'.$this->getPageURL().'" class="button">'.__('Reset search').'</a>'; }
144          echo '</p>'.
145          '</form>';
146
147          if ($query) {
148               echo 
149               '<p class="message">'.sprintf(
150                    __('Found %d result for search "%s":', 'Found %d results for search "%s":', count($this->data)), 
151                    count($this->data), html::escapeHTML($query)
152                    ).
153               '</p>';
154          }
155          return $this;
156     }
157
158     public function setNavSpecial($str)
159     {
160          $this->nav_special = (string) $str;
161          $this->nav_list = array_merge(str_split(self::$nav_indexes), array($this->nav_special));
162
163          return $this;
164     }
165
166     public function getNavQuery()
167     {
168          return isset($_REQUEST['m_nav']) && in_array($_REQUEST['m_nav'], $this->nav_list) ? $_REQUEST['m_nav'] : $this->nav_list[0];
169     }
170
171     public function displayNavMenu()
172     {
173          if (empty($this->data) || $this->getSearchQuery() !== null) {
174               return $this;
175          }
176
177          # Fetch modules required field
178          $indexes = array();
179          foreach ($this->data as $id => $module) {
180               if (!isset($module[$this->sort_field])) {
181                    continue;
182               }
183               $char = substr($module[$this->sort_field], 0, 1);
184               if (!in_array($char, $this->nav_list)) {
185                    $char = $this->nav_special;
186               }
187               if (!isset($indexes[$char])) {
188                    $indexes[$char] = 0;
189               }
190               $indexes[$char]++;
191          }
192
193          $buttons = array();
194          foreach($this->nav_list as $char) {
195               # Selected letter
196               if ($this->getNavQuery() == $char) {
197                    $buttons[] = '<li class="active" title="'.__('current selection').'"><strong> '.$char.' </strong></li>';
198               }
199               # Letter having modules
200               elseif (!empty($indexes[$char])) {
201                    $title = sprintf(__('%d module', '%d modules', $indexes[$char]), $indexes[$char]);
202                    $buttons[] = '<li class="btn" title="'.$title.'"><a href="'.$this->getPageURL('m_nav='.$char).'" title="'.$title.'"> '.$char.' </a></li>';
203               }
204               # Letter without modules
205               else {
206                    $buttons[] = '<li class="btn no-link" title="'.__('no module').'"> '.$char.' </li>';
207               }
208          }
209          # Parse navigation menu
210          echo '<div class="pager">'.__('Browse index:').' <ul>'.implode('',$buttons).'</ul></div>';
211
212          return $this;
213     }
214
215     public function setSortField($field, $asc=true)
216     {
217          $this->sort_field = $field;
218          $this->sort_asc = (boolean) $asc;
219
220          return $this;
221     }
222
223     public function getSortQuery()
224     {
225          return !empty($_REQUEST['m_sort']) ? $_REQUEST['m_sort'] : $this->sort_field;
226     }
227
228     public function displaySortForm()
229     {
230          //not yet implemented
231     }
232
233     /** @todo Use new mesasge system **/
234     public function displayMessage($action)
235     {
236          switch($action) {
237               case 'activate': 
238                    $str = __('Module successfully activated.'); break;
239               case 'deactivate': 
240                    $str = __('Module successfully deactivated.'); break;
241               case 'delete': 
242                    $str = __('Module successfully deleted.'); break;
243               case 'install': 
244                    $str = __('Module successfully installed.'); break;
245               case 'update': 
246                    $str = __('Module successfully updated.'); break;
247               default:
248                    $str = ''; break;
249          }
250          if (!empty($str)) {
251               dcPage::success($str);
252          }
253     }
254
255     public function setModules($modules)
256     {
257          $this->data = array();
258          if (!empty($modules) && is_array($modules)) {
259               foreach($modules as $id => $module) {
260                    $this->data[$id] = self::parseModuleInfo($id, $module);
261               }
262          }
263          return $this;
264     }
265
266     public function getModules()
267     {
268          return $this->data;
269     }
270
271     public static function parseModuleInfo($id, $module)
272     {
273          $label = empty($module['label']) ? $id : $module['label'];
274          $name = __(empty($module['name']) ? $label : $module['name']);
275         
276          return array_merge(
277               # Default values
278               array(
279                    'desc'                   => '',
280                    'author'            => '',
281                    'version'                => 0,
282                    'current_version'   => 0,
283                    'root'                   => '',
284                    'root_writable'     => false,
285                    'permissions'       => null,
286                    'parent'            => null,
287                    'priority'               => 1000,
288                    'standalone_config' => false,
289                    'support'                => '',
290                    'section'                => '',
291                    'tags'                   => '',
292                    'details'                => '',
293                    'sshot'             => ''
294               ),
295               # Module's values
296               $module,
297               # Clean up values
298               array(
299                    'id'                     => $id,
300                    'sid'                    => self::sanitizeString($id),
301                    'label'             => $label,
302                    'name'                   => $name,
303                    'sname'             => self::sanitizeString($name)
304               )
305          );
306     }
307
308     public static function isDistributedModule($module)
309     {
310          $distributed_modules = self::$distributed_modules;
311
312          return is_array($distributed_modules) && in_array($module, $distributed_modules);
313     }
314
315     public static function sortModules($modules, $field, $asc=true)
316     {
317          $sorter = array();
318          foreach($modules as $id => $module) {
319               $sorter[$id] = isset($module[$field]) ? $module[$field] : $field;
320          }
321          array_multisort($sorter, $asc ? SORT_ASC : SORT_DESC, $modules);
322
323          return $modules;
324     }
325
326     public function displayModulesList($cols=array('name', 'config', 'version', 'desc'), $actions=array(), $nav_limit=false)
327     {
328          echo 
329          '<div class="table-outer">'.
330          '<table id="'.html::escapeHTML($this->list_id).'" class="modules'.(in_array('expander', $cols) ? ' expandable' : '').'">'.
331          '<caption class="hidden">'.html::escapeHTML(__('Modules list')).'</caption><tr>';
332
333          if (in_array('name', $cols)) {
334               echo 
335               '<th class="first nowrap"'.(in_array('icon', $cols) ? ' colspan="2"' : '').'>'.__('Name').'</th>';
336          }
337
338          if (in_array('version', $cols)) {
339               echo 
340               '<th class="nowrap count" scope="col">'.__('Version').'</th>';
341          }
342
343          if (in_array('current_version', $cols)) {
344               echo 
345               '<th class="nowrap count" scope="col">'.__('Current version').'</th>';
346          }
347
348          if (in_array('desc', $cols)) {
349               echo 
350               '<th class="nowrap" scope="col">'.__('Details').'</th>';
351          }
352
353          if (in_array('distrib', $cols)) {
354               echo '<th'.(in_array('desc', $cols) ? '' : ' class="maximal"').'></th>';
355          }
356
357          if (!empty($actions) && $this->core->auth->isSuperAdmin()) {
358               echo 
359               '<th class="minimal nowrap">'.__('Action').'</th>';
360          }
361
362          echo 
363          '</tr>';
364
365          $sort_field = $this->getSortQuery();
366
367          # Sort modules by $sort_field (default sname)
368          $modules = $this->getSearchQuery() === null ?
369               self::sortModules($this->data, $sort_field, $this->sort_asc) :
370               $this->data;
371
372          $count = 0;
373          foreach ($modules as $id => $module)
374          {
375               # Show only requested modules
376               if ($nav_limit && $this->getSearchQuery() === null) {
377                    $char = substr($module[$sort_field], 0, 1);
378                    if (!in_array($char, $this->nav_list)) {
379                         $char = $this->nav_special;
380                    }
381                    if ($this->getNavQuery() != $char) {
382                         continue;
383                    }
384               }
385
386               echo 
387               '<tr class="line" id="'.html::escapeHTML($this->list_id).'_m_'.html::escapeHTML($id).'">';
388
389               if (in_array('icon', $cols)) {
390                    echo 
391                    '<td class="module-icon nowrap">'.sprintf(
392                         '<img alt="%1$s" title="%1$s" src="%2$s" />', 
393                         html::escapeHTML($id), file_exists($module['root'].'/icon.png') ? 'index.php?pf='.$id.'/icon.png' : 'images/module.png'
394                    ).'</td>';
395               }
396
397               # Link to config file
398               $config = in_array('config', $cols) && !empty($module['root']) && file_exists(path::real($module['root'].'/_config.php'));
399
400               echo 
401               '<td class="module-name nowrap" scope="row">'.($config ? 
402                    '<a href="'.$this->getPageURL('module='.$id.'&conf=1').'" title"'.sprintf(__('Configure module "%s"'), html::escapeHTML($module['name'])).'">'.html::escapeHTML($module['name']).'</a>' : 
403                    html::escapeHTML($module['name'])
404               ).'</td>';
405
406               if (in_array('version', $cols)) {
407                    echo 
408                    '<td class="module-version nowrap count">'.html::escapeHTML($module['version']).'</td>';
409               }
410
411               if (in_array('current_version', $cols)) {
412                    echo 
413                    '<td class="module-current-version nowrap count">'.html::escapeHTML($module['current_version']).'</td>';
414               }
415
416               if (in_array('desc', $cols)) {
417                    echo 
418                    '<td class="module-desc maximal">'.html::escapeHTML($module['desc']).'</td>';
419               }
420
421               if (in_array('distrib', $cols)) {
422                    echo 
423                    '<td class="module-distrib">'.(self::isDistributedModule($id) ? 
424                         '<img src="images/dotclear_pw.png" alt="'.
425                         __('Module from official distribution').'" title="'.
426                         __('module from official distribution').'" />' 
427                    : '').'</td>';
428               }
429
430               if (!empty($actions) && $this->core->auth->isSuperAdmin()) {
431                    $buttons = $this->getActions($id, $module, $actions);
432
433                    echo 
434                    '<td class="module-actions nowrap">'.
435
436                    '<form action="'.$this->getPageURL().'" method="post">'.
437                    '<div>'.
438                    $this->core->formNonce().
439                    form::hidden(array('module'), html::escapeHTML($id)).
440                    form::hidden(array('tab'), $this->page_tab).
441
442                    implode(' ', $buttons).
443
444                    '</div>'.
445                    '</form>'.
446
447                    '</td>';
448               }
449
450               echo 
451               '</tr>';
452
453               $count++;
454          }
455          echo 
456          '</table></div>';
457
458          if(!$count && $this->getSearchQuery() === null) {
459               echo 
460               '<p class="message">'.__('No module matches your search.').'</p>';
461          }
462     }
463
464     protected function getActions($id, $module, $actions)
465     {
466          $submits = array();
467
468          # Use loop to keep requested order
469          foreach($actions as $action) {
470               switch($action) {
471
472                    # Deactivate
473                    case 'activate': if ($module['root_writable']) {
474                         $submits[] = 
475                         '<input type="submit" name="activate" value="'.__('Activate').'" />';
476                    } break;
477
478                    # Activate
479                    case 'deactivate': if ($module['root_writable']) {
480                         $submits[] = 
481                         '<input type="submit" name="deactivate" value="'.__('Deactivate').'" class="reset" />';
482                    } break;
483
484                    # Delete
485                    case 'delete': if ($this->isPathDeletable($module['root'])) {
486                         $submits[] = 
487                         '<input type="submit" class="delete" name="delete" value="'.__('Delete').'" />';
488                    } break;
489
490                    # Install (from store)
491                    case 'install': if ($this->path_writable) {
492                         $submits[] = 
493                         '<input type="submit" name="install" value="'.__('Install').'" />';
494                    } break;
495
496                    # Update (from store)
497                    case 'update': if ($this->path_writable) {
498                         $submits[] = 
499                         '<input type="submit" name="update" value="'.__('Update').'" />';
500                    } break;
501               }
502          }
503
504          return $submits;
505     }
506
507     public function doActions($prefix)
508     {
509          if (empty($_POST) || !empty($_REQUEST['conf']) 
510          || !$this->core->auth->isSuperAdmin() || !$this->isPathWritable()) {
511               return null;
512          }
513
514          # List actions
515          if (!empty($_POST['module'])) {
516
517               $id = $_POST['module'];
518
519               if (!empty($_POST['activate'])) {
520
521                    $enabled = $this->modules->getDisabledModules();
522                    if (!isset($enabled[$id])) {
523                         throw new Exception(__('No such module.'));
524                    }
525
526                    # --BEHAVIOR-- moduleBeforeActivate
527                    $this->core->callBehavior($prefix.'BeforeActivate', $id);
528
529                    $this->modules->activateModule($id);
530
531                    # --BEHAVIOR-- moduleAfterActivate
532                    $this->core->callBehavior($prefix.'AfterActivate', $id);
533
534                    http::redirect($this->getPageURL('msg=activate'));
535               }
536
537               elseif (!empty($_POST['deactivate'])) {
538
539                    if (!$this->modules->moduleExists($id)) {
540                         throw new Exception(__('No such module.'));
541                    }
542
543                    $module = $this->modules->getModules($id);
544                    $module['id'] = $id;
545
546                    if (!$module['root_writable']) {
547                         throw new Exception(__('You don\'t have permissions to deactivate this module.'));
548                    }
549
550                    # --BEHAVIOR-- moduleBeforeDeactivate
551                    $this->core->callBehavior($prefix.'BeforeDeactivate', $module);
552
553                    $this->modules->deactivateModule($id);
554
555                    # --BEHAVIOR-- moduleAfterDeactivate
556                    $this->core->callBehavior($prefix.'AfterDeactivate', $module);
557
558                    http::redirect($this->getPageURL('msg=deactivate'));
559               }
560
561               elseif (!empty($_POST['delete'])) {
562
563                    $disabled = $this->modules->getDisabledModules();
564                    if (!isset($disabled[$id])) {
565
566                         if (!$this->modules->moduleExists($id)) {
567                              throw new Exception(__('No such module.'));
568                         }
569
570                         $module = $this->modules->getModules($id);
571                         $module['id'] = $id;
572
573                         if (!$this->isPathDeletable($module['root'])) {
574                              throw new Exception(__("You don't have permissions to delete this module."));
575                         }
576
577                         # --BEHAVIOR-- moduleBeforeDelete
578                         $this->core->callBehavior($prefix.'BeforeDelete', $module);
579
580                         $this->modules->deleteModule($id);
581
582                         # --BEHAVIOR-- moduleAfterDelete
583                         $this->core->callBehavior($prefix.'AfterDelete', $module);
584                    }
585                    else {
586                         $this->modules->deleteModule($id, true);
587                    }
588
589                    http::redirect($this->getPageURL('msg=delete'));
590               }
591
592               elseif (!empty($_POST['install'])) {
593
594                    $updated = $this->store->get();
595                    if (!isset($updated[$id])) {
596                         throw new Exception(__('No such module.'));
597                    }
598
599                    $module = $updated[$id];
600                    $module['id'] = $id;
601
602                    $dest = $this->getPath().'/'.basename($module['file']);
603
604                    # --BEHAVIOR-- moduleBeforeAdd
605                    $this->core->callBehavior($prefix.'BeforeAdd', $module);
606
607                    $ret_code = $this->store->process($module['file'], $dest);
608
609                    # --BEHAVIOR-- moduleAfterAdd
610                    $this->core->callBehavior($prefix.'AfterAdd', $module);
611
612                    http::redirect($this->getPageURL('msg='.($ret_code == 2 ? 'update' : 'install')));
613               }
614
615               elseif (!empty($_POST['update'])) {
616
617                    $updated = $store->get();
618                    if (!isset($updated[$id])) {
619                         throw new Exception(__('No such module.'));
620                    }
621
622                    if (!$this->modules->moduleExists($id)) {
623                         throw new Exception(__('No such module.'));
624                    }
625
626                    $module = $updated[$id];
627                    $module['id'] = $id;
628               
629                    if (!self::$allow_multi_install) {
630                         $dest = $module['root'].'/../'.basename($module['file']);
631                    }
632                    else {
633                         $dest = $this->getPath().'/'.basename($module['file']);
634                         if ($module['root'] != $dest) {
635                              @file_put_contents($module['root'].'/_disabled', '');
636                         }
637                    }
638
639                    # --BEHAVIOR-- moduleBeforeUpdate
640                    $this->core->callBehavior($prefix.'BeforeUpdate', $module);
641
642                    $this->store->process($module['file'], $dest);
643
644                    # --BEHAVIOR-- moduleAfterUpdate
645                    $this->core->callBehavior($prefix.'AfterUpdate', $module);
646
647                    http::redirect($this->getPageURL('msg=upadte'));
648               }
649          }
650          # Manual actions
651          elseif (!empty($_POST['upload_pkg']) && !empty($_FILES['pkg_file']) 
652               || !empty($_POST['fetch_pkg']) && !empty($_POST['pkg_url']))
653          {
654               if (empty($_POST['your_pwd']) || !$this->core->auth->checkPassword(crypt::hmac(DC_MASTER_KEY, $_POST['your_pwd']))) {
655                    throw new Exception(__('Password verification failed'));
656               }
657
658               if (!empty($_POST['upload_pkg'])) {
659                    files::uploadStatus($_FILES['pkg_file']);
660                   
661                    $dest = $this->getPath().'/'.$_FILES['pkg_file']['name'];
662                    if (!move_uploaded_file($_FILES['pkg_file']['tmp_name'], $dest)) {
663                         throw new Exception(__('Unable to move uploaded file.'));
664                    }
665               }
666               else {
667                    $url = urldecode($_POST['pkg_url']);
668                    $dest = $this->getPath().'/'.basename($url);
669                    $this->store->download($url, $dest);
670               }
671
672               # --BEHAVIOR-- moduleBeforeAdd
673               $this->core->callBehavior($prefix.'BeforeAdd', null);
674
675               $ret_code = $this->store->install($dest);
676
677               # --BEHAVIOR-- moduleAfterAdd
678               $this->core->callBehavior($prefix.'AfterAdd', null);
679
680               http::redirect($this->getPageURL('msg='.($ret_code == 2 ? 'update' : 'install')).'#'.$prefix);
681          }
682
683          return null;
684     }
685
686     public function displayManualForm()
687     {
688          if (!$this->core->auth->isSuperAdmin() || !$this->isPathWritable()) {
689               return null;
690          }
691
692          # 'Upload module' form
693          echo
694          '<form method="post" action="'.$this->getPageURL().'" id="uploadpkg" enctype="multipart/form-data" class="fieldset">'.
695          '<h4>'.__('Upload a zip file').'</h4>'.
696          '<p class="field"><label for="pkg_file" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Zip file path:').'</label> '.
697          '<input type="file" name="pkg_file" id="pkg_file" /></p>'.
698          '<p class="field"><label for="your_pwd1" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '.
699          form::password(array('your_pwd','your_pwd1'),20,255).'</p>'.
700          '<p><input type="submit" name="upload_pkg" value="'.__('Upload').'" />'.
701          form::hidden(array('tab'), $this->getPageTab()).
702          $this->core->formNonce().'</p>'.
703          '</form>';
704         
705          # 'Fetch module' form
706          echo
707          '<form method="post" action="'.$this->getPageURL().'" id="fetchpkg" class="fieldset">'.
708          '<h4>'.__('Download a zip file').'</h4>'.
709          '<p class="field"><label for="pkg_url" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Zip file URL:').'</label> '.
710          form::field(array('pkg_url','pkg_url'),40,255).'</p>'.
711          '<p class="field"><label for="your_pwd2" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '.
712          form::password(array('your_pwd','your_pwd2'),20,255).'</p>'.
713          '<p><input type="submit" name="fetch_pkg" value="'.__('Download').'" />'.
714          form::hidden(array('tab'), $this->getPageTab()).
715          $this->core->formNonce().'</p>'.
716          '</form>';
717     }
718
719     /**
720      *
721      * We need to get configuration content in three steps
722      * and out of this class to keep backward compatibility.
723      *
724      * if ($xxx->setConfigurationFile()) {
725      *   include $xxx->getConfigurationFile();
726      * }
727      * $xxx->setConfigurationContent();
728      * ... [put here page headers and other stuff]
729      * $xxx->getConfigurationContent();
730      *
731      */
732     public function setConfigurationFile($id=null)
733     {
734          if (empty($_REQUEST['conf']) || empty($_REQUEST['module']) && !$id) {
735               return false;
736          }
737         
738          if (!empty($_REQUEST['module']) && empty($id)) {
739               $id = $_REQUEST['module'];
740          }
741
742          if (!$this->modules->moduleExists($id)) {
743               $core->error->add(__('Unknow module ID'));
744               return false;
745          }
746
747          $module = $this->modules->getModules($id);
748          $module = self::parseModuleInfo($id, $module);
749          $file = path::real($module['root'].'/_config.php');
750
751          if (!file_exists($file)) {
752               $core->error->add(__('This module has no configuration file.'));
753               return false;
754          }
755
756          $this->config_module = $module;
757          $this->config_file = $file;
758          $this->config_content = '';
759
760          if (!defined('DC_CONTEXT_MODULE')) {
761               define('DC_CONTEXT_MODULE', true);
762          }
763
764          return true;
765     }
766
767     public function getConfigurationFile()
768     {
769          if (!$this->config_file) {
770               return null;
771          }
772
773          ob_start();
774
775          return $this->config_file;
776     }
777
778     public function setConfigurationContent()
779     {
780          if ($this->config_file) {
781               $this->config_content = ob_get_contents();
782          }
783
784          ob_end_clean();
785
786          return !empty($this->file_content);
787     }
788
789     public function getConfigurationContent()
790     {
791          if (!$this->config_file) {
792               return null;
793          }
794
795          if (!$this->config_module['standalone_config']) {
796               echo
797               '<form id="module_config" action="'.$this->getPageURL('conf=1').'" method="post" enctype="multipart/form-data">'.
798               '<h3>'.sprintf(__('Configure plugin "%s"'), html::escapeHTML($this->config_module['name'])).'</h3>'.
799               '<p><a class="back" href="'.$this->getPageURL().'#plugins">'.__('Back').'</a></p>';
800          }
801
802          echo $this->config_content;
803
804          if (!$this->config_module['standalone_config']) {
805               echo
806               '<p class="clear"><input type="submit" name="save" value="'.__('Save').'" />'.
807               form::hidden('module', $this->config_module['id']).
808               $this->core->formNonce().'</p>'.
809               '</form>';
810          }
811
812          return true;
813     }
814
815     public static function sanitizeString($str)
816     {
817          return preg_replace('/[^A-Za-z0-9\@\#+_-]/', '', strtolower($str));
818     }
819}
820
821class adminThemesList extends adminModulesList
822{
823     protected $page_url = 'blog_theme.php';
824
825     public function displayModulesList($cols=array('name', 'config', 'version', 'desc'), $actions=array(), $nav_limit=false)
826     {
827          echo 
828          '<div id="'.html::escapeHTML($this->list_id).'" class="modules'.(in_array('expander', $cols) ? ' expandable' : '').' one-box">';
829
830          $sort_field = $this->getSortQuery();
831
832          # Sort modules by id
833          $modules = $this->getSearchQuery() === null ?
834               self::sortModules($this->data, $sort_field, $this->sort_asc) :
835               $this->data;
836
837          $res = '';
838          $count = 0;
839          foreach ($modules as $id => $module)
840          {
841               # Show only requested modules
842               if ($nav_limit && $this->getSearchQuery() === null) {
843                    $char = substr($module[$sort_field], 0, 1);
844                    if (!in_array($char, $this->nav_list)) {
845                         $char = $this->nav_special;
846                    }
847                    if ($this->getNavQuery() != $char) {
848                         continue;
849                    }
850               }
851
852               $current = $this->core->blog->settings->system->theme == $id;
853               $distrib = self::isDistributedModule($id) ? ' dc-box' : '';
854
855               $theme_url = preg_match('#^http(s)?://#', $this->core->blog->settings->system->themes_url) ?
856                    http::concatURL($this->core->blog->settings->system->themes_url, '/'.$id) :
857                    http::concatURL($this->core->blog->url, $this->core->blog->settings->system->themes_url.'/'.$id);
858
859               $has_conf = file_exists(path::real($this->core->blog->themes_path.'/'.$id).'/_config.php');
860               $has_css = file_exists(path::real($this->core->blog->themes_path.'/'.$id).'/style.css');
861               $parent = $module['parent'];
862               $has_parent = !empty($module['parent']);
863               if ($has_parent) {
864                    $is_parent_present = $this->modules->moduleExists($parent);
865               }
866
867               $line = 
868               '<div class="box '.($current ? 'medium current-theme' : 'small theme').$distrib.'">';
869
870               if (in_array('name', $cols)) {
871                    $line .= 
872                    '<h4 class="module-name">'.html::escapeHTML($module['name']).'</h4>';
873               }
874
875               if (in_array('sshot', $cols)) {
876                    # Screenshot from url
877                    if (preg_match('#^http(s)?://#', $module['sshot'])) {
878                         $sshot = $module['sshot'];
879                    }
880                    # Screenshot from installed module
881                    elseif (file_exists($this->core->blog->themes_path.'/'.$id.'/screenshot.jpg')) {
882                         $sshot = $this->getPageURL('shot='.rawurlencode($id));
883                    }
884                    # Default screenshot
885                    else {
886                         $sshot = 'images/noscreenshot.png';
887                    }
888
889                    $line .= 
890                    '<div class="module-sshot"><img src="'.$sshot.'" alt="'.
891                    sprintf(__('%s screenshot.'), html::escapeHTML($module['name'])).'" /></div>';
892               }
893
894               $line .= 
895               '<div class="module-infos toggle-bloc">'.
896               '<p>';
897
898               if (in_array('desc', $cols)) {
899                    $line .= 
900                    '<span class="module-desc">'.html::escapeHTML($module['desc']).'</span> ';
901               }
902
903               if (in_array('author', $cols)) {
904                    $line .= 
905                    '<span class="module-author">'.sprintf(__('by %s'),html::escapeHTML($module['author'])).'</span> ';
906               }
907
908               if (in_array('version', $cols)) {
909                    $line .= 
910                    '<span class="module-version">'.sprintf(__('version %s'),html::escapeHTML($module['version'])).'</span> ';
911               }
912
913               if (in_array('parent', $cols) && $has_parent) {
914                    if ($is_parent_present) {
915                         $line .= 
916                         '<span class="module-parent-ok">'.sprintf(__('(built on "%s")'),html::escapeHTML($parent)).'</span> ';
917                    }
918                    else {
919                         $line .= 
920                         '<span class="module-parent-missing">'.sprintf(__('(requires "%s")'),html::escapeHTML($parent)).'</span> ';
921                    }
922               }
923
924               if (in_array('version', $cols)) {
925                    $line .= 
926                    '<span class="module-version">'.sprintf(__('version %s'),html::escapeHTML($module['version'])).'</span> ';
927               }
928
929               $has_details = in_array('details', $cols) && !empty($module['details']);
930               $has_support = in_array('support', $cols) && !empty($module['support']);
931               if ($has_details || $has_support) {
932                    $line .=
933                    '<span class="mod-more">'.__('Help:').' ';
934
935                    if ($has_details) {
936                         $line .= 
937                         '<a class="module-details" href="'.$module['details'].'">'.__('Details').'</a>';
938                    }
939
940                    if ($has_support) {
941                         $line .= 
942                         ' - <a class="module-support" href="'.$module['support'].'">'.__('Support').'</a>';
943                    }
944
945                    $line .=
946                    '</span>';
947               }
948
949               $line .= 
950               '</p>'.
951               '</div>';
952
953               $line .= 
954               '<div class="module-actions toggle-bloc">';
955               
956               # _GET actions
957
958               if ($current && $has_css) {
959                    $line .= 
960                    '<p><a href="'.$theme_url.'/style.css" class="button">'.__('View stylesheet').'</a></p>';
961               }
962               if ($current && $has_conf) {
963                    $line .= 
964                    '<p><a href="'.$this->getPageURL('module='.$id.'&conf=1', false).'" class="button">'.__('Configure theme').'</a></p>';
965               }
966
967               # Plugins actions
968               if ($current) {
969                    # --BEHAVIOR-- adminCurrentThemeDetails
970                    $line .= 
971                    $this->core->callBehavior('adminCurrentThemeDetails', $this->core, $id, $module);
972               }
973
974               # _POST actions
975               if (!empty($actions)) {
976                    $line .=
977                    '<form action="'.$this->getPageURL().'" method="post">'.
978                    '<div>'.
979                    $this->core->formNonce().
980                    form::hidden(array('module'), html::escapeHTML($id)).
981                    form::hidden(array('tab'), $this->page_tab).
982
983                    implode(' ', $this->getActions($id, $module, $actions)).
984 
985                    '</div>'.
986                    '</form>';
987               }
988
989               $line .= 
990               '</div>';
991
992               $line .=
993               '</div>';
994
995               $count++;
996
997               $res = $current ? $line.$res : $res.$line;
998          }
999          echo 
1000          $res.
1001          '</div>';
1002
1003          if(!$count && $this->getSearchQuery() === null) {
1004               echo 
1005               '<p class="message">'.__('No module matches your search.').'</p>';
1006          }
1007     }
1008
1009     protected function getActions($id, $module, $actions)
1010     {
1011          $submits = array();
1012
1013          $this->core->blog->settings->addNamespace('system');
1014          if ($id != $this->core->blog->settings->system->theme) {
1015
1016               # Select theme to use on curent blog
1017               if (in_array('select', $actions) && $this->path_writable) {
1018                    $submits[] = '<input type="submit" name="select" value="'.__('Choose').'" />';
1019               }
1020          }
1021
1022          return array_merge(
1023               $submits,
1024               parent::getActions($id, $module, $actions)
1025          );
1026     }
1027
1028     public function doActions($prefix)
1029     {
1030          if (!empty($_POST) && empty($_REQUEST['conf']) && $this->isPathWritable()) {
1031
1032               # Select theme to use on curent blog
1033               if (!empty($_POST['module']) && !empty($_POST['select'])) {
1034                    $id = $_POST['module'];
1035
1036                    if (!$this->modules->moduleExists($id)) {
1037                         throw new Exception(__('No such module.'));
1038                    }
1039
1040                    $this->core->blog->settings->addNamespace('system');
1041                    $this->core->blog->settings->system->put('theme',$id);
1042                    $this->core->blog->triggerBlog();
1043
1044                    http::redirect($this->getPageURL('msg=select').'#themes');
1045               }
1046          }
1047
1048          return parent::doActions($prefix);
1049     }
1050}
Note: See TracBrowser for help on using the repository browser.

Sites map