Dotclear

source: inc/admin/lib.moduleslist.php @ 2221:97c02a257458

Revision 2221:97c02a257458, 27.9 KB checked in by Anne Kozlika <kozlika@…>, 12 years ago (diff)

Trois fois rien (wip thèmes)

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

Sites map