root/branches/release-36/lib/MT/CMS/Blog.pm @ 2115

Revision 2115, 82.0 kB (checked in by bchoate, 19 months ago)

Paginate rebuild operation for list action to publish archive templates. Added 'save and rebuild' button for archive templates. BugId:79515

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