Merge branch 'master' of https://github.com/jgoodman/Freeside
[freeside.git] / rt / lib / RT / Installer.pm
1 # BEGIN BPS TAGGED BLOCK {{{
2 #
3 # COPYRIGHT:
4 #
5 # This software is Copyright (c) 1996-2014 Best Practical Solutions, LLC
6 #                                          <sales@bestpractical.com>
7 #
8 # (Except where explicitly superseded by other copyright notices)
9 #
10 #
11 # LICENSE:
12 #
13 # This work is made available to you under the terms of Version 2 of
14 # the GNU General Public License. A copy of that license should have
15 # been provided with this software, but in any event can be snarfed
16 # from www.gnu.org.
17 #
18 # This work is distributed in the hope that it will be useful, but
19 # WITHOUT ANY WARRANTY; without even the implied warranty of
20 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21 # General Public License for more details.
22 #
23 # You should have received a copy of the GNU General Public License
24 # along with this program; if not, write to the Free Software
25 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26 # 02110-1301 or visit their web page on the internet at
27 # http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
28 #
29 #
30 # CONTRIBUTION SUBMISSION POLICY:
31 #
32 # (The following paragraph is not intended to limit the rights granted
33 # to you to modify and distribute this software under the terms of
34 # the GNU General Public License and is only of importance to you if
35 # you choose to contribute your changes and enhancements to the
36 # community by submitting them to Best Practical Solutions, LLC.)
37 #
38 # By intentionally submitting any modifications, corrections or
39 # derivatives to this work, or any other work intended for use with
40 # Request Tracker, to Best Practical Solutions, LLC, you confirm that
41 # you are the copyright holder for those contributions and you grant
42 # Best Practical Solutions,  LLC a nonexclusive, worldwide, irrevocable,
43 # royalty-free, perpetual, license to use, copy, create derivative
44 # works based on those contributions, and sublicense and distribute
45 # those contributions and any derivatives thereof.
46 #
47 # END BPS TAGGED BLOCK }}}
48
49 package RT::Installer;
50 use strict;
51 use warnings;
52
53 use DateTime;
54
55 require UNIVERSAL::require;
56 my %Meta = (
57     DatabaseType => {
58         Widget          => '/Widgets/Form/Select',
59         WidgetArguments => {
60             Description => 'Database type',    # loc
61             Values      => [
62                 grep {
63                     my $m = 'DBD::' . $_;
64                     $m->require ? 1 : 0
65                   } qw/mysql Pg SQLite Oracle/
66             ],
67             ValuesLabel => {
68                 mysql  => 'MySQL',             #loc
69                 Pg     => 'PostgreSQL',        #loc
70                 SQLite => 'SQLite',            #loc
71                 Oracle => 'Oracle',            #loc
72             },
73         },
74     },
75     DatabaseHost => {
76         Widget          => '/Widgets/Form/String',
77         WidgetArguments => {
78             Description => 'Database host', #loc
79             Default => 1,
80             DefaultLabel => "Keep 'localhost' if you're not sure. Leave blank to connect locally over a socket", #loc
81             Hints => "The domain name of your database server (like 'db.example.com').",       #loc
82         },
83     },
84     DatabasePort => {
85         Widget          => '/Widgets/Form/Integer',
86         WidgetArguments => {
87             Description => 'Database port',         #loc
88             Default     => 1,
89             DefaultLabel =>
90               'Leave empty to use the default value for your database',              #loc
91         },
92     },
93     DatabaseName => {
94         Widget          => '/Widgets/Form/String',
95         WidgetArguments => {
96             Description => 'Database name',                       #loc
97         },
98     },
99     DatabaseAdmin => {
100         SkipWrite       => 1,
101         Widget          => '/Widgets/Form/String',
102         WidgetArguments => {
103             Default => 1,
104             Hints => "Leave this alone to use the default dba username for your database type", #loc
105             Description => 'DBA username', # loc
106             DefaultLabel => '',
107         },
108     },
109     DatabaseAdminPassword => {
110         SkipWrite       => 1,
111         Widget          => '/Widgets/Form/String',
112         WidgetArguments => {
113             Description => 'DBA password',  #loc
114             DefaultLabel => "The DBA's database password",#loc
115             Type => 'password',
116             Hints => "You must provide the dba's password so we can create the RT database and user.",
117         },
118     },
119     DatabaseUser => {
120         Widget          => '/Widgets/Form/String',
121         WidgetArguments => {
122             Description => 'Database username for RT',                      #loc
123             Hints => 'RT will connect to the database using this user.  It will be created for you.', #loc
124         },
125     },
126     DatabasePassword => {
127         Widget          => '/Widgets/Form/String',
128         WidgetArguments => {
129             Description => 'Database password for RT',                      #loc
130             Type        => 'password',
131             Hints       => 'The password RT should use to connect to the database.',
132         },
133     },
134     DatabaseRequireSSL => {
135         Widget          => '/Widgets/Form/Boolean',
136         WidgetArguments => {
137             Description => 'Use SSL?',    # loc
138         },
139     },
140     rtname => {
141         Widget          => '/Widgets/Form/String',
142         WidgetArguments => {
143             Description => 'Site name',                        #loc
144             Hints => 'RT will use this string to uniquely identify your installation and looks for it in the subject of emails to decide what ticket a message applies to.  We recommend that you set this to your internet domain. (ex: example.com)' #loc
145         },
146     },
147     MinimumPasswordLength => {
148         Widget          => '/Widgets/Form/Integer',
149         WidgetArguments => {
150             Description => 'Minimum password length',    #loc
151         },
152     },
153     Password => {
154         SkipWrite       => 1,
155         Widget          => '/Widgets/Form/String',
156         WidgetArguments => {
157             Description => 'Administrative password', #loc
158             Hints => 'RT will create a user called "root" and set this as their password', #loc
159             Type => 'password',
160         },
161     },
162     OwnerEmail => {
163         Widget          => '/Widgets/Form/String',
164         WidgetArguments => {
165             Description => 'RT Administrator Email',                   #loc
166             Hints => "When RT can't handle an email message, where should it be forwarded?", #loc
167         },
168     },
169     CommentAddress => {
170         Widget          => '/Widgets/Form/String',
171         WidgetArguments => {
172             Description => 'Comment address',                           #loc
173             Hints =>
174 'the default addresses that will be listed in From: and Reply-To: headers of comment mail.' #loc
175         },
176     },
177     CorrespondAddress => {
178         Widget          => '/Widgets/Form/String',
179         WidgetArguments => {
180             Description => 'Correspond address',    #loc
181             Hints =>
182 'the default addresses that will be listed in From: and Reply-To: headers of correspondence mail.' #loc
183         },
184     },
185     SendmailPath => {
186         Widget          => '/Widgets/Form/String',
187         WidgetArguments => {
188             Hints => 'Where to find your sendmail binary.',    #loc
189             Description => 'Path to sendmail', #loc
190         },
191     },
192     Timezone => {
193         Widget          => '/Widgets/Form/Select',
194         WidgetArguments => {
195             Description => 'Timezone',                              #loc
196             Callback    => sub {
197                 my $ret;
198                 $ret->{Values} = ['', DateTime::TimeZone->all_names];
199
200                 my $dt = DateTime->now;
201                 for my $tz ( DateTime::TimeZone->all_names ) {
202                     $dt->set_time_zone( $tz );
203                     $ret->{ValuesLabel}{$tz} =
204                         $tz . ' ' . $dt->strftime('%z');
205                 }
206                 $ret->{ValuesLabel}{''} = 'System Default'; #loc
207
208                 return $ret;
209             },
210         },
211     },
212     WebDomain => {
213         Widget          => '/Widgets/Form/String',
214         WidgetArguments => {
215             Description => 'Domain name',                  #loc
216             Hints => "Don't include http://, just something like 'localhost', 'rt.example.com'", #loc
217         },
218     },
219     WebPort => {
220         Widget          => '/Widgets/Form/Integer',
221         WidgetArguments => {
222             Description => 'Web port',                     #loc
223             Hints => 'which port your web server will listen to, e.g. 8080', #loc
224         },
225     },
226
227 );
228
229 sub Meta {
230     my $class = shift;
231     my $type  = shift;
232     return $Meta{$type} if $type;
233     return \%Meta;
234 }
235
236 sub CurrentValue {
237     my $class = shift;
238     my $type  = shift;
239     $type = $class if !ref $class && $class && $class ne 'RT::Installer';
240
241     return undef unless $type;
242     return $RT::Installer
243       && exists $RT::Installer->{InstallConfig}{$type}
244       ? $RT::Installer->{InstallConfig}{$type}
245       : scalar RT->Config->Get($type);
246 }
247
248 sub CurrentValues {
249     my $class = shift;
250     my @types = @_;
251     push @types, $class if !ref $class && $class && $class ne 'RT::Installer';
252
253     return { map { $_ => CurrentValue($_) } @types };
254 }
255
256 sub ConfigFile {
257     require File::Spec;
258     return $ENV{RT_SITE_CONFIG} || File::Spec->catfile( $RT::EtcPath, 'RT_SiteConfig.pm' );
259 }
260
261 sub SaveConfig {
262     my $class = shift;
263
264     my $file = $class->ConfigFile;
265
266     my $content;
267
268     {
269         local $/;
270         open( my $fh, '<', $file ) or die $!;
271         $content = <$fh>;
272         $content =~ s/^\s*1;\s*$//m;
273     }
274
275     # make organization the same as rtname
276     $RT::Installer->{InstallConfig}{Organization} =
277       $RT::Installer->{InstallConfig}{rtname};
278
279     if ( open my $fh, '>', $file ) {
280         for ( sort keys %{ $RT::Installer->{InstallConfig} } ) {
281
282             # we don't want to store root's password in config.
283             next if $class->Meta($_) and $class->Meta($_)->{SkipWrite};
284
285             $RT::Installer->{InstallConfig}{$_} = ''
286               unless defined $RT::Installer->{InstallConfig}{$_};
287
288             # remove obsolete settings we'll add later
289             $content =~ s/^\s* Set \s* \( \s* \$$_ .*$//xm;
290
291             $content .= "Set( \$$_, '$RT::Installer->{InstallConfig}{$_}' );\n";
292         }
293         $content .= "1;\n";
294         print $fh $content;
295         close $fh;
296
297         return ( 1, "Successfully saved configuration to $file." );
298     }
299
300     return ( 0, "Cannot save configuration to $file: $!" );
301 }
302
303 =head1 NAME
304
305     RT::Installer - RT's Installer
306
307 =head1 SYNOPSYS
308
309     use RT::Installer;
310     my $meta = RT::Installer->Meta;
311
312 =head1 DESCRIPTION
313
314 C<RT::Installer> class provides access to RT Installer Meta
315
316 =cut
317
318 RT::Base->_ImportOverlays();
319
320 1;
321