Dotclear

source: inc/admin/lib.moduleslist.php @ 2157:bdd306788929

Revision 2157:bdd306788929, 16.1 KB checked in by Anne Kozlika <kozlika@…>, 12 years ago (diff)

Un peu de cosmétique (wip)

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

Sites map