root/branches/release-35/lib/MT/CMS/Blog.pm @ 1957

Revision 1957, 77.6 kB (checked in by bchoate, 20 months ago)

Fixes for propogation of build_type from template to templatemaps. BugId:79370

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