root/branches/release-38/lib/MT/App/Wizard.pm @ 2402

Revision 2402, 31.1 kB (checked in by bchoate, 18 months ago)

Added Digest::MD5 to optional module requirements. BugId:79843

Line 
1# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
2# This program is distributed under the terms of the
3# GNU General Public License, version 2.
4#
5# $Id$
6
7package MT::App::Wizard;
8
9use strict;
10use base qw( MT::App );
11
12use MT::Util qw( trim );
13
14sub id { 'wizard' }
15
16sub init {
17    my $app = shift;
18    my %param = @_;
19    $app->init_core();
20    my $cfg = $app->config;
21    $cfg->define($app->component('core')->registry('config_settings'));
22    $app->init_core_registry();
23    $cfg->UsePlugins(0);
24    $app->SUPER::init(@_);
25    $app->{mt_dir} ||= $ENV{MT_HOME} || $param{Directory};
26    $app->{is_admin} = 1;
27    $app->add_methods(
28        pre_start => \&pre_start,
29        run_step => \&run_step,
30    );
31    $app->{template_dir} = 'wizard';
32    $app->config->set('StaticWebPath', $app->static_path);
33    return $app;
34}
35
36sub init_request {
37    my $app = shift;
38
39    $app->{default_mode} = 'pre_start';
40
41    # prevents init_request from trying to process the configuration file.
42    $app->SUPER::init_request(@_);
43    $app->set_no_cache;
44    $app->{requires_login} = 0;
45
46    my $mode = $app->mode;
47    return unless $mode eq 'previous_step' || $mode eq 'next_step'
48        || $mode eq 'retry' || $mode eq 'test';
49
50    my $step = $app->param('step') || '';
51
52    my $prev_step = 'pre_start';
53    my $new_step = '';
54
55    if ($mode eq 'retry') {
56        $new_step = $step;
57    } elsif ($mode eq 'test') {
58        $new_step = $step;
59    } else {
60        my $steps = $app->wizard_steps;
61        foreach my $s (@$steps) {
62            if ($mode eq 'next_step') {
63                if ($prev_step eq $step) {
64                    $new_step = $s->{key};
65                    $app->param('save', 1)
66                        if $app->request_method eq 'POST';
67                    last;
68                }
69            } elsif ($mode eq 'previous_step') {
70                if ($s->{key} eq $step) {
71                    $new_step = $prev_step if $prev_step;
72                    last;
73                }
74            }
75            $prev_step = $s->{key};
76        }
77    }
78
79    $app->param('next_step', $new_step);
80    $app->mode('run_step');
81}
82
83sub init_core_registry {
84    my $app = shift;
85    my $core = $app->component("core");
86    $core->{registry}{applications}{wizard} = {
87        wizard_steps => {
88            start => {
89                order => 0,
90                handler => \&start,
91                params => [qw(set_static_uri_to set_static_file_to)],
92            },
93            configure => {
94                order => 100,
95                handler => \&configure,
96                params => [qw(dbpath dbname dbport dbserver dbsocket
97                    dbtype dbuser dbpass publish_charset)]
98            },
99            optional => {
100                order => 200,
101                handler => \&optional,
102                params => [qw(mail_transfer sendmail_path smtp_server
103                    test_mail_address)]
104            },
105            cfg_dir => {
106                order => 300,
107                handler => \&cfg_dir,
108                params => ['temp_dir'],
109                condition => \&cfg_dir_conditions,
110            },
111            seed => {
112                order => 10000,
113                handler => \&seed,
114            },
115        },
116        optional_packages => {
117            'HTML::Entities' => {
118                link => 'http://search.cpan.org/dist/HTML-Entities',
119                label => 'This module is needed to encode special characters, but this feature can be turned off using the NoHTMLEntities option in mt-config.cgi.',
120            },
121            'LWP::UserAgent' => {
122                link => 'http://search.cpan.org/dist/LWP',
123                label => 'This module is needed if you wish to use the TrackBack system, the weblogs.com ping, or the MT Recently Updated ping.',
124            },
125            'SOAP::Lite' => {
126                link => 'http://search.cpan.org/dist/SOAP-Lite',
127                version => 0.50,
128                label => 'This module is needed if you wish to use the MT XML-RPC server implementation.',
129            },
130            'File::Temp' => {
131                link => 'http://search.cpan.org/dist/File-Temp',
132                label => 'This module is needed if you would like to be able to overwrite existing files when you upload.',
133            },
134            'List::Util' => {
135                link => 'http://search.cpan.org/dist/Scalar-List-Utils',
136                label => 'List::Util is optional; It is needed if you want to use the Publish Queue feature.',
137            },
138            'Scalar::Util' => {
139                link => 'http://search.cpan.org/dist/Scalar-List-Utils',
140                label => 'Scalar::Util is optional; It is needed if you want to use the Publish Queue feature.',
141            },
142            'Image::Magick' => {
143                link => 'http://www.imagemagick.org/script/perl-magick.php',
144                label => 'This module is needed if you would like to be able to create thumbnails of uploaded images.',
145            },
146            'Storable' => {
147                link => 'http://search.cpan.org/dist/Storable',
148                label => 'This module is required by certain MT plugins available from third parties.',
149            },
150            'Crypt::DSA' => {
151                link => 'http://search.cpan.org/dist/Crypt-DSA',
152                label => 'This module accelerates comment registration sign-ins.',
153            },
154            'MIME::Base64' => {
155                link => 'http://search.cpan.org/dist/MIME-Base64',
156                label => 'This module is needed to enable comment registration.',
157            },
158            'XML::Atom' => {
159                link => 'http://search.cpan.org/dist/XML-Atom',
160                label => 'This module enables the use of the Atom API.',
161            },
162            'Archive::Tar' => {
163                link => 'http://search.cpan.org/dist/Archive-Tar',
164                label => 'This module is required in order to archive files in backup/restore operation.',
165            },
166            'IO::Compress::Gzip' => {
167                link => 'http://search.cpan.org/dist/IO-Compress-Zlib',
168                label => 'This module is required in order to compress files in backup/restore operation.',
169            },
170            'IO::Uncompress::Gunzip' => {
171                link => 'http://search.cpan.org/dist/IO-Compress-Zlib',
172                label => 'This module is required in order to decompress files in backup/restore operation.',
173            },
174            'Archive::Zip' => {
175                link => 'http://search.cpan.org/dist/Archive-Zip',
176                label => 'This module is required in order to archive files in backup/restore operation.',
177            },
178            'XML::SAX' => {
179                link => 'http://search.cpan.org/dist/XML-SAX',
180                label => 'This module and its dependencies are required in order to restore from a backup.',
181            },
182            'Digest::SHA1' => {
183                link => 'http://search.cpan.org/dist/Digest-SHA1',
184                label => 'This module and its dependencies are required in order to allow commenters to be authenticated by OpenID providers including Vox and LiveJournal.',
185            },
186            'Mail::Sendmail' => {
187                link => 'http://search.cpan.org/dist/Mail-Sendmail',
188                label => 'This module is required for sending mail via SMTP Server.',
189            },
190            'Safe' => {
191                link => 'http://search.cpan.org/dist/Safe',
192                label => 'This module is used in test attribute of MTIf conditional tag.',
193            },
194            'Digest::MD5' => {
195                link => 'http://search.cpan.org/dist/Digest-MD5',
196                label => 'This module is used by the Markdown text filter.',
197            },
198        },
199        required_packages => {
200            'Image::Size' => {
201                link => 'http://search.cpan.org/dist/Image-Size',
202                label => 'This module is required for file uploads (to determine the size of uploaded images in many different formats).',
203            },
204            'CGI::Cookie' => {
205                link => 'http://search.cpan.org/search?query=cgi-cookie&mode=module',
206                label => 'This module is required for cookie authentication.',
207            },
208            'DBI' => {
209                link => 'http://search.cpan.org/dist/DBI',
210                label => 'DBI is required to store data in database.',
211                version => 1.21,
212            },
213            'CGI' => {
214                link => 'http://search.cpan.org/dist/CGI.pm',
215                label => 'CGI is required for all Movable Type application functionality.',
216            },
217            'File::Spec' => {
218                link => 'http://search.cpan.org/dist/File-Spec',
219                version => 0.8,
220                label => 'File::Spec is required for path manipulation across operating systems.',
221            }
222        },
223    };
224}
225
226sub run_step {
227    my $app = shift;
228    my $steps = $app->registry("wizard_steps");
229    my $next_step = $app->param('next_step');
230    my $curr_step = $app->param('step');
231    my $h = $steps->{$curr_step}{handler};
232
233    my %param = $app->unserialize_config;
234    my $keys = $app->config_keys;
235    if ($curr_step) {
236        foreach (@{ $keys->{$curr_step} }) {
237            $param{$_} = $app->param($_)
238                if defined $app->param($_);
239        }
240
241        if ($app->param('save')) {
242            $app->param('config', $app->serialize_config(%param));
243        }
244    }
245
246    $h = $steps->{$next_step}{handler};
247
248    if (!$h) {
249        return $app->pre_start();
250    }
251
252    $h = $app->handler_to_coderef($h)
253        unless ref($h) eq 'CODE';
254
255    $app->param('step', $next_step);
256    return $h->($app, %param);
257}
258
259sub config_keys {
260    my $app = shift;
261    my $steps = $app->registry("wizard_steps");
262    my $keys = {};
263    foreach my $key (keys %$steps) {
264        my $p = $steps->{$key}{params};
265        $keys->{$key} = $p if $p;
266    }
267    return $keys;
268}
269
270sub init_config {
271    return 1;
272}
273
274sub pre_start {
275    my $app = shift;
276    my %param;
277
278    eval { use File::Spec; };
279    my ($cfg, $cfg_exists, $static_file_path);
280    if (!$@) {
281        $cfg = File::Spec->catfile($app->{mt_dir}, 'mt-config.cgi');
282        $cfg_exists |= 1 if -f $cfg;
283
284        $static_file_path = File::Spec->catfile($app->static_file_path);
285    }
286
287    $param{cfg_exists} = $cfg_exists;
288    $param{valid_static_path} = 1 if $app->is_valid_static_path($app->static_path);
289    $param{mt_static_exists} = $app->mt_static_exists;
290    $param{static_file_path} = $static_file_path;
291
292    return $app->build_page("start.tmpl", \%param);
293}
294
295sub wizard_steps {
296    my $app = shift;
297    my @steps;
298    my $steps = $app->registry("wizard_steps");
299    my $active_step = $app->param('step') || 'start';
300    my %param = $app->unserialize_config;
301    foreach my $key (keys %$steps) {
302        if (my $cond = $steps->{$key}{condition}) {
303            if (!ref($cond)) {
304                $cond = $app->handler_to_coderef($cond);
305            }
306            next unless ref($cond) eq 'CODE';
307            next unless $cond->($app, \%param);
308        }
309        push @steps, {
310            key => $key,
311            active => $active_step eq $key,
312            %{$steps->{$key}},
313        };
314    }
315    @steps = sort { $a->{order} <=> $b->{order} } @steps;
316    return \@steps;
317}
318
319sub build_page {
320    my $app = shift;
321    my ($tmpl, $param) = @_;
322
323    $param ||= {};
324    my $steps = $app->wizard_steps;
325    $param->{'wizard_steps'} = $steps;
326    $param->{'step'} = $app->param('step');
327
328    return $app->SUPER::build_page($tmpl, $param);
329}
330
331sub start {
332    my $app = shift;
333    my %param = @_;
334
335    my $static_path = $app->param('set_static_uri_to');
336    my $static_file_path = defined $param{set_static_file_to} ?
337        $param{set_static_file_to} :
338        $app->param('set_static_file_to');
339    $param{set_static_file_to} = $static_file_path;
340
341    # test for static_path
342    unless ($app->param('set_static_uri_to')) {
343        $param{uri_invalid} = 1;
344        return $app->build_page("start.tmpl", \%param);
345    }
346
347    $static_path = $app->cgipath . $static_path
348        unless $static_path =~ m#^(https?:/)?/#;
349    $static_path =~ s#(^\s+|\s+$)##;
350    $static_path .= '/' unless $static_path =~ m!/$!;
351
352    unless ($app->is_valid_static_path($static_path)) {
353        $param{uri_invalid} = 1;
354        $param{set_static_uri_to} = $app->param('set_static_uri_to');
355        return $app->build_page("start.tmpl", \%param);
356    }
357
358    $app->config->set('StaticWebPath', $static_path);
359
360    # test for static_file_path
361    unless ($static_file_path) {
362        $param{file_invalid} = 1;
363        return $app->build_page("start.tmpl", \%param);
364    }
365   
366    if (!(-d $static_file_path) || !(-f File::Spec->catfile($static_file_path, "mt.js"))) {
367        $param{file_invalid} = 1;
368        $param{set_static_uri_to} = $app->param('set_static_uri_to');
369        return $app->build_page("start.tmpl", \%param);
370    }
371    $param{config} = $app->serialize_config(%param);
372    $param{static_file} = $static_file_path;
373
374    # test for required packages...
375    my $req = $app->registry("required_packages");
376    my @REQ;
377    foreach my $key (keys %$req) {
378        my $pkg = $req->{$key};
379        push @REQ, [ $key, $pkg->{version} || 0, 1, $pkg->{label}, $key, $pkg->{link} ];
380    }
381    my ($needed) = $app->module_check(\@REQ);
382    if (@$needed) {
383        $param{package_loop} = $needed;
384        $param{required} = 1;
385        return $app->build_page("packages.tmpl", \%param);
386    }
387
388    my @DATA;
389    my $drivers = $app->object_drivers;
390    foreach my $key (keys %$drivers) {
391        my $driver = $drivers->{$key};
392        my $label = $driver->{label};
393        my $link = 'http://search.cpan.org/dist/' . $driver->{dbd_package};
394        $link =~ s/::/-/g;
395        push @DATA, [ $driver->{dbd_package}, $driver->{dbd_version}, 0,
396            $app->translate("The [_1] database driver is required to use [_2].", $driver->{dbd_package}, $label),
397            $label, $link ];
398    }
399    my ($db_missing) = $app->module_check(\@DATA);
400    if ((scalar @$db_missing) == (scalar @DATA)) {
401        $param{package_loop} = $db_missing;
402        $param{missing_db_or_optional} = 1;
403        $param{missing_db} = 1;
404        return $app->build_page("packages.tmpl", \%param);
405    }
406
407    my $opt = $app->registry("optional_packages");
408    my @OPT;
409    foreach my $key (keys %$opt) {
410        my $pkg = $opt->{$key};
411        push @OPT, [ $key, $pkg->{version} || 0, 0, $pkg->{label}, $key, $pkg->{link} ];
412    }
413    my ($opt_missing) = $app->module_check(\@OPT);
414    push @$opt_missing, @$db_missing;
415    if (@$opt_missing) {
416        $param{package_loop} = $opt_missing;
417        $param{missing_db_or_optional} = 1;
418        $param{optional} = 1;
419        return $app->build_page("packages.tmpl", \%param);
420    }
421
422    $param{success} = 1;
423    return $app->build_page("packages.tmpl", \%param);
424}
425
426sub object_drivers {
427    my $app = shift;
428    my $drivers = $app->registry("object_drivers") || {};
429    return $drivers;
430}
431
432sub configure {
433    my $app = shift;
434    my %param = @_;
435
436    $param{set_static_uri_to} = $app->param('set_static_uri_to');
437    # set static web path
438    $app->config->set('StaticWebPath', $param{set_static_uri_to});
439    delete $param{publish_charset};
440    if (my $dbtype = $param{dbtype}) {
441        $param{"dbtype_$dbtype"} = 1;
442        if ($dbtype eq 'mysql') {
443            $param{login_required} = 1;
444        } elsif ($dbtype eq 'postgres') {
445            $param{login_required} = 1;
446        } elsif ($dbtype eq 'oracle') {
447            $param{login_required} = 1;
448        } elsif ($dbtype eq 'mssqlserver') {
449            $param{login_required} = 1;
450            $param{publish_charset} = $app->param('publish_charset') || ($app->{cfg}->DefaultLanguage eq 'ja' ? 'Shift_JIS' : 'ISO-8859-1');
451        } elsif ($dbtype eq 'sqlite') {
452            $param{path_required} = 1;
453        } elsif ($dbtype eq 'sqlite2') {
454            $param{path_required} = 1;
455        }
456    }
457
458    my @DATA;
459    my $drivers = $app->object_drivers;
460    foreach my $key (keys %$drivers) {
461        my $driver = $drivers->{$key};
462        my $label = $driver->{label};
463        my $link = 'http://search.cpan.org/dist/' . $driver->{dbd_package};
464        $link =~ s/::/-/g;
465        push @DATA, [ $driver->{dbd_package}, $driver->{dbd_version}, 0,
466            $app->translate("The [_1] driver is required to use [_2].", $driver->{dbd_package}, $label),
467            $label, $link ];
468    }
469    my ($missing, $dbmod) = $app->module_check(\@DATA);
470    if (scalar(@$dbmod) == 0) {
471        $param{missing_db_or_optional} = 1;
472        $param{missing_db} = 1;
473        $param{package_loop} = $missing;
474        return $app->build_page("packages.tmpl", \%param);
475    }
476    foreach (@$dbmod) {
477        if ($_->{module} eq 'DBD::mysql') {
478            $_->{id} = 'mysql';
479        } elsif ($_->{module} eq 'DBD::Pg') {
480            $_->{id} = 'postgres';
481        } elsif ($_->{module} eq 'DBD::Oracle') {
482            $_->{id} = 'oracle';
483        } elsif ($_->{module} eq 'DBD::ODBC1.13') {
484            $_->{id} = 'mssqlserver';
485        } elsif ($_->{module} eq 'DBD::ODBC1.14') {
486            $_->{id} = 'umssqlserver';
487        } elsif ($_->{module} eq 'DBD::SQLite') {
488            $_->{id} = 'sqlite';
489        } elsif ($_->{module} eq 'DBD::SQLite2') {
490            $_->{id} = 'sqlite2';
491        }
492        if ($param{dbtype} && ($param{dbtype} eq $_->{id})) {
493            $_->{selected} = 1;
494        }
495    }
496    $param{db_loop} = $dbmod;
497    $param{one_db} = $#$dbmod == 0; # db module is only one or not
498    $param{config} = $app->serialize_config(%param);
499
500    my $ok = 1;
501    my ($err_msg, $err_more);
502    if ($app->param('test')) {
503        # if check successfully and push continue then goto next step
504        $ok = 0;
505        my $dbtype = $param{dbtype};
506        my $driver = $drivers->{$dbtype}{config_package}
507            if exists $drivers->{$dbtype};
508        $param{dbserver_null} = 1 unless $param{dbserver};
509
510        if ($driver) {
511            my $cfg = $app->config;
512            $cfg->ObjectDriver($driver);
513            $cfg->Database($param{dbname}) if $param{dbname};
514            $cfg->DBUser($param{dbuser}) if $param{dbuser};
515            $cfg->DBPassword($param{dbpass}) if $param{dbpass};
516            $cfg->DBPort($param{dbport}) if $param{dbport};
517            $cfg->DBSocket($param{dbsocket}) if $param{dbsocket};
518            $cfg->DBHost($param{dbserver}) 
519              if $param{dbserver} && ( $param{dbtype} ne 'oracle' );
520            $cfg->PublishCharset($param{publish_charset})
521                if $param{publish_charset};
522            if ($dbtype eq 'sqlite' || $dbtype eq 'sqlite2') {
523                require File::Spec;
524                my $db_file = $param{dbpath};
525                if (!File::Spec->file_name_is_absolute($db_file)) {
526                    $db_file = File::Spec->catfile($app->{mt_dir}, $db_file);
527                }
528                $cfg->Database($db_file) if  $db_file;
529                $param{dbpath} = $db_file if  $db_file;
530                if ($dbtype eq 'sqlite2') {
531                    $cfg->UseSQLite2(1);
532                }
533            }
534            # test loading of object driver with these parameters...
535            require MT::ObjectDriverFactory;
536            my $od = MT::ObjectDriverFactory->new($driver);
537            eval { $od->rw_handle; }; ## to test connection
538            if (my $err = $@) {
539                $err_msg = $app->translate('An error occurred while attempting to connect to the database.  Check the settings and try again.');
540                $err_more = $err;
541            } else {
542                $ok = 1;
543            }
544        }
545        if ($ok) {
546            $param{success} = 1;
547            return $app->build_page("configure.tmpl", \%param);
548        }
549        $param{connect_error} = 1;
550        $param{error} = $err_msg;
551        $param{error_more} = $err_more;
552    }
553
554    $app->build_page("configure.tmpl", \%param);
555}
556
557my @Sendmail = qw( /usr/lib/sendmail /usr/sbin/sendmail /usr/ucblib/sendmail );
558
559sub cfg_dir_conditions {
560    my $app = shift;
561    my ($param) = @_;
562    if ($^O ne 'MSWin32') {
563        # check for writable temp directory
564        if (-w "/tmp") {
565            return 0;
566        }
567    }
568    return 1;
569}
570
571sub cfg_dir {
572    my $app = shift;
573    my %param = @_;
574
575    $param{set_static_uri_to} = $app->param('set_static_uri_to');
576
577    # set static web path
578    $app->config->set('StaticWebPath', $param{set_static_uri_to});
579
580    $param{config} = $app->serialize_config(%param);
581
582    my $temp_dir;
583    if ($app->param('test')) {
584        $param{changed} = 1;
585        if ($param{temp_dir}) {
586            $temp_dir = $param{temp_dir};
587        } else {
588            $param{invalid_error} = 1;
589        }
590    } else {
591        if ($param{temp_dir}) {
592            $temp_dir = $param{temp_dir};
593            $param{changed} = 1;
594        } else {
595            $temp_dir = $app->config->TempDir;
596            if (!-d $temp_dir) {
597                if ($^O eq 'MSWin32') {
598                    $temp_dir = 'C:\Windows\Temp';
599                }
600            }
601            $param{temp_dir} = $temp_dir;
602        }
603    }
604
605    # check temp dir
606    if ($temp_dir) {
607        if (!-d $temp_dir) {
608            $param{not_found_error} = 1;
609        } elsif (!-w $temp_dir) {
610            $param{not_write_error} = 1;
611        } else {
612            $param{success} = 1;
613        }
614    }
615
616    $app->build_page("cfg_dir.tmpl", \%param);
617}
618
619sub optional {
620    my $app = shift;
621    my %param = @_;
622
623    $param{set_static_uri_to} = $app->param('set_static_uri_to');
624
625    # set static web path
626    $app->config->set('StaticWebPath', $param{set_static_uri_to});
627
628    # discover sendmail
629    my $mgr = $app->config;
630    my $sm_loc;
631    for my $loc ($param{sendmail_path}, @Sendmail) {
632        next unless $loc;
633        $sm_loc = $loc, last if -x $loc && !-d $loc;
634    }
635    $param{sendmail_path} = $sm_loc || '';
636
637    my $transfer;
638    push @$transfer, {id => 'smtp', name => $app->translate('SMTP Server')};
639    push @$transfer, {id => 'sendmail', name => $app->translate('Sendmail')};
640
641    foreach(@$transfer){
642        if ($_->{id} eq $param{mail_transfer}) {
643            $_->{selected} = 1;
644        }
645    }
646
647    $param{'use_'.$param{mail_transfer}} = 1;
648    $param{mail_loop} = $transfer;
649    $param{config} = $app->serialize_config(%param);
650
651    my $ok = 1;
652    my $err_msg;
653    if ($app->param('test')) {
654        $ok = 0;
655        if ($param{test_mail_address}){
656            my $cfg = $app->config;
657            $cfg->MailTransfer($param{mail_transfer}) if $param{mail_transfer};
658            $cfg->SMTPServer($param{smtp_server}) if $param{mail_transfer} && ($param{mail_transfer} eq 'smtp') && $param{smtp_server};
659            $cfg->SendMailPath($param{sendmail_path}) if $param{mail_transfer} && ($param{mail_transfer} eq 'sendmail') && $param{sendmail_path};
660            my %head = (id => 'wizard_test',
661                        To => $param{test_mail_address},
662                        From => $cfg->EmailAddressMain || $param{test_mail_address},
663                        Subject => $app->translate("Test email from Movable Type Configuration Wizard") );
664            my $charset = $cfg->MailEncoding || $cfg->PublishCharset;
665            $head{'Content-Type'} = qq(text/plain; charset="$charset");
666
667            my $body = $app->translate("This is the test email sent by your new installation of Movable Type.");
668
669            require MT::Mail;
670            $ok = MT::Mail->send(\%head, $body);
671
672            if ($ok){
673                $param{success} = 1;
674                return $app->build_page("optional.tmpl", \%param);
675            }else{
676                $err_msg = MT::Mail->errstr;
677            }
678        }
679       
680        $param{send_error} = 1;
681        $param{error} = $err_msg;
682    }
683    $app->build_page("optional.tmpl", \%param);
684}
685
686sub seed {
687    my $app = shift;
688    my %param = @_;
689
690    # input data unserialize to config
691    unless (keys(%param)) {
692        $param{config} = $app->param('config');
693    }else{
694        $param{config} = $app->serialize_config(%param);
695    }
696
697    $param{static_file_path} = $param{set_static_file_to};
698
699    require URI;
700    my $uri = URI->new($app->cgipath);
701    $param{cgi_path} = $uri->path;
702    $uri = URI->new($app->param->param('set_static_uri_to'));
703    $param{static_web_path} = $uri->path;
704    $param{static_uri} = $uri->path;
705    my $drivers = $app->object_drivers;
706
707    my $r_uri = $ENV{REQUEST_URI} || $ENV{SCRIPT_NAME};
708    if ($ENV{MOD_PERL} || (($r_uri =~ m/\/mt-wizard\.(\w+)(\?.*)?$/) && ($1 ne 'cgi'))) {
709        my $new = '';
710        if ($ENV{MOD_PERL}) {
711            $param{mod_perl} = 1;
712        } else {
713            $new = '.' . $1;
714        }
715        my @scripts;
716        my $cfg = $app->config;
717        my @cfg_keys = grep { /Script$/ } keys %{ $cfg->{__settings} };
718        $param{mt_script} = $app->config->AdminScript;
719        foreach my $key (@cfg_keys) {
720            my $path = $cfg->get($key);
721            $path =~ s/\.cgi$/$new/;
722            if (-e File::Spec->catfile($app->{mt_dir}, $path)) {
723                $param{mt_script} = $path if $key eq 'AdminScript';
724                push @scripts, { name => $key, path => $path };
725            }
726        }
727        if (@scripts) {
728            $param{script_loop} = \@scripts if @scripts;
729            $param{non_cgi_suffix} = 1;
730        }
731    } else {
732        $param{mt_script} = $app->config->AdminScript;
733    }
734
735    # unserialize database configuration
736    if (my $dbtype = $param{dbtype}) {
737        if ($dbtype eq 'sqlite') {
738            $param{use_dbms} = 1;
739            $param{object_driver} = 'DBI::sqlite';
740            $param{database_name} = $param{dbpath};
741        } elsif ($dbtype eq 'sqlite2') {
742            $param{use_dbms} = 1;
743            $param{use_sqlite2} = 1;
744            $param{object_driver} = 'DBI::sqlite';
745            $param{database_name} = $param{dbpath};
746        } else {
747            $param{use_dbms} = 1;
748            $param{object_driver} = $drivers->{$dbtype}{config_package};
749            $param{database_name} = $param{dbname};
750            $param{database_username} = $param{dbuser};
751            $param{database_password} = $param{dbpass} if $param{dbpass};
752            $param{database_host} = $param{dbserver}
753                if ($dbtype ne 'oracle') && $param{dbserver};
754            $param{database_port} = $param{dbport} if $param{dbport};
755            $param{database_socket} = $param{dbsocket} if $param{dbsocket};
756            $param{use_setnames} =  $param{setnames} if $param{setnames};
757            $param{publish_charset} =  $param{publish_charset}
758                if $param{publish_charset};
759        }
760    }
761
762    if ($param{temp_dir} eq $app->config->TempDir) {
763        $param{temp_dir} = '';
764    }
765
766    # authentication configuration
767    $param{help_url} = $app->help_url();
768
769    my $tmpls = $app->registry("wizard_template") || [];
770
771    my @tmpl_loop;
772    require MT::Template;
773    foreach my $code (@$tmpls) {
774        if ($code = $app->handler_to_coderef($code)) {
775            push @tmpl_loop, { tmpl_code => $code };
776        }
777    }
778
779    $param{tmpl_loop} = \@tmpl_loop;
780
781    my $data = $app->build_page("mt-config.tmpl", \%param);
782
783    my $cfg_file = File::Spec->catfile($app->{mt_dir}, 'mt-config.cgi');
784    if (!-f $cfg_file) {
785        # write!
786        if (open OUT, ">$cfg_file") {
787            print OUT $data;
788            close OUT;
789        }
790        $param{config_created} = 1 if -f $cfg_file;
791        $param{config_file} = $cfg_file;
792        if ((!-f $cfg_file) && $app->param->param('manually')) {
793            $param{file_not_found} = 1;
794            $param{manually} = 1;
795        }
796    } elsif($app->param->param('manually')) {
797        $param{config_created} = 1 if -f $cfg_file;
798        $param{config_file} = $cfg_file;
799    }
800
801    # back to the complete screen
802    return $app->build_page("complete.tmpl", \%param);
803}
804
805sub serialize_config {
806    my $app = shift;
807    my %param = @_;
808 
809    require MT::Serialize;
810    my $ser = MT::Serialize->new('MT');
811    my $keys = $app->config_keys();
812    my %set;
813    foreach my $key (keys %$keys) {
814        foreach my $p (@{$keys->{$key}}) {
815            $set{$p} = $param{$p};
816        }
817    }
818    my $set = \%set;
819    unpack 'H*', $ser->serialize(\$set);
820}
821
822sub unserialize_config {
823    my $app = shift;
824    my $data = $app->param('config');
825    my %config;
826    if ($data) {
827        $data = pack 'H*', $data;
828        require MT::Serialize;
829        my $ser = MT::Serialize->new('MT');
830        my $thawed = $ser->unserialize($data);
831        if ($thawed) {
832            my $saved_cfg = $$thawed;
833            if (keys %$saved_cfg) {
834                foreach my $p (keys %$saved_cfg) {
835                    $config{$p} = $saved_cfg->{$p};
836                }
837            }
838        }
839    }
840    %config;
841}
842
843sub cgipath {
844    my $app = shift;
845
846    # these work for Apache... need to test for IIS...
847    my $host = $ENV{SERVER_NAME} || $ENV{HTTP_HOST};
848    $host =~ s/:\d+//; # eliminate any port that may be present
849    my $port = $ENV{SERVER_PORT};
850    # REQUEST_URI for CGI-compliant servers; SCRIPT_NAME for IIS.
851    my $uri = $ENV{REQUEST_URI} || $ENV{SCRIPT_NAME};
852    $uri =~ s!/mt-wizard(\.f?cgi|\.f?pl)(\?.*)?$!/!;
853
854    my $cgipath = '';
855    $cgipath = $port == 443 ? 'https' : 'http';
856    $cgipath .= '://' . $host;
857    $cgipath .= ($port == 443 || $port == 80) ? '' : ':' . $port;
858    $cgipath .= $uri;
859
860    $cgipath;
861}
862
863sub module_check {
864    my $self = shift;
865    my $modules = shift;
866    my (@missing, @ok);
867    foreach my $ref (@$modules) {
868        my($mod, $ver, $req, $desc, $name, $link) = @$ref;
869        eval("use $mod" . ($ver ? " $ver;" : ";"));
870        $mod .= $ver if $mod eq 'DBD::ODBC';
871        if ($@) {
872            push @missing, { module => $mod,
873                             version => $ver,
874                             required => $req,
875                             description => $desc,
876                             label => $name,
877                             link => $link };
878        } else {
879            push @ok, { module => $mod,
880                        version => $ver,
881                        required => $req,
882                        description => $desc,
883                        label => $name,
884                        link => $link };
885        }
886    }
887    (\@missing, \@ok);
888}
889
890sub static_path {
891    my $app = shift;
892    my $static_path = '';
893
894    if ($app->config->StaticWebPath ne '') {
895        $static_path = $app->config->StaticWebPath;
896        $static_path .= '/' unless $static_path =~ m!/$!;
897        return $static_path;
898    }
899    return $app->mt_static_exists ? $app->cgipath.'mt-static/' : '';
900}
901
902sub mt_static_exists {
903    my $app = shift;
904    return (-f File::Spec->catfile($app->{mt_dir}, "mt-static", "mt.js")) ? 1 : 0;
905}
906
907sub is_valid_static_path {
908    my $app = shift;
909    my ($static_uri) = @_;
910
911    my $path;
912    if ($static_uri =~ m/^http/i) {
913        $path = $static_uri . 'mt.js';
914    } elsif($static_uri =~ m#^/#) {
915        my $host = $ENV{SERVER_NAME} || $ENV{HTTP_HOST};
916        $host =~ s/:\d+//; # eliminate any port that may be present
917        my $port = $ENV{SERVER_PORT};
918        $path = $port == 443 ? 'https' : 'http';
919        $path .= '://' . $host;
920        $path .= ($port == 443 || $port == 80) ? '' : ':' . $port;
921        $path .= $static_uri . 'mt.js';
922    }
923    else {
924        $path = $app->cgipath . $static_uri . 'mt.js';
925    }
926
927    require LWP::UserAgent;
928    my $ua = LWP::UserAgent->new;
929    my $request = HTTP::Request->new(GET => $path);
930    my $response = $ua->request($request);
931    $response->is_success and ($response->content_length() != 0) && ($response->content =~ m/function\s+openManual/s);
932}
9331;
934__END__
935
936=head1 NAME
937
938MT::App::Wizard
939
940=head1 METHODS
941
942TODO
943
944=head1 AUTHOR & COPYRIGHT
945
946Please see L<MT/AUTHOR & COPYRIGHT>.
947
948=cut
Note: See TracBrowser for help on using the browser.