Dotclear

source: inc/admin/lib.moduleslist.php @ 2192:511c654d4adb

Revision 2192:511c654d4adb, 26.9 KB checked in by Denis Jean-Chirstian <contact@…>, 12 years ago (diff)

Next step for themes manager, to be continued

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

Sites map