root/branches/release-33/lib/MT/CMS/Blog.pm @ 1778

Revision 1778, 76.4 kB (checked in by bchoate, 20 months ago)

Changes to update type-based touches prior to any rebuilding. Added 'pre_build', 'post_build' callbacks that wrap entire build process (pre_build is called at start of multi-request build process; post_build is called at the end). Added a total publish time message at end of build process. BugId:74814

  • Property svn:keywords set to Id Revision
Line 
1package MT::CMS::Blog;
2
3use strict;
4
5sub edit {
6    my $cb = shift;
7    my ($app, $id, $obj, $param) = @_;
8
9    my $q = $app->param;
10    my $cfg = $app->config;
11    my $blog = $app->blog;
12    my $blog_id = $id;
13
14    if ($id) {
15        require MT::IPBanList;
16        my $output = $param->{output} ||= 'cfg_prefs.tmpl';
17        $param->{need_full_rebuild}  = 1 if $q->param('need_full_rebuild');
18        $param->{need_index_rebuild} = 1 if $q->param('need_index_rebuild');
19        $param->{show_ip_info} = $cfg->ShowIPInformation;
20        $param->{use_plugins} = $cfg->UsePlugins;
21
22        my $entries_on_index = ( $obj->entries_on_index || 0 );
23        if ($entries_on_index) {
24            $param->{'list_on_index'} = $entries_on_index;
25            $param->{'posts'}         = 1;
26        }
27        else {
28            $param->{'list_on_index'} = ( $obj->days_on_index || 0 );
29            $param->{'days'} = 1;
30        }
31        my $lang = $obj->language || 'en';
32        $lang = 'en' if lc($lang) eq 'en-us' || lc($lang) eq 'en_us';
33        $lang = 'ja' if lc($lang) eq 'jp';
34        $param->{ 'language_' . $lang } = 1;
35
36        $param->{system_allow_comments} = $cfg->AllowComments;
37        $param->{system_allow_pings}    = $cfg->AllowPings;
38        $param->{tk_available}          = eval { require MIME::Base64; 1; }
39          && eval { require LWP::UserAgent; 1 };
40        $param->{'auto_approve_commenters'} =
41          !$obj->manual_approve_commenters;
42        $param->{identity_system}     = $app->config('IdentitySystem');
43        $param->{handshake_return}    = $app->base . $app->mt_uri;
44        $param->{"moderate_comments"} = $obj->moderate_unreg_comments;
45        $param->{ "moderate_comments_"
46              . ( $obj->moderate_unreg_comments || 0 ) } = 1;
47        $param->{ "moderate_pings_" . ( $obj->moderate_pings || 0 ) } = 1;
48
49        my $cmtauth_reg = $app->registry('commenter_authenticators');
50        foreach my $auth ( keys %$cmtauth_reg ) {
51            $cmtauth_reg->{$auth}->{disabled} = 1
52              if exists( $cmtauth_reg->{$auth}->{condition} )
53              && !( $cmtauth_reg->{$auth}->{condition}->() );
54        }
55        if ( my $auths = $blog->commenter_authenticators ) {
56            foreach ( split ',', $auths ) {
57                if ( 'MovableType' eq $_ ) {
58                    $param->{enabled_MovableType} = 1;
59                }
60                else {
61                    $cmtauth_reg->{$_}->{enabled} = 1;
62                }
63            }
64        }
65        my @cmtauth_loop;
66        foreach ( keys %$cmtauth_reg ) {
67            $cmtauth_reg->{$_}->{key} = $_;
68            if (
69                UNIVERSAL::isa(
70                    $cmtauth_reg->{$_}->{plugin}, 'MT::Plugin'
71                )
72              )
73            {
74                push @cmtauth_loop, $cmtauth_reg->{$_};
75            }
76        }
77        unshift @cmtauth_loop, $cmtauth_reg->{'TypeKey'}
78          if exists( $cmtauth_reg->{'TypeKey'} )
79          && $blog->remote_auth_token;
80        unshift @cmtauth_loop, $cmtauth_reg->{'Vox'}
81          if exists $cmtauth_reg->{'Vox'};
82        unshift @cmtauth_loop, $cmtauth_reg->{'LiveJournal'}
83          if exists $cmtauth_reg->{'LiveJournal'};
84        unshift @cmtauth_loop, $cmtauth_reg->{'OpenID'}
85          if exists $cmtauth_reg->{'OpenID'};
86
87        $param->{cmtauth_loop} = \@cmtauth_loop;
88
89        if ( $output eq 'cfg_prefs.tmpl' ) {
90            $app->add_breadcrumb( $app->translate('General Settings') );
91
92            my $lang = $obj->language || 'en';
93            $lang = 'en' if lc($lang) eq 'en-us' || lc($lang) eq 'en_us';
94            $lang = 'ja' if lc($lang) eq 'jp';
95            $param->{ 'language_' . $lang } = 1;
96
97            if ( $obj->cc_license ) {
98                $param->{cc_license_name} =
99                  MT::Util::cc_name( $obj->cc_license );
100                $param->{cc_license_image_url} =
101                  MT::Util::cc_image( $obj->cc_license );
102                $param->{cc_license_url} =
103                  MT::Util::cc_url( $obj->cc_license );
104            }
105        }
106        elsif ( $output eq 'cfg_entry.tmpl' ) {
107            ## load entry preferences for new/edit entry page of the blog
108            my $pref_param = $app->load_entry_prefs;
109            %$param = ( %$param, %$pref_param );
110            $param->{ 'sort_order_posts_'
111                  . ( $obj->sort_order_posts || 0 ) } = 1;
112            $param->{ 'status_default_' . $obj->status_default } = 1
113              if $obj->status_default;
114            $param->{ 'allow_comments_default_'
115                  . ( $obj->allow_comments_default || 0 ) } = 1;
116            $param->{system_allow_pings} =
117              $cfg->AllowPings && $blog->allow_pings;
118            $param->{system_allow_comments} = $cfg->AllowComments
119              && ( $blog->allow_reg_comments
120                || $blog->allow_unreg_comments );
121            my $replace_fields = $blog->smart_replace_fields || '';
122            my @replace_fields = split( /,/, $replace_fields );
123            foreach my $fld (@replace_fields) {
124                $param->{ 'nwc_' . $fld } = 1;
125            }
126            $param->{ 'nwc_smart_replace_' . ( $blog->smart_replace || 0 ) } = 1;
127            $param->{ 'nwc_replace_none' } = ( $blog->smart_replace || 0 ) == 2;
128        }
129        elsif ( $output eq 'cfg_web_services.tmpl' ) {
130            $param->{system_disabled_notify_pings} =
131              $cfg->DisableNotificationPings;
132            $param->{system_allow_outbound_pings} =
133              $cfg->OutboundTrackbackLimit eq 'any';
134            my %selected_pings = map { $_ => 1 }
135              split ',', ($obj->update_pings || '');
136            my $pings = $app->registry('ping_servers');
137            my @pings;
138            push @pings,
139              {
140                key   => $_,
141                label => $pings->{$_}->{label},
142                exists( $selected_pings{$_} ) ? ( selected => 1 ) : (),
143              } foreach keys %$pings;
144            $param->{pings_loop} = \@pings;
145        }
146        elsif ( $output eq 'cfg_comments.tmpl' ) {
147            $param->{email_new_comments_1} =
148              ( $obj->email_new_comments || 0 ) == 1;
149            $param->{email_new_comments_2} =
150              ( $obj->email_new_comments || 0 ) == 2;
151            $param->{nofollow_urls}     = $obj->nofollow_urls;
152            $param->{follow_auth_links} = $obj->follow_auth_links;
153            $param->{ 'sort_order_comments_'
154                  . ( $obj->sort_order_comments || 0 ) } = 1;
155            $param->{global_sanitize_spec} = $cfg->GlobalSanitizeSpec;
156            $param->{ 'sanitize_spec_' . ( $obj->sanitize_spec ? 1 : 0 ) } =
157              1;
158            $param->{sanitize_spec_manual} = $obj->sanitize_spec
159              if $obj->sanitize_spec;
160            $param->{allow_comments} = $blog->allow_reg_comments
161              || $blog->allow_unreg_comments;
162            $param->{use_comment_confirmation} =
163              defined $blog->use_comment_confirmation
164              ? $blog->use_comment_confirmation
165              : 0;
166            $param->{system_allow_comments} = $cfg->AllowComments
167              && ( $blog->allow_reg_comments
168                || $blog->allow_unreg_comments );
169            my @cps = MT->captcha_providers;
170
171            foreach my $cp (@cps) {
172                if ( ( $blog->captcha_provider || '' ) eq $cp->{key} ) {
173                    $cp->{selected} = 1;
174                }
175            }
176            $param->{captcha_loop} = \@cps;
177        }
178        elsif ( $output eq 'cfg_trackbacks.tmpl' ) {
179            $param->{email_new_pings_1} = ( $obj->email_new_pings || 0 ) == 1;
180            $param->{email_new_pings_2} = ( $obj->email_new_pings || 0 ) == 2;
181            $param->{nofollow_urls}     = $obj->nofollow_urls;
182            $param->{system_allow_selected_pings} =
183              $cfg->OutboundTrackbackLimit eq 'selected';
184            $param->{system_allow_outbound_pings} =
185              $cfg->OutboundTrackbackLimit eq 'any';
186            $param->{system_allow_local_pings} =
187                 ( $cfg->OutboundTrackbackLimit eq 'local' )
188              || ( $cfg->OutboundTrackbackLimit eq 'any' );
189        }
190        elsif ( $output eq 'cfg_registration.tmpl' ) {
191            $param->{commenter_authenticators} =
192              $obj->commenter_authenticators;
193            my $registration = $cfg->CommenterRegistration;
194            if ( $registration->{Allow} ) {
195                $param->{registration} =
196                  $blog->allow_commenter_regist ? 1 : 0;
197            }
198            else {
199                $param->{system_disallow_registration} = 1;
200            }
201            $param->{allow_reg_comments} = $blog->allow_reg_comments;
202            $param->{allow_unreg_comments} = $blog->allow_unreg_comments;
203            $param->{require_typekey_emails} = $obj->require_typekey_emails;
204        }
205        elsif ( $output eq 'cfg_spam.tmpl' ) {
206            my $threshold = $obj->junk_score_threshold || 0;
207            $threshold = '+' . $threshold if $threshold > 0;
208            $param->{junk_score_threshold} = $threshold;
209            $param->{junk_folder_expiry}   = $obj->junk_folder_expiry || 60;
210            $param->{auto_delete_junk}     = $obj->junk_folder_expiry;
211        }
212        elsif ( $output eq 'cfg_archives.tmpl' ) {
213            $app->add_breadcrumb( $app->translate('Publishing Settings') );
214            if (   $obj->column('archive_path')
215                || $obj->column('archive_url') )
216            {
217                $param->{enable_archive_paths} = 1;
218                $param->{archive_path}         = $obj->column('archive_path');
219                $param->{archive_url}          = $obj->column('archive_url');
220            }
221            else {
222                $param->{archive_path} = '';
223                $param->{archive_url}  = '';
224            }
225            $param->{ 'archive_type_preferred_'
226                  . $blog->archive_type_preferred } = 1
227              if $blog->archive_type_preferred;
228            my $at = $blog->archive_type;
229            if ( $at && $at ne 'None' ) {
230                my @at = split /,/, $at;
231                for my $at (@at) {
232                    $param->{ 'archive_type_' . $at } = 1;
233                }
234            }
235            if ( $blog->publish_queue ) {
236                $param->{publish_queue} = 1;
237            }
238            if ( $blog->include_cache ) {
239                $param->{include_cache} = 1;
240            }
241        }
242        elsif ( $output eq 'cfg_plugin.tmpl' ) {
243            $app->add_breadcrumb( $app->translate('Plugin Settings') );
244            $param->{blog_view} = 1;
245            require MT::CMS::Plugin;
246            MT::CMS::Plugin::build_plugin_table( $app,
247                param => $param,
248                scope => 'blog:' . $blog_id
249            );
250            $param->{can_config} = 1;
251        }
252        else {
253            $app->add_breadcrumb( $app->translate('Settings') );
254        }
255        ( my $offset = $obj->server_offset ) =~ s![-\.]!_!g;
256        $offset =~ s!_0+$!!; # fix syntax highlight ->!
257        $param->{ 'server_offset_' . $offset } = 1;
258        if ( $output eq 'cfg_comments.tmpl' ) {
259            ## Load text filters.
260            $param->{text_filters_comments} =
261              $app->load_text_filters( $obj->convert_paras_comments,
262                'comment' );
263        }
264        elsif ( $output eq 'cfg_entry.tmpl' ) {
265            ## Load text filters.
266            $param->{text_filters} =
267              $app->load_text_filters( $obj->convert_paras, 'entry' );
268        }
269        $param->{nav_config} = 1;
270        $param->{error} = $app->errstr if $app->errstr;
271    } else {
272        $app->add_breadcrumb( $app->translate('New Blog') );
273        ( my $tz = $cfg->DefaultTimezone ) =~ s![-\.]!_!g;
274        $tz =~ s!_00$!!; # fix syntax highlight ->!
275        $param->{ 'server_offset_' . $tz } = 1;
276        $param->{'can_edit_config'}        = $app->user->can_create_blog;
277        $param->{'can_set_publish_paths'}  = $app->user->can_create_blog;
278
279        my $sets = $app->registry("template_sets");
280        $sets->{$_}{key} = $_ for keys %$sets;
281        $sets->{'mt_blog'}{selected} = 1;
282        $sets = $app->filter_conditional_list([ values %$sets ]);
283        no warnings;
284        @$sets = sort { $a->{order} <=> $b->{order} } @$sets;
285        $param->{'template_set_loop'} = $sets;
286        $param->{'template_set_index'} = $#$sets;
287    }
288
289    if (   !$param->{site_path}
290        && !( $param->{site_path} = $app->config('DefaultSiteRoot') ) )
291    {
292        my $cwd = $app->document_root;
293        $cwd = File::Spec->catdir($cwd, 'BLOG-NAME'); # for including the end of directory separator
294        $cwd =~ s!BLOG-NAME\z!!;                      # canonpath() remove it
295        $cwd =~ s!([\\/])cgi(?:-bin)?([\\/].*)?$!$1!;
296        $cwd =~ s!([\\/])mt[\\/]?$!$1!i;
297        $param->{suggested_site_path} = $cwd;
298    }
299    if ( !$param->{id} ) {
300        if ( $param->{site_path} ) {
301            $param->{site_path} =
302              File::Spec->catdir( $param->{site_path}, 'BLOG-NAME' );
303        }
304        else {
305            $param->{suggested_site_path} =
306              File::Spec->catdir( $param->{suggested_site_path},
307                'BLOG-NAME' );
308        }
309    }
310
311    # If not yet defined, set the site_url to the config default, if one exists.
312    $param->{site_url} ||= $app->config('DefaultSiteURL');
313    if ( !$param->{site_url} ) {
314        $param->{suggested_site_url} = $app->base . '/';
315        $param->{suggested_site_url} =~ s!/cgi(?:-bin)?(/.*)?$!/!;
316        $param->{suggested_site_url} =~ s!/mt/?$!/!i;
317    }
318    if ( !$param->{id} ) {
319        if ( $param->{site_url} ) {
320            $param->{site_url} .= '/'
321              unless $param->{site_url} =~ /\/$/;
322            $param->{site_url} .= 'BLOG-NAME/';
323        }
324        else {
325            $param->{suggested_site_url} .= '/'
326              unless $param->{suggested_site_url} =~ /\/$/;
327            $param->{suggested_site_url} .= 'BLOG-NAME/';
328        }
329    }
330    1;
331}
332
333sub list {
334    my $app = shift;
335
336    $app->return_to_dashboard( redirect => 1 ) if $app->param('blog_id');
337
338    my $author    = $app->user;
339    my $list_pref = $app->list_pref('blog');
340
341    my $limit  = $list_pref->{rows};
342    my $offset = $app->param('offset') || 0;
343    my $args   = { offset => $offset, sort => 'name' };
344    $args->{limit} = $limit + 1;
345    unless ( $author->is_superuser ) {
346        $args->{join} = MT::Permission->join_on(
347            'blog_id',
348            { author_id => $author->id },
349            { unique    => 1 }
350        );
351    }
352    my $blog_class       = $app->model('blog');
353    my %param            = %$list_pref;
354    my @blogs            = $blog_class->load( undef, $args );
355    my $can_edit_authors = $author->is_superuser;
356    my $blog_loop        = make_blog_list( $app, \@blogs );
357
358    if ($blog_loop) {
359        ## We tried to load $limit + 1 entries above; if we actually got
360        ## $limit + 1 back, we know we have another page of entries.
361        my $have_next = @$blog_loop > $limit;
362        pop @$blog_loop while @$blog_loop > $limit;
363        if ($offset) {
364            $param{prev_offset}     = 1;
365            $param{prev_offset_val} = $offset - $limit;
366            $param{prev_offset_val} = 0 if $param{prev_offset_val} < 0;
367        }
368        if ($have_next) {
369            $param{next_offset}     = 1;
370            $param{next_offset_val} = $offset + $limit;
371        }
372    }
373    $param{offset}      = $offset;
374    $param{object_type} = 'blog';
375    $param{list_start}  = $offset + 1;
376    delete $args->{limit};
377    delete $args->{offset};
378    $param{list_total} = $blog_class->count( undef, $args );
379    $param{list_end}        = $offset + ( $blog_loop ? scalar @$blog_loop : 0 );
380    $param{next_max}        = $param{list_total} - $limit;
381    $param{next_max}        = 0 if ( $param{next_max} || 0 ) < $offset + 1;
382    $param{can_create_blog} = $author->can_create_blog;
383    $param{saved_deleted}   = $app->param('saved_deleted');
384    $param{refreshed}       = $app->param('refreshed');
385    $param{nav_blogs}       = 1;
386    $param{list_noncron}    = 1;
387    $param{search_label}    = $app->translate('Blogs');
388
389    if ($blog_loop) {
390        $param{object_loop} = $param{blog_table}[0]{object_loop} = $blog_loop;
391        $app->load_list_actions( 'blog', \%param );
392    }
393
394    $param{page_actions} = $app->page_actions('list_blog');
395    $param{feed_name}    = $app->translate("Blog Activity Feed");
396    $param{feed_url}     = $app->make_feed_link('blog');
397    $app->add_breadcrumb( $app->translate("Blogs") );
398    $param{nav_weblogs} = 1;
399    $param{object_label} = $blog_class->class_label;
400    $param{object_label_plural} = $blog_class->class_label_plural;
401    $param{screen_class} = "list-blog";
402    $param{screen_id} = "list-blog";
403    $param{listing_screen} = 1;
404    return $app->load_tmpl( 'list_blog.tmpl', \%param );
405}
406
407sub cfg_archives {
408    my $app = shift;
409    my %param;
410    %param = %{ $_[0] } if $_[0];
411    my $q = $app->param;
412
413    my $blog_id = $q->param('blog_id');
414
415    return $app->return_to_dashboard( redirect => 1 ) unless $blog_id;
416
417    my $blog = $app->model('blog')->load($blog_id);
418    my @data;
419    for my $at ( split /\s*,\s*/, $blog->archive_type ) {
420        my $archiver = $app->publisher->archiver($at);
421        next unless $archiver;
422        next if 'entry' ne $archiver->entry_class;
423        my $archive_label = $archiver->archive_label;
424        $archive_label = $at unless $archive_label;
425        $archive_label = $archive_label->() if ( ref $archive_label ) eq 'CODE';
426        push @data,
427          {
428            archive_type_translated => $archive_label,
429            archive_type            => $at,
430            archive_type_is_preferred =>
431              ( $blog->archive_type_preferred eq $at ? 1 : 0 ),
432          };
433    }
434    @data = sort { MT::App::CMS::archive_type_sorter( $a, $b ) } @data;
435    $param{entry_archive_types} = \@data;
436    $param{saved_deleted}       = 1 if $q->param('saved_deleted');
437    $param{saved_added}         = 1 if $q->param('saved_added');
438    $param{archives_changed}    = 1 if $q->param('archives_changed');
439    $param{no_writedir}         = $q->param('no_writedir');
440    $param{no_cachedir}         = $q->param('no_cachedir');
441    $param{no_writecache}       = $q->param('no_writecache');
442    $param{dynamicity}          = $blog->custom_dynamic_templates || 'none';
443    $param{include_system}      = $blog->include_system || '';
444
445    if ( $app->config->ObjectDriver =~ qr/(db[id]::)?sqlite/i ) {
446        $param{hide_build_option} = 1
447          unless $app->config->UseSQLite2;
448    }
449    my $mtview_path = File::Spec->catfile( $blog->site_path(), "mtview.php" );
450
451    if ( -f $mtview_path ) {
452        open my ($fh), $mtview_path;
453        while ( my $line = <$fh> ) {
454            $param{dynamic_caching} = 1
455              if $line =~ m/^\s*\$mt->caching\s*=\s*true;/i;
456            $param{dynamic_conditional} = 1
457              if $line =~ /^\s*\$mt->conditional\s*=\s*true;/i;
458        }
459        close $fh;
460    }
461    $param{output} = 'cfg_archives.tmpl';
462    $q->param( '_type', 'blog' );
463    $q->param( 'id',    $blog_id );
464    $param{screen_class} = "settings-screen archive-settings";
465    $param{object_type}  = 'author';
466    $param{search_label} = $app->translate('Users');
467    $app->forward( "view", \%param );
468}
469
470sub cfg_prefs {
471    my $app     = shift;
472    my $q       = $app->param;
473    my $blog_id = scalar $q->param('blog_id');
474    return $app->return_to_dashboard( redirect => 1 )
475      unless $blog_id;
476    $q->param( '_type', 'blog' );
477    $q->param( 'id',    $blog_id );
478    my $blog_prefs = $app->user_blog_prefs;
479    my $perms      = $app->permissions;
480    return $app->error( $app->translate('Permission denied.') )
481      unless $app->user->is_superuser()
482      || (
483        $perms
484        && (   $perms->can_edit_config
485            || $perms->can_administer_blog
486            || $perms->can_set_publish_paths )
487      );
488    my $output = 'cfg_prefs.tmpl';
489    $app->forward("view",
490        {
491            output       => $output,
492            screen_class => 'settings-screen general-screen'
493        }
494    );
495}
496
497sub cfg_web_services {
498    my $app     = shift;
499    my $q       = $app->param;
500    my $blog_id = scalar $q->param('blog_id');
501    return $app->return_to_dashboard( redirect => 1 )
502      unless $blog_id;
503    $q->param( '_type', 'blog' );
504    $q->param( 'id',    scalar $q->param('blog_id') );
505    $app->forward( "view",
506        {
507            output       => 'cfg_web_services.tmpl',
508            screen_class => 'settings-screen web-services-settings'
509        }
510    );
511}
512
513sub rebuild_phase {
514    my $app  = shift;
515    my $type = $app->param('_type') || 'entry';
516    my @ids  = $app->param('id');
517    $app->{goback} = "window.location='" . $app->return_uri . "'";
518    $app->{value} ||= $app->translate('Go Back');
519    if ( $type eq 'entry' ) {
520        my %ids = map { $_ => 1 } @ids;
521        return $app->rebuild_these( \%ids );
522    }
523    elsif ( $type eq 'template' ) {
524        require MT::Template;
525        foreach (@ids) {
526            my $template = MT::Template->load($_);
527            $app->rebuild_indexes(
528                Template => $template,
529                Force    => 1
530            ) or return;
531        }
532    }
533    $app->run_callbacks('post_build');
534    $app->call_return;
535}
536
537sub rebuild_pages {
538    my $app   = shift;
539    my $perms = $app->permissions
540      or return $app->error( $app->translate("No permissions") );
541    require MT::Entry;
542    require MT::Blog;
543    my $q             = $app->param;
544    my $start_time    = $q->param('start_time');
545
546    if ( ! $start_time ) {
547        # start of build; invoke callback
548        $app->run_callbacks('pre_build');
549        $start_time = time;
550    }
551
552    my $blog_id       = int($q->param('blog_id'));
553    return $app->errtrans("Invalid request.") unless $blog_id;
554
555    my $blog          = MT::Blog->load($blog_id);
556    my $order         = $q->param('type');
557    my @order         = split /,/, $order;
558    my $next          = $q->param('next');
559    my $done          = 0;
560    my $type          = $order[$next];
561    my $archiver      = $app->publisher->archiver($type);
562    my $archive_label = $archiver ? $archiver->archive_label : '';
563
564    $archive_label = $app->translate($type) unless $archive_label;
565    $archive_label = $archive_label->() if ( ref $archive_label ) eq 'CODE';
566    $next++;
567    $done++ if $next >= @order;
568    my $offset = 0;
569    my ($total) = $q->param('total');
570
571    my ($tmpl_saved);
572
573    # Make sure errors go to a sensible place when in fs mode
574    # TODO: create contin. earlier, pass it thru
575    if ( $app->param('fs') ) {
576        my ( $type, $obj_id ) = $app->param('type') =~ m/(entry|index)-(\d+)/;
577        if ( $type && $obj_id ) {
578            my $edit_type = $type;
579            $edit_type = 'template' if $type eq 'index';
580            if ($type eq 'entry') {
581                require MT::Entry;
582                my $entry = MT::Entry->load($obj_id);
583                $edit_type = $entry->class;
584            }
585            $app->{goback} =
586              "window.location='"
587              . $app->object_edit_uri( $edit_type, $obj_id ) . "'";
588            $app->{value} ||= $app->translate('Go Back');
589        }
590    }
591
592    # FIXME: Wrap the entire rebuild operation with begin/end callbacks
593    if ( $type eq 'all' ) {
594        return $app->error( $app->translate("Permission denied.") )
595          unless $perms->can_rebuild;
596
597        # FIXME: Rebuild the entire blog????
598        $app->rebuild( BlogID => $blog_id )
599          or return $app->publish_error();
600    }
601    elsif ( $type eq 'index' ) {
602        return $app->error( $app->translate("Permission denied.") )
603          unless $perms->can_rebuild;
604        $app->rebuild_indexes( BlogID => $blog_id )
605            or return $app->publish_error();
606    }
607    elsif ( $type =~ /^index-(\d+)$/ ) {
608        return $app->error( $app->translate("Permission denied.") )
609          unless $perms->can_rebuild;
610        my $tmpl_id = $1;
611        require MT::Template;
612        $tmpl_saved = MT::Template->load($tmpl_id);
613        $app->rebuild_indexes(
614            BlogID   => $blog_id,
615            Template => $tmpl_saved,
616            Force    => 1
617        ) or return $app->publish_error();
618        $order = $app->translate( "index template '[_1]'", $tmpl_saved->name );
619    }
620    elsif ( $type =~ /^entry-(\d+)$/ ) {
621        my $entry_id = $1;
622        require MT::Entry;
623        my $entry = MT::Entry->load($entry_id);
624        return $app->error( $app->translate("Permission denied.") )
625          unless $perms->can_edit_entry( $entry, $app->user );
626        $app->rebuild_entry(
627            Entry             => $entry,
628            BuildDependencies => 1,
629            OldPrevious       => $q->param('old_previous'),
630            OldNext           => $q->param('old_next')
631        ) or return $app->publish_error();
632        $order = "entry '" . $entry->title . "'";
633    }
634    elsif ( $archiver->category_based ) {
635        return $app->error( $app->translate("Permission denied.") )
636          unless $perms->can_rebuild;
637        $offset = $q->param('offset') || 0;
638        my $start = time;
639        my $count = 0;
640        my $cb    = sub {
641            $count++;
642            return time - $start > 20 ? 0 : 1;
643        };
644        if ( $offset < $total ) {
645            $app->rebuild(
646                BlogID         => $blog_id,
647                ArchiveType    => $type,
648                NoIndexes      => 1,
649                Offset         => $offset,
650                Limit          => $app->config->EntriesPerRebuild,
651                FilterCallback => $cb,
652            ) or return $app->publish_error();
653            $offset += $count;
654        }
655        if ( $offset < $total ) {
656            $done-- if $done;
657            $next--;
658        }
659        else {
660            $offset = 0;
661        }
662    }
663    elsif ($type) {
664        my $special = 0;
665        my @options = $app->{rebuild_options} ||= {};
666        $app->run_callbacks( 'rebuild_options', $app, \@options );
667        for my $optn (@options) {
668            if ( ( $optn->{key} || '' ) eq $type ) {
669                $optn->{code}->();
670                $special = 1;
671            }
672        }
673        if ( !$special ) {
674            return $app->error( $app->translate("Permission denied.") )
675              unless $perms->can_rebuild;
676            $offset = $q->param('offset') || 0;
677            if ( $offset < $total ) {
678                my $start = time;
679                my $count = 0;
680                my $cb    = sub {
681                    $count++;
682                    return time - $start > 20 ? 0 : 1;
683                };
684                $app->rebuild(
685                    BlogID         => $blog_id,
686                    ArchiveType    => $type,
687                    NoIndexes      => 1,
688                    Offset         => $offset,
689                    Limit          => $app->config->EntriesPerRebuild,
690                    FilterCallback => $cb,
691                ) or return $app->publish_error();
692                $offset += $count;
693            }
694            if ( $offset < $total ) {
695                $done-- if $done;
696                $next--;
697            }
698            else {
699                $offset = 0;
700            }
701        }
702    }
703
704    # Rebuild done--now form the continuation.
705    unless ($done) {
706        my $dynamic   = 0;
707        my $type_name = $order[$next];
708
709        ## If we're moving on to the next rebuild step, recalculate the
710        ## limit.
711        my $static_count;
712        if ( $type_name !~ m/^index/ ) {
713            $static_count = $blog->count_static_templates($type_name) || 0;
714        }
715        else {
716            $static_count = 1;
717        }
718        if ( !$static_count ) {
719            $dynamic = 1;
720        }
721        elsif ( defined($offset) && $offset == 0 ) {
722            $dynamic = 0;
723        }
724        if ( $offset == 0 ) {
725
726            # determine total
727            if ( my $archiver = $app->publisher->archiver($type_name) ) {
728                if ( $archiver->entry_based || $archiver->date_based ) {
729                    my $entry_class = $archiver->entry_class || 'entry';
730                    require MT::Entry;
731                    my $terms = {
732                        class   => $entry_class,
733                        status  => MT::Entry::RELEASE(),
734                        blog_id => $blog_id,
735                    };
736                    $total = MT::Entry->count($terms);
737                }
738                elsif ( $archiver->category_based ) {
739                    require MT::Category;
740                    my $terms = { blog_id => $blog_id, };
741                    $total = MT::Category->count($terms);
742                }
743                elsif ( $archiver->author_based ) {
744                    require MT::Author;
745                    require MT::Entry;
746                    my $terms = {
747                        blog_id => $blog_id,
748                        status  => MT::Entry::RELEASE(),
749                        class   => 'entry',
750                    };
751                    $total = MT::Author->count(
752                        undef,
753                        {
754                            join   => MT::Entry->join_on( 'author_id', $terms, { unique => 1 } ),
755                            unique => 1,
756                        }
757                    );
758                }
759            }
760        }
761
762        my $type = $order[$next];
763        if ($type) {
764            $archiver      = $app->publisher->archiver($type);
765            $archive_label = $archiver ? $archiver->archive_label : '';
766            $archive_label = $app->translate($type) unless $archive_label;
767            $archive_label = $archive_label->()
768              if ( ref $archive_label ) eq 'CODE';
769        }
770
771        my $complete =
772          $total
773          ? ( $total == $offset ? 100 : int( ( $offset / $total ) * 100 ) )
774          : 0;
775
776        my %param = (
777            build_type      => $order,
778            build_next      => $next,
779            build_type_name => $archive_label,
780            archives        => $archiver ? 1 : 0,
781            total           => $total,
782            offset          => $offset,
783            complete        => $complete,
784            start_time      => $start_time,
785            incomplete      => 100 - $complete,
786            entry_id        => scalar $q->param('entry_id'),
787            dynamic         => $dynamic,
788            is_new          => scalar $q->param('is_new'),
789            old_status      => scalar $q->param('old_status')
790        );
791        $app->load_tmpl( 'rebuilding.tmpl', \%param );
792    }
793    else {
794        $app->run_callbacks( 'post_build' );
795        if ( $q->param('entry_id') ) {
796            require MT::Entry;
797            my $entry = MT::Entry->load( scalar $q->param('entry_id') );
798            require MT::Blog;
799            my $blog = MT::Blog->load( $entry->blog_id );
800            require MT::CMS::Entry;
801            MT::CMS::Entry::ping_continuation( $app,
802                $entry, $blog,
803                OldStatus => scalar $q->param('old_status'),
804                IsNew     => scalar $q->param('is_new'),
805            );
806        }
807        else {
808            my $all          = $order =~ /,/;
809            my $type         = $order;
810            my $is_one_index = $order =~ /index template/;
811            my $is_entry     = $order =~ /entry/;
812            my $built_type;
813            if ( $is_entry || $is_one_index ) {
814                ( $built_type = $type ) =~
815                  s/^(entry|index template)/$app->translate($1)/e;
816            }
817            else {
818                $built_type = $app->translate($type);
819            }
820            my %param = (
821                all             => $all,
822                type            => $archive_label,
823                is_one_index    => $is_one_index,
824                is_entry        => $is_entry,
825                archives        => $type ne 'index',
826                start_timestamp => MT::Util::epoch2ts($blog, $start_time),
827                total_time      => time - $start_time,
828            );
829            if ($is_one_index) {
830                $param{tmpl_url} = $blog->site_url;
831                $param{tmpl_url} .= '/' if $param{tmpl_url} !~ m!/$!;
832                $param{tmpl_url} .= $tmpl_saved->outfile;
833            }
834            if ( $q->param('fs') ) {    # full screen--go to a useful app page
835                my $type = $q->param('type');
836                $type =~ /index-(\d+)/;
837                my $tmpl_id = $1;
838                $app->run_callbacks( 'rebuild', $blog );
839                return $app->redirect(
840                    $app->uri(
841                        'mode' => 'view',
842                        args   => {
843                            '_type'       => 'template',
844                            id            => $tmpl_id,
845                            blog_id       => $blog->id,
846                            saved_rebuild => 1
847                        }
848                    )
849                );
850            }
851            else {    # popup--just go to cnfrmn. page
852                return $app->load_tmpl( 'popup/rebuilt.tmpl', \%param );
853            }
854        }
855    }
856}
857
858sub rebuild_new_phase {
859    my ($app) = @_;
860    my %reb_set = map { $_ => 1 } $app->param('id');
861    $app->rebuild_these( \%reb_set, how => MT::App::CMS::NEW_PHASE() );
862}
863
864sub start_rebuild_pages {
865    my $app           = shift;
866    my $q             = $app->param;
867    my $start_time    = $q->param('start_time');
868
869    if ( ! $start_time ) {
870        # start of build; invoke callback
871        $app->run_callbacks('pre_build');
872        $start_time = time;
873    }
874
875    my $type          = $q->param('type');
876    my $next          = $q->param('next') || 0;
877    my @order         = split /,/, $type;
878    my $total         = $q->param('total') || 0;
879    my $type_name     = $order[$next];
880    my $archiver      = $app->publisher->archiver($type_name);
881    my $archive_label = $archiver ? $archiver->archive_label : '';
882    $archive_label = $app->translate($type_name) unless $archive_label;
883    $archive_label = $archive_label->() if ( ref $archive_label ) eq 'CODE';
884    my $blog_id = $q->param('blog_id');
885
886    if ($archiver) {
887        if ( $archiver->entry_based || $archiver->date_based ) {
888            my $entry_class = $archiver->entry_class || 'entry';
889            require MT::Entry;
890            my $terms = {
891                class   => $entry_class,
892                status  => MT::Entry::RELEASE(),
893                blog_id => $blog_id,
894            };
895            $total = MT::Entry->count($terms);
896        }
897        elsif ( $archiver->category_based ) {
898            require MT::Category;
899            my $terms = {
900                blog_id => $blog_id,
901                class   => $archiver->category_class,
902            };
903            $total = MT::Category->count($terms);
904        }
905        elsif ( $archiver->author_based ) {
906            require MT::Author;
907            require MT::Entry;
908            my $terms = {
909                blog_id => $blog_id,
910                status  => MT::Entry::RELEASE(),
911                class => 'entry',
912            };
913            $total = MT::Author->count(
914                undef,
915                {
916                    join   => MT::Entry->join_on( 'author_id', $terms, { unique => 1 } ),
917                    unique => 1,
918                }
919            );
920        }
921    }
922
923    my %param = (
924        build_type      => $type,
925        build_next      => $next,
926        total           => $total,
927        start_time      => $start_time,
928        complete        => 0,
929        incomplete      => 100,
930        build_type_name => $archive_label
931    );
932
933    if ( $type_name =~ /^index-(\d+)$/ ) {
934        my $tmpl_id = $1;
935        require MT::Template;
936        my $tmpl = MT::Template->load($tmpl_id);
937        $param{build_type_name} =
938          $app->translate( "index template '[_1]'", $tmpl->name );
939        $param{is_one_index} = 1;
940    }
941    elsif ( $type_name =~ /^entry-(\d+)$/ ) {
942        my $entry_id = $1;
943        require MT::Entry;
944        my $entry = MT::Entry->load($entry_id);
945        $param{build_type_name} =
946          $app->translate( "[_1] '[_2]'", $entry->class_label, $entry->title );
947        $param{is_entry} = 1;
948        $param{entry_id} = $entry_id;
949        for my $col (qw( is_new old_status old_next old_previous )) {
950            $param{$col} = $q->param($col);
951        }
952    }
953    $param{is_full_screen} = ( $param{is_entry} )
954      || $q->param('single_template');
955    $param{page_titles} = [ { bc_name => 'Rebuilding' } ];
956    $app->load_tmpl( 'rebuilding.tmpl', \%param );
957}
958
959sub rebuild_confirm {
960    my $app     = shift;
961    my $blog_id = $app->param('blog_id');
962    require MT::Blog;
963    my $blog = MT::Blog->load($blog_id);
964    my $at = $blog->archive_type || '';
965    my ( @blog_at, @at, @data );
966    my $archiver;
967    my $archive_label;
968
969    if ( $at && $at ne 'None' ) {
970        @blog_at = split /,/, $at;
971        require MT::PublishOption;
972        foreach my $t (@blog_at) {
973            $archiver = $app->publisher->archiver($t);
974            next unless $archiver;    # ignore unknown archive types
975            next if MT::PublishOption::archive_build_type($t) == MT::PublishOption::DISABLED();
976            push @at, $t;
977            $archive_label = $archiver->archive_label;
978            $archive_label = $at unless $archive_label;
979            $archive_label = $archive_label->()
980              if ( ref $archive_label ) eq 'CODE';
981            push(
982                @data,
983                {
984                    archive_type       => $t,
985                    archive_type_label => $archive_label
986                }
987            );
988        }
989    }
990    my $order     = join ',', @at, 'index';
991    my $entry_pkg = $app->model('entry');
992    my %param     = (
993        archive_type_loop => \@data,
994        build_order       => $order,
995        build_next        => 0,
996    );
997    $param{index_selected} = ( $app->param('prompt') || "" ) eq 'index';
998
999    if ( my $tmpl_id = $app->param('tmpl_id') ) {
1000        require MT::Template;
1001        my $tmpl = MT::Template->load($tmpl_id);
1002        $param{index_tmpl_id}   = $tmpl->id;
1003        $param{index_tmpl_name} = $tmpl->name;
1004    }
1005    my $options = $app->registry("rebuild_options") || {};
1006    my @options;
1007    if ($options) {
1008        foreach my $opt ( keys %$options ) {
1009            $options->{$opt}{key} ||= $opt;
1010            push @options, $options->{$opt};
1011        }
1012    }
1013    $app->run_callbacks( 'rebuild_options', $app, \@options );
1014    my $rebuild_options = $app->filter_conditional_list( \@options );
1015    $param{rebuild_option_loop} = $rebuild_options;
1016    $param{refocus}             = 1;
1017    $app->add_breadcrumb( $app->translate('Publish Site') );
1018    $app->load_tmpl( 'popup/rebuild_confirm.tmpl', \%param );
1019}
1020
1021sub save_favorite_blogs {
1022    my $app = shift;
1023    $app->validate_magic() or return;
1024    my $fav = $app->param('id');
1025    return unless int($fav) > 0;
1026    $app->add_to_favorite_blogs($fav);
1027    $app->send_http_header("text/javascript+json");
1028    return 'true';
1029}
1030
1031sub cc_return {
1032    my $app   = shift;
1033    my $code  = $app->param('license_code');
1034    my $url   = $app->param('license_url');
1035    my $image = $app->param('license_button');
1036    my %param = ( license_name => MT::Util::cc_name($code) );
1037    if ($url) {
1038        $param{license_code} = "$code $url $image";
1039    }
1040    else {
1041        $param{license_code} = $code;
1042    }
1043    $app->load_tmpl( 'cc_return.tmpl', \%param );
1044}
1045
1046sub handshake {
1047    my $app               = shift;
1048    my $blog_id           = $app->param('blog_id');
1049    my $remote_auth_token = $app->param('remote_auth_token');
1050
1051    my %param = ();
1052    $param{remote_auth_token} = $remote_auth_token;
1053    $app->load_tmpl( 'handshake_return.tmpl', \%param );
1054}
1055
1056sub update_welcome_message {
1057    my $app = shift;
1058    $app->validate_magic or return;
1059
1060    my $perms = $app->permissions;
1061    return $app->errtrans("Permission denied.")
1062      unless $perms && $perms->can_edit_config;
1063
1064    my $blog_id    = $app->param('blog_id');
1065    my $message    = $app->param('welcome-message-text');
1066    my $blog_class = $app->model('blog');
1067    my $blog       = $blog_class->load($blog_id)
1068      or return $app->error( $app->translate("Invalid blog") );
1069    $blog->welcome_msg($message);
1070    $blog->save;
1071    $app->redirect(
1072        $app->uri( mode => 'menu', args => { blog_id => $blog_id } ) );
1073}
1074
1075sub dialog_select_weblog {
1076    my $app = shift;
1077
1078    #return $app->errtrans("Permission denied.")
1079    #    unless $app->user->is_superuser;
1080
1081    my $favorites = $app->param('select_favorites');
1082    my %favorite;
1083    my $confirm_js;
1084    my $terms = {};
1085    my $args  = {};
1086    if ($favorites) {
1087        my $auth = $app->user or return;
1088        if ( my @favs = @{ $auth->favorite_blogs || [] } ) {
1089            $terms->{id} = \@favs;
1090            $args->{not}{id} = 1;
1091        }
1092        $confirm_js = 'saveFavorite';
1093    }
1094
1095    my $hasher = sub {
1096        my ( $obj, $row ) = @_;
1097        $row->{label} = $row->{name};
1098        $row->{'link'} = $row->{site_url};
1099    };
1100
1101    $app->listing(
1102        {
1103            type     => 'blog',
1104            code     => $hasher,
1105            template => 'dialog/select_weblog.tmpl',
1106            terms    => $terms,
1107            args     => $args,
1108            params   => {
1109                dialog_title  => $app->translate("Select Blog"),
1110                items_prompt  => $app->translate("Selected Blog"),
1111                search_prompt => $app->translate(
1112                    "Type a blog name to filter the choices below."),
1113                panel_label       => $app->translate("Blog Name"),
1114                panel_description => $app->translate("Description"),
1115                panel_type        => 'blog',
1116                panel_multi       => defined $app->param('multi')
1117                ? $app->param('multi')
1118                : 0,
1119                panel_searchable => 1,
1120                panel_first      => 1,
1121                panel_last       => 1,
1122                list_noncron     => 1,
1123                return_url       => $app->uri . '?'
1124                  . ( $app->param('return_args') || '' ),
1125                confirm_js => $confirm_js,
1126                idfield    => ( $app->param('idfield') || '' ),
1127                namefield  => ( $app->param('namefield') || '' ),
1128            },
1129        }
1130    );
1131}
1132
1133sub can_view {
1134    my ( $eh, $app, $id ) = @_;
1135    my $perms = $app->permissions;
1136    if ( $id
1137        && ( $perms->can_set_publish_paths && !$perms->can_administer_blog ) )
1138    {
1139        return 1 if 'view' eq $app->mode;
1140    }
1141    if (
1142        (
1143            $id && !(
1144                   $perms->can_edit_config
1145                || $perms->can_set_publish_paths
1146                || $perms->can_manage_feedback
1147            )
1148        )
1149        || ( !$id && !$app->user->can_create_blog )
1150      )
1151    {
1152        return 0;
1153    }
1154    1;
1155}
1156
1157sub can_save {
1158    my ( $eh, $app, $id ) = @_;
1159    my $perms = $app->permissions;
1160    return ( $id
1161          && ( $perms->can_edit_config || $perms->can_set_publish_paths ) )
1162      || ( !$id && $app->user->can_create_blog );
1163}
1164
1165sub can_delete {
1166    my ( $eh, $app, $obj ) = @_;
1167    my $author = $app->user;
1168    return 1 if $author->is_superuser();
1169    require MT::Permission;
1170    my $perms = $author->permissions( $obj->id );
1171    return $perms && $perms->can_administer_blog;
1172}
1173
1174sub pre_save {
1175    my $eh = shift;
1176    my ( $app, $obj ) = @_;
1177    if ( !$app->param('overlay')
1178        && $app->param('cfg_screen') )
1179    {
1180
1181        # Checkbox options have to be blanked if they aren't passed.
1182        my $screen = $app->param('cfg_screen');
1183        my @fields;
1184        if ( $screen eq 'cfg_web_services' ) {
1185        }
1186        elsif ( $screen eq 'cfg_archives' ) {
1187            @fields = qw( file_extension );
1188        }
1189        elsif ( $screen eq 'cfg_templatemaps' ) {
1190        }
1191        elsif ( $screen eq 'cfg_comments' ) {
1192            @fields = qw( allow_comment_html autolink_urls
1193              use_comment_confirmation );
1194        }
1195        elsif ( $screen eq 'cfg_registration' ) {
1196            @fields = qw( allow_commenter_regist
1197              require_comment_emails allow_unreg_comments
1198              require_typekey_emails );
1199        }
1200        elsif ( $screen eq 'cfg_entry' ) {
1201            @fields = qw( allow_comments_default
1202              allow_pings_default );
1203        }
1204        elsif ( $screen eq 'cfg_trackbacks' ) {
1205            @fields = qw( allow_pings moderate_pings
1206              autodiscover_links internal_autodiscovery );
1207        }
1208        elsif ( $screen eq 'cfg_plugins' ) {
1209        }
1210        for my $cb (@fields) {
1211            unless ( defined $app->param($cb) ) {
1212
1213      # two possibilities: user unchecked the option, or user was not allowed to
1214      # set the value (and therefore there was no field to submit).
1215                my $perms = $app->permissions;
1216                if (
1217                    $app->user->is_superuser
1218                    || (
1219                        $perms
1220                        && (   $perms->can_administer_blog
1221                            || $perms->can_edit_config )
1222                    )
1223                  )
1224                {
1225                    $obj->$cb(0);
1226                }
1227                else {
1228                    delete $obj->{column_values}->{$cb};
1229                    delete $obj->{changed_cols}->{$cb};
1230                }
1231            }
1232        }
1233        if ( $screen eq 'cfg_comments' ) {
1234
1235            # value for comments:  1 == Accept from anyone
1236            #                      2 == Accept authenticated only
1237            #                      0 == No comments
1238            if ( $app->param('allow_comments') ) {
1239                $obj->allow_reg_comments(1);
1240            }
1241            else {
1242                $obj->allow_unreg_comments(0);
1243                $obj->allow_reg_comments(0);
1244            }
1245            $obj->moderate_unreg_comments( $app->param('moderate_comments') );
1246            $obj->nofollow_urls( $app->param('nofollow_urls')         ? 1 : 0 );
1247            $obj->follow_auth_links( $app->param('follow_auth_links') ? 1 : 0 );
1248            my $cp_old = $obj->captcha_provider;
1249            $obj->captcha_provider( $app->param('captcha_provider') );
1250            my $rebuild = $cp_old ne $obj->captcha_provider ? 1 : 0;
1251            $app->add_return_arg( need_full_rebuild => 1 ) if $rebuild;
1252        }
1253        if ( $screen eq 'cfg_web_services' ) {
1254            my $tok = '';
1255            ( $tok = $obj->remote_auth_token ) =~ s/\s//g;
1256            $obj->remote_auth_token($tok);
1257
1258            my $ping_servers = $app->registry('ping_servers');
1259            my @pings_list;
1260            push @pings_list, $_ foreach grep {
1261                defined( $app->param( 'ping_' . $_ ) )
1262                  && $app->param( 'ping_' . $_ )
1263              }
1264              keys %$ping_servers;
1265            $obj->update_pings( join( ',', @pings_list ) );
1266        }
1267        if ( $screen eq 'cfg_entry' ) {
1268            my %param = $_[0] ? %{ $_[0] } : ();
1269            my $pref_param = $app->load_entry_prefs;
1270            %param = ( %param, %$pref_param );
1271        }
1272        if ( $screen eq 'cfg_trackbacks' ) {
1273            if ( my $pings = $app->param('allow_pings') ) {
1274                if ($pings) {
1275                    $obj->moderate_pings( $app->param('moderate_pings') );
1276                    $obj->nofollow_urls( $app->param('nofollow_urls') ? 1 : 0 );
1277                }
1278                else {
1279                    $obj->moderate_pings(1);
1280                    $obj->email_new_pings(1);
1281                }
1282            }
1283        }
1284        if ( $screen eq 'cfg_registration' ) {
1285            $obj->allow_commenter_regist(
1286                $app->param('allow_commenter_regist') );
1287            $obj->allow_unreg_comments( $app->param('allow_unreg_comments') );
1288            if ( $app->param('allow_unreg_comments') ) {
1289                $obj->require_comment_emails(
1290                    $app->param('require_comment_emails') );
1291            }
1292            else {
1293                $obj->require_comment_emails(0);
1294            }
1295            my @authenticators;
1296
1297            my $c = $app->registry('commenter_authenticators');
1298            foreach ( keys %$c ) {
1299                if ( $app->param( 'enabled_' . $_ ) ) {
1300                    push @authenticators, $_;
1301                }
1302            }
1303            push @authenticators, 'MovableType'
1304              if $app->param('enabled_MovableType');
1305            my $c_old = $obj->commenter_authenticators;
1306            $obj->commenter_authenticators( join( ',', @authenticators ) );
1307            my $rebuild = $obj->commenter_authenticators ne $c_old ? 1 : 0;
1308            if ( $app->param('enabled_TypeKey') ) {
1309                $rebuild = $obj->require_typekey_emails ? 0 : 1;
1310                $obj->require_typekey_emails(
1311                    $app->param('require_typekey_emails') );
1312            }
1313            else {
1314                $obj->require_typekey_emails(0);
1315            }
1316            my $tok = '';
1317            ( $tok = $obj->remote_auth_token ) =~ s/\s//g;
1318            $obj->remote_auth_token($tok);
1319
1320            $app->add_return_arg( need_full_rebuild => 1 ) if $rebuild;
1321        }
1322        if ( $screen eq 'cfg_spam' ) {
1323            my $threshold = $app->param('junk_score_threshold');
1324            $threshold =~ s/\+//;
1325            $threshold ||= 0;
1326            $obj->junk_score_threshold($threshold);
1327            if ( my $expiry = $app->param('junk_folder_expiry') ) {
1328                $obj->junk_folder_expiry($expiry);
1329            }
1330            my $perms = $app->permissions;
1331            unless ( defined $app->param('auto_delete_junk') ) {
1332                if (
1333                    $app->user->is_superuser
1334                    || (
1335                        $perms
1336                        && (   $perms->can_administer_blog
1337                            || $perms->can_edit_config )
1338                    )
1339                  )
1340                {
1341                    $obj->junk_folder_expiry(0);
1342                }
1343                else {
1344                    delete $obj->{column_values}{junk_folder_expiry};
1345                    delete $obj->{changed_cols}{junk_folder_expiry};
1346                }
1347            }
1348        }
1349        if ( $screen eq 'cfg_entry' ) {
1350            my %param = $_[0] ? %{ $_[0] } : ();
1351            my $pref_param = $app->load_entry_prefs;
1352            %param = ( %param, %$pref_param );
1353            $param{ 'sort_order_posts_' . ( $obj->sort_order_posts || 0 ) } = 1;
1354            $param{words_in_excerpt} = 40
1355              unless defined $param{words_in_excerpt}
1356              && $param{words_in_excerpt} ne '';
1357            if ( $app->param('days_or_posts') eq 'days' ) {
1358                $obj->days_on_index( $app->param('list_on_index') );
1359                $obj->entries_on_index(0);
1360            }
1361            else {
1362                $obj->entries_on_index( $app->param('list_on_index') );
1363                $obj->days_on_index(0);
1364            }
1365            $obj->basename_limit(15)
1366              if $obj->basename_limit < 15;    # 15 is the *minimum*
1367            $obj->basename_limit(250)
1368              if $obj->basename_limit > 250;    # 15 is the *maximum*
1369        }
1370        if ( $screen eq 'cfg_archives' ) {
1371            if ( my $dcty = $app->param('dynamicity') ) {
1372                $obj->custom_dynamic_templates($dcty);
1373            }
1374            $obj->include_system( $app->param('include_system') || '' );
1375            if ( !$app->param('enable_archive_paths') ) {
1376                $obj->archive_url('');
1377                $obj->archive_path('');
1378            }
1379        }
1380    }
1381    else {
1382
1383        #$obj->is_dynamic(0) unless defined $app->{query}->param('is_dynamic');
1384    }
1385
1386    if ( ( $obj->sanitize_spec || '' ) eq '1' ) {
1387        $obj->sanitize_spec( scalar $app->param('sanitize_spec_manual') );
1388    }
1389
1390    1;
1391}
1392
1393sub _update_finfos {
1394    my ($app, $new_virtual, $where) = @_;
1395    my $finfo_class = MT->model('fileinfo');
1396    my $driver = $finfo_class->driver;
1397    my $dbd = $driver->dbd;
1398
1399    my $stmt = MT::ObjectDriver::SQL->new;
1400
1401    if ($where) {
1402        my $new_where = {};
1403        while (my ($key, $val) = each %$where) {
1404            my $new_key = $dbd->db_column_name($finfo_class->datasource, $key);
1405            $new_where->{$new_key} = $val;
1406        }
1407        $stmt->add_complex_where([ $new_where ]);
1408    }
1409    my $virtual_col = $dbd->db_column_name($finfo_class->datasource, 'virtual');
1410    $stmt->add_complex_where([ { $virtual_col => { op => '!=', value => $new_virtual } } ]);
1411
1412    my $sql = join q{ }, 'UPDATE', $driver->table_for($finfo_class), 'SET',
1413        $virtual_col, '= ?', $stmt->as_sql_where();
1414
1415    my $dbh = $driver->rw_handle;
1416    $dbh->do($sql, {}, $new_virtual, @{ $stmt->{bind} })
1417        or return $app->error($dbh->errstr || $DBI::errstr);
1418    1;
1419}
1420
1421sub post_save {
1422    my $eh = shift;
1423    my ( $app, $obj, $original ) = @_;
1424
1425    my $perms = $app->permissions;
1426    return 1
1427      unless $app->user->is_superuser
1428      || $app->user->can_create_blog
1429      || ( $perms && $perms->can_edit_config );
1430
1431    my $screen = $app->param('cfg_screen') || '';
1432    if ( $screen eq 'cfg_archives' ) {
1433        if ( my $dcty = $app->param('dynamicity') ) {
1434            my $dcty_changed = $dcty ne $original->custom_dynamic_templates ? 1 : 0;
1435
1436            if ($dcty_changed) {
1437
1438                # Apply publishing rules for templates based on
1439                # publishing method selected:
1440                #     none (0% publish queue, all static)
1441                #     async_all (100% publish queue)
1442                #     async_partial (high-priority templates publish synchronously (main index, preferred indiv. archives, feed templates))
1443                #     all (100% dynamic)
1444                #     archives (archives dynamic, static indexes)
1445                #     custom (custom configuration)
1446
1447                if ( $dcty eq 'none' ) {
1448                    require MT::Template;
1449                    my @tmpls = MT::Template->load({
1450                        blog_id       => $obj->id,
1451                        build_dynamic => 1,
1452                    });
1453                    for my $tmpl (@tmpls) {
1454                        $tmpl->build_dynamic(0);
1455                        $tmpl->save;
1456                    }
1457                }
1458                update_dynamicity(
1459                    $app,
1460                    $obj,
1461                    $app->param('dynamic_cache')       ? 1 : 0,
1462                    $app->param('dynamic_conditional') ? 1 : 0
1463                );
1464            }
1465
1466            if (!$dcty_changed || $dcty eq 'custom') {
1467                # do nothing
1468            }
1469            elsif ($dcty eq 'none') {
1470                _update_finfos($app, 0);
1471            }
1472            elsif ($dcty eq 'all') {
1473                _update_finfos($app, 1);
1474            }
1475            elsif ($dcty eq 'archives') {
1476                # Only archives have template maps.
1477                _update_finfos($app, 1, { templatemap_id => \'is not null' });
1478                _update_finfos($app, 0, { templatemap_id => \'is null' });
1479            }
1480
1481            # If either of the publishing paths changed, rebuild the fileinfos.
1482            my $path_changed = 0;
1483            for my $path_field (qw( site_path archive_path site_url archive_url )) {
1484                $path_changed = 1 && last if $app->param($path_field)
1485                    && $app->param($path_field) ne $original->$path_field();
1486            }
1487
1488            if ($path_changed) {
1489                $app->rebuild( BlogID => $obj->id, NoStatic => 1 )
1490                    or return $app->publish_error();
1491            }
1492        }
1493
1494        cfg_archives_save($app, $obj) or return;
1495    }
1496    if ( $screen eq 'cfg_prefs' ) {
1497        my $blog_id = $obj->id;
1498
1499        # FIXME: Needs to exclude MT::Permission records for groups
1500        $app->model('permission')
1501          ->load( { blog_id => $blog_id, author_id => 0 } );
1502        if ( !$perms ) {
1503            $perms = $app->model('permission')->new;
1504            $perms->blog_id($blog_id);
1505            $perms->author_id(0);
1506        }
1507    }
1508    if ( $screen eq 'cfg_entry' ) {
1509        my $blog_id = $obj->id;
1510
1511        # FIXME: Needs to exclude MT::Permission records for groups
1512        my $perms =
1513          $app->model('permission')
1514          ->load( { blog_id => $blog_id, author_id => 0 } );
1515        if ( !$perms ) {
1516            $perms = $app->model('permission')->new;
1517            $perms->blog_id($blog_id);
1518            $perms->author_id(0);
1519        }
1520        my $prefs = $app->_entry_prefs_from_params;
1521        if ($prefs) {
1522            $perms->entry_prefs($prefs);
1523            $perms->save
1524              or return $app->errtrans( "Saving permissions failed: [_1]",
1525                $perms->errstr );
1526        }
1527    }
1528
1529    if ( !$original->id ) {    # If the object is new, the "orignal" was blank
1530        ## If this is a new blog, we need to set up a permissions
1531        ## record for the existing user.
1532        $obj->create_default_templates( $obj->template_set );
1533
1534        # Add this blog to the user's "favorite blogs", pushing any 10th
1535        # blog off the list
1536        my $auth = $app->user;
1537
1538        # FIXME: Should we still be doing this?
1539        my $perms = $app->model('permission')->new;
1540        $perms->author_id( $auth->id );
1541        $perms->blog_id( $obj->id );
1542        $perms->set_full_permissions;
1543        $perms->save;
1544
1545        # permission granted - need to update commenting cookie
1546        my %cookies = $app->cookies();
1547        $app->cookie_val();
1548        my ($x, $y, $remember) = split(/::/, $cookies{$app->user_cookie()}->value);
1549        my $cookie  = $cookies{'commenter_id'};
1550        my $cookie_value = $cookie ? $cookie->value : '';
1551        my ($id, $blog_ids) = split(':', $cookie_value);
1552        if ( $blog_ids ne 'S' && $blog_ids ne 'N' ) {
1553            $blog_ids .= ",'" . $obj->id . "'";
1554        }
1555        my $timeout = $remember ? '+10y' : 0;
1556        $timeout = '+' . $app->config->CommentSessionTimeout . 's' unless $timeout;
1557        my %id_kookee = (-name => "commenter_id",
1558                           -value => $auth->id . ':' . $blog_ids,
1559                           -path => '/',
1560                           ($timeout ? (-expires => $timeout) : ()));
1561        $app->bake_cookie(%id_kookee);
1562
1563        require MT::Log;
1564        $app->log(
1565            {
1566                message => $app->translate(
1567                    "Blog '[_1]' (ID:[_2]) created by '[_3]'",
1568                    $obj->name, $obj->id, $auth->name
1569                ),
1570                level    => MT::Log::INFO(),
1571                class    => 'blog',
1572                category => 'new',
1573            }
1574        );
1575
1576        $app->run_callbacks( 'blog_template_set_change', { blog => $obj } );
1577    }
1578    else {
1579
1580        # if you've changed the comment configuration
1581        if (
1582            (
1583                grep { $original->column($_) ne $obj->column($_) }
1584                qw(allow_unreg_comments allow_reg_comments remote_auth_token)
1585            )
1586          )
1587        {
1588            if ( RegistrationAffectsArchives( $obj->id, 'Individual' ) ) {
1589                $app->add_return_arg( need_full_rebuild => 1 );
1590            }
1591            else {
1592                $app->add_return_arg( need_index_rebuild => 1 );
1593            }
1594        }
1595
1596        # if other settings were changed that would affect published pages:
1597        if ( grep { $original->column($_) ne $obj->column($_) }
1598            qw(allow_pings allow_comment_html) )
1599        {
1600            $app->add_return_arg( need_full_rebuild => 1 );
1601        }
1602
1603        if ( ($original->template_set || '') ne ($obj->template_set || '') ) {
1604            $app->run_callbacks( 'blog_template_set_change', { blog => $obj } );
1605            $app->add_return_arg( need_full_rebuild => 1 );
1606        }
1607    }
1608    1;
1609}
1610
1611sub save_filter {
1612    my $eh    = shift;
1613    my ($app) = @_;
1614    my $name  = $app->param('name');
1615    if ( defined $name ) {
1616        $name =~ s/(^\s+|\s+$)//g;
1617        $app->param( 'name', $name );
1618    }
1619    my $perms = $app->permissions;
1620    my $screen = $app->param('cfg_screen') || '';
1621    return $eh->error( MT->translate("You did not specify a blog name.") )
1622      if ( !( $screen && $perms->can_edit_config )
1623        && ( defined $app->param('name') && ( $app->param('name') eq '' ) ) );
1624    return $eh->error( MT->translate("Site URL must be an absolute URL.") )
1625      if ( $screen eq 'cfg_archives' )
1626      && $perms->can_set_publish_paths
1627      && $app->param('site_url') !~ m.^https?://.;
1628    return $eh->error( MT->translate("Archive URL must be an absolute URL.") )
1629      if ( $screen eq 'cfg_archives' )
1630      && $perms->can_set_publish_paths
1631      && $app->param('archive_url') !~ m.^https?://.
1632      && $app->param('enable_archive_paths');
1633    return $eh->error( MT->translate("You did not specify an Archive Root.") )
1634      if ( $screen eq 'cfg_archives' )
1635      && $app->param('archive_path') =~ m/^\s*$/
1636      && $app->param('enable_archive_paths');
1637    return 1;
1638}
1639
1640sub post_delete {
1641    my ( $eh, $app, $obj ) = @_;
1642
1643    $app->log(
1644        {
1645            message => $app->translate(
1646                "Blog '[_1]' (ID:[_2]) deleted by '[_3]'",
1647                $obj->name, $obj->id, $app->user->name
1648            ),
1649            level    => MT::Log::INFO(),
1650            class    => 'blog',
1651            category => 'delete'
1652        }
1653    );
1654    $app->_delete_pseudo_association(undef, $obj->id);
1655}
1656
1657sub make_blog_list {
1658    my $app = shift;
1659    my ($blogs) = @_;
1660
1661    my $author = $app->user;
1662    my $data;
1663    my $can_edit_authors = 1 if $author->is_superuser;
1664    my @blog_ids = map { $_->id } @$blogs; 
1665    my %counts;
1666    my $e_iter = $app->model('entry')->count_group_by(
1667        { blog_id => \@blog_ids },
1668        { group => [ 'blog_id' ] }
1669    );
1670    while ( my ($e_count, $e_blog_id) = $e_iter->() ) {
1671        $counts{$e_blog_id}{'entry'} = $e_count;
1672    }
1673    my $c_iter = $app->model('comment')->count_group_by(
1674        { blog_id => \@blog_ids },
1675        { group => [ 'blog_id' ] }
1676    );
1677    while ( my ($c_count, $c_blog_id) = $c_iter->() ) {
1678        $counts{$c_blog_id}{'comment'} = $c_count;
1679    }
1680    my $p_iter = $app->model('tbping')->count_group_by(
1681        { blog_id => \@blog_ids },
1682        { group => [ 'blog_id' ] }
1683    );
1684    while ( my ($p_count, $p_blog_id) = $p_iter->() ) {
1685        $counts{$p_blog_id}{'ping'} = $p_count;
1686    }
1687
1688    for my $blog (@$blogs) {
1689        my $blog_id = $blog->id;
1690        my $perms   = $author->permissions($blog_id);
1691        my $row     = {
1692            id          => $blog->id,
1693            name        => $blog->name,
1694            description => $blog->description,
1695            site_url    => $blog->site_url
1696        };
1697        $row->{num_entries}  = $counts{$blog_id}{'entry'};
1698        $row->{num_comments} = $counts{$blog_id}{'comment'};
1699        $row->{num_pings}    = $counts{$blog_id}{'ping'};
1700        $row->{can_create_post}  = $perms->can_create_post;
1701        $row->{can_edit_entries} = $perms->can_create_post
1702          || $perms->can_edit_all_posts
1703          || $perms->can_publish_post;
1704        $row->{can_edit_templates} = $perms->can_edit_templates;
1705        $row->{can_edit_config}    = $perms->can_edit_config
1706          || $perms->can_administer_blog;
1707        $row->{can_set_publish_paths} = $perms->can_set_publish_paths
1708          || $perms->can_administer_blog;
1709        $row->{can_manage_feedback} = $perms->can_manage_feedback;
1710        $row->{can_edit_assets}     = $perms->can_edit_assets;
1711        $row->{can_administer_blog} = $perms->can_administer_blog;
1712        push @$data, $row;
1713    }
1714    $data;
1715}
1716
1717sub build_blog_table {
1718    my $app = shift;
1719    my (%args) = @_;
1720
1721    my $blog_class    = $app->model('blog');
1722    my $tbp_class     = $app->model('ping');
1723    my $entry_class   = $app->model('entry');
1724    my $comment_class = $app->model('comment');
1725
1726    my $iter;
1727    if ( $args{load_args} ) {
1728        my $class = $app->model('blog');
1729        $iter = $class->load_iter( @{ $args{load_args} } );
1730    }
1731    elsif ( $args{iter} ) {
1732        $iter = $args{iter};
1733    }
1734    elsif ( $args{items} ) {
1735        $iter = sub { pop @{ $args{items} } };
1736    }
1737    return [] unless $iter;
1738    my $param = $args{param};
1739
1740    my $author           = $app->user;
1741    my $can_edit_authors = $author->is_superuser;
1742    my @data;
1743    my $i;
1744    my ( $entry_count, $ping_count, $comment_count );
1745    while ( my $blog = $iter->() ) {
1746        my $blog_id = $blog->id;
1747        my $row     = {
1748            id          => $blog->id,
1749            name        => $blog->name,
1750            description => $blog->description,
1751            site_url    => $blog->site_url
1752        };
1753
1754        # we should use count by group here...
1755        $row->{num_entries} =
1756          ( $entry_count ? $entry_count->{$blog_id} : $entry_count->{$blog_id} =
1757              MT::Entry->count( { blog_id => $blog_id } ) )
1758          || 0;
1759        $row->{num_comments} = (
1760              $comment_count
1761            ? $comment_count->{$blog_id}
1762            : $comment_count->{$blog_id} = MT::Comment->count(
1763                { blog_id => $blog_id, junk_status => [ 0, 1 ] }
1764            )
1765          )
1766          || 0;
1767        $row->{num_pings} = (
1768            $ping_count ? $ping_count->{$blog_id} : $ping_count->{$blog_id} =
1769              MT::TBPing->count(
1770                { blog_id => $blog_id, junk_status => [ 0, 1 ] }
1771              )
1772        ) || 0;
1773        $row->{num_authors} = 0;
1774
1775        # FIXME: This isn't efficient
1776        my $iter = MT::Permission->load_iter(
1777            {
1778                blog_id => [ 0, $blog_id ],
1779
1780                #    role_mask => [ 2, undef ]
1781                #}, {
1782                #    range_incl => { 'role_mask' => 1 }
1783            }
1784        );
1785        my %a;
1786        while ( my $p = $iter->() ) {
1787            next if exists $a{ $p->author_id };
1788            $a{ $p->author_id } = 1;
1789            $row->{num_authors}++ if $p->can_create_post;
1790        }
1791        if ( $author->is_superuser ) {
1792            $row->{can_create_post}       = 1;
1793            $row->{can_edit_entries}      = 1;
1794            $row->{can_edit_templates}    = 1;
1795            $row->{can_edit_config}       = 1;
1796            $row->{can_set_publish_paths} = 1;
1797            $row->{can_administer_blog}   = 1;
1798        }
1799        else {
1800            my $perms = $author->permissions($blog_id);
1801            $row->{can_create_post}  = $perms->can_create_post;
1802            $row->{can_edit_entries} = $perms->can_create_post
1803              || $perms->can_edit_all_posts
1804              || $perms->can_publish_post;
1805            $row->{can_edit_templates} = $perms->can_edit_templates;
1806            $row->{can_edit_config}    = $perms->can_edit_config
1807              || $perms->can_administer_blog;
1808            $row->{can_set_publish_paths} = $perms->can_set_publish_paths
1809              || $perms->can_administer_blog;
1810            $row->{can_administer_blog} = $perms->can_administer_blog;
1811        }
1812        $row->{object} = $blog;
1813        push @data, $row;
1814    }
1815
1816    if (@data) {
1817        $param->{blog_table}[0]{object_loop} = \@data;
1818        $app->load_list_actions( 'blog', \%$param );
1819        $param->{object_loop} = $param->{blog_table}[0]{object_loop};
1820    }
1821
1822    \@data;
1823}
1824
1825sub cfg_blog {
1826    my $q = $_[0]->{query};
1827    $q->param( '_type', 'blog' );
1828    $q->param( 'id',    scalar $q->param('blog_id') );
1829    $_[0]->forward( "view", { output => 'cfg_prefs.tmpl' } );
1830}
1831
1832sub _switch_publish_options {
1833    my ( $blog, $current, $new ) = @_;
1834    require MT::Template;
1835    require MT::TemplateMap;
1836    my @tmpl = MT::Template->load( { blog_id => $blog->id } );
1837    for my $tmpl (@tmpl) {
1838        next
1839          if !( $tmpl->type =~ m/^(individual|page|category|archive|index)$/ );
1840        if ( $tmpl->build_type == $current ) {
1841            $tmpl->build_type($new);
1842            $tmpl->save;
1843        }
1844        my @tmpl_maps = MT::TemplateMap->load( { template_id => $tmpl->id } );
1845        foreach my $tmpl_map (@tmpl_maps) {
1846            if ( $tmpl_map->build_type == $current ) {
1847                $tmpl_map->build_type($new);
1848                $tmpl_map->save;
1849            }
1850        }
1851    }
1852    1;
1853}
1854
1855sub cfg_archives_save {
1856    my $app = shift;
1857    my ($blog) = @_;
1858
1859    my $at = $app->param('preferred_archive_type');
1860    $blog->archive_type_preferred($at);
1861    my $pq = $app->param('publish_queue');
1862    $blog->publish_queue( $pq ? 1 : 0 );
1863    $blog->include_cache( $app->param('include_cache') ? 1 : 0 );
1864    $blog->save
1865      or return $app->error(
1866        $app->translate( "Saving blog failed: [_1]", $blog->errstr ) );
1867
1868    require MT::PublishOption;
1869    if ($pq) {
1870        _switch_publish_options(
1871            $blog,
1872            MT::PublishOption::ONDEMAND(),
1873            MT::PublishOption::ASYNC()
1874        );
1875    }
1876    else {
1877        _switch_publish_options(
1878            $blog,
1879            MT::PublishOption::ASYNC(),
1880            MT::PublishOption::ONDEMAND()
1881        );
1882    }
1883}
1884
1885sub RegistrationAffectsArchives {
1886    my ( $blog_id, $archive_type ) = @_;
1887    require MT::TemplateMap;
1888    require MT::Template;
1889    my @tms = MT::TemplateMap->load(
1890        {
1891            archive_type => $archive_type,
1892            blog_id      => $blog_id
1893        }
1894    );
1895    grep { $_->text =~ /<MT:?IfRegistration/i }
1896      map { MT::Template->load( $_->template_id ) } @tms;
1897}
1898
1899sub update_dynamicity {
1900    my $app = shift;
1901    my ( $blog, $cache, $conditional ) = @_;
1902    my $dcty = $blog->custom_dynamic_templates;
1903
1904    if ( ($dcty eq 'async_partial') || ($dcty eq 'async_all') ) {
1905        # these behave like static publishing
1906        $dcty = 'none';
1907    }
1908
1909    if ( $dcty eq 'none' ) {
1910        require MT::Template;
1911        my @templates = MT::Template->load( { blog_id => $blog->id } );
1912        for my $tmpl (@templates) {
1913            $tmpl->build_dynamic(0);
1914            $tmpl->save();
1915        }
1916    }
1917    elsif ( $dcty eq 'archives' ) {
1918        require MT::Template;
1919        my @templates = MT::Template->load( { blog_id => $blog->id } );
1920        for my $tmpl (@templates) {
1921            $tmpl->build_dynamic( $tmpl->type ne 'index' ? 1 : 0 );
1922            $tmpl->save();
1923        }
1924    }
1925    elsif ( $dcty eq 'custom' ) {
1926    }
1927    elsif ( $dcty eq 'all' ) {
1928        require MT::Template;
1929        my @templates = MT::Template->load(
1930            {
1931                blog_id => $blog->id,
1932
1933                # FIXME: enumeration of types
1934                type =>
1935                  [ 'index', 'archive', 'individual', 'page', 'category' ],
1936            }
1937        );
1938        for my $tmpl (@templates) {
1939            $tmpl->build_dynamic(1);
1940            $tmpl->save();
1941        }
1942    }
1943
1944    if ( $dcty ne 'none' ) {
1945        prepare_dynamic_publishing($app, @_, $blog->site_path, $blog->site_url);
1946        if ( $blog->archive_path ) {
1947            prepare_dynamic_publishing($app, @_, $blog->archive_path, $blog->archive_url);
1948        }
1949        my $compiled_template_path =
1950          File::Spec->catfile( $blog->site_path(), 'templates_c' );
1951        if ( -d $compiled_template_path ) {
1952            $app->add_return_arg( 'no_writecache' => 1 )
1953              unless ( -w $compiled_template_path );
1954        }
1955        else {
1956            $app->add_return_arg( 'no_cachedir' => 1 )
1957              unless ( -d $compiled_template_path );
1958        }
1959
1960        # FIXME: use FileMgr
1961        if ($cache) {
1962            my $cache_path = File::Spec->catfile( $blog->site_path(), 'cache' );
1963            if ( -d $cache_path ) {
1964                $app->add_return_arg( 'no_write_cache_path' => 1 )
1965                  unless ( -w $cache_path );
1966            }
1967            else {
1968                $app->add_return_arg( 'no_cache_path' => 1 )
1969                  unless ( -d $cache_path );
1970            }
1971        }
1972    }
1973    $app->add_return_arg( dynamic_set => 1 );
1974}
1975
1976sub prepare_dynamic_publishing {
1977    my ( $cb, $blog, $cache, $conditional, $site_path, $site_url ) = @_;
1978
1979    my $htaccess_path = File::Spec->catfile( $site_path, ".htaccess" );
1980    my $mtview_path   = File::Spec->catfile( $site_path, "mtview.php" );
1981
1982    ## Don't re-create when files are there in callback.
1983    return 1
1984      if !defined($cache)
1985      && !defined($conditional)
1986      && ( 'MT::Callback' eq ref($cb) )
1987      && ( -f $htaccess_path )
1988      && ( -f $mtview_path );
1989    return 1 if ( 'none' eq $blog->custom_dynamic_templates );
1990
1991    require File::Spec;
1992
1993    # IIS itself does not handle .htaccess,
1994    # but IISPassword (3rd party) does and dies with this.
1995    if ( $ENV{SERVER_SOFTWARE} !~ /Microsoft-IIS/ ) {
1996        eval {
1997            require URI;
1998            my $mtview_server_url = new URI( $site_url );
1999            $mtview_server_url = $mtview_server_url->path();
2000            $mtview_server_url .=
2001              ( $mtview_server_url =~ m|/$| ? "" : "/" ) . "mtview.php";
2002
2003            my $contents = "";
2004            if ( open( HT, $htaccess_path ) ) {
2005                local $/ = undef;
2006                $contents = <HT>;
2007                close HT;
2008            }
2009            if ( $contents !~ /^\s*Rewrite(Cond|Engine|Rule)\b/m ) {
2010                my $htaccess = <<HTACCESS;
2011
2012## %%%%%%% Movable Type generated this part; don't remove this line! %%%%%%%
2013# Disable fancy indexes, so mtview.php gets a chance...
2014Options -Indexes +SymLinksIfOwnerMatch
2015  <IfModule mod_rewrite.c>
2016  # The mod_rewrite solution is the preferred way to invoke
2017  # dynamic pages, because of its flexibility.
2018
2019  # Add mtview.php to the list of DirectoryIndex options, listing it last,
2020  # so it is invoked only if the common choices aren't present...
2021  <IfModule mod_dir.c>
2022    DirectoryIndex index.php index.html index.htm default.htm default.html default.asp $mtview_server_url
2023  </IfModule>
2024
2025  RewriteEngine on
2026
2027  # don't serve mtview.php if the request is for a real directory
2028  # (allows the DirectoryIndex lookup to function)
2029  RewriteCond %{REQUEST_FILENAME} !-d
2030
2031  # don't serve mtview.php if the request is for a real file
2032  # (allows the actual file to be served)
2033  RewriteCond %{REQUEST_FILENAME} !-f
2034  # anything else is handed to mtview.php for resolution
2035  RewriteRule ^(.*)\$ $mtview_server_url [L,QSA]
2036</IfModule>
2037
2038<IfModule !mod_rewrite.c>
2039  # if mod_rewrite is unavailable, we forward any missing page
2040  # or unresolved directory index requests to mtview
2041  # if mtview.php can resolve the request, it returns a 200
2042  # result code which prevents any 4xx error code from going
2043  # to the server's access logs. However, an error will be
2044  # reported in the error log file. If this is your only choice,
2045  # and you want to suppress these messages, adding a "LogLevel crit"
2046  # directive within your VirtualHost or root configuration for
2047  # Apache will turn them off.
2048  ErrorDocument 404 $mtview_server_url
2049  ErrorDocument 403 $mtview_server_url
2050</IfModule>
2051## ******* Movable Type generated this part; don't remove this line! *******
2052
2053HTACCESS
2054
2055                $blog->file_mgr->mkpath( $site_path );
2056
2057                open( HT, ">>$htaccess_path" )
2058                  || die "Couldn't open $htaccess_path for appending";
2059                print HT $htaccess || die "Couldn't write to $htaccess_path";
2060                close HT;
2061            }
2062        };
2063        if ($@) { print STDERR $@; }
2064    }
2065
2066    eval {
2067        my $mv_contents = '';
2068        if ( -f $mtview_path ) {
2069            open( my $mv, "<$mtview_path" );
2070            while ( my $line = <$mv> ) {
2071                $mv_contents .= $line if ( $line !~ m!^//|<\?(?:php)?|\?>! );
2072            }
2073            close $mv;
2074        }
2075        my $cgi_path = MT->instance->server_path() || "";
2076        $cgi_path =~ s!/*$!!;
2077        my $mtphp_path = File::Spec->canonpath("$cgi_path/php/mt.php");
2078        my $blog_id    = $blog->id;
2079        my $config     = MT->instance->{cfg_file};
2080        my $cache_code = $cache ? "\n    \$mt->caching = true;" : '';
2081        my $conditional_code =
2082          $conditional ? "\n    \$mt->conditional = true;" : '';
2083        my $new_mtview = <<NEW_MTVIEW;
2084
2085    include('$mtphp_path');
2086    \$mt = new MT($blog_id, '$config');$cache_code$conditional_code
2087    \$mt->view();
2088NEW_MTVIEW
2089
2090        if ( $new_mtview ne substr( $mv_contents, 0, length($new_mtview) ) ) {
2091            $mv_contents =~ s!\n!\n//!gs;
2092            my $mtview = <<MTVIEW;
2093<?php
2094$new_mtview
2095$mv_contents
2096?>
2097MTVIEW
2098
2099            $blog->file_mgr->mkpath( $site_path );
2100            open( my $mv, ">$mtview_path" )
2101              || die "Couldn't open $mtview_path for appending";
2102            print $mv $mtview || die "Couldn't write to $mtview_path";
2103            close $mv;
2104        }
2105    };
2106    if ($@) { print STDERR $@; }
2107
2108    my $compiled_template_path =
2109      File::Spec->catfile( $site_path, 'templates_c' );
2110    my $fmgr        = $blog->file_mgr;
2111    my $cfg         = MT->config;
2112    my $saved_umask = $cfg->DirUmask;
2113    $cfg->DirUmask('0000');
2114    $fmgr->mkpath($compiled_template_path);
2115    $cfg->DirUmask($saved_umask);
2116    my $message = q();
2117
2118    if ( -d $compiled_template_path ) {
2119        $message = MT->translate(
2120'Error: Movable Type cannot write to the template cache directory. Please check the permissions for the directory called <code>[_1]</code> underneath your blog directory.',
2121            'templates_c'
2122        ) unless ( -w $compiled_template_path );
2123    }
2124    else {
2125        $message = MT->translate(
2126'Error: Movable Type was not able to create a directory to cache your dynamic templates. You should create a directory called <code>[_1]</code> underneath your blog directory.',
2127            'templates_c'
2128        ) unless ( -d $compiled_template_path );
2129    }
2130
2131    # FIXME: use FileMgr
2132    if ($cache) {
2133        my $cache_path = File::Spec->catfile( $blog->site_path(), 'cache' );
2134        $cfg->DirUmask('0000');
2135        $fmgr->mkpath($cache_path);
2136        $cfg->DirUmask($saved_umask);
2137        if ( -d $cache_path ) {
2138            $message = MT->translate(
2139'Error: Movable Type cannot write to the template cache directory. Please check the permissions for the directory called <code>[_1]</code> underneath your blog directory.',
2140                'cache'
2141            ) unless ( -w $cache_path );
2142        }
2143        else {
2144            $message = MT->translate(
2145'Error: Movable Type was not able to create a directory to cache your dynamic templates. You should create a directory called <code>[_1]</code> underneath your blog directory.',
2146                'cache'
2147            ) unless ( -d $cache_path );
2148        }
2149    }
2150    MT->log(
2151        {
2152            message => $message,
2153            level   => MT::Log::ERROR(),
2154            class   => 'system',
2155        }
2156    );
2157}
2158
21591;
Note: See TracBrowser for help on using the browser.