root/trunk/lib/MT/CMS/Blog.pm @ 3082

Revision 3082, 82.9 kB (checked in by bchoate, 14 months ago)

Merging fireball branch changes to-date to trunk: svn merge -r2974:3081 http://code.sixapart.com/svn/movabletype/branches/fireball .

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