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

Revision 1776, 75.9 kB (checked in by mpaschal, 20 months ago)

Update 'virtual' field of fileinfos directly when dynamicity changes
Don't recreate fileinfos when dynamicity changes, only when publishing path does (but when publishing path changes, recreate fileinfos even if publishing statically, as we always keep fileinfos nowadays)
Don't cache fileinfos, so updating directly is not a problem
BugzID: 67300

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