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

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

Create required files and directories for dynamic publishing according to the selected publishing profile.

Also "rebuild" the necessary files to rename those files and append .static to the file name. BugId:79364

  • 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'ErrMovable 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'ErrMovable 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.