root/branches/release-30/lib/MT/CMS/Template.pm @ 1392

Revision 1392, 45.9 kB (checked in by bchoate, 21 months ago)

Fix for call to populate_archive_loop

  • Property svn:keywords set to Id Revision
Line 
1package MT::CMS::Template;
2
3use strict;
4
5sub edit {
6    my $cb = shift;
7    my ($app, $id, $obj, $param) = @_;
8
9    my $q = $app->param;
10    my $blog_id = $q->param('blog_id');
11    my $type = $q->param('_type');
12    my $blog = $app->blog;
13    my $cfg = $app->config;
14    my $perms = $app->permissions;
15
16    if ($id) {
17        # FIXME: Template types should not be enumerated here
18        $param->{nav_templates} = 1;
19        my $tab;
20        if ( $obj->type eq 'index' ) {
21            $tab = 'index';
22            $param->{template_group_trans} = $app->translate('index');
23        }
24        elsif ($obj->type eq 'archive'
25            || $obj->type eq 'individual'
26            || $obj->type eq 'category'
27            || $obj->type eq 'page' )
28        {
29
30            # FIXME: enumeration of types
31            $tab = 'archive';
32            $param->{template_group_trans} = $app->translate('archive');
33        }
34        elsif ( $obj->type eq 'custom' ) {
35            $tab = 'module';
36            $param->{template_group_trans} = $app->translate('module');
37        }
38        elsif ( $obj->type eq 'widget' ) {
39            $tab = 'widget';
40            $param->{template_group_trans} = $app->translate('widget');
41        }
42        elsif ( $obj->type eq 'email' ) {
43            $tab = 'email';
44            $param->{template_group_trans} = $app->translate('email');
45        }
46        else {
47            $tab = 'system';
48            $param->{template_group_trans} = $app->translate('system');
49        }
50        $param->{template_group} = $tab;
51        $blog_id = $obj->blog_id;
52
53        # FIXME: enumeration of types
54             $param->{has_name} = $obj->type eq 'index'
55          || $obj->type eq 'custom'
56          || $obj->type eq 'widget'
57          || $obj->type eq 'archive'
58          || $obj->type eq 'category'
59          || $obj->type eq 'page'
60          || $obj->type eq 'individual';
61        if ( !$param->{has_name} ) {
62            $param->{ 'type_' . $obj->type } = 1;
63            $param->{name} = $obj->name;
64        }
65        $app->add_breadcrumb( $param->{name} );
66        $param->{has_outfile} = $obj->type eq 'index';
67        $param->{has_rebuild} =
68          (      ( $obj->type eq 'index' )
69              && ( ( $blog->custom_dynamic_templates || "" ) ne 'all' ) );
70        $param->{custom_dynamic} =
71          $blog && ( $blog->custom_dynamic_templates || "" ) eq 'custom';
72        $param->{has_build_options} =
73          ( $param->{custom_dynamic} || $param->{has_rebuild} );
74
75        # FIXME: enumeration of types
76             $param->{is_special} = $param->{type} ne 'index'
77          && $param->{type} ne 'archive'
78          && $param->{type} ne 'category'
79          && $param->{type} ne 'page'
80          && $param->{type} ne 'individual';
81             $param->{has_build_options} = $param->{has_build_options}
82          && $param->{type} ne 'custom'
83          && $param->{type} ne 'widget'
84          && !$param->{is_special};
85        $param->{rebuild_me} =
86          defined $obj->rebuild_me ? $obj->rebuild_me : 1;
87        $param->{search_label} = $app->translate('Templates');
88        $param->{object_type}  = 'template';
89        my $published_url = $obj->published_url;
90        $param->{published_url} = $published_url if $published_url;
91        $param->{saved_rebuild} = 1 if $q->param('saved_rebuild');
92
93        $app->load_list_actions( 'template', $param );
94
95        $obj->compile;
96        if ( $obj->{errors} && @{ $obj->{errors} } ) {
97            $param->{error} = $app->translate(
98                "One or more errors were found in this template.");
99            $param->{error} .= "<ul>\n";
100            foreach my $err ( @{ $obj->{errors} } ) {
101                $param->{error} .= "<li>"
102                  . MT::Util::encode_html( $err->{message} )
103                  . "</li>\n";
104            }
105            $param->{error} .= "</ul>\n";
106        }
107
108        # Populate list of included templates
109        if ( my $includes = $obj->getElementsByTagName('Include') ) {
110            my @includes;
111            my @widgets;
112            my %seen;
113            foreach my $tag (@$includes) {
114                my $include = {};
115                my $mod = $include->{include_module} = $tag->[1]->{module} || $tag->[1]->{widget};
116                next unless $mod;
117                my $type = $tag->[1]->{widget} ? 'widget' : 'custom';
118                next if exists $seen{$type}{$mod};
119                $seen{$type}{$mod} = 1;
120                my $other = MT::Template->load(
121                    {
122                        blog_id => [ $obj->blog_id, 0 ],
123                        name    => $mod,
124                        type    => $type,
125                    }, {
126                        sort      => 'blog_id',
127                        direction => 'descend',
128                    }
129                );
130                if ($other) {
131                    $include->{include_link} = $app->mt_uri(
132                        mode => 'view',
133                        args => {
134                            blog_id => $other->blog_id || 0,
135                            '_type' => 'template',
136                            id      => $other->id
137                        }
138                    );
139                }
140                else {
141                    $include->{create_link} = $app->mt_uri(
142                        mode => 'view',
143                        args => {
144                            blog_id => $obj->blog_id,
145                            '_type' => 'template',
146                            type    => $type,
147                            name    => $mod,
148                        }
149                    );
150                }
151                if ($type eq 'widget') {
152                    push @widgets, $include;
153                } else {
154                    push @includes, $include;
155                }
156            }
157            $param->{include_loop} = \@includes if @includes;
158            $param->{widget_loop} = \@widgets if @widgets;
159        }
160        my @sets = ( @{ $obj->getElementsByTagName('WidgetSet') || [] }, @{ $obj->getElementsByTagName('WidgetManager') || [] } );
161        if ( @sets ) {
162            my @widget_sets;
163            my %seen;
164            foreach my $set (@sets) {
165                my $name = $set->[1]->{name};
166                next unless $name;
167                next if $seen{$name};
168                $seen{$name} = 1;
169                push @widget_sets, {
170                    include_link => $app->mt_uri(
171                        mode => 'edit_widget',
172                        args => {
173                            blog_id => $obj->blog_id,
174                            widgetmanager => $name,
175                        },
176                    ),
177                    include_module => $name,
178                };
179            }
180            $param->{widget_set_loop} = \@widget_sets if @widget_sets;
181        }
182        $param->{have_includes} = 1 if $param->{widget_set_loop} || $param->{include_loop} || $param->{widget_loop};
183        # Populate archive types for creating new map
184        my $obj_type = $obj->type;
185        if (   $obj_type eq 'individual'
186            || $obj_type eq 'page'
187            || $obj_type eq 'author'
188            || $obj_type eq 'category'
189            || $obj_type eq 'archive' )
190        {
191            my @at = $app->publisher->archive_types;
192            my @archive_types;
193            for my $at (@at) {
194                my $archiver      = $app->publisher->archiver($at);
195                my $archive_label = $archiver->archive_label;
196                $archive_label = $at unless $archive_label;
197                $archive_label = $archive_label->()
198                  if ( ref $archive_label ) eq 'CODE';
199                if (   ( $obj_type eq 'archive' )
200                    || ( $obj_type eq 'author' )
201                    || ( $obj_type eq 'category' ) )
202                {
203
204                    # only include if it is NOT an entry-based archive type
205                    next if $archiver->entry_based;
206                }
207                elsif ( $obj_type eq 'page' ) {
208                    # only include if it is a entry-based archive type and page
209                    next unless $archiver->entry_based;
210                    next if $archiver->entry_class ne 'page';
211                }
212                elsif ( $obj_type eq 'individual' ) {
213                    # only include if it is a entry-based archive type and entry
214                    next unless $archiver->entry_based;
215                    next if $archiver->entry_class eq 'page';
216                }
217                push @archive_types,
218                  {
219                    archive_type_translated => $archive_label,
220                    archive_type            => $at,
221                  };
222                @archive_types =
223                  sort { MT::App::CMS::archive_type_sorter( $a, $b ) } @archive_types;
224            }
225            $param->{archive_types} = \@archive_types;
226
227            # Populate template maps for this template
228            my $maps = _populate_archive_loop( $app, $blog, $obj );
229            $param->{object_loop} = $param->{template_map_loop} = $maps
230              if @$maps;
231        }
232    } else {
233        my $new_tmpl = $q->param('create_new_template');
234        my $template_type;
235        if ($new_tmpl) {
236            if ( $new_tmpl =~ m/^blank:(.+)/ ) {
237                $template_type = $1;
238                $param->{type} = $1;
239            }
240            elsif ( $new_tmpl =~ m/^default:([^:]+):(.+)/ ) {
241                $template_type = $1;
242                $template_type = 'custom' if $template_type eq 'module';
243                my $template_id = $2;
244                my $set = $blog ? $blog->template_set : undef;
245                require MT::DefaultTemplates;
246                my $def_tmpl = MT::DefaultTemplates->templates($set) || [];
247                my ($tmpl) =
248                  grep { $_->{identifier} eq $template_id } @$def_tmpl;
249                $param->{text} = $app->translate_templatized( $tmpl->{text} )
250                  if $tmpl;
251                $param->{type} = $template_type;
252            }
253        }
254        else {
255            $template_type = $q->param('type');
256            $template_type = 'custom' if 'module' eq $template_type;
257            $param->{type}   = $template_type;
258        }
259        return $app->errtrans("Create template requires type")
260          unless $template_type;
261        $param->{nav_templates} = 1;
262        my $tab;
263
264        # FIXME: enumeration of types
265        if ( $template_type eq 'index' ) {
266            $tab = 'index';
267            $param->{template_group_trans} = $app->translate('index');
268        }
269        elsif ($template_type eq 'archive'
270            || $template_type eq 'individual'
271            || $template_type eq 'category'
272            || $template_type eq 'page' )
273        {
274            $tab                         = 'archive';
275            $param->{template_group_trans} = $app->translate('archive');
276            $param->{type_archive}         = 1;
277            my @types = (
278                {
279                    key   => 'archive',
280                    label => $app->translate('Archive')
281                },
282                {
283                    key   => 'individual',
284                    label => $app->translate('Entry or Page')
285                },
286            );
287            $param->{new_archive_types} = \@types;
288        }
289        elsif ( $template_type eq 'custom' ) {
290            $tab = 'module';
291            $param->{template_group_trans} = $app->translate('module');
292        }
293        elsif ( $template_type eq 'widget' ) {
294            $tab = 'widget';
295            $param->{template_group_trans} = $app->translate('widget');
296        }
297        else {
298            $tab = 'system';
299            $param->{template_group_trans} = $app->translate('system');
300        }
301        $param->{template_group} = $tab;
302        $app->translate($tab);
303        $app->add_breadcrumb( $app->translate('New Template') );
304
305        # FIXME: enumeration of types
306             $param->{has_name} = $template_type eq 'index'
307          || $template_type eq 'custom'
308          || $template_type eq 'widget'
309          || $template_type eq 'archive'
310          || $template_type eq 'category'
311          || $template_type eq 'page'
312          || $template_type eq 'individual';
313        $param->{has_outfile} = $template_type eq 'index';
314        $param->{has_rebuild} =
315          (      ( $template_type eq 'index' )
316              && ( ( $blog->custom_dynamic_templates || "" ) ne 'all' ) );
317        $param->{custom_dynamic} =
318          $blog && $blog->custom_dynamic_templates eq 'custom';
319        $param->{has_build_options} =
320             $blog && ($blog->custom_dynamic_templates eq 'custom'
321          || $param->{has_rebuild});
322
323        # FIXME: enumeration of types
324             $param->{is_special} = $param->{type} ne 'index'
325          && $param->{type} ne 'archive'
326          && $param->{type} ne 'category'
327          && $param->{type} ne 'page'
328          && $param->{type} ne 'individual';
329             $param->{has_build_options} = $param->{has_build_options}
330          && $param->{type} ne 'custom'
331          && $param->{type} ne 'widget'
332          && !$param->{is_special};
333
334        $param->{rebuild_me} = 1;
335        $param->{name}       = MT::Util::decode_url( $app->param('name') )
336          if $app->param('name');
337    }
338    my $set = $blog ? $blog->template_set : undef;
339    require MT::DefaultTemplates;
340    my $tmpls = MT::DefaultTemplates->templates($set);
341    my @tmpl_ids;
342    foreach my $dtmpl (@$tmpls) {
343        if ( !$param->{has_name} ) {
344            if ($obj->type eq 'email') {
345                if ($dtmpl->{identifier} eq $obj->identifier) {
346                    $param->{template_name_label} = $dtmpl->{label};
347                    $param->{template_name}       = $dtmpl->{name};
348                }
349            }
350            else {
351                if ( $dtmpl->{type} eq $obj->type ) {
352                    $param->{template_name_label} = $dtmpl->{label};
353                    $param->{template_name}       = $dtmpl->{name};
354                }
355            }
356        }
357        if ( $dtmpl->{type} eq 'index' ) {
358            push @tmpl_ids,
359              {
360                label    => $dtmpl->{label},
361                key      => $dtmpl->{key},
362                selected => $dtmpl->{key} eq
363                  ( ( $obj ? $obj->identifier : undef ) || '' ),
364              };
365        }
366    }
367    $param->{index_identifiers} = \@tmpl_ids;
368
369    $param->{"type_$param->{type}"} = 1;
370    if ($perms) {
371        my $pref_param =
372          $app->load_template_prefs( $perms->template_prefs );
373        %$param = ( %$param, %$pref_param );
374    }
375
376    # Populate structure for template snippets
377    if ( my $snippets = $app->registry('template_snippets') || {} ) {
378        my @snippets;
379        for my $snip_id ( keys %$snippets ) {
380            my $label = $snippets->{$snip_id}{label};
381            $label = $label->() if ref($label) eq 'CODE';
382            push @snippets,
383              {
384                id      => $snip_id,
385                trigger => $snippets->{$snip_id}{trigger},
386                label   => $label,
387                content => $snippets->{$snip_id}{content},
388              };
389        }
390        @snippets = sort { $a->{label} cmp $b->{label} } @snippets;
391        $param->{template_snippets} = \@snippets;
392    }
393
394    # Populate structure for tag documentation
395    my $all_tags = MT::Component->registry("tags");
396    my $tag_docs = {};
397    foreach my $tag_set (@$all_tags) {
398        my $url = $tag_set->{help_url};
399        $url = $url->() if ref($url) eq 'CODE';
400        # hey, at least give them a google search
401        $url ||= 'http://www.google.com/search?q=mt%t';
402        my $tag_list = '';
403        foreach my $type (qw( block function )) {
404            my $tags = $tag_set->{$type} or next;
405            $tag_list .= ($tag_list eq '' ? '' : ',') . join(",", keys(%$tags));
406        }
407        $tag_list =~ s/(^|,)plugin(,|$)/,/;
408        if (exists $tag_docs->{$url}) {
409            $tag_docs->{$url} .= ',' . $tag_list;
410        }
411        else {
412            $tag_docs->{$url} = $tag_list;
413        }
414    }
415    $param->{tag_docs} = $tag_docs;
416    $param->{link_doc} = $app->help_url('appendices/tags/');
417
418    # template language
419    $param->{template_lang} = 'html';
420    if ( $obj && $obj->outfile ) {
421        if ( $obj->outfile =~ m/\.(css|js|html|php|pl|asp)$/ ) {
422            $param->{template_lang} = {
423                css => 'css',
424                js => 'javascript',
425                html => 'html',
426                php => 'php',
427                pl => 'perl',
428                asp => 'asp',
429            }->{$1};
430        }
431    }
432
433    1;
434}
435
436sub list {
437    my $app = shift;
438
439    my $perms = $app->blog ? $app->permissions : $app->user->permissions;
440    return $app->return_to_dashboard( redirect => 1 )
441      unless $perms || $app->user->is_superuser;
442    if ( $perms && !$perms->can_edit_templates ) {
443        return $app->return_to_dashboard( permission => 1 );
444    }
445
446    require MT::Template;
447    my $blog_id = $app->param('blog_id') || 0;
448    my $filter  = $app->param('filter_key');
449    if ( !$filter ) {
450        if ($app->blog) {
451            $filter = 'index_templates';
452            $app->param( 'filter_key', 'index_templates' );
453        }
454        else {
455            $filter = 'module_templates';
456            $app->param( 'filter_key', 'module_templates' );
457        }
458    }
459    else {
460        # global index templates redirect to module templates
461        if ( !$app->blog && $filter eq 'index_templates' ) {
462            $filter = 'module_templates';
463            $app->param( 'filter_key', 'module_templates' );
464        }
465    }
466    my $terms = { blog_id => $blog_id };
467    my $args  = { sort    => 'name' };
468
469    my $hasher = sub {
470        my ( $obj, $row ) = @_;
471        my $template_type;
472        my $type = $row->{type} || '';
473        if ( $type =~ m/^(individual|page|category|archive)$/ ) {
474            $template_type = 'archive';
475        }
476        elsif ( $type eq 'widget' ) {
477            $template_type = 'widget';
478        }
479        elsif ( $type eq 'index' ) {
480            $template_type = 'index';
481        }
482        elsif ( $type eq 'custom' ) {
483            $template_type = 'module';
484        }
485        elsif ( $type eq 'email' ) {
486            $template_type = 'email';
487        }
488        elsif ( $type eq 'backup' ) {
489            $template_type = 'backup';
490        }
491        else {
492            $template_type = 'system';
493        }
494        $row->{template_type} = $template_type;
495        $row->{type} = 'entry' if $type eq 'individual';
496        my $published_url = $obj->published_url;
497        $row->{published_url} = $published_url if $published_url;
498    };
499
500    my $params        = {};
501    my $template_type = $filter;
502    $template_type =~ s/_templates//;
503    my $template_type_label = $app->translate($template_type);
504    if ( $template_type_label eq $template_type ) {
505        $template_type_label = "\u$template_type";
506    }
507    $params->{template_type}       = $template_type;
508    $params->{template_type_label} = $template_type_label;
509
510    #@tt_loop = sort { $a->{label} cmp $b->{label} } @tt_loop;
511    #$params->{template_type_loop} = \@tt_loop;
512
513    $app->load_list_actions( 'template', $params );
514    $params->{page_actions} = $app->page_actions('list_templates');
515    $params->{search_label} = $app->translate("Templates");
516    $params->{blog_view} = 1;
517    $params->{refreshed} = $app->param('refreshed');
518    $params->{published} = $app->param('published');
519
520    return $app->listing(
521        {
522            type     => 'template',
523            terms    => $terms,
524            args     => $args,
525            params   => $params,
526            no_limit => 1,
527            code     => $hasher,
528        }
529    );
530}
531
532sub reset_blog_templates {
533    my $app   = shift;
534    my $q     = $app->param;
535    my $perms = $app->permissions
536      or return $app->error( $app->translate("No permissions") );
537    return $app->error( $app->translate("Permission denied.") )
538      unless $perms->can_edit_templates;
539    $app->validate_magic() or return;
540    my $blog = MT::Blog->load( $perms->blog_id );
541    require MT::Template;
542    my @tmpl = MT::Template->load( { blog_id => $blog->id } );
543
544    for my $tmpl (@tmpl) {
545        $tmpl->remove or return $app->error( $tmpl->errstr );
546    }
547    my $set = $blog ? $blog->template_set : undef;
548    require MT::DefaultTemplates;
549    my $tmpl_list = MT::DefaultTemplates->templates($set) || [];
550    my @arch_tmpl;
551    for my $val (@$tmpl_list) {
552        $val->{name} = $app->translate( $val->{name} );
553        $val->{text} = $app->translate_templatized( $val->{text} );
554        my $tmpl = MT::Template->new;
555        $tmpl->set_values($val);
556        $tmpl->build_dynamic(0);
557        $tmpl->blog_id( $blog->id );
558        $tmpl->save
559          or return $app->error(
560            $app->translate(
561                "Populating blog with default templates failed: [_1]",
562                $tmpl->errstr
563            )
564          );
565
566        # FIXME: enumeration of types
567        if (   $val->{type} eq 'archive'
568            || $val->{type} eq 'category'
569            || $val->{type} eq 'page'
570            || $val->{type} eq 'individual' )
571        {
572            push @arch_tmpl, $tmpl;
573        }
574    }
575
576    ## Set up mappings from new templates to archive types.
577    for my $tmpl (@arch_tmpl) {
578        my (@at);
579
580        # FIXME: enumeration of types
581        if ( $tmpl->type eq 'archive' ) {
582            @at = qw( Daily Weekly Monthly Category );
583        }
584        elsif ( $tmpl->type eq 'page' ) {
585            @at = qw( Page );
586        }
587        elsif ( $tmpl->type eq 'individual' ) {
588            @at = qw( Individual );
589        }
590        require MT::TemplateMap;
591        for my $at (@at) {
592            my $map = MT::TemplateMap->new;
593            $map->archive_type($at);
594            $map->is_preferred(1);
595            $map->template_id( $tmpl->id );
596            $map->blog_id( $tmpl->blog_id );
597            $map->save
598              or return $app->error(
599                $app->translate(
600                    "Setting up mappings failed: [_1]",
601                    $map->errstr
602                )
603              );
604        }
605    }
606    $app->redirect(
607        $app->uri(
608            'mode' => 'list',
609            args =>
610              { '_type' => 'template', blog_id => $blog->id, 'reset' => 1 }
611        )
612    );
613}
614
615sub _generate_map_table {
616    my $app = shift;
617    my ( $blog_id, $template_id ) = @_;
618
619    require MT::Template;
620    require MT::Blog;
621    my $blog     = MT::Blog->load($blog_id);
622    my $template = MT::Template->load($template_id);
623    my $tmpl     = $app->load_tmpl('include/archive_maps.tmpl');
624    my $maps     = _populate_archive_loop( $app, $blog, $template );
625    $tmpl->param( { object_type => 'templatemap' } );
626    $tmpl->param( { object_loop => $maps } ) if @$maps;
627    my $html = $tmpl->output();
628
629    if ( $html =~ m/<__trans / ) {
630        $html = $app->translate_templatized($html);
631    }
632    $html;
633}
634
635sub _populate_archive_loop {
636    my $app = shift;
637    my ( $blog, $obj ) = @_;
638
639    my $index = $app->config('IndexBasename');
640    my $ext = $blog->file_extension || '';
641    $ext = '.' . $ext if $ext ne '';
642
643    require MT::TemplateMap;
644    my @tmpl_maps = MT::TemplateMap->load( { template_id => $obj->id } );
645    my @maps;
646    my %types;
647    foreach my $map_obj (@tmpl_maps) {
648        my $map = {};
649        $map->{map_id}           = $map_obj->id;
650        $map->{map_is_preferred} = $map_obj->is_preferred;
651        my $at = $map->{archive_type} = $map_obj->archive_type;
652        $types{$at}++;
653        $map->{ 'archive_type_preferred_' . $blog->archive_type_preferred } = 1
654          if $blog->archive_type_preferred;
655        $map->{file_template} = $map_obj->file_template
656          if $map_obj->file_template;
657
658        my $archiver = $app->publisher->archiver($at);
659        next unless $archiver;
660        $map->{archive_label} = $archiver->archive_label;
661        my $tmpls     = $archiver->default_archive_templates;
662        my $tmpl_loop = [];
663        foreach (@$tmpls) {
664            my $name = $_->{label};
665            $name =~ s/\.html$/$ext/;
666            $name =~ s/index$ext$/$index$ext/;
667            push @$tmpl_loop,
668              {
669                name    => $name,
670                value   => $_->{template},
671                default => ( $_->{default} || 0 )
672              };
673        }
674
675        my $custom = 1;
676
677        foreach (@$tmpl_loop) {
678            if (   ( !$map->{file_template} && $_->{default} )
679                || ( $map->{file_template} eq $_->{value} ) )
680            {
681                $_->{selected}        = 1;
682                $custom               = 0;
683                $map->{file_template} = $_->{value}
684                  if !$map->{file_template};
685            }
686        }
687        if ($custom) {
688            unshift @$tmpl_loop,
689              {
690                name     => $map->{file_template},
691                value    => $map->{file_template},
692                selected => 1,
693              };
694        }
695
696        $map->{archive_tmpl_loop} = $tmpl_loop;
697        if (
698            1 < MT::TemplateMap->count(
699                { archive_type => $at, blog_id => $obj->blog_id }
700            )
701          )
702        {
703            $map->{has_multiple_archives} = 1;
704        }
705
706        push @maps, $map;
707    }
708    @maps = sort { MT::App::CMS::archive_type_sorter( $a, $b ) } @maps;
709    return \@maps;
710}
711
712sub delete_map {
713    my $app = shift;
714    $app->validate_magic() or return;
715    my $perms = $app->{perms}
716      or return $app->error( $app->translate("No permissions") );
717    my $q  = $app->param;
718    my $id = $q->param('id');
719
720    require MT::TemplateMap;
721    MT::TemplateMap->remove( { id => $id } );
722    my $html =
723      _generate_map_table( $app, $q->param('blog_id'),
724        $q->param('template_id') );
725    $app->{no_print_body} = 1;
726    $app->send_http_header("text/plain");
727    $app->print($html);
728}
729
730sub add_map {
731    my $app = shift;
732    $app->validate_magic() or return;
733    my $perms = $app->{perms}
734      or return $app->error( $app->translate("No permissions") );
735
736    my $q = $app->param;
737
738    require MT::TemplateMap;
739    my $blog_id = $q->param('blog_id');
740    my $at      = $q->param('new_archive_type');
741    my $count   = MT::TemplateMap->count(
742        {
743            blog_id      => $blog_id,
744            archive_type => $at
745        }
746    );
747    my $map = MT::TemplateMap->new;
748    $map->is_preferred( $count ? 0 : 1 );
749    $map->template_id( scalar $q->param('template_id') );
750    $map->blog_id($blog_id);
751    $map->archive_type($at);
752    $map->save
753      or return $app->error(
754        $app->translate( "Saving map failed: [_1]", $map->errstr ) );
755    my $html =
756      _generate_map_table( $app, $blog_id, scalar $q->param('template_id') );
757    $app->rebuild(
758        BlogID      => $blog_id,
759        ArchiveType => $at,
760        TemplateMap => $map,
761        TemplateID  => scalar $q->param('template_id'),
762        NoStatic    => 1
763    ) or return $app->publish_error();
764    $app->{no_print_body} = 1;
765    $app->send_http_header("text/plain");
766    $app->print($html);
767}
768
769sub delete_map {
770    my $app = shift;
771    $app->validate_magic() or return;
772    my $perms = $app->{perms}
773      or return $app->error( $app->translate("No permissions") );
774    my $q  = $app->param;
775    my $id = $q->param('id');
776
777    require MT::TemplateMap;
778    MT::TemplateMap->remove( { id => $id } );
779    my $html =
780      _generate_map_table( $app, $q->param('blog_id'),
781        $q->param('template_id') );
782    $app->{no_print_body} = 1;
783    $app->send_http_header("text/plain");
784    $app->print($html);
785}
786
787sub add_map {
788    my $app = shift;
789    $app->validate_magic() or return;
790    my $perms = $app->{perms}
791      or return $app->error( $app->translate("No permissions") );
792
793    my $q = $app->param;
794
795    require MT::TemplateMap;
796    my $blog_id = $q->param('blog_id');
797    my $at      = $q->param('new_archive_type');
798    my $count   = MT::TemplateMap->count(
799        {
800            blog_id      => $blog_id,
801            archive_type => $at
802        }
803    );
804    my $map = MT::TemplateMap->new;
805    $map->is_preferred( $count ? 0 : 1 );
806    $map->template_id( scalar $q->param('template_id') );
807    $map->blog_id($blog_id);
808    $map->archive_type($at);
809    $map->save
810      or return $app->error(
811        $app->translate( "Saving map failed: [_1]", $map->errstr ) );
812    my $html =
813      _generate_map_table( $app, $blog_id, scalar $q->param('template_id') );
814    $app->rebuild(
815        BlogID      => $blog_id,
816        ArchiveType => $at,
817        TemplateMap => $map,
818        TemplateID  => scalar $q->param('template_id'),
819        NoStatic    => 1
820    ) or return $app->publish_error();
821    $app->{no_print_body} = 1;
822    $app->send_http_header("text/plain");
823    $app->print($html);
824}
825
826sub can_view {
827    my ( $eh, $app, $id ) = @_;
828    my $perms = $app->permissions;
829    return !$id || ($perms && $perms->can_edit_templates) || (!$app->blog && $app->user->can_edit_templates);
830}
831
832sub can_save {
833    my ( $eh, $app, $id ) = @_;
834    my $perms = $app->permissions;
835    return ($perms && $perms->can_edit_templates) || (!$perms && $app->user->can_edit_templates);
836}
837
838sub can_delete {
839    my ( $eh, $app, $obj ) = @_;
840    return 1 if $app->user->is_superuser();
841    my $perms = $app->permissions;
842    return ($perms && $perms->can_edit_templates) || (!$perms && $app->user->can_edit_templates);
843}
844
845sub pre_save {
846    my $eh = shift;
847    my ( $app, $obj ) = @_;
848
849    $obj->rebuild_me(0) 
850      if $app->param('current_rebuild_me')
851      && !$app->param('rebuild_me');
852    $obj->build_dynamic(0)
853      if $app->param('current_build_dynamic')
854      && !$app->param('build_dynamic');
855
856    ## Strip linefeed characters.
857    ( my $text = $obj->text ) =~ tr/\r//d;
858
859    if ($text =~ m/<(MT|_)_trans/i) {
860        $text = $app->translate_templatized($text);
861    }
862
863    $obj->text($text);
864
865    # update text heights if necessary
866    if ( my $perms = $app->permissions ) {
867        my $prefs = $perms->template_prefs || '';
868        my $text_height = $app->param('text_height');
869        if ( defined $text_height ) {
870            my ($pref_text_height) = $prefs =~ m/\btext:(\d+)\b/;
871            $pref_text_height ||= 0;
872            if ( $text_height != $pref_text_height ) {
873                if ( $prefs =~ m/\btext\b/ ) {
874                    $prefs =~ s/\btext(:\d+)\b/text:$text_height/;
875                }
876                else {
877                    $prefs = 'text:' . $text_height . ',' . $prefs;
878                }
879            }
880        }
881
882        if ( $prefs ne ( $perms->template_prefs || '' ) ) {
883            $perms->template_prefs($prefs);
884            $perms->save;
885        }
886    }
887    1;
888}
889
890sub post_save {
891    my $eh = shift;
892    my ( $app, $obj, $original ) = @_;
893
894    my $sess_obj = $app->autosave_session_obj;
895    $sess_obj->remove if $sess_obj;
896
897    require MT::TemplateMap;
898    my $q = $app->param;
899    my @p = $q->param;
900    for my $p (@p) {
901        if ( $p =~ /^archive_tmpl_preferred_(\w+)_(\d+)$/ ) {
902            my $at     = $1;
903            my $map_id = $2;
904            my $map    = MT::TemplateMap->load($map_id);
905            $map->prefer( $q->param($p) );    # prefer method saves in itself
906        }
907        elsif ( $p =~ /^archive_file_tmpl_(\d+)$/ ) {
908            my $map_id = $1;
909            my $map    = MT::TemplateMap->load($map_id);
910            $map->file_template( $q->param($p) );
911            $map->save;
912        }
913    }
914
915    if ( !$original->id ) {
916        $app->log(
917            {
918                message => $app->translate(
919                    "Template '[_1]' (ID:[_2]) created by '[_3]'",
920                    $obj->name, $obj->id, $app->user->name
921                ),
922                level    => MT::Log::INFO(),
923                class    => 'template',
924                category => 'new',
925            }
926        );
927    }
928
929    if ( $obj->build_dynamic ) {
930        if ( $obj->type eq 'index' ) {
931            $app->rebuild_indexes(
932                BlogID   => $obj->blog_id,
933                Template => $obj,
934                NoStatic => 1,
935            ) or return $app->publish_error();    # XXXX
936        }
937        else {
938            $app->rebuild(
939                BlogID     => $obj->blog_id,
940                TemplateID => $obj->id,
941                NoStatic   => 1,
942            ) or return $app->publish_error();
943        }
944    }
945    1;
946}
947
948sub post_delete {
949    my ( $eh, $app, $obj ) = @_;
950
951    $app->log(
952        {
953            message => $app->translate(
954                "Template '[_1]' (ID:[_2]) deleted by '[_3]'",
955                $obj->name, $obj->id, $app->user->name
956            ),
957            level    => MT::Log::INFO(),
958            class    => 'system',
959            category => 'delete'
960        }
961    );
962}
963
964sub build_template_table {
965    my $app = shift;
966    my (%args) = @_;
967
968    my $perms     = $app->permissions;
969    my $list_pref = $app->list_pref('template');
970    my $limit     = $args{limit};
971    my $param     = $args{param} || {};
972    my $iter;
973    if ( $args{load_args} ) {
974        my $class = $app->model('template');
975        $iter = $class->load_iter( @{ $args{load_args} } );
976    }
977    elsif ( $args{iter} ) {
978        $iter = $args{iter};
979    }
980    elsif ( $args{items} ) {
981        $iter = sub { pop @{ $args{items} } };
982        $limit = scalar @{ $args{items} };
983    }
984    return [] unless $iter;
985
986    my @data;
987    my $i;
988    my %blogs;
989    while ( my $tmpl = $iter->() ) {
990        my $blog = $blogs{ $tmpl->blog_id } ||=
991          MT::Blog->load( $tmpl->blog_id );
992        my $row = $tmpl->column_values;
993        $row->{name} = '' if !defined $row->{name};
994        $row->{name} =~ s/^\s+|\s+$//g;
995        $row->{name} = "(" . $app->translate("No Name") . ")"
996          if $row->{name} eq '';
997        my $published_url = $tmpl->published_url;
998        $row->{published_url} = $published_url if $published_url;
999
1000        # FIXME: enumeration of types
1001        $row->{can_delete} = 1
1002          if $tmpl->type =~ m/(custom|index|archive|page|individual|category)/;
1003        if ($blog) {
1004            $row->{weblog_name} = $blog->name;
1005        }
1006        elsif ($tmpl->blog_id) {
1007            $row->{weblog_name} = '* ' . $app->translate('Orphaned') . ' *';
1008        }
1009        else {
1010            $row->{weblog_name} = '* ' . $app->translate('Global Templates') . ' *';
1011        }
1012        $row->{object} = $tmpl;
1013        push @data, $row;
1014        last if @data > $limit;
1015    }
1016    return [] unless @data;
1017
1018    $param->{template_table}[0]              = {%$list_pref};
1019    $param->{template_table}[0]{object_loop} = \@data;
1020    $param->{template_table}[0]{object_type} = 'template';
1021    $app->load_list_actions( 'template', $param );
1022    $param->{object_loop} = \@data;
1023    \@data;
1024}
1025
1026sub refresh_all_templates {
1027    my ($app) = @_;
1028
1029    my $backup = 0;
1030    if ($app->param('backup')) {
1031        # refresh templates dialog uses a 'backup' field
1032        $backup = 1;
1033    }
1034
1035    my $template_set = $app->param('template_set');
1036    my $refresh_type = $app->param('refresh_type') || 'refresh';
1037
1038    my $t = time;
1039
1040    my @id;
1041    if ($app->param('blog_id')) {
1042        @id = ( scalar $app->param('blog_id') );
1043    }
1044    else {
1045        @id = $app->param('id');
1046        if (! @id) {
1047            # refresh global templates
1048            @id = ( 0 );
1049        }
1050    }
1051
1052    require MT::Template;
1053    require MT::DefaultTemplates;
1054    require MT::Blog;
1055    require MT::Permission;
1056    require MT::Util;
1057
1058    foreach my $blog_id (@id) {
1059        my $blog;
1060        if ($blog_id) {
1061            $blog = MT::Blog->load($blog_id);
1062            next unless $blog;
1063        }
1064        if ( !$app->user->is_superuser() ) {
1065            my $perms = MT::Permission->load(
1066                { blog_id => $blog_id, author_id => $app->user->id } );
1067            if (
1068                !$perms
1069                || (   !$perms->can_edit_templates()
1070                    && !$perms->can_administer_blog() )
1071              )
1072            {
1073                next;
1074            }
1075        }
1076
1077        my $tmpl_list;
1078        if ($blog_id) {
1079
1080            if ($refresh_type eq 'clean') {
1081                # the user wants to back up all templates and
1082                # install the new ones
1083
1084                my @ts = MT::Util::offset_time_list( $t, $blog_id );
1085                my $ts = sprintf "%04d-%02d-%02d %02d:%02d:%02d",
1086                    $ts[5] + 1900, $ts[4] + 1, @ts[ 3, 2, 1, 0 ];
1087
1088                my $tmpl_iter = MT::Template->load_iter({
1089                    blog_id => $blog_id,
1090                    type => { not => 'backup' },
1091                });
1092
1093                while (my $tmpl = $tmpl_iter->()) {
1094                    if ($backup) {
1095                        # zap all template maps
1096                        require MT::TemplateMap;
1097                        MT::TemplateMap->remove({
1098                            template_id => $tmpl->id,
1099                        });
1100                        $tmpl->type('backup');
1101                        $tmpl->name(
1102                            $tmpl->name . ' (Backup from ' . $ts . ')' );
1103                        $tmpl->identifier(undef);
1104                        $tmpl->rebuild_me(0);
1105                        $tmpl->linked_file(undef);
1106                        $tmpl->outfile('');
1107                        $tmpl->save;
1108                    } else {
1109                        $tmpl->remove;
1110                    }
1111                }
1112
1113                # This also creates our template mappings
1114                $blog->create_default_templates( $template_set ||
1115                    $blog->template_set || 'mt_blog' );
1116
1117                if ($template_set) {
1118                    $blog->template_set( $template_set );
1119                    $blog->save;
1120                    $app->run_callbacks( 'blog_template_set_change', { blog => $blog } );
1121                }
1122
1123                next;
1124            }
1125
1126            $tmpl_list = MT::DefaultTemplates->templates($template_set || $blog->template_set) || MT::DefaultTemplates->templates();
1127        }
1128        else {
1129            $tmpl_list = MT::DefaultTemplates->templates();
1130        }
1131
1132        foreach my $val (@$tmpl_list) {
1133            if ($blog_id) {
1134                # when refreshing blog templates,
1135                # skip over global templates which
1136                # specify a blog_id of 0...
1137                next if $val->{global};
1138            }
1139            else {
1140                next unless exists $val->{global};
1141            }
1142
1143            if ( !$val->{orig_name} ) {
1144                $val->{orig_name} = $val->{name};
1145                $val->{name}      = $app->translate( $val->{name} );
1146                $val->{text}      = $app->translate_templatized( $val->{text} );
1147            }
1148
1149            my $orig_name = $val->{orig_name};
1150
1151            my @ts = MT::Util::offset_time_list( $t, ( $blog_id ? $blog_id : undef ) );
1152            my $ts = sprintf "%04d-%02d-%02d %02d:%02d:%02d", $ts[5] + 1900,
1153              $ts[4] + 1, @ts[ 3, 2, 1, 0 ];
1154
1155            my $terms = {};
1156            $terms->{blog_id} = $blog_id;
1157            $terms->{type} = $val->{type};
1158            if ( $val->{type} =~
1159                m/^(archive|individual|page|category|index|custom|widget)$/ )
1160            {
1161                $terms->{name} = $val->{name};
1162            }
1163            else {
1164                $terms->{identifier} = $val->{identifier};
1165            }
1166
1167            # this should only return 1 template; we're searching
1168            # within a given blog for a specific type of template (for
1169            # "system" templates; or for a type + name, which should be
1170            # unique for that blog.
1171            my $tmpl = MT::Template->load($terms);
1172            if ($tmpl && $backup) {
1173
1174                # check for default template text...
1175                # if it is a default template, then outright replace it
1176                my $text = $tmpl->text;
1177                $text =~ s/\s+//g;
1178
1179                my $def_text = $val->{text};
1180                $def_text =~ s/\s+//g;
1181
1182                # if it has been customized, back it up to a new tmpl record
1183                if ($def_text ne $text) {
1184                    my $backup = $tmpl->clone;
1185                    delete $backup->{column_values}
1186                      ->{id};    # make sure we don't overwrite original
1187                    delete $backup->{changed_cols}->{id};
1188                    $backup->name(
1189                        $backup->name . $app->translate( ' (Backup from [_1])', $ts ) );
1190                    $backup->type('backup');
1191                    # if ( $backup->type !~
1192                    #         m/^(archive|individual|page|category|index|custom|widget)$/ )
1193                    # {
1194                    #     $backup->type('custom')
1195                    #       ;      # system templates can't be created
1196                    # }
1197                    $backup->outfile('');
1198                    $backup->linked_file( $tmpl->linked_file );
1199                    $backup->identifier(undef);
1200                    $backup->rebuild_me(0);
1201                    $backup->build_dynamic(0);
1202                    $backup->save;
1203                }
1204            }
1205            if ($tmpl) {
1206                # we found that the previous template had not been
1207                # altered, so replace it with new default template...
1208                $tmpl->text( $val->{text} );
1209                $tmpl->identifier( $val->{identifier} );
1210                $tmpl->type( $val->{type} )
1211                  ; # fixes mismatch of types for cases like "archive" => "individual"
1212                $tmpl->linked_file('');
1213                $tmpl->save;
1214            }
1215            else {
1216                # create this one...
1217                my $tmpl = new MT::Template;
1218                $tmpl->build_dynamic(0);
1219                $tmpl->set_values(
1220                    {
1221                        text       => $val->{text},
1222                        name       => $val->{name},
1223                        type       => $val->{type},
1224                        identifier => $val->{identifier},
1225                        outfile    => $val->{outfile},
1226                        rebuild_me => $val->{rebuild_me}
1227                    }
1228                );
1229                $tmpl->blog_id($blog_id);
1230                $tmpl->save
1231                  or return $app->error(
1232                        $app->translate("Error creating new template: ")
1233                      . $tmpl->errstr );
1234            }
1235        }
1236    }
1237
1238    $app->add_return_arg( 'refreshed' => 1 );
1239    $app->call_return;
1240}
1241
1242sub refresh_individual_templates {
1243    my ($app) = @_;
1244
1245    require MT::Util;
1246
1247    my $user = $app->user;
1248    my $perms = $app->permissions;
1249    return $app->error(
1250        $app->translate(
1251            "Permission denied.")
1252      )
1253      #TODO: system level-designer permission
1254      unless $user->is_superuser() || $user->can_edit_templates()
1255      || ( $perms
1256        && ( $perms->can_edit_templates()
1257          || $perms->can_administer_blog ) );
1258
1259    my $set;
1260    if ( my $blog_id = $app->param('blog_id') ) {
1261        my $blog = $app->model('blog')->load($blog_id);
1262        $set = $blog->template_set()
1263            if $blog;
1264    }
1265
1266    require MT::DefaultTemplates;
1267    my $tmpl_list = MT::DefaultTemplates->templates($set) or return;
1268
1269    my $trnames    = {};
1270    my $tmpl_types = {};
1271    my $tmpl_ids   = {};
1272    my $tmpls      = {};
1273    foreach my $tmpl (@$tmpl_list) {
1274        $tmpl->{text} = $app->translate_templatized( $tmpl->{text} );
1275        $tmpl_ids->{ $tmpl->{identifier} } = $tmpl
1276            if $tmpl->{identifier};
1277        $trnames->{ $app->translate( $tmpl->{name} ) } = $tmpl->{name};
1278        if ( $tmpl->{type} !~ m/^(archive|individual|page|category|index|custom|widget)$/ )
1279        {
1280            $tmpl_types->{ $tmpl->{type} } = $tmpl;
1281        }
1282        else {
1283            $tmpls->{ $tmpl->{type} }{ $tmpl->{name} } = $tmpl;
1284        }
1285    }
1286
1287    my $t = time;
1288
1289    my @msg;
1290    my @id = $app->param('id');
1291    require MT::Template;
1292    foreach my $tmpl_id (@id) {
1293        my $tmpl = MT::Template->load($tmpl_id);
1294        next unless $tmpl;
1295        my $blog_id = $tmpl->blog_id;
1296
1297        # FIXME: permission check -- for this blog_id
1298
1299        my @ts = MT::Util::offset_time_list( $t, $blog_id );
1300        my $ts = sprintf "%04d-%02d-%02d %02d:%02d:%02d", $ts[5] + 1900,
1301          $ts[4] + 1, @ts[ 3, 2, 1, 0 ];
1302
1303        my $orig_name = $trnames->{ $tmpl->name } || $tmpl->name;
1304        my $val = ( $tmpl->identifier ? $tmpl_ids->{ $tmpl->identifier() } : undef )
1305          || $tmpl_types->{ $tmpl->type() }
1306          || $tmpls->{ $tmpl->type() }{$orig_name};
1307        if ( !$val ) {
1308            push @msg,
1309              $app->translate(
1310"Skipping template '[_1]' since it appears to be a custom template.",
1311                $tmpl->name
1312              );
1313            next;
1314        }
1315
1316        my $text = $tmpl->text;
1317        $text =~ s/\s+//g;
1318
1319        my $def_text = $val->{text};
1320        $def_text =~ s/\s+//g;
1321
1322        if ($text ne $def_text) {
1323            # if it has been customized, back it up to a new tmpl record
1324            my $backup = $tmpl->clone;
1325            delete $backup->{column_values}
1326              ->{id};    # make sure we don't overwrite original
1327            delete $backup->{changed_cols}->{id};
1328            $backup->name( $backup->name . ' (Backup from ' . $ts . ')' );
1329            $backup->type('backup');
1330            $backup->outfile('');
1331            $backup->linked_file( $tmpl->linked_file );
1332            $backup->rebuild_me(0);
1333            $backup->build_dynamic(0);
1334            $backup->identifier(undef);
1335            $backup->save;
1336            push @msg,
1337              $app->translate(
1338    'Refreshing template <strong>[_3]</strong> with <a href="?__mode=view&amp;blog_id=[_1]&amp;_type=template&amp;id=[_2]">backup</a>',
1339                  $blog_id, $backup->id, $tmpl->name );
1340
1341            # we found that the previous template had not been
1342            # altered, so replace it with new default template...
1343            $tmpl->text( $val->{text} );
1344            $tmpl->identifier( $val->{identifier} );
1345            $tmpl->linked_file('');
1346            $tmpl->save;
1347        } else {
1348            push @msg, $app->translate("Skipping template '[_1]' since it has not been changed.", $tmpl->name);
1349        }
1350    }
1351    my @msg_loop;
1352    push @msg_loop, { message => $_ } foreach @msg;
1353
1354    $app->build_page( 'refresh_results.tmpl',
1355        { message_loop => \@msg_loop, return_url => $app->return_uri } );
1356}
1357
1358sub publish_index_templates {
1359    my $app = shift;
1360    $app->validate_magic or return;
1361
1362    # permission check
1363    my $perms = $app->permissions;
1364    return $app->errtrans("Permission denied.")
1365        unless $app->user->is_superuser ||
1366            $perms->can_administer_blog ||
1367            $perms->can_rebuild;
1368
1369    my $blog = $app->blog;
1370    my $templates = MT->model('template')->lookup_multi([ $app->param('id') ]);
1371    TEMPLATE: for my $tmpl (@$templates) {
1372        next TEMPLATE if !defined $tmpl;
1373        next TEMPLATE if $tmpl->blog_id != $blog->id;
1374        $app->rebuild_indexes(
1375            Blog     => $blog,
1376            Template => $tmpl,
1377        );
1378    }
1379
1380    $app->call_return( published => 1 );
1381}
1382
13831;
Note: See TracBrowser for help on using the browser.