]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - actions/designadminpanel.php
156c3f1ab505a2bb919caeeb8c9d02e744545f1c
[quix0rs-gnu-social.git] / actions / designadminpanel.php
1 <?php
2 /**
3  * StatusNet, the distributed open-source microblogging tool
4  *
5  * Design administration panel
6  *
7  * PHP version 5
8  *
9  * LICENCE: This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU Affero General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU Affero General Public License for more details.
18  *
19  * You should have received a copy of the GNU Affero General Public License
20  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
21  *
22  * @category  Settings
23  * @package   StatusNet
24  * @author    Evan Prodromou <evan@status.net>
25  * @author    Zach Copley <zach@status.net>
26  * @author    Sarven Capadisli <csarven@status.net>
27  * @copyright 2008-2009 StatusNet, Inc.
28  * @license   http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
29  * @link      http://status.net/
30  */
31
32 if (!defined('STATUSNET')) {
33     exit(1);
34 }
35
36 /**
37  * Administer design settings
38  *
39  * @category Admin
40  * @package  StatusNet
41  * @author   Evan Prodromou <evan@status.net>
42  * @author   Zach Copley <zach@status.net>
43  * @author   Sarven Capadisli <csarven@status.net>
44  * @license  http://www.fsf.org/licensing/licenses/agpl-3.0.html GNU Affero General Public License version 3.0
45  * @link     http://status.net/
46  */
47
48 class DesignadminpanelAction extends AdminPanelAction
49 {
50
51     /* The default site design */
52     var $design = null;
53
54     /**
55      * Returns the page title
56      *
57      * @return string page title
58      */
59
60     function title()
61     {
62         return _('Design');
63     }
64
65     /**
66      * Instructions for using this form.
67      *
68      * @return string instructions
69      */
70
71     function getInstructions()
72     {
73         return _('Design settings for this StatusNet site.');
74     }
75
76     /**
77      * Get the default design and show the design admin panel form
78      *
79      * @return void
80      */
81
82     function showForm()
83     {
84         $this->design = Design::siteDesign();
85         $form = new DesignAdminPanelForm($this);
86         $form->show();
87         return;
88     }
89
90     /**
91      * Save settings from the form
92      *
93      * @return void
94      */
95
96     function saveSettings()
97     {
98         if ($this->arg('save')) {
99             $this->saveDesignSettings();
100         } else if ($this->arg('defaults')) {
101             $this->restoreDefaults();
102         } else {
103             $this->clientError(_('Unexpected form submission.'));
104         }
105     }
106
107     /**
108      * Save the new design settings
109      *
110      * @return void
111      */
112
113     function saveDesignSettings()
114     {
115         // Workaround for PHP returning empty $_POST and $_FILES when POST
116         // length > post_max_size in php.ini
117
118         if (empty($_FILES)
119             && empty($_POST)
120             && ($_SERVER['CONTENT_LENGTH'] > 0)
121         ) {
122             $msg = _('The server was unable to handle that much POST ' .
123                 'data (%s bytes) due to its current configuration.');
124             $this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
125             return;
126         }
127
128         // check for an image upload
129
130         $bgimage = $this->saveBackgroundImage();
131
132         static $settings = array(
133             'site' => array('theme', 'logo'),
134             'theme' => array('server', 'dir', 'path'),
135             'avatar' => array('server', 'dir', 'path'),
136             'background' => array('server', 'dir', 'path')
137         );
138
139         $values = array();
140
141         foreach ($settings as $section => $parts) {
142             foreach ($parts as $setting) {
143                 $values[$section][$setting] = $this->trimmed("$section-$setting");
144             }
145         }
146
147         $this->validate($values);
148
149         // assert(all values are valid);
150
151         $bgcolor = new WebColor($this->trimmed('design_background'));
152         $ccolor  = new WebColor($this->trimmed('design_content'));
153         $sbcolor = new WebColor($this->trimmed('design_sidebar'));
154         $tcolor  = new WebColor($this->trimmed('design_text'));
155         $lcolor  = new WebColor($this->trimmed('design_links'));
156
157         $onoff = $this->arg('design_background-image_onoff');
158
159         $on   = false;
160         $off  = false;
161
162         if ($onoff == 'on') {
163             $on = true;
164         } else {
165             $off = true;
166         }
167
168         $tile = $this->boolean('design_background-image_repeat');
169
170         $config = new Config();
171
172         $config->query('BEGIN');
173
174         foreach ($settings as $section => $parts) {
175             foreach ($parts as $setting) {
176                 Config::save($section, $setting, $values[$section][$setting]);
177             }
178         }
179
180         if (isset($bgimage)) {
181             Config::save('design', 'backgroundimage', $bgimage);
182         }
183
184         Config::save('design', 'backgroundcolor', $bgcolor->intValue());
185         Config::save('design', 'contentcolor', $ccolor->intValue());
186         Config::save('design', 'sidebarcolor', $sbcolor->intValue());
187         Config::save('design', 'textcolor', $tcolor->intValue());
188         Config::save('design', 'linkcolor', $lcolor->intValue());
189
190         // Hack to use Design's bit setter
191         $scratch = new Design();
192         $scratch->setDisposition($on, $off, $tile);
193
194         Config::save('design', 'disposition', $scratch->disposition);
195
196         $config->query('COMMIT');
197
198         return;
199     }
200
201     /**
202       * Restore the default design
203       *
204       * @return void
205       */
206
207     function restoreDefaults()
208     {
209         $this->deleteSetting('site', 'logo');
210         $this->deleteSetting('site', 'theme');
211
212         $settings = array(
213             'theme', 'backgroundimage', 'backgroundcolor', 'contentcolor',
214             'sidebarcolor', 'textcolor', 'linkcolor', 'disposition'
215         );
216
217         foreach ($settings as $setting) {
218             $this->deleteSetting('design', $setting);
219         }
220
221         // XXX: Should we restore the default dir settings, etc.? --Z
222     }
223
224     /**
225      * Save the background image if the user uploaded one
226      *
227      * @return string $filename the filename of the image
228      */
229
230     function saveBackgroundImage()
231     {
232         $filename = null;
233
234         if ($_FILES['design_background-image_file']['error'] ==
235             UPLOAD_ERR_OK) {
236
237             $filepath = null;
238
239             try {
240                 $imagefile =
241                     ImageFile::fromUpload('design_background-image_file');
242             } catch (Exception $e) {
243                 $this->clientError('Unable to save background image.');
244                 return;
245             }
246
247             // Note: site design background image has a special filename
248
249             $filename = Design::filename('site-design-background',
250                 image_type_to_extension($imagefile->type),
251                     common_timestamp());
252
253             $filepath = Design::path($filename);
254
255             move_uploaded_file($imagefile->filepath, $filepath);
256
257             // delete any old backround img laying around
258
259             if (isset($this->design->backgroundimage)) {
260                 @unlink(Design::path($design->backgroundimage));
261             }
262
263             return $filename;
264         }
265     }
266
267     /**
268      * Attempt to validate setting values
269      *
270      * @return void
271      */
272
273     function validate(&$values)
274     {
275
276         if (!empty($values['site']['logo']) &&
277             !Validate::uri($values['site']['logo'], array('allowed_schemes' => array('http', 'https')))) {
278             $this->clientError(_("Invalid logo URL."));
279         }
280
281         if (!in_array($values['site']['theme'], Theme::listAvailable())) {
282             $this->clientError(sprintf(_("Theme not available: %s"), $values['site']['theme']));
283         }
284
285         // Make sure the directories are there
286
287         if (!empty($values['theme']['dir']) && !is_readable($values['theme']['dir'])) {
288             $this->clientError(sprintf(_("Theme directory not readable: %s"), $values['theme']['dir']));
289         }
290
291         if (empty($values['avatar']['dir']) || !is_writable($values['avatar']['dir'])) {
292             $this->clientError(sprintf(_("Avatar directory not writable: %s"), $values['avatar']['dir']));
293         }
294
295         if (empty($values['background']['dir']) || !is_writable($values['background']['dir'])) {
296             $this->clientError(sprintf(_("Background directory not writable: %s"), $values['background']['dir']));
297         }
298
299         // Do we need to do anything else but validate the
300         // other fields for length?  Design settings are
301         // validated elsewhere --Z
302
303         static $settings = array(
304             'theme' => array('server', 'path'),
305             'avatar' => array('server', 'path'),
306             'background' => array('server', 'path')
307         );
308
309         foreach ($settings as $section => $parts) {
310             foreach ($parts as $setting) {
311                 if (mb_strlen($values[$section][$setting]) > 255) {
312                     $this->clientError(sprintf(_("Max length for %s %s is 255 characters."),
313                         $section, $setting));
314                         return;
315                 }
316             }
317         }
318     }
319
320     /**
321      * Add the Farbtastic stylesheet
322      *
323      * @return void
324      */
325
326     function showStylesheets()
327     {
328         parent::showStylesheets();
329         $this->cssLink('css/farbtastic.css','base','screen, projection, tv');
330     }
331
332     /**
333      * Add the Farbtastic scripts
334      *
335      * @return void
336      */
337
338     function showScripts()
339     {
340         parent::showScripts();
341
342         $this->script('js/farbtastic/farbtastic.js');
343         $this->script('js/userdesign.go.js');
344
345         $this->autofocus('design_background-image_file');
346     }
347
348 }
349
350 class DesignAdminPanelForm extends AdminForm
351 {
352
353     /**
354      * ID of the form
355      *
356      * @return int ID of the form
357      */
358
359     function id()
360     {
361         return 'form_design_admin_panel';
362     }
363
364     /**
365      * class of the form
366      *
367      * @return string class of the form
368      */
369
370     function formClass()
371     {
372         return 'form_settings';
373     }
374
375     /**
376      * HTTP method used to submit the form
377      *
378      * For image data we need to send multipart/form-data
379      * so we set that here too
380      *
381      * @return string the method to use for submitting
382      */
383
384     function method()
385     {
386         $this->enctype = 'multipart/form-data';
387
388         return 'post';
389     }
390
391     /**
392      * Action of the form
393      *
394      * @return string URL of the action
395      */
396
397     function action()
398     {
399         return common_local_url('designadminpanel');
400     }
401
402     /**
403      * Data elements of the form
404      *
405      * @return void
406      */
407
408     function formData()
409     {
410
411         $this->out->elementStart('fieldset', array('id' => 'settings_logo'));
412         $this->out->element('legend', null, _('Change logo'));
413
414         $this->out->elementStart('ul', 'form_data');
415
416         $this->li();
417         $this->input('logo', _('Site logo'), 'Logo for the site (full URL)', 'site');
418         $this->unli();
419
420         $this->out->elementEnd('ul');
421
422         $this->out->elementEnd('fieldset');
423         $this->out->elementStart('fieldset', array('id' => 'settings_theme'));
424         $this->out->element('legend', null, _('Change theme'));
425
426         $this->out->elementStart('ul', 'form_data');
427
428         $themes = Theme::listAvailable();
429
430         // XXX: listAvailable() can return an empty list if you
431         // screw up your settings, so just in case:
432
433         if (empty($themes)) {
434             $themes = array('default', 'default');
435         }
436
437         asort($themes);
438         $themes = array_combine($themes, $themes);
439
440         $this->li();
441         $this->out->dropdown('site-theme', _('Site theme'),
442                              $themes, _('Theme for the site.'),
443                              false, $this->value('theme', 'site'));
444         $this->unli();
445
446         $this->li();
447         $this->input('server', _('Theme server'), 'Server for themes', 'theme');
448         $this->unli();
449
450         $this->li();
451         $this->input('path', _('Theme path'), 'Web path to themes', 'theme');
452         $this->unli();
453
454         $this->li();
455         $this->input('dir', _('Theme directory'), 'Directory where themes are located', 'theme');
456         $this->unli();
457
458         $this->out->elementEnd('ul');
459
460         $this->out->elementEnd('fieldset');
461         $this->out->elementStart('fieldset', array('id' => 'settings_avatar'));
462         $this->out->element('legend', null, _('Avatar Settings'));
463
464         $this->out->elementStart('ul', 'form_data');
465
466         $this->li();
467         $this->input('server', _('Avatar server'), 'Server for avatars', 'avatar');
468         $this->unli();
469
470         $this->li();
471         $this->input('path', _('Avatar path'), 'Web path to avatars', 'avatar');
472         $this->unli();
473
474         $this->li();
475         $this->input('dir', _('Avatar directory'), 'Directory where avatars are located', 'avatar');
476         $this->unli();
477
478         $this->out->elementEnd('ul');
479
480         $this->out->elementEnd('fieldset');
481
482         $design = $this->out->design;
483
484         $this->out->elementStart('fieldset', array('id' =>
485             'settings_design_background-image'));
486         $this->out->element('legend', null, _('Change background image'));
487         $this->out->elementStart('ul', 'form_data');
488
489         $this->li();
490         $this->out->element('label', array('for' => 'design_background-image_file'),
491                                 _('Background'));
492         $this->out->element('input', array('name' => 'design_background-image_file',
493                                      'type' => 'file',
494                                      'id' => 'design_background-image_file'));
495         $this->out->element('p', 'form_guide',
496             sprintf(_('You can upload a background image for the site. ' .
497               'The maximum file size is %1$s.'), ImageFile::maxFileSize()));
498         $this->out->element('input', array('name' => 'MAX_FILE_SIZE',
499                                           'type' => 'hidden',
500                                           'id' => 'MAX_FILE_SIZE',
501                                           'value' => ImageFile::maxFileSizeInt()));
502         $this->unli();
503
504         if (!empty($design->backgroundimage)) {
505
506             $this->out->elementStart('li', array('id' =>
507                 'design_background-image_onoff'));
508
509             $this->out->element('img', array('src' =>
510                 Design::url($design->backgroundimage)));
511
512             $attrs = array('name' => 'design_background-image_onoff',
513                            'type' => 'radio',
514                            'id' => 'design_background-image_on',
515                            'class' => 'radio',
516                            'value' => 'on');
517
518             if ($design->disposition & BACKGROUND_ON) {
519                 $attrs['checked'] = 'checked';
520             }
521
522             $this->out->element('input', $attrs);
523
524             $this->out->element('label', array('for' => 'design_background-image_on',
525                                           'class' => 'radio'),
526                                           _('On'));
527
528             $attrs = array('name' => 'design_background-image_onoff',
529                            'type' => 'radio',
530                            'id' => 'design_background-image_off',
531                            'class' => 'radio',
532                            'value' => 'off');
533
534             if ($design->disposition & BACKGROUND_OFF) {
535                 $attrs['checked'] = 'checked';
536             }
537
538             $this->out->element('input', $attrs);
539
540             $this->out->element('label', array('for' => 'design_background-image_off',
541                                           'class' => 'radio'),
542                                           _('Off'));
543             $this->out->element('p', 'form_guide', _('Turn background image on or off.'));
544             $this->unli();
545
546             $this->li();
547             $this->out->checkbox('design_background-image_repeat',
548                             _('Tile background image'),
549                             ($design->disposition & BACKGROUND_TILE) ? true : false);
550             $this->unli();
551         }
552
553         $this->li();
554         $this->input('server', _('Background server'), 'Server for backgrounds', 'background');
555         $this->unli();
556
557         $this->li();
558         $this->input('path', _('Background path'), 'Web path to backgrounds', 'background');
559         $this->unli();
560
561         $this->li();
562         $this->input('dir', _('Background directory'), 'Directory where backgrounds are located', 'background');
563         $this->unli();
564
565         $this->out->elementEnd('ul');
566         $this->out->elementEnd('fieldset');
567
568         $this->out->elementStart('fieldset', array('id' => 'settings_design_color'));
569         $this->out->element('legend', null, _('Change colours'));
570
571         $this->out->elementStart('ul', 'form_data');
572
573         try {
574
575             $bgcolor = new WebColor($design->backgroundcolor);
576
577             $this->li();
578             $this->out->element('label', array('for' => 'swatch-1'), _('Background'));
579             $this->out->element('input', array('name' => 'design_background',
580                                           'type' => 'text',
581                                           'id' => 'swatch-1',
582                                           'class' => 'swatch',
583                                           'maxlength' => '7',
584                                           'size' => '7',
585                                           'value' => ''));
586             $this->unli();
587
588             $ccolor = new WebColor($design->contentcolor);
589
590             $this->li();
591             $this->out->element('label', array('for' => 'swatch-2'), _('Content'));
592             $this->out->element('input', array('name' => 'design_content',
593                                           'type' => 'text',
594                                           'id' => 'swatch-2',
595                                           'class' => 'swatch',
596                                           'maxlength' => '7',
597                                           'size' => '7',
598                                           'value' => ''));
599             $this->unli();
600
601             $sbcolor = new WebColor($design->sidebarcolor);
602
603             $this->li();
604             $this->out->element('label', array('for' => 'swatch-3'), _('Sidebar'));
605             $this->out->element('input', array('name' => 'design_sidebar',
606                                         'type' => 'text',
607                                         'id' => 'swatch-3',
608                                         'class' => 'swatch',
609                                         'maxlength' => '7',
610                                         'size' => '7',
611                                         'value' => ''));
612             $this->unli();
613
614             $tcolor = new WebColor($design->textcolor);
615
616             $this->li();
617             $this->out->element('label', array('for' => 'swatch-4'), _('Text'));
618             $this->out->element('input', array('name' => 'design_text',
619                                         'type' => 'text',
620                                         'id' => 'swatch-4',
621                                         'class' => 'swatch',
622                                         'maxlength' => '7',
623                                         'size' => '7',
624                                         'value' => ''));
625             $this->unli();
626
627             $lcolor = new WebColor($design->linkcolor);
628
629             $this->li();
630             $this->out->element('label', array('for' => 'swatch-5'), _('Links'));
631             $this->out->element('input', array('name' => 'design_links',
632                                          'type' => 'text',
633                                          'id' => 'swatch-5',
634                                          'class' => 'swatch',
635                                          'maxlength' => '7',
636                                          'size' => '7',
637                                          'value' => ''));
638             $this->unli();
639
640         } catch (WebColorException $e) {
641             common_log(LOG_ERR, 'Bad color values in site design: ' .
642                 $e->getMessage());
643         }
644
645         $this->out->elementEnd('fieldset');
646
647         $this->out->elementEnd('ul');
648     }
649
650     /**
651      * Action elements
652      *
653      * @return void
654      */
655
656     function formActions()
657     {
658         $this->out->submit('defaults', _('Use defaults'), 'submit form_action-default',
659                 'defaults', _('Restore default designs'));
660
661         $this->out->element('input', array('id' => 'settings_design_reset',
662                                          'type' => 'reset',
663                                          'value' => 'Reset',
664                                          'class' => 'submit form_action-primary',
665                                          'title' => _('Reset back to default')));
666
667         $this->out->submit('save', _('Save'), 'submit form_action-secondary',
668                 'save', _('Save design'));
669     }
670
671
672     /**
673      * Utility to simplify some of the duplicated code around
674      * params and settings. Overriding the input() in the base class
675      * to handle a whole bunch of cases of settings with the same
676      * name under different sections.
677      *
678      * @param string $setting      Name of the setting
679      * @param string $title        Title to use for the input
680      * @param string $instructions Instructions for this field
681      * @param string $section      config section, default = 'site'
682      *
683      * @return void
684      */
685
686     function input($setting, $title, $instructions, $section='site')
687     {
688         $this->out->input("$section-$setting", $title, $this->value($setting, $section), $instructions);
689     }
690
691 }