Dotclear

source: inc/admin/lib.moduleslist.php @ 2149:04a490b510cc

Revision 2149:04a490b510cc, 15.4 KB checked in by Denis Jean-Chirstian <contact@…>, 12 years ago (diff)

Put actions on modules lists helper (and some stuff)

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

Sites map