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

Revision 2003, 81.3 kB (checked in by fumiakiy, 20 months ago)

L10 Japanese the Cal release, take one.

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