]> git.mxchange.org Git - quix0rs-gnu-social.git/blob - actions/designadminpanel.php
fix notices in dumpschema
[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         // TRANS: Message used as title for design settings for the site.
63         return _('Design');
64     }
65
66     /**
67      * Instructions for using this form.
68      *
69      * @return string instructions
70      */
71
72     function getInstructions()
73     {
74         return _('Design settings for this StatusNet site');
75     }
76
77     /**
78      * Get the default design and show the design admin panel form
79      *
80      * @return void
81      */
82
83     function showForm()
84     {
85         $this->design = Design::siteDesign();
86         $form = new DesignAdminPanelForm($this);
87         $form->show();
88         return;
89     }
90
91     /**
92      * Save settings from the form
93      *
94      * @return void
95      */
96
97     function saveSettings()
98     {
99         if ($this->arg('save')) {
100             $this->saveDesignSettings();
101         } else if ($this->arg('defaults')) {
102             $this->restoreDefaults();
103         } else {
104             $this->clientError(_('Unexpected form submission.'));
105         }
106     }
107
108     /**
109      * Save the new design settings
110      *
111      * @return void
112      */
113
114     function saveDesignSettings()
115     {
116         // Workaround for PHP returning empty $_POST and $_FILES when POST
117         // length > post_max_size in php.ini
118
119         if (empty($_FILES)
120             && empty($_POST)
121             && ($_SERVER['CONTENT_LENGTH'] > 0)
122         ) {
123             // TRANS: Client error displayed when the number of bytes in a POST request exceeds a limit.
124             // TRANS: %s is the number of bytes of the CONTENT_LENGTH.
125             $msg = _m('The server was unable to handle that much POST data (%s byte) due to its current configuration.',
126                       'The server was unable to handle that much POST data (%s bytes) due to its current configuration.',
127                       intval($_SERVER['CONTENT_LENGTH']));
128             $this->clientException(sprintf($msg, $_SERVER['CONTENT_LENGTH']));
129             return;
130         }
131
132         // check for file uploads
133
134         $bgimage = $this->saveBackgroundImage();
135         $customTheme = $this->saveCustomTheme();
136
137         $oldtheme = common_config('site', 'theme');
138         if ($customTheme) {
139             // This feels pretty hacky :D
140             $this->args['theme'] = $customTheme;
141             $themeChanged = true;
142         } else {
143             $themeChanged = ($this->trimmed('theme') != $oldtheme);
144         }
145
146         static $settings = array('theme', 'logo', 'ssllogo');
147
148         $values = array();
149
150         foreach ($settings as $setting) {
151             $values[$setting] = $this->trimmed($setting);
152         }
153
154         $this->validate($values);
155
156         $config = new Config();
157
158         $config->query('BEGIN');
159
160         if ($themeChanged) {
161             // If the theme has changed, reset custom colors and let them pick
162             // up the new theme's defaults.
163             $colors = array('background', 'content', 'sidebar', 'text', 'link');
164             foreach ($colors as $colorKey) {
165                 // Clear from global config so we see defaults on this page...
166                 $GLOBALS['config']['design'][$colorKey . 'color'] = false;
167
168                 // And remove old settings from DB...
169                 $this->deleteSetting('design', $colorKey . 'color');
170             }
171         } else {
172             // Only save colors from the form if the theme has not changed.
173             //
174             // @fixme a future more ajaxy form should allow theme switch
175             // and color customization in one step.
176
177             $bgcolor = new WebColor($this->trimmed('design_background'));
178             $ccolor  = new WebColor($this->trimmed('design_content'));
179             $sbcolor = new WebColor($this->trimmed('design_sidebar'));
180             $tcolor  = new WebColor($this->trimmed('design_text'));
181             $lcolor  = new WebColor($this->trimmed('design_links'));
182
183             Config::save('design', 'backgroundcolor', $bgcolor->intValue());
184             Config::save('design', 'contentcolor', $ccolor->intValue());
185             Config::save('design', 'sidebarcolor', $sbcolor->intValue());
186             Config::save('design', 'textcolor', $tcolor->intValue());
187             Config::save('design', 'linkcolor', $lcolor->intValue());
188         }
189
190         $onoff = $this->arg('design_background-image_onoff');
191
192         $on   = false;
193         $off  = false;
194
195         if ($onoff == 'on') {
196             $on = true;
197         } else {
198             $off = true;
199         }
200
201         $tile = $this->boolean('design_background-image_repeat');
202
203         // Hack to use Design's bit setter
204         $scratch = new Design();
205         $scratch->setDisposition($on, $off, $tile);
206
207         Config::save('design', 'disposition', $scratch->disposition);
208
209         foreach ($settings as $setting) {
210             Config::save('site', $setting, $values[$setting]);
211         }
212
213         if (isset($bgimage)) {
214             Config::save('design', 'backgroundimage', $bgimage);
215         }
216
217         if (common_config('custom_css', 'enabled')) {
218             $css = $this->arg('css');
219             if ($css != common_config('custom_css', 'css')) {
220                 Config::save('custom_css', 'css', $css);
221             }
222         }
223
224         $config->query('COMMIT');
225     }
226
227     /**
228       * Restore the default design
229       *
230       * @return void
231       */
232
233     function restoreDefaults()
234     {
235         $this->deleteSetting('site', 'logo');
236         $this->deleteSetting('site', 'ssllogo');
237         $this->deleteSetting('site', 'theme');
238
239         $settings = array(
240             'theme', 'backgroundimage', 'backgroundcolor', 'contentcolor',
241             'sidebarcolor', 'textcolor', 'linkcolor', 'disposition'
242         );
243
244         foreach ($settings as $setting) {
245             $this->deleteSetting('design', $setting);
246         }
247
248         // XXX: Should we restore the default dir settings, etc.? --Z
249
250         // XXX: I can't get it to show the new settings without forcing
251         // this terrible reload -- FIX ME!
252         common_redirect(common_local_url('designadminpanel'), 303);
253     }
254
255     /**
256      * Save the background image if the user uploaded one
257      *
258      * @return string $filename the filename of the image
259      */
260
261     function saveBackgroundImage()
262     {
263         $filename = null;
264         if (isset($_FILES['design_background-image_file']['error']) &&
265             $_FILES['design_background-image_file']['error'] ==
266             UPLOAD_ERR_OK) {
267
268             $filepath = null;
269
270             try {
271                 $imagefile =
272                     ImageFile::fromUpload('design_background-image_file');
273             } catch (Exception $e) {
274                 $this->clientError('Unable to save background image.');
275                 return;
276             }
277
278             // Note: site design background image has a special filename
279
280             $filename = Design::filename('site-design-background',
281                 image_type_to_extension($imagefile->type),
282                     common_timestamp());
283
284             $filepath = Design::path($filename);
285
286             move_uploaded_file($imagefile->filepath, $filepath);
287
288             // delete any old backround img laying around
289
290             if (isset($this->design->backgroundimage)) {
291                 @unlink(Design::path($design->backgroundimage));
292             }
293
294             return $filename;
295         }
296     }
297
298     /**
299      * Save the custom theme if the user uploaded one.
300      *
301      * @return mixed custom theme name, if succesful, or null if no theme upload.
302      * @throws ClientException for invalid theme archives
303      * @throws ServerException if trouble saving the theme files
304      */
305
306     function saveCustomTheme()
307     {
308         if (common_config('theme_upload', 'enabled') &&
309             $_FILES['design_upload_theme']['error'] == UPLOAD_ERR_OK) {
310
311             $upload = ThemeUploader::fromUpload('design_upload_theme');
312             $basedir = common_config('local', 'dir');
313             if (empty($basedir)) {
314                 $basedir = INSTALLDIR . '/local';
315             }
316             $name = 'custom'; // @todo allow multiples, custom naming?
317             $outdir = $basedir . '/theme/' . $name;
318             $upload->extract($outdir);
319             return $name;
320         } else {
321             return null;
322         }
323     }
324
325     /**
326      * Attempt to validate setting values
327      *
328      * @return void
329      */
330
331     function validate(&$values)
332     {
333         if (!empty($values['logo']) &&
334             !Validate::uri($values['logo'], array('allowed_schemes' => array('http', 'https')))) {
335             $this->clientError(_('Invalid logo URL.'));
336         }
337
338         if (!empty($values['ssllogo']) &&
339             !Validate::uri($values['ssllogo'], array('allowed_schemes' => array('https')))) {
340             $this->clientError(_('Invalid SSL logo URL.'));
341         }
342
343         if (!in_array($values['theme'], Theme::listAvailable())) {
344             $this->clientError(sprintf(_("Theme not available: %s."), $values['theme']));
345         }
346     }
347
348     /**
349      * Add the Farbtastic stylesheet
350      *
351      * @return void
352      */
353
354     function showStylesheets()
355     {
356         parent::showStylesheets();
357         $this->cssLink('js/farbtastic/farbtastic.css',null,'screen, projection, tv');
358     }
359
360     /**
361      * Add the Farbtastic scripts
362      *
363      * @return void
364      */
365
366     function showScripts()
367     {
368         parent::showScripts();
369
370         $this->script('farbtastic/farbtastic.js');
371         $this->script('userdesign.go.js');
372
373         $this->autofocus('design_background-image_file');
374     }
375
376 }
377
378 class DesignAdminPanelForm extends AdminForm
379 {
380
381     /**
382      * ID of the form
383      *
384      * @return int ID of the form
385      */
386
387     function id()
388     {
389         return 'form_design_admin_panel';
390     }
391
392     /**
393      * class of the form
394      *
395      * @return string class of the form
396      */
397
398     function formClass()
399     {
400         return 'form_settings';
401     }
402
403     /**
404      * HTTP method used to submit the form
405      *
406      * For image data we need to send multipart/form-data
407      * so we set that here too
408      *
409      * @return string the method to use for submitting
410      */
411
412     function method()
413     {
414         $this->enctype = 'multipart/form-data';
415
416         return 'post';
417     }
418
419     /**
420      * Action of the form
421      *
422      * @return string URL of the action
423      */
424
425     function action()
426     {
427         return common_local_url('designadminpanel');
428     }
429
430     /**
431      * Data elements of the form
432      *
433      * @return void
434      */
435
436     function formData()
437     {
438         $this->showLogo();
439         $this->showTheme();
440         $this->showBackground();
441         $this->showColors();
442         $this->showAdvanced();
443     }
444
445     function showLogo()
446     {
447         $this->out->elementStart('fieldset', array('id' => 'settings_design_logo'));
448         $this->out->element('legend', null, _('Change logo'));
449
450         $this->out->elementStart('ul', 'form_data');
451
452         $this->li();
453         $this->input('logo', _('Site logo'), 'Logo for the site (full URL)');
454         $this->unli();
455
456         $this->li();
457         $this->input('ssllogo', _('SSL logo'), 'Logo to show on SSL pages');
458         $this->unli();
459
460         $this->out->elementEnd('ul');
461
462         $this->out->elementEnd('fieldset');
463
464     }
465
466     function showTheme()
467     {
468         $this->out->elementStart('fieldset', array('id' => 'settings_design_theme'));
469         $this->out->element('legend', null, _('Change theme'));
470
471         $this->out->elementStart('ul', 'form_data');
472
473         $themes = Theme::listAvailable();
474
475         // XXX: listAvailable() can return an empty list if you
476         // screw up your settings, so just in case:
477
478         if (empty($themes)) {
479             $themes = array('default', 'default');
480         }
481
482         asort($themes);
483         $themes = array_combine($themes, $themes);
484
485         $this->li();
486         $this->out->dropdown('theme', _('Site theme'),
487                              $themes, _('Theme for the site.'),
488                              false, $this->value('theme'));
489         $this->unli();
490
491         if (common_config('theme_upload', 'enabled')) {
492             $this->li();
493             $this->out->element('label', array('for' => 'design_upload_theme'), _('Custom theme'));
494             $this->out->element('input', array('id' => 'design_upload_theme',
495                                                'name' => 'design_upload_theme',
496                                                'type' => 'file'));
497             $this->out->element('p', 'form_guide', _('You can upload a custom StatusNet theme as a .ZIP archive.'));
498             $this->unli();
499         }
500
501         $this->out->elementEnd('ul');
502
503         $this->out->elementEnd('fieldset');
504     }
505
506     function showBackground()
507     {
508         $design = $this->out->design;
509
510         $this->out->elementStart('fieldset', array('id' =>
511             'settings_design_background-image'));
512         $this->out->element('legend', null, _('Change background image'));
513         $this->out->elementStart('ul', 'form_data');
514
515         $this->li();
516         $this->out->element('label', array('for' => 'design_background-image_file'),
517                                 _('Background'));
518         $this->out->element('input', array('name' => 'design_background-image_file',
519                                      'type' => 'file',
520                                      'id' => 'design_background-image_file'));
521         $this->out->element('p', 'form_guide',
522             sprintf(_('You can upload a background image for the site. ' .
523               'The maximum file size is %1$s.'), ImageFile::maxFileSize()));
524         $this->out->element('input', array('name' => 'MAX_FILE_SIZE',
525                                           'type' => 'hidden',
526                                           'id' => 'MAX_FILE_SIZE',
527                                           'value' => ImageFile::maxFileSizeInt()));
528         $this->unli();
529
530         if (!empty($design->backgroundimage)) {
531
532             $this->out->elementStart('li', array('id' =>
533                 'design_background-image_onoff'));
534
535             $this->out->element('img', array('src' =>
536                 Design::url($design->backgroundimage)));
537
538             $attrs = array('name' => 'design_background-image_onoff',
539                            'type' => 'radio',
540                            'id' => 'design_background-image_on',
541                            'class' => 'radio',
542                            'value' => 'on');
543
544             if ($design->disposition & BACKGROUND_ON) {
545                 $attrs['checked'] = 'checked';
546             }
547
548             $this->out->element('input', $attrs);
549
550             $this->out->element('label', array('for' => 'design_background-image_on',
551                                           'class' => 'radio'),
552                                           // TRANS: Used as radio button label to add a background image.
553                                           _('On'));
554
555             $attrs = array('name' => 'design_background-image_onoff',
556                            'type' => 'radio',
557                            'id' => 'design_background-image_off',
558                            'class' => 'radio',
559                            'value' => 'off');
560
561             if ($design->disposition & BACKGROUND_OFF) {
562                 $attrs['checked'] = 'checked';
563             }
564
565             $this->out->element('input', $attrs);
566
567             $this->out->element('label', array('for' => 'design_background-image_off',
568                                           'class' => 'radio'),
569                                           // TRANS: Used as radio button label to not add a background image.
570                                           _('Off'));
571             $this->out->element('p', 'form_guide', _('Turn background image on or off.'));
572             $this->unli();
573
574             $this->li();
575             $this->out->checkbox('design_background-image_repeat',
576                             _('Tile background image'),
577                             ($design->disposition & BACKGROUND_TILE) ? true : false);
578             $this->unli();
579         }
580
581         $this->out->elementEnd('ul');
582         $this->out->elementEnd('fieldset');
583     }
584
585     function showColors()
586     {
587         $design = $this->out->design;
588
589         $this->out->elementStart('fieldset', array('id' => 'settings_design_color'));
590         $this->out->element('legend', null, _('Change colours'));
591
592         $this->out->elementStart('ul', 'form_data');
593
594         try {
595             // @fixme avoid loop unrolling in non-performance-critical contexts like this
596
597             $bgcolor = new WebColor($design->backgroundcolor);
598
599             $this->li();
600             $this->out->element('label', array('for' => 'swatch-1'), _('Background'));
601             $this->out->element('input', array('name' => 'design_background',
602                                           'type' => 'text',
603                                           'id' => 'swatch-1',
604                                           'class' => 'swatch',
605                                           'maxlength' => '7',
606                                           'size' => '7',
607                                           'value' => ''));
608             $this->unli();
609
610             $ccolor = new WebColor($design->contentcolor);
611
612             $this->li();
613             $this->out->element('label', array('for' => 'swatch-2'), _('Content'));
614             $this->out->element('input', array('name' => 'design_content',
615                                           'type' => 'text',
616                                           'id' => 'swatch-2',
617                                           'class' => 'swatch',
618                                           'maxlength' => '7',
619                                           'size' => '7',
620                                           'value' => ''));
621             $this->unli();
622
623             $sbcolor = new WebColor($design->sidebarcolor);
624
625             $this->li();
626             $this->out->element('label', array('for' => 'swatch-3'), _('Sidebar'));
627             $this->out->element('input', array('name' => 'design_sidebar',
628                                         'type' => 'text',
629                                         'id' => 'swatch-3',
630                                         'class' => 'swatch',
631                                         'maxlength' => '7',
632                                         'size' => '7',
633                                         'value' => ''));
634             $this->unli();
635
636             $tcolor = new WebColor($design->textcolor);
637
638             $this->li();
639             $this->out->element('label', array('for' => 'swatch-4'), _('Text'));
640             $this->out->element('input', array('name' => 'design_text',
641                                         'type' => 'text',
642                                         'id' => 'swatch-4',
643                                         'class' => 'swatch',
644                                         'maxlength' => '7',
645                                         'size' => '7',
646                                         'value' => ''));
647             $this->unli();
648
649             $lcolor = new WebColor($design->linkcolor);
650
651             $this->li();
652             $this->out->element('label', array('for' => 'swatch-5'), _('Links'));
653             $this->out->element('input', array('name' => 'design_links',
654                                          'type' => 'text',
655                                          'id' => 'swatch-5',
656                                          'class' => 'swatch',
657                                          'maxlength' => '7',
658                                          'size' => '7',
659                                          'value' => ''));
660             $this->unli();
661
662         } catch (WebColorException $e) {
663             // @fixme normalize them individually!
664             common_log(LOG_ERR, 'Bad color values in site design: ' .
665                 $e->getMessage());
666         }
667
668         $this->out->elementEnd('fieldset');
669
670         $this->out->elementEnd('ul');
671     }
672
673     function showAdvanced()
674     {
675         if (common_config('custom_css', 'enabled')) {
676             $this->out->elementStart('fieldset', array('id' => 'settings_design_advanced'));
677             $this->out->element('legend', null, _('Advanced'));
678             $this->out->elementStart('ul', 'form_data');
679
680             $this->li();
681             $this->out->element('label', array('for' => 'css'), _('Custom CSS'));
682             $this->out->element('textarea', array('name' => 'css',
683                                             'id' => 'css',
684                                             'cols' => '50',
685                                             'rows' => '10'),
686                                 strval(common_config('custom_css', 'css')));
687             $this->unli();
688
689             $this->out->elementEnd('fieldset');
690             $this->out->elementEnd('ul');
691         }
692     }
693
694     /**
695      * Action elements
696      *
697      * @return void
698      */
699
700     function formActions()
701     {
702         $this->out->submit('defaults', _('Use defaults'), 'submit form_action-default',
703                 'defaults', _('Restore default designs'));
704
705         $this->out->element('input', array('id' => 'settings_design_reset',
706                                          'type' => 'reset',
707                                          'value' => 'Reset',
708                                          'class' => 'submit form_action-primary',
709                                          'title' => _('Reset back to default')));
710
711         $this->out->submit('save', _('Save'), 'submit form_action-secondary',
712                 'save', _('Save design'));
713     }
714
715 }