Dotclear

source: inc/admin/lib.moduleslist.php @ 2222:30fe556de226

Revision 2222:30fe556de226, 28.6 KB checked in by Denis Jean-Chirstian <contact@…>, 12 years ago (diff)

Enhance repository search engine (and some fix)

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                    'score'                  => 0
273               ),
274               # Module's values
275               $module,
276               # Clean up values
277               array(
278                    'id'                     => $id,
279                    'sid'                    => self::sanitizeString($id),
280                    'label'             => $label,
281                    'name'                   => $name,
282                    'sname'             => self::sanitizeString($name)
283               )
284          );
285     }
286
287     public static function isDistributedModule($module)
288     {
289          $distributed_modules = self::$distributed_modules;
290
291          return is_array($distributed_modules) && in_array($module, $distributed_modules);
292     }
293
294     public static function sortModules($modules, $field, $asc=true)
295     {
296          $sorter = array();
297          foreach($modules as $id => $module) {
298               $sorter[$id] = isset($module[$field]) ? $module[$field] : $field;
299          }
300          array_multisort($sorter, $asc ? SORT_ASC : SORT_DESC, $modules);
301
302          return $modules;
303     }
304
305     public function displayModulesList($cols=array('name', 'config', 'version', 'desc'), $actions=array(), $nav_limit=false)
306     {
307          echo 
308          '<div class="table-outer">'.
309          '<table id="'.html::escapeHTML($this->list_id).'" class="modules'.(in_array('expander', $cols) ? ' expandable' : '').'">'.
310          '<caption class="hidden">'.html::escapeHTML(__('Modules list')).'</caption><tr>';
311
312          if (in_array('name', $cols)) {
313               echo 
314               '<th class="first nowrap"'.(in_array('icon', $cols) ? ' colspan="2"' : '').'>'.__('Name').'</th>';
315          }
316
317          if (in_array('score', $cols) && $this->getSearchQuery() !== null && defined('DC_DEBUG') && DC_DEBUG) {
318               echo 
319               '<th class="nowrap">'.__('Score').'</th>';
320          }
321
322          if (in_array('version', $cols)) {
323               echo 
324               '<th class="nowrap count" scope="col">'.__('Version').'</th>';
325          }
326
327          if (in_array('current_version', $cols)) {
328               echo 
329               '<th class="nowrap count" scope="col">'.__('Current version').'</th>';
330          }
331
332          if (in_array('desc', $cols)) {
333               echo 
334               '<th class="nowrap" scope="col">'.__('Details').'</th>';
335          }
336
337          if (in_array('distrib', $cols)) {
338               echo '<th'.(in_array('desc', $cols) ? '' : ' class="maximal"').'></th>';
339          }
340
341          if (!empty($actions) && $this->core->auth->isSuperAdmin()) {
342               echo 
343               '<th class="minimal nowrap">'.__('Action').'</th>';
344          }
345
346          echo 
347          '</tr>';
348
349          $sort_field = $this->getSortQuery();
350
351          # Sort modules by $sort_field (default sname)
352          $modules = $this->getSearchQuery() === null ?
353               self::sortModules($this->data, $sort_field, $this->sort_asc) :
354               $this->data;
355
356          $count = 0;
357          foreach ($modules as $id => $module)
358          {
359               # Show only requested modules
360               if ($nav_limit && $this->getSearchQuery() === null) {
361                    $char = substr($module[$sort_field], 0, 1);
362                    if (!in_array($char, $this->nav_list)) {
363                         $char = $this->nav_special;
364                    }
365                    if ($this->getNavQuery() != $char) {
366                         continue;
367                    }
368               }
369
370               echo 
371               '<tr class="line" id="'.html::escapeHTML($this->list_id).'_m_'.html::escapeHTML($id).'">';
372
373               if (in_array('icon', $cols)) {
374                    echo 
375                    '<td class="module-icon nowrap">'.sprintf(
376                         '<img alt="%1$s" title="%1$s" src="%2$s" />', 
377                         html::escapeHTML($id), file_exists($module['root'].'/icon.png') ? 'index.php?pf='.$id.'/icon.png' : 'images/module.png'
378                    ).'</td>';
379               }
380
381               # Link to config file
382               $config = in_array('config', $cols) && !empty($module['root']) && file_exists(path::real($module['root'].'/_config.php'));
383
384               echo 
385               '<td class="module-name nowrap" scope="row">'.($config ? 
386                    '<a href="'.$this->getPageURL('module='.$id.'&conf=1').'" title"'.sprintf(__('Configure module "%s"'), html::escapeHTML($module['name'])).'">'.html::escapeHTML($module['name']).'</a>' : 
387                    html::escapeHTML($module['name'])
388               ).'</td>';
389
390               # Display score only for debug purpose
391               if (in_array('score', $cols) && $this->getSearchQuery() !== null && defined('DC_DEBUG') && DC_DEBUG) {
392                    echo 
393                    '<td class="module-version nowrap count"><span class="debug">'.$module['score'].'</span></td>';
394               }
395
396               if (in_array('version', $cols)) {
397                    echo 
398                    '<td class="module-version nowrap count">'.html::escapeHTML($module['version']).'</td>';
399               }
400
401               if (in_array('current_version', $cols)) {
402                    echo 
403                    '<td class="module-current-version nowrap count">'.html::escapeHTML($module['current_version']).'</td>';
404               }
405
406               if (in_array('desc', $cols)) {
407                    echo 
408                    '<td class="module-desc maximal">'.html::escapeHTML($module['desc']).'</td>';
409               }
410
411               if (in_array('distrib', $cols)) {
412                    echo 
413                    '<td class="module-distrib">'.(self::isDistributedModule($id) ? 
414                         '<img src="images/dotclear_pw.png" alt="'.
415                         __('Module from official distribution').'" title="'.
416                         __('module from official distribution').'" />' 
417                    : '').'</td>';
418               }
419
420               if (!empty($actions) && $this->core->auth->isSuperAdmin()) {
421                    $buttons = $this->getActions($id, $module, $actions);
422
423                    echo 
424                    '<td class="module-actions nowrap">'.
425
426                    '<form action="'.$this->getPageURL().'" method="post">'.
427                    '<div>'.
428                    $this->core->formNonce().
429                    form::hidden(array('module'), html::escapeHTML($id)).
430                    form::hidden(array('tab'), $this->page_tab).
431
432                    implode(' ', $buttons).
433
434                    '</div>'.
435                    '</form>'.
436
437                    '</td>';
438               }
439
440               echo 
441               '</tr>';
442
443               $count++;
444          }
445          echo 
446          '</table></div>';
447
448          if(!$count && $this->getSearchQuery() === null) {
449               echo 
450               '<p class="message">'.__('No module matches your search.').'</p>';
451          }
452     }
453
454     protected function getActions($id, $module, $actions)
455     {
456          $submits = array();
457
458          # Use loop to keep requested order
459          foreach($actions as $action) {
460               switch($action) {
461
462                    # Deactivate
463                    case 'activate': if ($module['root_writable']) {
464                         $submits[] = 
465                         '<input type="submit" name="activate" value="'.__('Activate').'" />';
466                    } break;
467
468                    # Activate
469                    case 'deactivate': if ($module['root_writable']) {
470                         $submits[] = 
471                         '<input type="submit" name="deactivate" value="'.__('Deactivate').'" class="reset" />';
472                    } break;
473
474                    # Delete
475                    case 'delete': if ($this->isPathDeletable($module['root'])) {
476                         $submits[] = 
477                         '<input type="submit" class="delete" name="delete" value="'.__('Delete').'" />';
478                    } break;
479
480                    # Install (from store)
481                    case 'install': if ($this->path_writable) {
482                         $submits[] = 
483                         '<input type="submit" name="install" value="'.__('Install').'" />';
484                    } break;
485
486                    # Update (from store)
487                    case 'update': if ($this->path_writable) {
488                         $submits[] = 
489                         '<input type="submit" name="update" value="'.__('Update').'" />';
490                    } break;
491               }
492          }
493
494          return $submits;
495     }
496
497     public function doActions($prefix)
498     {
499          if (empty($_POST) || !empty($_REQUEST['conf']) 
500          || !$this->core->auth->isSuperAdmin() || !$this->isPathWritable()) {
501               return null;
502          }
503
504          # List actions
505          if (!empty($_POST['module'])) {
506
507               $id = $_POST['module'];
508
509               if (!empty($_POST['activate'])) {
510
511                    $enabled = $this->modules->getDisabledModules();
512                    if (!isset($enabled[$id])) {
513                         throw new Exception(__('No such module.'));
514                    }
515
516                    # --BEHAVIOR-- moduleBeforeActivate
517                    $this->core->callBehavior($prefix.'BeforeActivate', $id);
518
519                    $this->modules->activateModule($id);
520
521                    # --BEHAVIOR-- moduleAfterActivate
522                    $this->core->callBehavior($prefix.'AfterActivate', $id);
523
524                    dcPage::addSuccessNotice(__('Module has been successfully activated.'));
525                    http::redirect($this->getPageURL());
526               }
527
528               elseif (!empty($_POST['deactivate'])) {
529
530                    if (!$this->modules->moduleExists($id)) {
531                         throw new Exception(__('No such module.'));
532                    }
533
534                    $module = $this->modules->getModules($id);
535                    $module['id'] = $id;
536
537                    if (!$module['root_writable']) {
538                         throw new Exception(__('You don\'t have permissions to deactivate this module.'));
539                    }
540
541                    # --BEHAVIOR-- moduleBeforeDeactivate
542                    $this->core->callBehavior($prefix.'BeforeDeactivate', $module);
543
544                    $this->modules->deactivateModule($id);
545
546                    # --BEHAVIOR-- moduleAfterDeactivate
547                    $this->core->callBehavior($prefix.'AfterDeactivate', $module);
548
549                    dcPage::addSuccessNotice(__('Module has been successfully deactivated.'));
550                    http::redirect($this->getPageURL());
551               }
552
553               elseif (!empty($_POST['delete'])) {
554
555                    $disabled = $this->modules->getDisabledModules();
556                    if (!isset($disabled[$id])) {
557
558                         if (!$this->modules->moduleExists($id)) {
559                              throw new Exception(__('No such module.'));
560                         }
561
562                         $module = $this->modules->getModules($id);
563                         $module['id'] = $id;
564
565                         if (!$this->isPathDeletable($module['root'])) {
566                              throw new Exception(__("You don't have permissions to delete this module."));
567                         }
568
569                         # --BEHAVIOR-- moduleBeforeDelete
570                         $this->core->callBehavior($prefix.'BeforeDelete', $module);
571
572                         $this->modules->deleteModule($id);
573
574                         # --BEHAVIOR-- moduleAfterDelete
575                         $this->core->callBehavior($prefix.'AfterDelete', $module);
576                    }
577                    else {
578                         $this->modules->deleteModule($id, true);
579                    }
580
581                    dcPage::addSuccessNotice(__('Module has been successfully deleted.'));
582                    http::redirect($this->getPageURL());
583               }
584
585               elseif (!empty($_POST['install'])) {
586
587                    $updated = $this->store->get();
588                    if (!isset($updated[$id])) {
589                         throw new Exception(__('No such module.'));
590                    }
591
592                    $module = $updated[$id];
593                    $module['id'] = $id;
594
595                    $dest = $this->getPath().'/'.basename($module['file']);
596
597                    # --BEHAVIOR-- moduleBeforeAdd
598                    $this->core->callBehavior($prefix.'BeforeAdd', $module);
599
600                    $ret_code = $this->store->process($module['file'], $dest);
601
602                    # --BEHAVIOR-- moduleAfterAdd
603                    $this->core->callBehavior($prefix.'AfterAdd', $module);
604
605                    dcPage::addSuccessNotice($ret_code == 2 ?
606                         __('Module has been successfully updated.') :
607                         __('Module has been successfully installed.')
608                    );
609                    http::redirect($this->getPageURL());
610               }
611
612               elseif (!empty($_POST['update'])) {
613
614                    $updated = $store->get();
615                    if (!isset($updated[$id])) {
616                         throw new Exception(__('No such module.'));
617                    }
618
619                    if (!$this->modules->moduleExists($id)) {
620                         throw new Exception(__('No such module.'));
621                    }
622
623                    $module = $updated[$id];
624                    $module['id'] = $id;
625               
626                    if (!self::$allow_multi_install) {
627                         $dest = $module['root'].'/../'.basename($module['file']);
628                    }
629                    else {
630                         $dest = $this->getPath().'/'.basename($module['file']);
631                         if ($module['root'] != $dest) {
632                              @file_put_contents($module['root'].'/_disabled', '');
633                         }
634                    }
635
636                    # --BEHAVIOR-- moduleBeforeUpdate
637                    $this->core->callBehavior($prefix.'BeforeUpdate', $module);
638
639                    $this->store->process($module['file'], $dest);
640
641                    # --BEHAVIOR-- moduleAfterUpdate
642                    $this->core->callBehavior($prefix.'AfterUpdate', $module);
643
644                    dcPage::addSuccessNotice(__('Module has been successfully updated.'));
645                    http::redirect($this->getPageURL());
646               }
647          }
648          # Manual actions
649          elseif (!empty($_POST['upload_pkg']) && !empty($_FILES['pkg_file']) 
650               || !empty($_POST['fetch_pkg']) && !empty($_POST['pkg_url']))
651          {
652               if (empty($_POST['your_pwd']) || !$this->core->auth->checkPassword(crypt::hmac(DC_MASTER_KEY, $_POST['your_pwd']))) {
653                    throw new Exception(__('Password verification failed'));
654               }
655
656               if (!empty($_POST['upload_pkg'])) {
657                    files::uploadStatus($_FILES['pkg_file']);
658                   
659                    $dest = $this->getPath().'/'.$_FILES['pkg_file']['name'];
660                    if (!move_uploaded_file($_FILES['pkg_file']['tmp_name'], $dest)) {
661                         throw new Exception(__('Unable to move uploaded file.'));
662                    }
663               }
664               else {
665                    $url = urldecode($_POST['pkg_url']);
666                    $dest = $this->getPath().'/'.basename($url);
667                    $this->store->download($url, $dest);
668               }
669
670               # --BEHAVIOR-- moduleBeforeAdd
671               $this->core->callBehavior($prefix.'BeforeAdd', null);
672
673               $ret_code = $this->store->install($dest);
674
675               # --BEHAVIOR-- moduleAfterAdd
676               $this->core->callBehavior($prefix.'AfterAdd', null);
677
678               dcPage::addSuccessNotice($ret_code == 2 ?
679                    __('Module has been successfully updated.') :
680                    __('Module has been successfully installed.')
681               );
682               http::redirect($this->getPageURL().'#'.$prefix);
683          }
684
685          return null;
686     }
687
688     public function displayManualForm()
689     {
690          if (!$this->core->auth->isSuperAdmin() || !$this->isPathWritable()) {
691               return null;
692          }
693
694          # 'Upload module' form
695          echo
696          '<form method="post" action="'.$this->getPageURL().'" id="uploadpkg" enctype="multipart/form-data" class="fieldset">'.
697          '<h4>'.__('Upload a zip file').'</h4>'.
698          '<p class="field"><label for="pkg_file" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Zip file path:').'</label> '.
699          '<input type="file" name="pkg_file" id="pkg_file" /></p>'.
700          '<p class="field"><label for="your_pwd1" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '.
701          form::password(array('your_pwd','your_pwd1'),20,255).'</p>'.
702          '<p><input type="submit" name="upload_pkg" value="'.__('Upload').'" />'.
703          form::hidden(array('tab'), $this->getPageTab()).
704          $this->core->formNonce().'</p>'.
705          '</form>';
706         
707          # 'Fetch module' form
708          echo
709          '<form method="post" action="'.$this->getPageURL().'" id="fetchpkg" class="fieldset">'.
710          '<h4>'.__('Download a zip file').'</h4>'.
711          '<p class="field"><label for="pkg_url" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Zip file URL:').'</label> '.
712          form::field(array('pkg_url','pkg_url'),40,255).'</p>'.
713          '<p class="field"><label for="your_pwd2" class="classic required"><abbr title="'.__('Required field').'">*</abbr> '.__('Your password:').'</label> '.
714          form::password(array('your_pwd','your_pwd2'),20,255).'</p>'.
715          '<p><input type="submit" name="fetch_pkg" value="'.__('Download').'" />'.
716          form::hidden(array('tab'), $this->getPageTab()).
717          $this->core->formNonce().'</p>'.
718          '</form>';
719     }
720
721     /**
722      *
723      * We need to get configuration content in three steps
724      * and out of this class to keep backward compatibility.
725      *
726      * if ($xxx->setConfigurationFile()) {
727      *   include $xxx->getConfigurationFile();
728      * }
729      * $xxx->setConfigurationContent();
730      * ... [put here page headers and other stuff]
731      * $xxx->getConfigurationContent();
732      *
733      */
734     public function setConfigurationFile($id=null)
735     {
736          if (empty($_REQUEST['conf']) || empty($_REQUEST['module']) && !$id) {
737               return false;
738          }
739         
740          if (!empty($_REQUEST['module']) && empty($id)) {
741               $id = $_REQUEST['module'];
742          }
743
744          if (!$this->modules->moduleExists($id)) {
745               $core->error->add(__('Unknow module ID'));
746               return false;
747          }
748
749          $module = $this->modules->getModules($id);
750          $module = self::parseModuleInfo($id, $module);
751          $file = path::real($module['root'].'/_config.php');
752
753          if (!file_exists($file)) {
754               $core->error->add(__('This module has no configuration file.'));
755               return false;
756          }
757
758          $this->config_module = $module;
759          $this->config_file = $file;
760          $this->config_content = '';
761
762          if (!defined('DC_CONTEXT_MODULE')) {
763               define('DC_CONTEXT_MODULE', true);
764          }
765
766          return true;
767     }
768
769     public function getConfigurationFile()
770     {
771          if (!$this->config_file) {
772               return null;
773          }
774
775          ob_start();
776
777          return $this->config_file;
778     }
779
780     public function setConfigurationContent()
781     {
782          if ($this->config_file) {
783               $this->config_content = ob_get_contents();
784          }
785
786          ob_end_clean();
787
788          return !empty($this->file_content);
789     }
790
791     public function getConfigurationContent()
792     {
793          if (!$this->config_file) {
794               return null;
795          }
796
797          if (!$this->config_module['standalone_config']) {
798               echo
799               '<form id="module_config" action="'.$this->getPageURL('conf=1').'" method="post" enctype="multipart/form-data">'.
800               '<h3>'.sprintf(__('Configure plugin "%s"'), html::escapeHTML($this->config_module['name'])).'</h3>'.
801               '<p><a class="back" href="'.$this->getPageURL().'#plugins">'.__('Back').'</a></p>';
802          }
803
804          echo $this->config_content;
805
806          if (!$this->config_module['standalone_config']) {
807               echo
808               '<p class="clear"><input type="submit" name="save" value="'.__('Save').'" />'.
809               form::hidden('module', $this->config_module['id']).
810               $this->core->formNonce().'</p>'.
811               '</form>';
812          }
813
814          return true;
815     }
816
817     public static function sanitizeString($str)
818     {
819          return preg_replace('/[^A-Za-z0-9\@\#+_-]/', '', strtolower($str));
820     }
821}
822
823class adminThemesList extends adminModulesList
824{
825     protected $page_url = 'blog_theme.php';
826
827     public function displayModulesList($cols=array('name', 'config', 'version', 'desc'), $actions=array(), $nav_limit=false)
828     {
829          echo 
830          '<div id="'.html::escapeHTML($this->list_id).'" class="modules'.(in_array('expander', $cols) ? ' expandable' : '').' one-box">';
831
832          $sort_field = $this->getSortQuery();
833
834          # Sort modules by id
835          $modules = $this->getSearchQuery() === null ?
836               self::sortModules($this->data, $sort_field, $this->sort_asc) :
837               $this->data;
838
839          $res = '';
840          $count = 0;
841          foreach ($modules as $id => $module)
842          {
843               # Show only requested modules
844               if ($nav_limit && $this->getSearchQuery() === null) {
845                    $char = substr($module[$sort_field], 0, 1);
846                    if (!in_array($char, $this->nav_list)) {
847                         $char = $this->nav_special;
848                    }
849                    if ($this->getNavQuery() != $char) {
850                         continue;
851                    }
852               }
853
854               $current = $this->core->blog->settings->system->theme == $id;
855               $distrib = self::isDistributedModule($id) ? ' dc-box' : '';
856
857               $theme_url = preg_match('#^http(s)?://#', $this->core->blog->settings->system->themes_url) ?
858                    http::concatURL($this->core->blog->settings->system->themes_url, '/'.$id) :
859                    http::concatURL($this->core->blog->url, $this->core->blog->settings->system->themes_url.'/'.$id);
860
861               $has_conf = file_exists(path::real($this->core->blog->themes_path.'/'.$id).'/_config.php');
862               $has_css = file_exists(path::real($this->core->blog->themes_path.'/'.$id).'/style.css');
863               $parent = $module['parent'];
864               $has_parent = !empty($module['parent']);
865               if ($has_parent) {
866                    $is_parent_present = $this->modules->moduleExists($parent);
867               }
868
869               $line = 
870               '<div class="box '.($current ? 'medium current-theme' : 'small theme').$distrib.'">';
871
872               if (in_array('name', $cols)) {
873                    $line .= 
874                    '<h4 class="module-name">'.html::escapeHTML($module['name']).'</h4>';
875               }
876
877               # Display score only for debug purpose
878               if (in_array('score', $cols) && $this->getSearchQuery() !== null && defined('DC_DEBUG') && DC_DEBUG) {
879                    $line .= 
880                    '<p class="module-score debug">'.sprintf(__('Score: %s'), $module['score']).'</p>';
881               }
882
883               if (in_array('sshot', $cols)) {
884                    # Screenshot from url
885                    if (preg_match('#^http(s)?://#', $module['sshot'])) {
886                         $sshot = $module['sshot'];
887                    }
888                    # Screenshot from installed module
889                    elseif (file_exists($this->core->blog->themes_path.'/'.$id.'/screenshot.jpg')) {
890                         $sshot = $this->getPageURL('shot='.rawurlencode($id));
891                    }
892                    # Default screenshot
893                    else {
894                         $sshot = 'images/noscreenshot.png';
895                    }
896
897                    $line .= 
898                    '<div class="module-sshot"><img src="'.$sshot.'" alt="'.
899                    sprintf(__('%s screenshot.'), html::escapeHTML($module['name'])).'" /></div>';
900               }
901
902               $line .= 
903               '<div class="module-infos toggle-bloc">'.
904               '<p>';
905
906               if (in_array('desc', $cols)) {
907                    $line .= 
908                    '<span class="module-desc">'.html::escapeHTML($module['desc']).'</span> ';
909               }
910
911               if (in_array('author', $cols)) {
912                    $line .= 
913                    '<span class="module-author">'.sprintf(__('by %s'),html::escapeHTML($module['author'])).'</span> ';
914               }
915
916               if (in_array('version', $cols)) {
917                    $line .= 
918                    '<span class="module-version">'.sprintf(__('version %s'),html::escapeHTML($module['version'])).'</span> ';
919               }
920
921               if (in_array('current_version', $cols)) {
922                    $line .= 
923                    '<span class="module-current-version">'.sprintf(__('(current version %s)'),html::escapeHTML($module['current_version'])).'</span> ';
924               }
925
926               if (in_array('parent', $cols) && $has_parent) {
927                    if ($is_parent_present) {
928                         $line .= 
929                         '<span class="module-parent-ok">'.sprintf(__('(built on "%s")'),html::escapeHTML($parent)).'</span> ';
930                    }
931                    else {
932                         $line .= 
933                         '<span class="module-parent-missing">'.sprintf(__('(requires "%s")'),html::escapeHTML($parent)).'</span> ';
934                    }
935               }
936
937               $has_details = in_array('details', $cols) && !empty($module['details']);
938               $has_support = in_array('support', $cols) && !empty($module['support']);
939               if ($has_details || $has_support) {
940                    $line .=
941                    '<span class="mod-more">'.__('Help:').' ';
942
943                    if ($has_details) {
944                         $line .= 
945                         '<a class="module-details" href="'.$module['details'].'">'.__('Details').'</a>';
946                    }
947
948                    if ($has_support) {
949                         $line .= 
950                         ' - <a class="module-support" href="'.$module['support'].'">'.__('Support').'</a>';
951                    }
952
953                    $line .=
954                    '</span>';
955               }
956
957               $line .= 
958               '</p>'.
959               '</div>';
960
961               $line .= 
962               '<div class="module-actions toggle-bloc">';
963               
964               # _GET actions
965
966               if ($current && $has_css) {
967                    $line .= 
968                    '<p><a href="'.$theme_url.'/style.css">'.__('View stylesheet').'</a></p>';
969               }
970               if ($current && $has_conf) {
971                    $line .= 
972                    '<p><a href="'.$this->getPageURL('module='.$id.'&conf=1', false).'" class="button">'.__('Configure theme').'</a></p>';
973               }
974
975               # Plugins actions
976               if ($current) {
977                    # --BEHAVIOR-- adminCurrentThemeDetails
978                    $line .= 
979                    $this->core->callBehavior('adminCurrentThemeDetails', $this->core, $id, $module);
980               }
981
982               # _POST actions
983               if (!empty($actions)) {
984                    $line .=
985                    '<form action="'.$this->getPageURL().'" method="post">'.
986                    '<div>'.
987                    $this->core->formNonce().
988                    form::hidden(array('module'), html::escapeHTML($id)).
989                    form::hidden(array('tab'), $this->page_tab).
990
991                    implode(' ', $this->getActions($id, $module, $actions)).
992 
993                    '</div>'.
994                    '</form>';
995               }
996
997               $line .= 
998               '</div>';
999
1000               $line .=
1001               '</div>';
1002
1003               $count++;
1004
1005               $res = $current ? $line.$res : $res.$line;
1006          }
1007          echo 
1008          $res.
1009          '</div>';
1010
1011          if(!$count && $this->getSearchQuery() === null) {
1012               echo 
1013               '<p class="message">'.__('No module matches your search.').'</p>';
1014          }
1015     }
1016
1017     protected function getActions($id, $module, $actions)
1018     {
1019          $submits = array();
1020
1021          $this->core->blog->settings->addNamespace('system');
1022          if ($id != $this->core->blog->settings->system->theme) {
1023
1024               # Select theme to use on curent blog
1025               if (in_array('select', $actions) && $this->path_writable) {
1026                    $submits[] = '<input type="submit" name="select" value="'.__('Choose').'" />';
1027               }
1028          }
1029
1030          return array_merge(
1031               $submits,
1032               parent::getActions($id, $module, $actions)
1033          );
1034     }
1035
1036     public function doActions($prefix)
1037     {
1038          if (!empty($_POST) && empty($_REQUEST['conf']) && $this->isPathWritable()) {
1039
1040               # Select theme to use on curent blog
1041               if (!empty($_POST['module']) && !empty($_POST['select'])) {
1042                    $id = $_POST['module'];
1043
1044                    if (!$this->modules->moduleExists($id)) {
1045                         throw new Exception(__('No such module.'));
1046                    }
1047
1048                    $this->core->blog->settings->addNamespace('system');
1049                    $this->core->blog->settings->system->put('theme',$id);
1050                    $this->core->blog->triggerBlog();
1051
1052                    dcPage::addSuccessNotice(__('Module has been successfully selected.'));
1053                    http::redirect($this->getPageURL().'#themes');
1054               }
1055          }
1056
1057          return parent::doActions($prefix);
1058     }
1059}
Note: See TracBrowser for help on using the repository browser.

Sites map