Dotclear

source: inc/admin/lib.moduleslist.php @ 2163:d41b59b0ae2e

Revision 2163:d41b59b0ae2e, 15.8 KB checked in by Denis Jean-Chirstian <contact@…>, 12 years ago (diff)

Move maintenance configuration to the new plugins configurator

Line 
1<?php
2
3class adminModulesList
4{
5     public $core;
6     public $modules;
7
8     public static  $allow_multi_install;
9
10     protected $list_id = 'unknow';
11
12     protected $path = false;
13     protected $path_writable = false;
14     protected $path_pattern = false;
15
16     protected $page_url = 'plugins.php';
17     protected $page_qs = '?';
18     protected $page_tab = '';
19
20     public static $nav_indexes = 'abcdefghijklmnopqrstuvwxyz0123456789';
21     protected $nav_list = array();
22     protected $nav_special = 'other';
23
24     protected $sort_field = 'sname';
25     protected $sort_asc = true;
26
27     public function __construct($core, $root, $allow_multi_install=false)
28     {
29          $this->core = $core;
30          self::$allow_multi_install = (boolean) $allow_multi_install;
31          $this->setPathInfo($root);
32          $this->setNavSpecial(__('other'));
33
34          $this->init();
35     }
36
37     protected function init()
38     {
39          return null;
40     }
41
42     public function newList($list_id)
43     {
44          $this->modules = array();
45          $this->page_tab = '';
46          $this->list_id = $list_id;
47
48          return $this;
49     }
50
51     protected function setPathInfo($root)
52     {
53          $paths = explode(PATH_SEPARATOR, $root);
54          $path = array_pop($paths);
55          unset($paths);
56
57          $this->path = $path;
58          if (is_dir($path) && is_writeable($path)) {
59               $this->path_writable = true;
60               $this->path_pattern = preg_quote($path,'!');
61          }
62
63          return $this;
64     }
65
66     public function getPath()
67     {
68          return $this->path;
69     }
70
71     public function isPathWritable()
72     {
73          return $this->path_writable;
74     }
75
76     public function isPathDeletable($root)
77     {
78          return $this->path_writable 
79               && preg_match('!^'.$this->path_pattern.'!', $root) 
80               && $this->core->auth->isSuperAdmin();
81     }
82
83     public function setPageURL($url)
84     {
85          $this->page_qs = strpos('?', $url) ? '&' : '?';
86          $this->page_url = $url;
87
88          return $this;
89     }
90
91     public function getPageURL($queries='', $with_tab=true)
92     {
93          return $this->page_url.
94               (!empty($queries) ? $this->page_qs : '').
95               (is_array($queries) ? http_build_query($queries) : $queries).
96               ($with_tab && !empty($this->page_tab) ? '#'.$this->page_tab : '');
97     }
98
99     public function setPageTab($tab)
100     {
101          $this->page_tab = $tab;
102
103          return $this;
104     }
105
106     public function getPageTab()
107     {
108          return $this->page_tab;
109     }
110
111     public function getSearchQuery()
112     {
113          $query = !empty($_REQUEST['m_search']) ? trim($_REQUEST['m_search']) : null;
114          return strlen($query) > 1 ? $query : null;
115     }
116
117     public function displaySearchForm()
118     {
119          $query = $this->getSearchQuery();
120
121          if (empty($this->modules) && $query === null) {
122               return $this;
123          }
124
125          echo 
126          '<form action="'.$this->getPageURL().'" method="get" class="fieldset">'.
127          '<p><label for="m_search" class="classic">'.__('Search in repository:').'&nbsp;</label><br />'.
128          form::field(array('m_search','m_search'), 30, 255, html::escapeHTML($query)).
129          '<input type="submit" value="'.__('Search').'" /> ';
130          if ($query) { echo ' <a href="'.$this->getPageURL().'" class="button">'.__('Reset search').'</a>'; }
131          echo '</p>'.
132          '</form>';
133
134          if ($query) {
135               echo 
136               '<p class="message">'.sprintf(
137                    __('Found %d result for search "%s":', 'Found %d results for search "%s":', count($this->modules)), 
138                    count($this->modules), html::escapeHTML($query)
139                    ).
140               '</p>';
141          }
142          return $this;
143     }
144
145     public function setNavSpecial($str)
146     {
147          $this->nav_special = (string) $str;
148          $this->nav_list = array_merge(str_split(self::$nav_indexes), array($this->nav_special));
149
150          return $this;
151     }
152
153     public function getNavQuery()
154     {
155          return isset($_REQUEST['m_nav']) && in_array($_REQUEST['m_nav'], $this->nav_list) ? $_REQUEST['m_nav'] : $this->nav_list[0];
156     }
157
158     public function displayNavMenu()
159     {
160          if (empty($this->modules) || $this->getSearchQuery() !== null) {
161               return $this;
162          }
163
164          # Fetch modules required field
165          $indexes = array();
166          foreach ($this->modules as $id => $module) {
167               if (!isset($module[$this->sort_field])) {
168                    continue;
169               }
170               $char = substr($module[$this->sort_field], 0, 1);
171               if (!in_array($char, $this->nav_list)) {
172                    $char = $this->nav_special;
173               }
174               if (!isset($indexes[$char])) {
175                    $indexes[$char] = 0;
176               }
177               $indexes[$char]++;
178          }
179
180          $buttons = array();
181          foreach($this->nav_list as $char) {
182               # Selected letter
183               if ($this->getNavQuery() == $char) {
184                    $buttons[] = '<li class="active" title="'.__('current selection').'"><strong> '.$char.' </strong></li>';
185               }
186               # Letter having modules
187               elseif (!empty($indexes[$char])) {
188                    $title = sprintf(__('%d module', '%d modules', $indexes[$char]), $indexes[$char]);
189                    $buttons[] = '<li class="btn" title="'.$title.'"><a href="'.$this->getPageURL('m_nav='.$char).'" title="'.$title.'"> '.$char.' </a></li>';
190               }
191               # Letter without modules
192               else {
193                    $buttons[] = '<li class="btn no-link" title="'.__('no module').'"> '.$char.' </li>';
194               }
195          }
196          # Parse navigation menu
197          echo '<div class="pager">'.__('Browse index:').' <ul>'.implode('',$buttons).'</ul></div>';
198
199          return $this;
200     }
201
202     public function setSortField($field, $asc=true)
203     {
204          $this->sort_field = $field;
205          $this->sort_asc = (boolean) $asc;
206
207          return $this;
208     }
209
210     public function getSortQuery()
211     {
212          return !empty($_REQUEST['m_sort']) ? $_REQUEST['m_sort'] : $this->sort_field;
213     }
214
215     public function displaySortForm()
216     {
217          //not yet implemented
218     }
219
220     public function displayMessage($action)
221     {
222          switch($action) {
223               case 'activate': 
224                    $str = __('Module successfully activated.'); break;
225               case 'deactivate': 
226                    $str = __('Module successfully deactivated.'); break;
227               case 'delete': 
228                    $str = __('Module successfully deleted.'); break;
229               case 'install': 
230                    $str = __('Module successfully installed.'); break;
231               case 'update': 
232                    $str = __('Module successfully updated.'); break;
233               default:
234                    $str = ''; break;
235          }
236          if (!empty($str)) {
237               dcPage::success($str);
238          }
239     }
240
241     public function setModules($modules)
242     {
243          $this->modules = array();
244          foreach($modules as $id => $module) {
245               $this->modules[$id] = self::setModuleInfo($id, $module);
246          }
247
248          return $this;
249     }
250
251     public function getModules()
252     {
253          return $this->modules;
254     }
255
256     public static function setModuleInfo($id, $module)
257     {
258          $label = empty($module['label']) ? $id : $module['label'];
259          $name = __(empty($module['name']) ? $label : $module['name']);
260         
261          return array_merge(
262               # Default values
263               array(
264                    'desc'                   => '',
265                    'author'            => '',
266                    'version'                => 0,
267                    'current_version'   => 0,
268                    'root'                   => '',
269                    'root_writable'     => false,
270                    'permissions'       => null,
271                    'parent'            => null,
272                    'priority'               => 1000,
273                    'standalone_config' => false,
274                    'support'                => '',
275                    'section'                => '',
276                    'tags'                   => '',
277                    'details'                => ''
278               ),
279               # Module's values
280               $module,
281               # Clean up values
282               array(
283                    'id'                     => $id,
284                    'sid'                    => self::sanitizeString($id),
285                    'label'             => $label,
286                    'name'                   => $name,
287                    'sname'             => self::sanitizeString($name)
288               )
289          );
290     }
291
292     public static function isDistributedModule($module)
293     {
294          return in_array($module, array(
295               'aboutConfig',
296               'akismet',
297               'antispam',
298               'attachments',
299               'blogroll',
300               'blowupConfig',
301               'daInstaller',
302               'fairTrackbacks',
303               'importExport',
304               'maintenance',
305               'pages',
306               'pings',
307               'simpleMenu',
308               'tags',
309               'themeEditor',
310               'userPref',
311               'widgets'
312          ));
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 id
368          $modules = $this->getSearchQuery() === null ?
369               self::sortModules($this->modules, $sort_field, $this->sort_asc) :
370               $this->modules;
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).'" title="'.
388               sprintf(__('Configure module "%"'), html::escapeHTML($module['name'])).'">';
389
390               if (in_array('icon', $cols)) {
391                    echo 
392                    '<td class="nowrap icon">'.sprintf(
393                         '<img alt="%1$s" title="%1$s" src="%2$s" />', 
394                         html::escapeHTML($id), file_exists($module['root'].'/icon.png') ? 'index.php?pf='.$id.'/icon.png' : 'images/module.png'
395                    ).'</td>';
396               }
397
398               # Link to config file
399               $config = in_array('config', $cols) && !empty($module['root']) && file_exists(path::real($module['root'].'/_config.php'));
400
401               echo 
402               '<td class="nowrap" scope="row">'.($config ? 
403                    '<a href="'.$this->getPageURL('module='.$id.'&conf=1').'">'.html::escapeHTML($module['name']).'</a>' : 
404                    html::escapeHTML($module['name'])
405               ).'</td>';
406
407               if (in_array('version', $cols)) {
408                    echo 
409                    '<td class="nowrap count">'.html::escapeHTML($module['version']).'</td>';
410               }
411
412               if (in_array('current_version', $cols)) {
413                    echo 
414                    '<td class="nowrap count">'.html::escapeHTML($module['current_version']).'</td>';
415               }
416
417               if (in_array('desc', $cols)) {
418                    echo 
419                    '<td class="maximal">'.html::escapeHTML($module['desc']).'</td>';
420               }
421
422               if (in_array('distrib', $cols)) {
423                    echo 
424                    '<td class="distrib">'.(self::isDistributedModule($id) ? 
425                         '<img src="images/dotclear_pw.png" alt="'.
426                         __('Module from official distribution').'" title="'.
427                         __('module from official distribution').'" />' 
428                    : '').'</td>';
429               }
430
431               if (!empty($actions) && $this->core->auth->isSuperAdmin()) {
432                    echo 
433                    '<td class="nowrap">';
434
435                    $this->displayLineActions($id, $module, $actions);
436
437                    echo
438                    '</td>';
439               }
440
441               echo 
442               '</tr>';
443
444               $count++;
445          }
446          echo 
447          '</table></div>';
448
449          if(!$count) {
450               echo 
451               '<p class="message">'.__('No module matches your search.').'</p>';
452          }
453     }
454
455     protected function displayLineActions($id, $module, $actions)
456     {
457          $submits = array();
458
459          # Activate
460          if (in_array('deactivate', $actions) && $module['root_writable']) {
461               $submits[] = '<input type="submit" name="deactivate" value="'.__('Deactivate').'" />';
462          }
463
464          # Deactivate
465          if (in_array('activate', $actions) && $module['root_writable']) {
466               $submits[] = '<input type="submit" name="activate" value="'.__('Activate').'" />';
467          }
468
469          # Delete
470          if (in_array('delete', $actions) && $this->isPathDeletable($module['root'])) {
471               $submits[] = '<input type="submit" class="delete" name="delete" value="'.__('Delete').'" />';
472          }
473
474          # Install (form repository)
475          if (in_array('install', $actions) && $this->path_writable) {
476               $submits[] = '<input type="submit" name="install" value="'.__('Install').'" />';
477          }
478
479          # Update (from repository)
480          if (in_array('update', $actions) && $this->path_writable) {
481               $submits[] = '<input type="submit" name="update" value="'.__('Update').'" />';
482          }
483
484          # Parse form
485          if (!empty($submits)) {
486               echo 
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     }
497
498     public function executeAction($prefix, dcModules $modules, dcRepository $repository)
499     {
500          if (empty($_POST['module'])   || !$this->core->auth->isSuperAdmin() || !$this->isPathWritable()) {
501               return null;
502          }
503
504          $id = $_POST['module'];
505
506          if (!empty($_POST['activate'])) {
507
508               $enabled = $modules->getDisabledModules();
509               if (!isset($enabled[$id])) {
510                    throw new Exception(__('No such module.'));
511               }
512
513               # --BEHAVIOR-- moduleBeforeActivate
514               $this->core->callBehavior($type.'BeforeActivate', $id);
515
516               $modules->activateModule($id);
517
518               # --BEHAVIOR-- moduleAfterActivate
519               $this->core->callBehavior($type.'AfterActivate', $id);
520
521               http::redirect($this->getPageURL('msg=activate'));
522          }
523
524          if (!empty($_POST['deactivate'])) {
525
526               if (!$modules->moduleExists($id)) {
527                    throw new Exception(__('No such module.'));
528               }
529
530               $module = $modules->getModules($id);
531               $module['id'] = $id;
532
533               if (!$module['root_writable']) {
534                    throw new Exception(__('You don\'t have permissions to deactivate this module.'));
535               }
536
537               # --BEHAVIOR-- moduleBeforeDeactivate
538               $this->core->callBehavior($prefix.'BeforeDeactivate', $module);
539
540               $modules->deactivateModule($id);
541
542               # --BEHAVIOR-- moduleAfterDeactivate
543               $this->core->callBehavior($prefix.'AfterDeactivate', $module);
544
545               http::redirect($this->getPageURL('msg=deactivate'));
546          }
547
548          if (!empty($_POST['delete'])) {
549
550               $disabled = $modules->getDisabledModules();
551               if (!isset($disabled[$id])) {
552
553                    if (!$modules->moduleExists($id)) {
554                         throw new Exception(__('No such module.'));
555                    }
556
557                    $module = $modules->getModules($id);
558                    $module['id'] = $id;
559
560                    if (!$this->isPathDeletable($module['root'])) {
561                         throw new Exception(__("You don't have permissions to delete this module."));
562                    }
563
564                    # --BEHAVIOR-- moduleBeforeDelete
565                    $this->core->callBehavior($prefix.'BeforeDelete', $module);
566
567                    $modules->deleteModule($id);
568
569                    # --BEHAVIOR-- moduleAfterDelete
570                    $this->core->callBehavior($prefix.'AfterDelete', $module);
571               }
572               else {
573                    $modules->deleteModule($id, true);
574               }
575
576               http::redirect($this->getPageURL('msg=delete'));
577          }
578
579          if (!empty($_POST['update'])) {
580
581               $updated = $repository->get();
582               if (!isset($updated[$id])) {
583                    throw new Exception(__('No such module.'));
584               }
585
586               if (!$modules->moduleExists($id)) {
587                    throw new Exception(__('No such module.'));
588               }
589
590               $module = $updated[$id];
591               $module['id'] = $id;
592         
593               if (!self::$allow_multi_install) {
594                    $dest = $module['root'].'/../'.basename($module['file']);
595               }
596               else {
597                    $dest = $this->getPath().'/'.basename($module['file']);
598                    if ($module['root'] != $dest) {
599                         @file_put_contents($module['root'].'/_disabled', '');
600                    }
601               }
602
603               # --BEHAVIOR-- moduleBeforeUpdate
604               $this->core->callBehavior($type.'BeforeUpdate', $module);
605
606               $repository->process($module['file'], $dest);
607
608               # --BEHAVIOR-- moduleAfterUpdate
609               $this->core->callBehavior($type.'AfterUpdate', $module);
610
611               http::redirect($this->getPageURL('msg=upadte'));
612          }
613
614          if (!empty($_POST['install'])) {
615
616               $updated = $repository->get();
617               if (!isset($updated[$id])) {
618                    throw new Exception(__('No such module.'));
619               }
620
621               $module = $updated[$id];
622               $module['id'] = $id;
623
624               $dest = $this->getPath().'/'.basename($module['file']);
625
626               # --BEHAVIOR-- moduleBeforeAdd
627               $this->core->callBehavior($type.'BeforeAdd', $module);
628
629               $ret_code = $repository->process($module['file'], $dest);
630
631               # --BEHAVIOR-- moduleAfterAdd
632               $this->core->callBehavior($type.'AfterAdd', $module);
633
634               http::redirect($this->getPageURL('msg='.($ret_code == 2 ? 'update' : 'install')));
635          }
636     }
637
638     public static function sanitizeString($str)
639     {
640          return preg_replace('/[^A-Za-z0-9\@\#+_-]/', '', strtolower($str));
641     }
642}
643
644class adminThemesList extends adminModulesList
645{
646
647}
Note: See TracBrowser for help on using the repository browser.

Sites map