root/branches/release-34/lib/MT/CMS/Blog.pm @ 1866

Revision 1866, 77.4 kB (checked in by bchoate, 20 months ago)

Changes to store binary state to junk_status column. BugId:79280

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