~ubuntu-branches/debian/squeeze/movabletype-opensource/squeeze

« back to all changes in this revision

Viewing changes to lib/MT/CMS/Template.pm

  • Committer: Bazaar Package Importer
  • Author(s): Dominic Hargreaves
  • Date: 2008-06-13 23:28:40 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20080613232840-ya4jfxv1jgl45a3d
Tags: 4.2~rc2-1
* New upstream release candidate
* Update Standards-Version (no changes)
* Ensure that schema upgrade message is always seen

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
 
2
# This program is distributed under the terms of the
 
3
# GNU General Public License, version 2.
 
4
#
 
5
# $Id: Template.pm 2549 2008-06-11 00:42:59Z fumiakiy $
 
6
 
 
7
package MT::CMS::Template;
 
8
 
 
9
use strict;
 
10
 
 
11
sub edit {
 
12
    my $cb = shift;
 
13
    my ($app, $id, $obj, $param) = @_;
 
14
 
 
15
    my $q = $app->param;
 
16
    my $blog_id = $q->param('blog_id');
 
17
 
 
18
    # FIXME: enumeration of types
 
19
    unless ( $blog_id ) {
 
20
        my $type = $q->param('type') || ( $obj ? $obj->type : undef );
 
21
        return $app->return_to_dashboard( redirect => 1 )
 
22
            if $type eq 'archive'
 
23
            || $type eq 'individual'
 
24
            || $type eq 'category'
 
25
            || $type eq 'page'
 
26
            || $type eq 'index';
 
27
    }
 
28
 
 
29
    # to trigger autosave logic in main edit routine
 
30
    $param->{autosave_support} = 1;
 
31
 
 
32
    my $type = $q->param('_type');
 
33
    my $blog = $app->blog;
 
34
    my $cfg = $app->config;
 
35
    my $perms = $app->permissions;
 
36
    my $can_preview = 0;
 
37
 
 
38
    if ($blog) {
 
39
        # include_system/include_cache are only applicable
 
40
        # to blog-level templates
 
41
        $param->{include_system} = $blog->include_system;
 
42
        $param->{include_cache} = $blog->include_cache;
 
43
    }
 
44
 
 
45
    if ($id) {
 
46
        # FIXME: Template types should not be enumerated here
 
47
        $param->{nav_templates} = 1;
 
48
        my $tab;
 
49
        if ( $obj->type eq 'index' ) {
 
50
            $tab = 'index';
 
51
            $param->{template_group_trans} = $app->translate('index');
 
52
        }
 
53
        elsif ($obj->type eq 'archive'
 
54
            || $obj->type eq 'individual'
 
55
            || $obj->type eq 'category'
 
56
            || $obj->type eq 'page' )
 
57
        {
 
58
 
 
59
            # FIXME: enumeration of types
 
60
            $tab = 'archive';
 
61
            $param->{template_group_trans} = $app->translate('archive');
 
62
        }
 
63
        elsif ( $obj->type eq 'custom' ) {
 
64
            $tab = 'module';
 
65
            $param->{template_group_trans} = $app->translate('module');
 
66
        }
 
67
        elsif ( $obj->type eq 'widget' ) {
 
68
            $tab = 'widget';
 
69
            $param->{template_group_trans} = $app->translate('widget');
 
70
        }
 
71
        elsif ( $obj->type eq 'email' ) {
 
72
            $tab = 'email';
 
73
            $param->{template_group_trans} = $app->translate('email');
 
74
        }
 
75
        else {
 
76
            $tab = 'system';
 
77
            $param->{template_group_trans} = $app->translate('system');
 
78
        }
 
79
        $param->{template_group} = $tab;
 
80
        $blog_id = $obj->blog_id;
 
81
 
 
82
        # FIXME: enumeration of types
 
83
             $param->{has_name} = $obj->type eq 'index'
 
84
          || $obj->type eq 'custom'
 
85
          || $obj->type eq 'widget'
 
86
          || $obj->type eq 'archive'
 
87
          || $obj->type eq 'category'
 
88
          || $obj->type eq 'page'
 
89
          || $obj->type eq 'individual';
 
90
        if ( !$param->{has_name} ) {
 
91
            $param->{ 'type_' . $obj->type } = 1;
 
92
            $param->{name} = $obj->name;
 
93
        }
 
94
        $app->add_breadcrumb( $param->{name} );
 
95
        $param->{has_outfile} = $obj->type eq 'index';
 
96
        $param->{has_rebuild} =
 
97
          (      ( $obj->type eq 'index' )
 
98
              && ( ( $blog->custom_dynamic_templates || "" ) ne 'all' ) );
 
99
 
 
100
        # FIXME: enumeration of types
 
101
             $param->{is_special} = $param->{type} ne 'index'
 
102
          && $param->{type} ne 'archive'
 
103
          && $param->{type} ne 'category'
 
104
          && $param->{type} ne 'page'
 
105
          && $param->{type} ne 'individual';
 
106
             $param->{has_build_options} = $param->{has_build_options}
 
107
          && $param->{type} ne 'custom'
 
108
          && $param->{type} ne 'widget'
 
109
          && !$param->{is_special};
 
110
        $param->{search_label} = $app->translate('Templates');
 
111
        $param->{object_type}  = 'template';
 
112
        my $published_url = $obj->published_url;
 
113
        $param->{published_url} = $published_url if $published_url;
 
114
        $param->{saved_rebuild} = 1 if $q->param('saved_rebuild');
 
115
        require MT::PublishOption;
 
116
        $param->{static_maps} = $obj->build_type == MT::PublishOption::DYNAMIC() ? 0 : 1;
 
117
 
 
118
        my $filter = $app->param('filter_key');
 
119
        if ($param->{template_group} eq 'email') {
 
120
            $app->param( 'filter_key', 'email_templates' );
 
121
        }elsif  ($param->{template_group} eq 'system') {
 
122
            $app->param( 'filter_key', 'system_templates' );
 
123
        }
 
124
        $app->load_list_actions( 'template', $param );
 
125
        $app->param( 'filter_key', $filter );
 
126
 
 
127
        $obj->compile;
 
128
        if ( $obj->{errors} && @{ $obj->{errors} } ) {
 
129
            $param->{error} = $app->translate(
 
130
                "One or more errors were found in this template.");
 
131
            $param->{error} .= "<ul>\n";
 
132
            foreach my $err ( @{ $obj->{errors} } ) {
 
133
                $param->{error} .= "<li>"
 
134
                  . MT::Util::encode_html( $err->{message} )
 
135
                  . "</li>\n";
 
136
            }
 
137
            $param->{error} .= "</ul>\n";
 
138
        }
 
139
 
 
140
        # Populate list of included templates
 
141
        if ( my $includes = $obj->getElementsByTagName('Include') ) {
 
142
            my @includes;
 
143
            my @widgets;
 
144
            my %seen;
 
145
            foreach my $tag (@$includes) {
 
146
                my $include = {};
 
147
                my $mod = $include->{include_module} = $tag->[1]->{module} || $tag->[1]->{widget};
 
148
                next unless $mod;
 
149
                my $type = $tag->[1]->{widget} ? 'widget' : 'custom';
 
150
                next if exists $seen{$type}{$mod};
 
151
                $seen{$type}{$mod} = 1;
 
152
                my $other = MT::Template->load(
 
153
                    {
 
154
                        blog_id => [ $obj->blog_id, 0 ],
 
155
                        name    => $mod,
 
156
                        type    => $type,
 
157
                    }, {
 
158
                        sort      => 'blog_id',
 
159
                        direction => 'descend',
 
160
                    }
 
161
                );
 
162
                if ($other) {
 
163
                    $include->{include_link} = $app->mt_uri(
 
164
                        mode => 'view',
 
165
                        args => {
 
166
                            blog_id => $other->blog_id || 0,
 
167
                            '_type' => 'template',
 
168
                            id      => $other->id
 
169
                        }
 
170
                    );
 
171
                    # Try to compile template module if using MTInclude in this template.
 
172
                    $other->compile;
 
173
                    if ( $other->{errors} && @{ $other->{errors} } ) {
 
174
                        $param->{error} = $app->translate(
 
175
                            "One or more errors were found in included template module (".$other->name.").");
 
176
                        $param->{error} .= "<ul>\n";
 
177
                        foreach my $err ( @{ $other->{errors} } ) {
 
178
                            $param->{error} .= "<li>"
 
179
                              . MT::Util::encode_html( $err->{message} )
 
180
                              . "</li>\n";
 
181
                        }
 
182
                        $param->{error} .= "</ul>\n";
 
183
                    }
 
184
                }
 
185
                else {
 
186
                    $include->{create_link} = $app->mt_uri(
 
187
                        mode => 'view',
 
188
                        args => {
 
189
                            blog_id => $obj->blog_id,
 
190
                            '_type' => 'template',
 
191
                            type    => $type,
 
192
                            name    => $mod,
 
193
                        }
 
194
                    );
 
195
                }
 
196
                if ($type eq 'widget') {
 
197
                    push @widgets, $include;
 
198
                } else {
 
199
                    push @includes, $include;
 
200
                }
 
201
            }
 
202
            $param->{include_loop} = \@includes if @includes;
 
203
            $param->{widget_loop} = \@widgets if @widgets;
 
204
        }
 
205
        my @sets = ( @{ $obj->getElementsByTagName('WidgetSet') || [] }, @{ $obj->getElementsByTagName('WidgetManager') || [] } );
 
206
        if ( @sets ) {
 
207
            my @widget_sets;
 
208
            my %seen;
 
209
            foreach my $set (@sets) {
 
210
                my $name = $set->[1]->{name};
 
211
                next unless $name;
 
212
                next if $seen{$name};
 
213
                $seen{$name} = 1;
 
214
                my $wset = MT::Template->load(
 
215
                    {
 
216
                        blog_id => [ $obj->blog_id, 0 ],
 
217
                        name    => $name,
 
218
                        type    => 'widgetset',
 
219
                    }, {
 
220
                        sort      => 'blog_id',
 
221
                        direction => 'descend',
 
222
                    }
 
223
                );
 
224
                if ( $wset ) {
 
225
                    push @widget_sets, {
 
226
                        include_link => $app->mt_uri(
 
227
                            mode => 'edit_widget',
 
228
                            args => {
 
229
                                blog_id => $wset->blog_id,
 
230
                                id => $wset->id,
 
231
                            },
 
232
                        ),
 
233
                        include_module => $name,
 
234
                    };
 
235
                }
 
236
                else {
 
237
                    push @widget_sets, {
 
238
                        create_link => $app->mt_uri(
 
239
                            mode => 'edit_widget',
 
240
                            args => {
 
241
                                blog_id => $blog_id,
 
242
                                name    => $name
 
243
                            },
 
244
                        ),
 
245
                        include_module => $name,
 
246
                    };
 
247
                }
 
248
            }
 
249
            $param->{widget_set_loop} = \@widget_sets if @widget_sets;
 
250
        }
 
251
        $param->{have_includes} = 1 if $param->{widget_set_loop} || $param->{include_loop} || $param->{widget_loop};
 
252
        # Populate archive types for creating new map
 
253
        my $obj_type = $obj->type;
 
254
        if (   $obj_type eq 'individual'
 
255
            || $obj_type eq 'page'
 
256
            || $obj_type eq 'author'
 
257
            || $obj_type eq 'category'
 
258
            || $obj_type eq 'archive' )
 
259
        {
 
260
            my @at = $app->publisher->archive_types;
 
261
            my @archive_types;
 
262
            for my $at (@at) {
 
263
                my $archiver      = $app->publisher->archiver($at);
 
264
                my $archive_label = $archiver->archive_label;
 
265
                $archive_label = $at unless $archive_label;
 
266
                $archive_label = $archive_label->()
 
267
                  if ( ref $archive_label ) eq 'CODE';
 
268
                if (   ( $obj_type eq 'archive' )
 
269
                    || ( $obj_type eq 'author' )
 
270
                    || ( $obj_type eq 'category' ) )
 
271
                {
 
272
 
 
273
                    # only include if it is NOT an entry-based archive type
 
274
                    next if $archiver->entry_based;
 
275
                }
 
276
                elsif ( $obj_type eq 'page' ) {
 
277
                    # only include if it is a entry-based archive type and page
 
278
                    next unless $archiver->entry_based;
 
279
                    next if $archiver->entry_class ne 'page';
 
280
                }
 
281
                elsif ( $obj_type eq 'individual' ) {
 
282
                    # only include if it is a entry-based archive type and entry
 
283
                    next unless $archiver->entry_based;
 
284
                    next if $archiver->entry_class eq 'page';
 
285
                }
 
286
                push @archive_types,
 
287
                  {
 
288
                    archive_type_translated => $archive_label,
 
289
                    archive_type            => $at,
 
290
                  };
 
291
                @archive_types =
 
292
                  sort { MT::App::CMS::archive_type_sorter( $a, $b ) } @archive_types;
 
293
            }
 
294
            $param->{archive_types} = \@archive_types;
 
295
 
 
296
            # Populate template maps for this template
 
297
            my $maps = _populate_archive_loop( $app, $blog, $obj );
 
298
            if (@$maps) {
 
299
                $param->{object_loop} = $param->{template_map_loop} = $maps
 
300
                  if @$maps;
 
301
                my %at;
 
302
                my $build_type = MT::PublishOption::DYNAMIC();
 
303
                my $build_type_0 = 0;
 
304
                foreach my $map ( @$maps ) {
 
305
                    $at{ $map->{archive_label} } = 1;
 
306
                    $build_type_0 = $map->{map_build_type};
 
307
                    $build_type = $map->{map_build_type}
 
308
                        if MT::PublishOption::DYNAMIC() ne $map->{map_build_type};
 
309
                }
 
310
                $param->{enabled_archive_types} = join(", ", sort keys %at);
 
311
                $param->{static_maps} = $build_type == MT::PublishOption::DYNAMIC() ? 0 : 1;
 
312
                $param->{build_type_0} = 1 unless $build_type_0;
 
313
            }
 
314
        }
 
315
        # publish options
 
316
        $param->{build_type} = $obj->build_type;
 
317
        $param->{ 'build_type_' . ( $obj->build_type || 0 ) } = 1;
 
318
        #my ( $period, $interval ) = _get_schedule( $obj->build_interval );
 
319
        #$param->{ 'schedule_period_' . $period } = 1;
 
320
        #$param->{schedule_interval} = $interval;
 
321
        $param->{type} = 'custom' if $param->{type} eq 'module';
 
322
    } else {
 
323
        my $new_tmpl = $q->param('create_new_template');
 
324
        my $template_type;
 
325
        if ($new_tmpl) {
 
326
            if ( $new_tmpl =~ m/^blank:(.+)/ ) {
 
327
                $template_type = $1;
 
328
                $param->{type} = $1;
 
329
            }
 
330
            elsif ( $new_tmpl =~ m/^default:([^:]+):(.+)/ ) {
 
331
                $template_type = $1;
 
332
                $template_type = 'custom' if $template_type eq 'module';
 
333
                my $template_id = $2;
 
334
                my $set = $blog ? $blog->template_set : undef;
 
335
                require MT::DefaultTemplates;
 
336
                my $def_tmpl = MT::DefaultTemplates->templates($set) || [];
 
337
                my ($tmpl) =
 
338
                  grep { $_->{identifier} eq $template_id } @$def_tmpl;
 
339
                $param->{text} = $app->translate_templatized( $tmpl->{text} )
 
340
                  if $tmpl;
 
341
                $param->{type} = $template_type;
 
342
            }
 
343
        }
 
344
        else {
 
345
            $template_type = $q->param('type');
 
346
            $template_type = 'custom' if 'module' eq $template_type;
 
347
            $param->{type}   = $template_type;
 
348
        }
 
349
        return $app->errtrans("Create template requires type")
 
350
          unless $template_type;
 
351
        $param->{nav_templates} = 1;
 
352
        my $tab;
 
353
 
 
354
        # FIXME: enumeration of types
 
355
        if ( $template_type eq 'index' ) {
 
356
            $tab = 'index';
 
357
            $param->{template_group_trans} = $app->translate('index');
 
358
        }
 
359
        elsif ($template_type eq 'archive'
 
360
            || $template_type eq 'individual'
 
361
            || $template_type eq 'category'
 
362
            || $template_type eq 'page' )
 
363
        {
 
364
            $tab                         = 'archive';
 
365
            $param->{template_group_trans} = $app->translate('archive');
 
366
            $param->{type_archive}         = 1;
 
367
            my @types = (
 
368
                {
 
369
                    key   => 'archive',
 
370
                    label => $app->translate('Archive')
 
371
                },
 
372
                {
 
373
                    key   => 'individual',
 
374
                    label => $app->translate('Entry or Page')
 
375
                },
 
376
            );
 
377
            $param->{new_archive_types} = \@types;
 
378
        }
 
379
        elsif ( $template_type eq 'custom' ) {
 
380
            $tab = 'module';
 
381
            $param->{template_group_trans} = $app->translate('module');
 
382
        }
 
383
        elsif ( $template_type eq 'widget' ) {
 
384
            $tab = 'widget';
 
385
            $param->{template_group_trans} = $app->translate('widget');
 
386
        }
 
387
        else {
 
388
            $tab = 'system';
 
389
            $param->{template_group_trans} = $app->translate('system');
 
390
        }
 
391
        $param->{template_group} = $tab;
 
392
        $app->translate($tab);
 
393
        $app->add_breadcrumb( $app->translate('New Template') );
 
394
 
 
395
        # FIXME: enumeration of types
 
396
             $param->{has_name} = $template_type eq 'index'
 
397
          || $template_type eq 'custom'
 
398
          || $template_type eq 'widget'
 
399
          || $template_type eq 'archive'
 
400
          || $template_type eq 'category'
 
401
          || $template_type eq 'page'
 
402
          || $template_type eq 'individual';
 
403
        $param->{has_outfile} = $template_type eq 'index';
 
404
        $param->{has_rebuild} =
 
405
          (      ( $template_type eq 'index' )
 
406
              && ( ( $blog->custom_dynamic_templates || "" ) ne 'all' ) );
 
407
        $param->{custom_dynamic} =
 
408
          $blog && $blog->custom_dynamic_templates eq 'custom';
 
409
        $param->{has_build_options} =
 
410
             $blog && ($blog->custom_dynamic_templates eq 'custom'
 
411
          || $param->{has_rebuild});
 
412
 
 
413
        # FIXME: enumeration of types
 
414
             $param->{is_special} = $param->{type} ne 'index'
 
415
          && $param->{type} ne 'archive'
 
416
          && $param->{type} ne 'category'
 
417
          && $param->{type} ne 'page'
 
418
          && $param->{type} ne 'individual';
 
419
             $param->{has_build_options} = $param->{has_build_options}
 
420
          && $param->{type} ne 'custom'
 
421
          && $param->{type} ne 'widget'
 
422
          && !$param->{is_special};
 
423
 
 
424
        $param->{name}       = MT::Util::decode_url( $app->param('name') )
 
425
          if $app->param('name');
 
426
    }
 
427
    $param->{publish_queue_available} = eval 'require List::Util; require Scalar::Util; 1;';
 
428
 
 
429
    my $set = $blog ? $blog->template_set : undef;
 
430
    require MT::DefaultTemplates;
 
431
    my $tmpls = MT::DefaultTemplates->templates($set);
 
432
    my @tmpl_ids;
 
433
    foreach my $dtmpl (@$tmpls) {
 
434
        if ( !$param->{has_name} ) {
 
435
            if ($obj->type eq 'email') {
 
436
                if ($dtmpl->{identifier} eq $obj->identifier) {
 
437
                    $param->{template_name_label} = $dtmpl->{label};
 
438
                    $param->{template_name}       = $dtmpl->{name};
 
439
                }
 
440
            }
 
441
            else {
 
442
                if ( $dtmpl->{type} eq $obj->type ) {
 
443
                    $param->{template_name_label} = $dtmpl->{label};
 
444
                    $param->{template_name}       = $dtmpl->{name};
 
445
                }
 
446
            }
 
447
        }
 
448
        if ( $dtmpl->{type} eq 'index' ) {
 
449
            push @tmpl_ids,
 
450
              {
 
451
                label    => $dtmpl->{label},
 
452
                key      => $dtmpl->{key},
 
453
                selected => $dtmpl->{key} eq
 
454
                  ( ( $obj ? $obj->identifier : undef ) || '' ),
 
455
              };
 
456
        }
 
457
    }
 
458
    $param->{index_identifiers} = \@tmpl_ids;
 
459
 
 
460
    $param->{"type_$param->{type}"} = 1;
 
461
    if ($perms) {
 
462
        my $pref_param =
 
463
          $app->load_template_prefs( $perms->template_prefs );
 
464
        %$param = ( %$param, %$pref_param );
 
465
    }
 
466
 
 
467
    # Populate structure for template snippets
 
468
    if ( my $snippets = $app->registry('template_snippets') || {} ) {
 
469
        my @snippets;
 
470
        for my $snip_id ( keys %$snippets ) {
 
471
            my $label = $snippets->{$snip_id}{label};
 
472
            $label = $label->() if ref($label) eq 'CODE';
 
473
            push @snippets,
 
474
              {
 
475
                id      => $snip_id,
 
476
                trigger => $snippets->{$snip_id}{trigger},
 
477
                label   => $label,
 
478
                content => $snippets->{$snip_id}{content},
 
479
              };
 
480
        }
 
481
        @snippets = sort { $a->{label} cmp $b->{label} } @snippets;
 
482
        $param->{template_snippets} = \@snippets;
 
483
    }
 
484
 
 
485
    # Populate structure for tag documentation
 
486
    my $all_tags = MT::Component->registry("tags");
 
487
    my $tag_docs = {};
 
488
    foreach my $tag_set (@$all_tags) {
 
489
        my $url = $tag_set->{help_url};
 
490
        $url = $url->() if ref($url) eq 'CODE';
 
491
        # hey, at least give them a google search
 
492
        $url ||= 'http://www.google.com/search?q=mt%t';
 
493
        my $tag_list = '';
 
494
        foreach my $type (qw( block function )) {
 
495
            my $tags = $tag_set->{$type} or next;
 
496
            $tag_list .= ($tag_list eq '' ? '' : ',') . join(",", keys(%$tags));
 
497
        }
 
498
        $tag_list =~ s/(^|,)plugin(,|$)/,/;
 
499
        if (exists $tag_docs->{$url}) {
 
500
            $tag_docs->{$url} .= ',' . $tag_list;
 
501
        }
 
502
        else {
 
503
            $tag_docs->{$url} = $tag_list;
 
504
        }
 
505
    }
 
506
    $param->{tag_docs} = $tag_docs;
 
507
    $param->{link_doc} = $app->help_url('appendices/tags/');
 
508
 
 
509
    $param->{screen_id} = "edit-template-" . $param->{type};
 
510
 
 
511
    # template language
 
512
    $param->{template_lang} = 'html';
 
513
    if ( $obj && $obj->outfile ) {
 
514
        if ( $obj->outfile =~ m/\.(css|js|html|php|pl|asp)$/ ) {
 
515
            $param->{template_lang} = {
 
516
                css => 'css',
 
517
                js => 'javascript',
 
518
                html => 'html',
 
519
                php => 'php',
 
520
                pl => 'perl',
 
521
                asp => 'asp',
 
522
            }->{$1};
 
523
        }
 
524
    }
 
525
 
 
526
    if (($param->{type} eq 'custom') || ($param->{type} eq 'widget')) {
 
527
        if ($blog) {
 
528
            $param->{include_with_ssi}      = 0;
 
529
            $param->{cache_path}            = '';
 
530
            $param->{cache_expire_type}     = 0;
 
531
            $param->{cache_expire_period}   = '';
 
532
            $param->{cache_expire_interval} = 0;
 
533
            $param->{ssi_type} = uc $blog->include_system;
 
534
        }
 
535
        if ($obj) {
 
536
            $param->{include_with_ssi} = $obj->include_with_ssi
 
537
              if defined $obj->include_with_ssi;
 
538
            $param->{cache_path}       = $obj->cache_path
 
539
              if defined $obj->cache_path;
 
540
            $param->{cache_expire_type} = $obj->cache_expire_type
 
541
              if defined $obj->cache_expire_type;
 
542
            my ( $period, $interval ) =
 
543
              _get_schedule( $obj->cache_expire_interval );
 
544
            $param->{cache_expire_period}   = $period   if defined $period;
 
545
            $param->{cache_expire_interval} = $interval if defined $interval;
 
546
            my @events = split ',', ($obj->cache_expire_event || '');
 
547
            foreach my $name (@events) {
 
548
                $param->{ 'cache_expire_event_' . $name } = 1;
 
549
            }
 
550
        }
 
551
    }
 
552
 
 
553
    # if unset, default to 30 so if they choose to enable caching,
 
554
    # it will be preset to something sane.
 
555
    $param->{cache_expire_interval} ||= 30;
 
556
 
 
557
    $param->{dirty} = 1
 
558
        if $app->param('dirty');
 
559
 
 
560
    $param->{can_preview} = 1
 
561
        if (!$param->{is_special}) && (!$obj || ($obj && ($obj->outfile || '') !~ m/\.(css|xml|rss|js)$/));
 
562
 
 
563
    1;
 
564
}
 
565
 
 
566
sub list {
 
567
    my $app = shift;
 
568
 
 
569
    my $perms = $app->blog ? $app->permissions : $app->user->permissions;
 
570
    return $app->return_to_dashboard( redirect => 1 )
 
571
      unless $perms || $app->user->is_superuser;
 
572
    if ( $perms && !$perms->can_edit_templates ) {
 
573
        return $app->return_to_dashboard( permission => 1 );
 
574
    }
 
575
    my $blog = $app->blog;
 
576
 
 
577
    require MT::Template;
 
578
    my $blog_id = $app->param('blog_id') || 0;
 
579
    my $terms = { blog_id => $blog_id };
 
580
    my $args  = { sort    => 'name' };
 
581
 
 
582
    my $hasher = sub {
 
583
        my ( $obj, $row ) = @_;
 
584
        my $template_type;
 
585
        my $type = $row->{type} || '';
 
586
        if ( $type =~ m/^(individual|page|category|archive)$/ ) {
 
587
            $template_type = 'archive';
 
588
            # populate context with templatemap loop
 
589
            my $tblog = $obj->blog_id == $blog->id ? $blog : MT::Blog->load( $obj->blog_id );
 
590
            if ($tblog) {
 
591
                $row->{archive_types} = _populate_archive_loop( $app, $tblog, $obj );
 
592
            }
 
593
        }
 
594
        elsif ( $type eq 'widget' ) {
 
595
            $template_type = 'widget';
 
596
        }
 
597
        elsif ( $type eq 'index' ) {
 
598
            $template_type = 'index';
 
599
        }
 
600
        elsif ( $type eq 'custom' ) {
 
601
            $template_type = 'module';
 
602
        }
 
603
        elsif ( $type eq 'email' ) {
 
604
            $template_type = 'email';
 
605
        }
 
606
        elsif ( $type eq 'backup' ) {
 
607
            $template_type = 'backup';
 
608
        }
 
609
        else {
 
610
            $template_type = 'system';
 
611
        }
 
612
        $row->{use_cache} = ( ($obj->cache_expire_type || 0) != 0 ) ? 1 : 0;
 
613
        $row->{template_type} = $template_type;
 
614
        $row->{type} = 'entry' if $type eq 'individual';
 
615
        my $published_url = $obj->published_url;
 
616
        $row->{published_url} = $published_url if $published_url;
 
617
    };
 
618
 
 
619
    my $params        = {};
 
620
    my $filter = $app->param('filter_key');
 
621
    my $template_type = $filter || '';
 
622
    $template_type =~ s/_templates//;
 
623
 
 
624
    $params->{screen_class} = "list-template";
 
625
    $params->{listing_screen} = 1;
 
626
 
 
627
    $app->load_list_actions( 'template', $params );
 
628
    $params->{page_actions} = $app->page_actions('list_templates');
 
629
    $params->{search_label} = $app->translate("Templates");
 
630
    $params->{object_type} = 'template';
 
631
    $params->{blog_view} = 1;
 
632
    $params->{refreshed} = $app->param('refreshed');
 
633
    $params->{published} = $app->param('published');
 
634
    $params->{saved_copied} = $app->param('saved_copied');
 
635
    $params->{saved_deleted} = $app->param('saved_deleted');
 
636
    $params->{saved} = $app->param('saved');
 
637
 
 
638
    # determine list of system template types:
 
639
    my $scope;
 
640
    my $set;
 
641
    if ( $blog ) {
 
642
        $set   = $blog->template_set;
 
643
        $scope = 'system';
 
644
    }
 
645
    else {
 
646
        $scope = 'global:system';
 
647
    }
 
648
    my @tmpl_path = ( $set && ($set ne 'mt_blog')) ? ("template_sets", $set, 'templates', $scope) : ("default_templates", $scope);
 
649
    my $sys_tmpl = MT->registry(@tmpl_path) || {};
 
650
 
 
651
    my @tmpl_loop;
 
652
    my %types;
 
653
    if ($template_type ne 'backup') {
 
654
        if ($blog) {
 
655
            # blog template listings
 
656
            %types = ( 
 
657
                'index' => {
 
658
                    label => $app->translate("Index Templates"),
 
659
                    type => 'index',
 
660
                    order => 100,
 
661
                },
 
662
                'archive' => {
 
663
                    label => $app->translate("Archive Templates"),
 
664
                    type => ['archive', 'individual', 'page', 'category'],
 
665
                    order => 200,
 
666
                },
 
667
                'module' => {
 
668
                    label => $app->translate("Template Modules"),
 
669
                    type => 'custom',
 
670
                    order => 300,
 
671
                },
 
672
                'system' => {
 
673
                    label => $app->translate("System Templates"),
 
674
                    type => [ keys %$sys_tmpl ],
 
675
                    order => 400,
 
676
                },
 
677
            );
 
678
        } else {
 
679
            # global template listings
 
680
            %types = ( 
 
681
                'module' => {
 
682
                    label => $app->translate("Template Modules"),
 
683
                    type => 'custom',
 
684
                    order => 100,
 
685
                },
 
686
                'email' => {
 
687
                    label => $app->translate("Email Templates"),
 
688
                    type => 'email',
 
689
                    order => 200,
 
690
                },
 
691
                'system' => {
 
692
                    label => $app->translate("System Templates"),
 
693
                    type => [ keys %$sys_tmpl ],
 
694
                    order => 300,
 
695
                },
 
696
            );
 
697
        }
 
698
    } else {
 
699
        # global template listings
 
700
        %types = ( 
 
701
            'backup' => {
 
702
                label => $app->translate("Template Backups"),
 
703
                type => 'backup',
 
704
                order => 100,
 
705
            },
 
706
        );
 
707
    }
 
708
    my @types = sort { $types{$a}->{order} <=> $types{$b}->{order} } keys %types;
 
709
    if ($template_type) {
 
710
        @types = ( $template_type );
 
711
    }
 
712
    $app->delete_param('filter_key') if $filter;
 
713
    foreach my $tmpl_type (@types) {
 
714
        if ( $tmpl_type eq 'index' ) {
 
715
            $app->param( 'filter_key', 'index_templates' );
 
716
        }
 
717
        elsif ( $tmpl_type eq 'archive' ) {
 
718
            $app->param( 'filter_key', 'archive_templates' );
 
719
        }
 
720
        elsif ( $tmpl_type eq 'system' ) {
 
721
            $app->param( 'filter_key', 'system_templates' );
 
722
        }
 
723
        elsif ( $tmpl_type eq 'email' ) {
 
724
            $app->param( 'filter_key', 'email_templates' );
 
725
        }
 
726
        elsif ( $tmpl_type eq 'module' ) {
 
727
            $app->param( 'filter_key', 'module_templates' );
 
728
        }
 
729
        my $tmpl_param = {};
 
730
        unless ( exists($types{$tmpl_type}->{type})
 
731
          && 'ARRAY' eq ref($types{$tmpl_type}->{type})
 
732
          && 0 == scalar(@{$types{$tmpl_type}->{type}}) )
 
733
        {
 
734
            $terms->{type} = $types{$tmpl_type}->{type};
 
735
            $tmpl_param = $app->listing(
 
736
                {
 
737
                    type     => 'template',
 
738
                    terms    => $terms,
 
739
                    args     => $args,
 
740
                    no_limit => 1,
 
741
                    no_html  => 1,
 
742
                    code     => $hasher,
 
743
                }
 
744
            );
 
745
        }
 
746
        my $template_type_label = $types{$tmpl_type}->{label};
 
747
        $tmpl_param->{template_type} = $tmpl_type;
 
748
        $tmpl_param->{template_type_label} = $template_type_label;
 
749
        push @tmpl_loop, $tmpl_param;
 
750
    }
 
751
    if ($filter) {
 
752
        $params->{filter_key} = $filter;
 
753
        $params->{filter_label} = $types{$template_type}{label}
 
754
            if exists $types{$template_type};
 
755
        $app->param('filter_key', $filter);
 
756
    } else {
 
757
        # restore filter_key param (we modified it for the
 
758
        # sake of the individual table listings)
 
759
        $app->delete_param('filter_key');
 
760
    }
 
761
 
 
762
    $params->{template_type_loop} = \@tmpl_loop;
 
763
    $params->{screen_id} = "list-template";
 
764
 
 
765
    return $app->load_tmpl('list_template.tmpl', $params);
 
766
}
 
767
 
 
768
sub preview {
 
769
    my $app         = shift;
 
770
    my $q           = $app->param;
 
771
    my $blog_id     = $q->param('blog_id');
 
772
    my $blog        = $app->blog;
 
773
    my $id          = $q->param('id');
 
774
    my $tmpl;
 
775
    my $user_id = $app->user->id;
 
776
 
 
777
    # We can only do previews on blog templates. Have to publish
 
778
    # the preview file somewhere!
 
779
    return $app->errtrans("Invalid request.") unless $blog;
 
780
 
 
781
    require MT::Template;
 
782
    if ($id) {
 
783
        $tmpl = MT::Template->load( { id => $id, blog_id => $blog_id } )
 
784
            or return $app->errtrans( "Invalid request." );
 
785
    }
 
786
    else {
 
787
        $tmpl = MT::Template->new;
 
788
        $tmpl->id(-1);
 
789
        $tmpl->blog_id($blog_id);
 
790
    }
 
791
 
 
792
    my $names = $tmpl->column_names;
 
793
    my %values = map { $_ => scalar $app->param($_) } @$names;
 
794
    delete $values{'id'} unless $q->param('id');
 
795
 
 
796
    ## Strip linefeed characters.
 
797
    for my $col (qw( text )) {
 
798
        $values{$col} =~ tr/\r//d if $values{$col};
 
799
    }
 
800
    $tmpl->set_values( \%values );
 
801
 
 
802
    my $preview_basename = $app->preview_object_basename;
 
803
 
 
804
    my $type = $tmpl->type;
 
805
    my $preview_tmpl = $tmpl;
 
806
    my $archive_file;
 
807
    my $archive_url;
 
808
    my %param;
 
809
    my $blog_path = $blog->site_path;
 
810
    my $blog_url = $blog->site_url;
 
811
 
 
812
    if (($type eq 'custom') || ($type eq 'widget')) {
 
813
        # determine 'host' template
 
814
        $preview_tmpl = MT::Template->load({ blog_id => $blog_id, identifier => 'main_index' });
 
815
        if (!$preview_tmpl) {
 
816
            return $app->errtrans("Can't locate host template to preview module/widget.");
 
817
        }
 
818
        my $req = $app->request;
 
819
        # stash this module so that it is selected through a
 
820
        # MTInclude tag instead of the one in the database:
 
821
        my $tmpl_name = $tmpl->name;
 
822
        $tmpl_name =~ s/^Widget: // if $type eq 'widget';
 
823
        my $stash_id = 'template_' . $type . '::' . $blog_id . '::' . $tmpl_name;
 
824
        $req->stash($stash_id, [ $tmpl, $tmpl->tokens ]);
 
825
    } elsif (($type eq 'individual') || ($type eq 'page')) {
 
826
        my $ctx = $preview_tmpl->context;
 
827
        my $entry_type = $type eq 'individual' ? 'entry' : 'page';
 
828
        my ($obj) = create_preview_content($app, $blog, $entry_type, 1);
 
829
        $obj->basename( $preview_basename );
 
830
        $ctx->stash('entry', $obj);
 
831
        $ctx->{current_archive_type} = $type eq 'individual' ? 'Individual' : 'Page';
 
832
        if (($type eq 'individual') && $blog->archive_path) {
 
833
            $blog_path = $blog->archive_path;
 
834
            $blog_url = $blog->archive_url;
 
835
        }
 
836
        $archive_file = File::Spec->catfile( $blog_path, $obj->archive_file );
 
837
        $archive_url = $obj->archive_url;
 
838
 
 
839
        my $archiver = MT->publisher->archiver( $ctx->{current_archive_type} );
 
840
        my $tparams = $archiver->template_params;
 
841
        if ($tparams) {
 
842
            $ctx->var( $_, $tparams->{$_} ) for keys %$tparams;
 
843
        }
 
844
    } elsif ($type eq 'archive') {
 
845
        # some variety of archive template
 
846
        my $ctx = $preview_tmpl->context;
 
847
        require MT::TemplateMap;
 
848
        my $map = MT::TemplateMap->load( { template_id => $id, is_preferred => 1 });
 
849
        if (! $map) {
 
850
            return $app->error("Cannot preview without a template map!");
 
851
        }
 
852
        $ctx->{current_archive_type} = $map->archive_type;
 
853
        my $archiver = MT->publisher->archiver( $map->archive_type );
 
854
        my $tparams = $archiver->template_params;
 
855
        if ($tparams) {
 
856
            $ctx->var( $_, $tparams->{$_} ) for keys %$tparams;
 
857
        }
 
858
        my @entries = create_preview_content($app, $blog, $archiver->entry_class, 10);
 
859
        if ($archiver->date_based) {
 
860
            $ctx->{current_timestamp} = $entries[0]->authored_on;
 
861
            $ctx->{current_timestamp_end} = $entries[$#entries]->authored_on;
 
862
        }
 
863
        if ($archiver->author_based) {
 
864
            $ctx->stash('author', $app->user);
 
865
        }
 
866
        my $cat;
 
867
        if ($archiver->category_based) {
 
868
            $cat = new MT::Category;
 
869
            $cat->label($app->translate("Preview"));
 
870
            $cat->basename("preview");
 
871
            $cat->parent(0);
 
872
            $ctx->stash('archive_category', $cat);
 
873
        }
 
874
        $ctx->stash('entries', \@entries);
 
875
 
 
876
        my $file = MT->publisher->archive_file_for( $entries[0], $blog, $map->archive_type, $cat, $map, $ctx->{current_timestamp}, $app->user);
 
877
        $archive_file = File::Spec->catfile( $blog_path, $file );
 
878
        $archive_url = MT::Util::caturl( $blog_url, $file );
 
879
    } elsif ($type eq 'index') {
 
880
    } else {
 
881
        # for now, only index templates can be previewed
 
882
        return $app->errtrans("Invalid request.");
 
883
    }
 
884
 
 
885
    my $orig_file;
 
886
    my $path;
 
887
 
 
888
    # Default case; works for index templates (other template types should
 
889
    # have defined $archive_file by now).
 
890
    $archive_file = File::Spec->catfile( $blog_path, $preview_tmpl->outfile )
 
891
        unless defined $archive_file;
 
892
 
 
893
    ( $orig_file, $path ) = File::Basename::fileparse( $archive_file );
 
894
 
 
895
    $archive_url = MT::Util::caturl( $blog_url, $orig_file )
 
896
        unless defined $archive_url;
 
897
 
 
898
    my $file_ext;
 
899
    require File::Basename;
 
900
    $file_ext = $archive_file;
 
901
    if ($file_ext =~ m/\.[a-z]+$/) {
 
902
        $file_ext =~ s!.+\.!.!;
 
903
    } else {
 
904
        $file_ext = '';
 
905
    }
 
906
    $archive_file = File::Spec->catfile( $path, $preview_basename . $file_ext );
 
907
 
 
908
    my @data;
 
909
    $app->run_callbacks( 'cms_pre_preview.template', $app, $preview_tmpl, \@data );
 
910
 
 
911
    my $has_hires = eval 'require Time::HiRes; 1' ? 1 : 0;
 
912
    my $start_time = $has_hires ? Time::HiRes::time() : time;
 
913
 
 
914
    my $ctx = $preview_tmpl->context;
 
915
    $ctx->var('preview_template', 1);
 
916
    my $html = $preview_tmpl->output;
 
917
 
 
918
    $param{build_time} = $has_hires ? sprintf("%.3f", Time::HiRes::time() - $start_time ) : "~" . ( time - $start_time );
 
919
 
 
920
    unless ( defined($html) ) {
 
921
        return $app->error( $app->translate( "Publish error: [_1]",
 
922
            MT::Util::encode_html( $preview_tmpl->errstr ) ) );
 
923
    }
 
924
 
 
925
    # If MT is configured to do 'local' previews, convert all
 
926
    # the normal blog URLs into the domain used by MT itself (ie,
 
927
    # blog is published to www.example.com, which is a different
 
928
    # server from where MT runs, mt.example.com; previews therefore
 
929
    # should occur locally, so replace all http://www.example.com/
 
930
    # with http://mt.example.com/).
 
931
    my ($old_url, $new_url);
 
932
    if ($app->config('LocalPreviews')) {
 
933
        $old_url = $blog_url;
 
934
        $old_url =~ s!^(https?://[^/]+?/)(.*)?!$1!;
 
935
        $new_url = $app->base . '/';
 
936
        $html =~ s!\Q$old_url\E!$new_url!g;
 
937
    }
 
938
 
 
939
    my $fmgr = $blog->file_mgr;
 
940
 
 
941
    ## Determine if we need to build directory structure,
 
942
    ## and build it if we do. DirUmask determines
 
943
    ## directory permissions.
 
944
    require File::Basename;
 
945
    $path =~ s!/$!!
 
946
      unless $path eq '/';    ## OS X doesn't like / at the end in mkdir().
 
947
    unless ( $fmgr->exists($path) ) {
 
948
        $fmgr->mkpath($path);
 
949
    }
 
950
 
 
951
    if ( $fmgr->exists($path) && $fmgr->can_write($path) ) {
 
952
        $param{preview_file} = $preview_basename;
 
953
        my $preview_url = $archive_url;
 
954
        $preview_url =~ s! / \Q$orig_file\E ( /? ) $!/$preview_basename$file_ext$1!x;
 
955
 
 
956
        # We also have to translate the URL used for the
 
957
        # published file to be on the MT app domain.
 
958
        if (defined $new_url) {
 
959
            $preview_url =~ s!^\Q$old_url\E!$new_url!;
 
960
        }
 
961
 
 
962
        $param{preview_url}  = $preview_url;
 
963
 
 
964
        $fmgr->put_data( $html, $archive_file );
 
965
 
 
966
        # we have to make a record of this preview just in case it
 
967
        # isn't cleaned up by re-editing, saving or cancelling on
 
968
        # by the user.
 
969
        require MT::Session;
 
970
        my $sess_obj = MT::Session->get_by_key(
 
971
            {
 
972
                id   => $preview_basename,
 
973
                kind => 'TF',                # TF = Temporary File
 
974
                name => $archive_file,
 
975
            }
 
976
        );
 
977
        $sess_obj->start(time);
 
978
        $sess_obj->save;
 
979
    }
 
980
    else {
 
981
        return $app->error( $app->translate(
 
982
            "Unable to create preview file in this location: [_1]", $path ) );
 
983
    }
 
984
 
 
985
    $param{id} = $id if $id;
 
986
    $param{new_object} = $param{id} ? 0 : 1;
 
987
    $param{name} = $tmpl->name;
 
988
    $q->param( 'build_dynamic', $tmpl->build_dynamic );
 
989
    my $cols = $tmpl->column_names;
 
990
    for my $col (@$cols) {
 
991
        push @data,
 
992
          {
 
993
            data_name  => $col,
 
994
            data_value => scalar $q->param($col)
 
995
          };
 
996
    }
 
997
    $param{template_loop} = \@data;
 
998
    $param{object_type}  = $type;
 
999
    return $app->load_tmpl( 'preview_template_strip.tmpl', \%param );
 
1000
}
 
1001
 
 
1002
sub create_preview_content {
 
1003
    my ($app, $blog, $type, $number) = @_;
 
1004
 
 
1005
    my $blog_id = $blog->id;
 
1006
    my $entry_class = $app->model($type);
 
1007
    my @obj = $entry_class->load({
 
1008
        blog_id => $blog_id,
 
1009
        status => MT::Entry::RELEASE()
 
1010
    }, {
 
1011
        limit => $number || 1,
 
1012
        direction => 'descend',
 
1013
        'sort' => 'authored_on'
 
1014
    });
 
1015
    unless ( @obj ) {
 
1016
        # create a dummy object
 
1017
        my $obj = $entry_class->new;
 
1018
        $obj->blog_id($blog_id);
 
1019
        $obj->id(-1);
 
1020
        $obj->author_id( $app->user->id );
 
1021
        $obj->authored_on( $blog->current_timestamp );
 
1022
        $obj->status( MT::Entry::RELEASE() );
 
1023
        $obj->title($app->translate("Lorem ipsum"));
 
1024
        my $preview_text = $app->translate('LOREM_IPSUM_TEXT');
 
1025
        if ($preview_text eq 'LOREM_IPSUM_TEXT') {
 
1026
            $preview_text = q{Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Ut diam quam, accumsan eu, aliquam vel, ultrices a, augue. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Fusce hendrerit, lacus eget bibendum sollicitudin, mi tellus interdum neque, sit amet pretium tortor tellus id erat. Duis placerat justo ac erat. Duis posuere, risus eu elementum viverra, nisl lacus sagittis lorem, ac fermentum neque pede vitae arcu. Phasellus arcu elit, placerat eu, luctus posuere, tristique non, augue. In hac habitasse platea dictumst. Nunc non dolor et ipsum mattis malesuada. Praesent porta orci eu ligula. Ut dui augue, dapibus vitae, sodales in, lobortis non, felis. Aliquam feugiat mollis ipsum.};
 
1027
        }
 
1028
        my $preview_more = $app->translate('LORE_IPSUM_TEXT_MORE');
 
1029
        if ($preview_text eq 'LOREM_IPSUM_TEXT_MORE') {
 
1030
            $preview_more = q{Integer nunc nulla, vulputate sit amet, varius ac, faucibus ac, lectus. Nulla semper bibendum justo. In hac habitasse platea dictumst. Aliquam auctor pretium ante. Etiam porta consectetuer erat. Phasellus consequat, nisi eu suscipit elementum, metus leo malesuada pede, vel scelerisque lorem ligula in augue. Sed aliquet. Donec malesuada metus sit amet sapien. Integer non libero. Morbi egestas, mauris posuere consequat sodales, augue lectus suscipit velit, eu commodo lacus dolor congue justo. Suspendisse justo. Curabitur sagittis, lorem tincidunt elementum rhoncus, odio dolor mattis odio, quis ultrices ligula ipsum ac lacus. Nam et sapien ac lacus ultrices sollicitudin. Vestibulum ut dolor nec dui malesuada imperdiet. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
 
1031
 
 
1032
            Quisque pharetra libero quis nibh. Cras lacus orci, commodo et, fringilla non, lobortis non, mauris. Curabitur dui sapien, tristique imperdiet, ultrices vitae, gravida varius, ante. Maecenas ac arcu nec nibh euismod feugiat. Pellentesque sed orci eget enim egestas faucibus. Aenean laoreet leo ornare velit. Nunc fermentum dolor eget massa. Fusce fringilla, tellus in pellentesque sodales, urna mi hendrerit leo, vel adipiscing ligula odio sit amet risus. Cras rhoncus, mi et posuere gravida, purus sem porttitor nisl, auctor laoreet nisl turpis quis ligula. Aliquam in nisi tristique augue egestas lacinia. Aenean ante magna, facilisis a, faucibus at, aliquam laoreet, dui. Ut tellus leo, tristique a, pellentesque ac, bibendum non, ipsum. Curabitur eu neque pretium arcu accumsan tincidunt. Ut ipsum. Quisque congue accumsan elit. Nulla ligula felis, aliquam ultricies, vestibulum vestibulum, semper vel, sapien. Aenean sodales ligula venenatis tellus. Vestibulum leo. Morbi viverra convallis eros.
 
1033
 
 
1034
            Phasellus rhoncus pulvinar enim. Ut gravida ante nec lectus. Nam luctus gravida odio. Morbi vitae lorem vitae justo fermentum porttitor. Suspendisse vestibulum magna at purus. Cras nec sem. Duis id felis. Mauris hendrerit dapibus est. Donec semper. Praesent vehicula interdum velit. Ut sed tellus et diam venenatis pulvinar.};
 
1035
        }
 
1036
        $obj->text($preview_text);
 
1037
        $obj->text_more($preview_more);
 
1038
        $obj->keywords(MT->translate("sample, entry, preview"));
 
1039
        $obj->tags(qw( lorem ipsum sample preview ));
 
1040
        @obj = ($obj);
 
1041
    }
 
1042
    return @obj;
 
1043
}
 
1044
 
 
1045
sub reset_blog_templates {
 
1046
    my $app   = shift;
 
1047
    my $q     = $app->param;
 
1048
    my $perms = $app->permissions
 
1049
      or return $app->error( $app->translate("No permissions") );
 
1050
    return $app->error( $app->translate("Permission denied.") )
 
1051
      unless $perms->can_edit_templates;
 
1052
    $app->validate_magic() or return;
 
1053
    my $blog = MT::Blog->load( $perms->blog_id )
 
1054
        or return $app->error($app->translate('Can\'t load blog #[_1].', $perms->blog_id));
 
1055
    require MT::Template;
 
1056
    my @tmpl = MT::Template->load( { blog_id => $blog->id } );
 
1057
 
 
1058
    for my $tmpl (@tmpl) {
 
1059
        $tmpl->remove or return $app->error( $tmpl->errstr );
 
1060
    }
 
1061
    my $set = $blog ? $blog->template_set : undef;
 
1062
    require MT::DefaultTemplates;
 
1063
    my $tmpl_list = MT::DefaultTemplates->templates($set) || [];
 
1064
    my @arch_tmpl;
 
1065
    for my $val (@$tmpl_list) {
 
1066
        $val->{text} = $app->translate_templatized( $val->{text} );
 
1067
        my $tmpl = MT::Template->new;
 
1068
        if ( ( 'widgetset' eq $val->{type} )
 
1069
          && ( exists $val->{modulesets} ) ) {
 
1070
            my $modulesets = delete $val->{modulesets};
 
1071
            $tmpl->modulesets( join ',', @$modulesets );
 
1072
        }
 
1073
        $tmpl->set_values($val);
 
1074
        $tmpl->build_dynamic(0);
 
1075
        $tmpl->blog_id( $blog->id );
 
1076
        $tmpl->save
 
1077
          or return $app->error(
 
1078
            $app->translate(
 
1079
                "Populating blog with default templates failed: [_1]",
 
1080
                $tmpl->errstr
 
1081
            )
 
1082
          );
 
1083
 
 
1084
        # FIXME: enumeration of types
 
1085
        if (   $val->{type} eq 'archive'
 
1086
            || $val->{type} eq 'category'
 
1087
            || $val->{type} eq 'page'
 
1088
            || $val->{type} eq 'individual' )
 
1089
        {
 
1090
            push @arch_tmpl, $tmpl;
 
1091
        }
 
1092
    }
 
1093
 
 
1094
    ## Set up mappings from new templates to archive types.
 
1095
    for my $tmpl (@arch_tmpl) {
 
1096
        my (@at);
 
1097
 
 
1098
        # FIXME: enumeration of types
 
1099
        if ( $tmpl->type eq 'archive' ) {
 
1100
            @at = qw( Daily Weekly Monthly Category );
 
1101
        }
 
1102
        elsif ( $tmpl->type eq 'page' ) {
 
1103
            @at = qw( Page );
 
1104
        }
 
1105
        elsif ( $tmpl->type eq 'individual' ) {
 
1106
            @at = qw( Individual );
 
1107
        }
 
1108
        require MT::TemplateMap;
 
1109
        for my $at (@at) {
 
1110
            my $map = MT::TemplateMap->new;
 
1111
            $map->archive_type($at);
 
1112
            $map->is_preferred(1);
 
1113
            $map->template_id( $tmpl->id );
 
1114
            $map->blog_id( $tmpl->blog_id );
 
1115
            $map->save
 
1116
              or return $app->error(
 
1117
                $app->translate(
 
1118
                    "Setting up mappings failed: [_1]",
 
1119
                    $map->errstr
 
1120
                )
 
1121
              );
 
1122
        }
 
1123
    }
 
1124
    $app->redirect(
 
1125
        $app->uri(
 
1126
            'mode' => 'list',
 
1127
            args =>
 
1128
              { '_type' => 'template', blog_id => $blog->id, 'reset' => 1 }
 
1129
        )
 
1130
    );
 
1131
}
 
1132
 
 
1133
sub _generate_map_table {
 
1134
    my $app = shift;
 
1135
    my ( $blog_id, $template_id ) = @_;
 
1136
 
 
1137
    require MT::Template;
 
1138
    require MT::Blog;
 
1139
    my $blog     = MT::Blog->load($blog_id);
 
1140
    my $template = MT::Template->load($template_id);
 
1141
    my $tmpl     = $app->load_tmpl('include/archive_maps.tmpl');
 
1142
    my $maps     = _populate_archive_loop( $app, $blog, $template );
 
1143
    $tmpl->param( object_type => 'templatemap' );
 
1144
    $tmpl->param( publish_queue_available => eval 'require List::Util; require Scalar::Util; 1;' );
 
1145
    $tmpl->param( object_loop => $maps ) if @$maps;
 
1146
    my $html = $tmpl->output();
 
1147
 
 
1148
    if ( $html =~ m/<__trans / ) {
 
1149
        $html = $app->translate_templatized($html);
 
1150
    }
 
1151
    $html;
 
1152
}
 
1153
 
 
1154
sub _populate_archive_loop {
 
1155
    my $app = shift;
 
1156
    my ( $blog, $obj ) = @_;
 
1157
 
 
1158
    my $index = $app->config('IndexBasename');
 
1159
    my $ext = $blog->file_extension || '';
 
1160
    $ext = '.' . $ext if $ext ne '';
 
1161
 
 
1162
    require MT::TemplateMap;
 
1163
    my @tmpl_maps = MT::TemplateMap->load( { template_id => $obj->id } );
 
1164
    my @maps;
 
1165
    my %types;
 
1166
    foreach my $map_obj (@tmpl_maps) {
 
1167
        my $map = {};
 
1168
        $map->{map_id}           = $map_obj->id;
 
1169
        $map->{map_is_preferred} = $map_obj->is_preferred;
 
1170
        # publish options
 
1171
        $map->{map_build_type} = $map_obj->build_type;
 
1172
        $map->{ 'map_build_type_' . ( $map_obj->build_type || 0 ) } = 1;
 
1173
        my ( $period, $interval ) = _get_schedule( $map_obj->build_interval );
 
1174
        $map->{ 'map_schedule_period_' . $period } = 1
 
1175
            if defined $period;
 
1176
        $map->{map_schedule_interval} = $interval
 
1177
            if defined $interval;
 
1178
 
 
1179
        my $at = $map->{archive_type} = $map_obj->archive_type;
 
1180
        $types{$at}++;
 
1181
        $map->{ 'archive_type_preferred_' . $blog->archive_type_preferred } = 1
 
1182
          if $blog->archive_type_preferred;
 
1183
        $map->{file_template} = $map_obj->file_template
 
1184
          if $map_obj->file_template;
 
1185
 
 
1186
        my $archiver = $app->publisher->archiver($at);
 
1187
        next unless $archiver;
 
1188
        $map->{archive_label} = $archiver->archive_label;
 
1189
        my $tmpls     = $archiver->default_archive_templates;
 
1190
        my $tmpl_loop = [];
 
1191
        foreach (@$tmpls) {
 
1192
            my $name = $_->{label};
 
1193
            $name =~ s/\.html$/$ext/;
 
1194
            $name =~ s/index$ext$/$index$ext/;
 
1195
            push @$tmpl_loop,
 
1196
              {
 
1197
                name    => $name,
 
1198
                value   => $_->{template},
 
1199
                default => ( $_->{default} || 0 ),
 
1200
              };
 
1201
        }
 
1202
 
 
1203
        my $custom = 1;
 
1204
 
 
1205
        foreach (@$tmpl_loop) {
 
1206
            if (   ( !$map->{file_template} && $_->{default} )
 
1207
                || ( $map->{file_template} eq $_->{value} ) )
 
1208
            {
 
1209
                $_->{selected}        = 1;
 
1210
                $custom               = 0;
 
1211
                $map->{file_template} = $_->{value}
 
1212
                  if !$map->{file_template};
 
1213
            }
 
1214
        }
 
1215
        if ($custom) {
 
1216
            unshift @$tmpl_loop,
 
1217
              {
 
1218
                name     => $map->{file_template},
 
1219
                value    => $map->{file_template},
 
1220
                selected => 1,
 
1221
              };
 
1222
        }
 
1223
 
 
1224
        $map->{archive_tmpl_loop} = $tmpl_loop;
 
1225
        if (
 
1226
            1 < MT::TemplateMap->count(
 
1227
                { archive_type => $at, blog_id => $obj->blog_id }
 
1228
            )
 
1229
          )
 
1230
        {
 
1231
            $map->{has_multiple_archives} = 1;
 
1232
        }
 
1233
 
 
1234
        push @maps, $map;
 
1235
    }
 
1236
    @maps = sort { MT::App::CMS::archive_type_sorter( $a, $b ) } @maps;
 
1237
    return \@maps;
 
1238
}
 
1239
 
 
1240
sub delete_map {
 
1241
    my $app = shift;
 
1242
    $app->validate_magic() or return;
 
1243
    my $perms = $app->{perms}
 
1244
      or return $app->error( $app->translate("No permissions") );
 
1245
    my $q  = $app->param;
 
1246
    my $id = $q->param('id');
 
1247
 
 
1248
    require MT::TemplateMap;
 
1249
    MT::TemplateMap->remove( { id => $id } );
 
1250
    my $html =
 
1251
      _generate_map_table( $app, $q->param('blog_id'),
 
1252
        $q->param('template_id') );
 
1253
    $app->{no_print_body} = 1;
 
1254
    $app->send_http_header("text/plain");
 
1255
    $app->print($html);
 
1256
}
 
1257
 
 
1258
sub add_map {
 
1259
    my $app = shift;
 
1260
    $app->validate_magic() or return;
 
1261
    my $perms = $app->{perms}
 
1262
      or return $app->error( $app->translate("No permissions") );
 
1263
 
 
1264
    my $q = $app->param;
 
1265
 
 
1266
    require MT::TemplateMap;
 
1267
    my $blog_id = $q->param('blog_id');
 
1268
    my $at      = $q->param('new_archive_type');
 
1269
    my $exist   = MT::TemplateMap->exist(
 
1270
        {
 
1271
            blog_id      => $blog_id,
 
1272
            archive_type => $at
 
1273
        }
 
1274
    );
 
1275
    my $map = MT::TemplateMap->new;
 
1276
    $map->is_preferred( $exist ? 0 : 1 );
 
1277
    $map->template_id( scalar $q->param('template_id') );
 
1278
    $map->blog_id($blog_id);
 
1279
    $map->archive_type($at);
 
1280
    $map->save
 
1281
      or return $app->error(
 
1282
        $app->translate( "Saving map failed: [_1]", $map->errstr ) );
 
1283
    my $html =
 
1284
      _generate_map_table( $app, $blog_id, scalar $q->param('template_id') );
 
1285
    $app->{no_print_body} = 1;
 
1286
    $app->send_http_header("text/plain");
 
1287
    $app->print($html);
 
1288
}
 
1289
 
 
1290
sub can_view {
 
1291
    my ( $eh, $app, $id ) = @_;
 
1292
    my $perms = $app->permissions;
 
1293
    return !$id || ($perms && $perms->can_edit_templates) || (!$app->blog && $app->user->can_edit_templates);
 
1294
}
 
1295
 
 
1296
sub can_save {
 
1297
    my ( $eh, $app, $id ) = @_;
 
1298
    my $perms = $app->permissions;
 
1299
    return ($perms && $perms->can_edit_templates) || (!$perms && $app->user->can_edit_templates);
 
1300
}
 
1301
 
 
1302
sub can_delete {
 
1303
    my ( $eh, $app, $obj ) = @_;
 
1304
    return 1 if $app->user->is_superuser();
 
1305
    my $perms = $app->permissions;
 
1306
    return ($perms && $perms->can_edit_templates) || (!$perms && $app->user->can_edit_templates);
 
1307
}
 
1308
 
 
1309
sub pre_save {
 
1310
    my $eh = shift;
 
1311
    my ( $app, $obj ) = @_;
 
1312
 
 
1313
    ## Strip linefeed characters.
 
1314
    ( my $text = $obj->text ) =~ tr/\r//d;
 
1315
 
 
1316
    if ($text =~ m/<(MT|_)_trans/i) {
 
1317
        $text = $app->translate_templatized($text);
 
1318
    }
 
1319
 
 
1320
    $obj->text($text);
 
1321
 
 
1322
    # update text heights if necessary
 
1323
    if ( my $perms = $app->permissions ) {
 
1324
        my $prefs = $perms->template_prefs || '';
 
1325
        my $text_height = $app->param('text_height');
 
1326
        if ( defined $text_height ) {
 
1327
            my ($pref_text_height) = $prefs =~ m/\btext:(\d+)\b/;
 
1328
            $pref_text_height ||= 0;
 
1329
            if ( $text_height != $pref_text_height ) {
 
1330
                if ( $prefs =~ m/\btext\b/ ) {
 
1331
                    $prefs =~ s/\btext(:\d+)\b/text:$text_height/;
 
1332
                }
 
1333
                else {
 
1334
                    $prefs = 'text:' . $text_height . ',' . $prefs;
 
1335
                }
 
1336
            }
 
1337
        }
 
1338
 
 
1339
        if ( $prefs ne ( $perms->template_prefs || '' ) ) {
 
1340
            $perms->template_prefs($prefs);
 
1341
            $perms->save;
 
1342
        }
 
1343
    }
 
1344
 
 
1345
    # module caching
 
1346
    $obj->include_with_ssi( $app->param('include_with_ssi') ? 1 : 0 );
 
1347
    $obj->cache_path( $app->param('cache_path'));
 
1348
    my $cache_expire_type = defined $app->param('cache_expire_type')
 
1349
      ? $app->param('cache_expire_type')
 
1350
      : '0';
 
1351
    $obj->cache_expire_type($cache_expire_type);
 
1352
    my $period   = $app->param('cache_expire_period');
 
1353
    my $interval = $app->param('cache_expire_interval');
 
1354
    my $sec      = _get_interval( $period, $interval );
 
1355
    $obj->cache_expire_interval($sec) if defined $sec;
 
1356
    my $q = $app->param;
 
1357
    my @events;
 
1358
 
 
1359
    foreach my $name ( $q->param('cache_expire_event') ) {
 
1360
        push @events, $name;
 
1361
    }
 
1362
    $obj->cache_expire_event( join ',', @events ) if $#events >= 0;
 
1363
    if ( $cache_expire_type == 1 ) {
 
1364
        return $eh->error(
 
1365
            $app->translate("You should not be able to enter 0 as the time.") )
 
1366
          if $interval == 0;
 
1367
    }
 
1368
    elsif ( $cache_expire_type == 2 ) {
 
1369
        return $eh->error(
 
1370
            $app->translate("You must select at least one event checkbox.") )
 
1371
          if !@events;
 
1372
    }
 
1373
 
 
1374
    require MT::PublishOption;
 
1375
    my $build_type = $app->param('build_type');
 
1376
 
 
1377
    if ( $build_type == MT::PublishOption::SCHEDULED() ) {
 
1378
        my $period   = $app->param('schedule_period');
 
1379
        my $interval = $app->param('schedule_interval');
 
1380
        my $sec      = _get_interval( $period, $interval );
 
1381
        $obj->build_interval($sec);
 
1382
    }
 
1383
    my $rebuild_me = 1;
 
1384
    if (   $build_type == MT::PublishOption::DISABLED()
 
1385
        || $build_type == MT::PublishOption::MANUALLY() )
 
1386
    {
 
1387
        $rebuild_me = 0;
 
1388
    }
 
1389
    $obj->rebuild_me($rebuild_me);
 
1390
    1;
 
1391
}
 
1392
 
 
1393
sub post_save {
 
1394
    my $eh = shift;
 
1395
    my ( $app, $obj, $original ) = @_;
 
1396
 
 
1397
    my $sess_obj = $app->autosave_session_obj;
 
1398
    $sess_obj->remove if $sess_obj;
 
1399
 
 
1400
    my $dynamic = 0;
 
1401
    my $q = $app->param;
 
1402
    my $type = $q->param('type');
 
1403
    # FIXME: enumeration of types
 
1404
    if ( $type eq 'custom'
 
1405
      || $type eq 'index'
 
1406
      || $type eq 'widget'
 
1407
      || $type eq 'widgetset' )
 
1408
    {
 
1409
        $dynamic = $obj->build_dynamic;
 
1410
    }
 
1411
    else
 
1412
    {
 
1413
        # archive template specific post_save tasks
 
1414
        require MT::TemplateMap;
 
1415
        my @p = $q->param;
 
1416
        my @static_maps;
 
1417
        for my $p (@p) {
 
1418
            my $map;
 
1419
            if ( $p =~ /^archive_tmpl_preferred_(\w+)_(\d+)$/ ) {
 
1420
                my $at     = $1;
 
1421
                my $map_id = $2;
 
1422
                $map    = MT::TemplateMap->load($map_id)
 
1423
                    or next;
 
1424
                $map->prefer( $q->param($p) );    # prefer method saves in itself
 
1425
            }
 
1426
            elsif ( $p =~ /^archive_file_tmpl_(\d+)$/ ) {
 
1427
                my $map_id = $1;
 
1428
                $map    = MT::TemplateMap->load($map_id)
 
1429
                    or next;
 
1430
                $map->file_template( $q->param($p) );
 
1431
                $map->save;
 
1432
            }
 
1433
            elsif ( $p =~ /^map_build_type_(\d+)$/ ) {
 
1434
                my $map_id     = $1;
 
1435
                $map        = MT::TemplateMap->load($map_id)
 
1436
                    or next;
 
1437
                my $build_type = $q->param($p);
 
1438
                require MT::PublishOption;
 
1439
                # Populate maps that are changed from static to dynamic
 
1440
                # This should capture new map as well
 
1441
                push @static_maps, $map->id
 
1442
                    if ( ( $build_type ne $map->build_type )
 
1443
                      && ( MT::PublishOption::DYNAMIC() eq $build_type ) );
 
1444
                $map->build_type($build_type);
 
1445
                if ( $build_type == MT::PublishOption::SCHEDULED() ) {
 
1446
                    my $period   = $q->param( 'map_schedule_period_' . $map_id );
 
1447
                    my $interval = $q->param( 'map_schedule_interval_' . $map_id );
 
1448
                    my $sec      = _get_interval( $period, $interval );
 
1449
                    $map->build_interval($sec);
 
1450
                }
 
1451
                $map->save;
 
1452
            }
 
1453
            if ( !$dynamic
 
1454
              && $map && $map->build_type == MT::PublishOption::DYNAMIC() )
 
1455
            {
 
1456
                $dynamic = 1;
 
1457
            }
 
1458
        }
 
1459
        $app->{static_dynamic_maps} = @static_maps ? \@static_maps : 0;
 
1460
    }
 
1461
 
 
1462
    if ( !$original->id ) {
 
1463
        $app->log(
 
1464
            {
 
1465
                message => $app->translate(
 
1466
                    "Template '[_1]' (ID:[_2]) created by '[_3]'",
 
1467
                    $obj->name, $obj->id, $app->user->name
 
1468
                ),
 
1469
                level    => MT::Log::INFO(),
 
1470
                class    => 'template',
 
1471
                category => 'new',
 
1472
            }
 
1473
        );
 
1474
    }
 
1475
 
 
1476
    if ( $dynamic ) {
 
1477
        if ( $obj->type eq 'index' ) {
 
1478
            $app->rebuild_indexes(
 
1479
                BlogID   => $obj->blog_id,
 
1480
                Template => $obj,
 
1481
                NoStatic => 1,
 
1482
            ) or return $app->publish_error();    # XXXX
 
1483
        }
 
1484
        if ( my $blog = $app->blog ) {
 
1485
            require MT::CMS::Blog;
 
1486
            my ( $path, $url );
 
1487
            if ( $obj->type eq 'index' ) {
 
1488
                $path = $blog->site_path;
 
1489
                $url = $blog->site_url;
 
1490
            }
 
1491
            else {
 
1492
                # must be archive since other types can't be dynamic
 
1493
                if ( $path = $blog->archive_path ) {
 
1494
                    $url = $blog->archive_url;
 
1495
                }
 
1496
                else {
 
1497
                    $path = $blog->site_path;
 
1498
                    $url = $blog->site_url;
 
1499
                }
 
1500
            }
 
1501
            # specific arguments so not to overwrite mtview and htaccess
 
1502
            MT::CMS::Blog::prepare_dynamic_publishing(
 
1503
                $eh, 
 
1504
                $blog,
 
1505
                undef,
 
1506
                undef,
 
1507
                $path,
 
1508
                $url
 
1509
            );
 
1510
        }
 
1511
    }
 
1512
    1;
 
1513
}
 
1514
 
 
1515
sub post_delete {
 
1516
    my ( $eh, $app, $obj ) = @_;
 
1517
 
 
1518
    $app->log(
 
1519
        {
 
1520
            message => $app->translate(
 
1521
                "Template '[_1]' (ID:[_2]) deleted by '[_3]'",
 
1522
                $obj->name, $obj->id, $app->user->name
 
1523
            ),
 
1524
            level    => MT::Log::INFO(),
 
1525
            class    => 'system',
 
1526
            category => 'delete'
 
1527
        }
 
1528
    );
 
1529
}
 
1530
 
 
1531
sub build_template_table {
 
1532
    my $app = shift;
 
1533
    my (%args) = @_;
 
1534
 
 
1535
    my $perms     = $app->permissions;
 
1536
    my $list_pref = $app->list_pref('template');
 
1537
    my $limit     = $args{limit};
 
1538
    my $param     = $args{param} || {};
 
1539
    my $iter;
 
1540
    if ( $args{load_args} ) {
 
1541
        my $class = $app->model('template');
 
1542
        $iter = $class->load_iter( @{ $args{load_args} } );
 
1543
    }
 
1544
    elsif ( $args{iter} ) {
 
1545
        $iter = $args{iter};
 
1546
    }
 
1547
    elsif ( $args{items} ) {
 
1548
        $iter = sub { pop @{ $args{items} } };
 
1549
        $limit = scalar @{ $args{items} };
 
1550
    }
 
1551
    return [] unless $iter;
 
1552
 
 
1553
    my @data;
 
1554
    my $i;
 
1555
    my %blogs;
 
1556
    while ( my $tmpl = $iter->() ) {
 
1557
        my $blog = $blogs{ $tmpl->blog_id } ||=
 
1558
          MT::Blog->load( $tmpl->blog_id ) if $tmpl->blog_id;
 
1559
 
 
1560
        my $row = $tmpl->column_values;
 
1561
        $row->{name} = '' if !defined $row->{name};
 
1562
        $row->{name} =~ s/^\s+|\s+$//g;
 
1563
        $row->{name} = "(" . $app->translate("No Name") . ")"
 
1564
          if $row->{name} eq '';
 
1565
        my $published_url = $tmpl->published_url;
 
1566
        $row->{published_url} = $published_url if $published_url;
 
1567
        $row->{use_cache} = ( ($tmpl->cache_expire_type || 0) != 0 )  ? 1 : 0;
 
1568
 
 
1569
        # FIXME: enumeration of types
 
1570
        $row->{can_delete} = 1
 
1571
          if $tmpl->type =~ m/(custom|index|archive|page|individual|category|widget)/;
 
1572
        if ($blog) {
 
1573
            $row->{weblog_name} = $blog->name;
 
1574
        }
 
1575
        elsif ($tmpl->blog_id) {
 
1576
            $row->{weblog_name} = '* ' . $app->translate('Orphaned') . ' *';
 
1577
        }
 
1578
        else {
 
1579
            $row->{weblog_name} = '* ' . $app->translate('Global Templates') . ' *';
 
1580
        }
 
1581
        $row->{object} = $tmpl;
 
1582
        push @data, $row;
 
1583
        last if defined($limit) && (@data > $limit);
 
1584
    }
 
1585
    return [] unless @data;
 
1586
 
 
1587
    $param->{template_table}[0]              = {%$list_pref};
 
1588
    $param->{template_table}[0]{object_loop} = \@data;
 
1589
    $param->{template_table}[0]{object_type} = 'template';
 
1590
    $app->load_list_actions( 'template', $param );
 
1591
    $param->{object_loop} = \@data;
 
1592
    \@data;
 
1593
}
 
1594
 
 
1595
sub dialog_publishing_profile {
 
1596
    my $app = shift;
 
1597
    $app->validate_magic or return;
 
1598
 
 
1599
    my $blog = $app->blog;
 
1600
    $app->assert( $blog ) or return;
 
1601
 
 
1602
    # permission check
 
1603
    my $perms = $app->permissions;
 
1604
    return $app->errtrans("Permission denied.")
 
1605
        unless $app->user->is_superuser ||
 
1606
            $perms->can_administer_blog ||
 
1607
            $perms->can_edit_templates;
 
1608
 
 
1609
    my $param = {};
 
1610
    $param->{dynamicity} = $blog->custom_dynamic_templates || 'none';
 
1611
    $param->{screen_id} = "publishing-profile-dialog";
 
1612
    $param->{return_args} = $app->param('return_args');
 
1613
 
 
1614
    $app->build_page('dialog/publishing_profile.tmpl',
 
1615
        $param);
 
1616
}
 
1617
 
 
1618
sub dialog_refresh_templates {
 
1619
    my $app = shift;
 
1620
    $app->validate_magic or return;
 
1621
 
 
1622
    # permission check
 
1623
    my $perms = $app->permissions;
 
1624
    return $app->errtrans("Permission denied.")
 
1625
        unless $app->user->is_superuser ||
 
1626
            $perms->can_administer_blog ||
 
1627
            $perms->can_edit_templates;
 
1628
 
 
1629
    my $param = {};
 
1630
    my $blog = $app->blog;
 
1631
    $param->{return_args} = $app->param('return_args');
 
1632
 
 
1633
    if ($blog) {
 
1634
        $param->{blog_id} = $blog->id;
 
1635
 
 
1636
        my $sets = $app->registry("template_sets");
 
1637
        $sets->{$_}{key} = $_ for keys %$sets;
 
1638
        $sets = $app->filter_conditional_list([ values %$sets ]);
 
1639
 
 
1640
        no warnings; # some sets may not define an order
 
1641
        @$sets = sort { $a->{order} <=> $b->{order} } @$sets;
 
1642
        $param->{'template_set_loop'} = $sets;
 
1643
 
 
1644
        my $existing_set = $blog->template_set || 'mt_blog';
 
1645
        foreach (@$sets) {
 
1646
            if ($_->{key} eq $existing_set) {
 
1647
                $_->{selected} = 1;
 
1648
            }
 
1649
        }
 
1650
        $param->{'template_set_index'} = $#$sets;
 
1651
        $param->{'template_set_count'} = scalar @$sets;
 
1652
 
 
1653
        $param->{template_sets} = $sets;
 
1654
        $param->{screen_id} = "refresh-templates-dialog";
 
1655
    }
 
1656
 
 
1657
    # load template sets
 
1658
    $app->build_page('dialog/refresh_templates.tmpl',
 
1659
        $param);
 
1660
}
 
1661
 
 
1662
sub refresh_all_templates {
 
1663
    my ($app) = @_;
 
1664
 
 
1665
    my $backup = 0;
 
1666
    if ($app->param('backup')) {
 
1667
        # refresh templates dialog uses a 'backup' field
 
1668
        $backup = 1;
 
1669
    }
 
1670
 
 
1671
    my $template_set = $app->param('template_set');
 
1672
    my $refresh_type = $app->param('refresh_type') || 'refresh';
 
1673
 
 
1674
    my $t = time;
 
1675
 
 
1676
    my @id;
 
1677
    if ($app->param('blog_id')) {
 
1678
        @id = ( scalar $app->param('blog_id') );
 
1679
    }
 
1680
    else {
 
1681
        @id = $app->param('id');
 
1682
        if (! @id) {
 
1683
            # refresh global templates
 
1684
            @id = ( 0 );
 
1685
        }
 
1686
    }
 
1687
 
 
1688
    require MT::Template;
 
1689
    require MT::DefaultTemplates;
 
1690
    require MT::Blog;
 
1691
    require MT::Permission;
 
1692
    require MT::Util;
 
1693
 
 
1694
    foreach my $blog_id (@id) {
 
1695
        my $blog;
 
1696
        if ($blog_id) {
 
1697
            $blog = MT::Blog->load($blog_id);
 
1698
            next unless $blog;
 
1699
        }
 
1700
        if ( !$app->user->is_superuser() ) {
 
1701
            my $perms = MT::Permission->load(
 
1702
                { blog_id => $blog_id, author_id => $app->user->id } );
 
1703
            if (
 
1704
                !$perms
 
1705
                || (   !$perms->can_edit_templates()
 
1706
                    && !$perms->can_administer_blog() )
 
1707
              )
 
1708
            {
 
1709
                next;
 
1710
            }
 
1711
        }
 
1712
 
 
1713
        my $tmpl_list;
 
1714
        if ($blog_id) {
 
1715
 
 
1716
            if ($refresh_type eq 'clean') {
 
1717
                # the user wants to back up all templates and
 
1718
                # install the new ones
 
1719
 
 
1720
                my @ts = MT::Util::offset_time_list( $t, $blog_id );
 
1721
                my $ts = sprintf "%04d-%02d-%02d %02d:%02d:%02d",
 
1722
                    $ts[5] + 1900, $ts[4] + 1, @ts[ 3, 2, 1, 0 ];
 
1723
 
 
1724
                my $tmpl_iter = MT::Template->load_iter({
 
1725
                    blog_id => $blog_id,
 
1726
                    type => { not => 'backup' },
 
1727
                });
 
1728
 
 
1729
                while (my $tmpl = $tmpl_iter->()) {
 
1730
                    if ($backup) {
 
1731
                        # zap all template maps
 
1732
                        require MT::TemplateMap;
 
1733
                        MT::TemplateMap->remove({
 
1734
                            template_id => $tmpl->id,
 
1735
                        });
 
1736
                        $tmpl->type('backup');
 
1737
                        $tmpl->name(
 
1738
                            $tmpl->name . ' (Backup from ' . $ts . ')' );
 
1739
                        $tmpl->identifier(undef);
 
1740
                        $tmpl->rebuild_me(0);
 
1741
                        $tmpl->linked_file(undef);
 
1742
                        $tmpl->outfile('');
 
1743
                        $tmpl->save;
 
1744
                    } else {
 
1745
                        $tmpl->remove;
 
1746
                    }
 
1747
                }
 
1748
 
 
1749
                # This also creates our template mappings
 
1750
                $blog->create_default_templates( $template_set ||
 
1751
                    $blog->template_set || 'mt_blog' );
 
1752
 
 
1753
                if ($template_set) {
 
1754
                    $blog->template_set( $template_set );
 
1755
                    $blog->save;
 
1756
                    $app->run_callbacks( 'blog_template_set_change', { blog => $blog } );
 
1757
                }
 
1758
 
 
1759
                next;
 
1760
            }
 
1761
 
 
1762
            $tmpl_list = MT::DefaultTemplates->templates($template_set || $blog->template_set) || MT::DefaultTemplates->templates();
 
1763
        }
 
1764
        else {
 
1765
            $tmpl_list = MT::DefaultTemplates->templates();
 
1766
        }
 
1767
 
 
1768
        foreach my $val (@$tmpl_list) {
 
1769
            if ($blog_id) {
 
1770
                # when refreshing blog templates,
 
1771
                # skip over global templates which
 
1772
                # specify a blog_id of 0...
 
1773
                next if $val->{global};
 
1774
            }
 
1775
            else {
 
1776
                next unless exists $val->{global};
 
1777
            }
 
1778
 
 
1779
            if ( !$val->{orig_name} ) {
 
1780
                $val->{orig_name} = $val->{name};
 
1781
                $val->{text}      = $app->translate_templatized( $val->{text} );
 
1782
            }
 
1783
 
 
1784
            my $orig_name = $val->{orig_name};
 
1785
 
 
1786
            my @ts = MT::Util::offset_time_list( $t, ( $blog_id ? $blog_id : undef ) );
 
1787
            my $ts = sprintf "%04d-%02d-%02d %02d:%02d:%02d", $ts[5] + 1900,
 
1788
              $ts[4] + 1, @ts[ 3, 2, 1, 0 ];
 
1789
 
 
1790
            my $terms = {};
 
1791
            $terms->{blog_id} = $blog_id;
 
1792
            $terms->{type} = $val->{type};
 
1793
            if ( $val->{type} =~
 
1794
                m/^(archive|individual|page|category|index|custom|widget|widgetset)$/ )
 
1795
            {
 
1796
                $terms->{name} = $val->{name};
 
1797
            }
 
1798
            else {
 
1799
                $terms->{identifier} = $val->{identifier};
 
1800
            }
 
1801
 
 
1802
            # this should only return 1 template; we're searching
 
1803
            # within a given blog for a specific type of template (for
 
1804
            # "system" templates; or for a type + name, which should be
 
1805
            # unique for that blog.
 
1806
            my $tmpl = MT::Template->load($terms);
 
1807
            if ($tmpl && $backup) {
 
1808
 
 
1809
                # check for default template text...
 
1810
                # if it is a default template, then outright replace it
 
1811
                my $text = $tmpl->text;
 
1812
                $text =~ s/\s+//g;
 
1813
 
 
1814
                my $def_text = $val->{text};
 
1815
                $def_text =~ s/\s+//g;
 
1816
 
 
1817
                # if it has been customized, back it up to a new tmpl record
 
1818
                if ($def_text ne $text) {
 
1819
                    my $backup = $tmpl->clone;
 
1820
                    delete $backup->{column_values}
 
1821
                      ->{id};    # make sure we don't overwrite original
 
1822
                    delete $backup->{changed_cols}->{id};
 
1823
                    $backup->name(
 
1824
                        $backup->name . $app->translate( ' (Backup from [_1])', $ts ) );
 
1825
                    $backup->type('backup');
 
1826
                    # if ( $backup->type !~
 
1827
                    #         m/^(archive|individual|page|category|index|custom|widget)$/ )
 
1828
                    # {
 
1829
                    #     $backup->type('custom')
 
1830
                    #       ;      # system templates can't be created
 
1831
                    # }
 
1832
                    $backup->outfile('');
 
1833
                    $backup->linked_file( $tmpl->linked_file );
 
1834
                    $backup->identifier(undef);
 
1835
                    $backup->rebuild_me(0);
 
1836
                    $backup->build_dynamic(0);
 
1837
                    $backup->save;
 
1838
                }
 
1839
            }
 
1840
            if ($tmpl) {
 
1841
                # we found that the previous template had not been
 
1842
                # altered, so replace it with new default template...
 
1843
                if ( ( 'widgetset' eq $val->{type} )
 
1844
                  && ( exists $val->{widgets} ) ) {
 
1845
                    my $modulesets = delete $val->{widgets};
 
1846
                    $tmpl->modulesets( MT::Template->widgets_to_modulesets($modulesets, $blog_id) );
 
1847
                }
 
1848
                $tmpl->text( $val->{text} );
 
1849
                $tmpl->identifier( $val->{identifier} );
 
1850
                $tmpl->type( $val->{type} )
 
1851
                  ; # fixes mismatch of types for cases like "archive" => "individual"
 
1852
                $tmpl->linked_file('');
 
1853
                $tmpl->save;
 
1854
            }
 
1855
            else {
 
1856
                # create this one...
 
1857
                my $tmpl = new MT::Template;
 
1858
                if ( ( 'widgetset' eq $val->{type} )
 
1859
                  && ( exists $val->{widgets} ) ) {
 
1860
                    my $modulesets = delete $val->{widgets};
 
1861
                    $tmpl->modulesets( MT::Template->widgets_to_modulesets($modulesets, $blog_id) );
 
1862
                }
 
1863
                $tmpl->build_dynamic(0);
 
1864
                $tmpl->set_values(
 
1865
                    {
 
1866
                        text       => $val->{text},
 
1867
                        name       => $val->{name},
 
1868
                        type       => $val->{type},
 
1869
                        identifier => $val->{identifier},
 
1870
                        outfile    => $val->{outfile},
 
1871
                        rebuild_me => $val->{rebuild_me},
 
1872
                    }
 
1873
                );
 
1874
                $tmpl->blog_id($blog_id);
 
1875
                $tmpl->save
 
1876
                  or return $app->error(
 
1877
                        $app->translate("Error creating new template: ")
 
1878
                      . $tmpl->errstr );
 
1879
            }
 
1880
        }
 
1881
    }
 
1882
 
 
1883
    $app->add_return_arg( 'refreshed' => 1 );
 
1884
    $app->call_return;
 
1885
}
 
1886
 
 
1887
sub refresh_individual_templates {
 
1888
    my ($app) = @_;
 
1889
 
 
1890
    require MT::Util;
 
1891
 
 
1892
    my $user = $app->user;
 
1893
    my $perms = $app->permissions;
 
1894
    return $app->error(
 
1895
        $app->translate(
 
1896
            "Permission denied.")
 
1897
      )
 
1898
      #TODO: system level-designer permission
 
1899
      unless $user->is_superuser() || $user->can_edit_templates()
 
1900
      || ( $perms
 
1901
        && ( $perms->can_edit_templates()
 
1902
          || $perms->can_administer_blog ) );
 
1903
 
 
1904
    my $set;
 
1905
    if ( my $blog_id = $app->param('blog_id') ) {
 
1906
        my $blog = $app->model('blog')->load($blog_id)
 
1907
            or return $app->error($app->translate('Can\'t load blog #[_1].', $blog_id));
 
1908
        $set = $blog->template_set()
 
1909
            if $blog;
 
1910
    }
 
1911
 
 
1912
    require MT::DefaultTemplates;
 
1913
    my $tmpl_list = MT::DefaultTemplates->templates($set) or return;
 
1914
 
 
1915
    my $tmpl_types = {};
 
1916
    my $tmpl_ids   = {};
 
1917
    my $tmpls      = {};
 
1918
    foreach my $tmpl (@$tmpl_list) {
 
1919
        $tmpl->{text} = $app->translate_templatized( $tmpl->{text} );
 
1920
        $tmpl_ids->{ $tmpl->{identifier} } = $tmpl
 
1921
            if $tmpl->{identifier};
 
1922
        if ( $tmpl->{type} !~ m/^(archive|individual|page|category|index|custom|widget)$/ )
 
1923
        {
 
1924
            $tmpl_types->{ $tmpl->{type} } = $tmpl;
 
1925
        }
 
1926
        else {
 
1927
            $tmpls->{ $tmpl->{type} }{ $tmpl->{name} } = $tmpl;
 
1928
        }
 
1929
    }
 
1930
 
 
1931
    my $t = time;
 
1932
 
 
1933
    my @msg;
 
1934
    my @id = $app->param('id');
 
1935
    require MT::Template;
 
1936
    foreach my $tmpl_id (@id) {
 
1937
        my $tmpl = MT::Template->load($tmpl_id);
 
1938
        next unless $tmpl;
 
1939
        my $blog_id = $tmpl->blog_id;
 
1940
 
 
1941
        # FIXME: permission check -- for this blog_id
 
1942
 
 
1943
        my @ts = MT::Util::offset_time_list( $t, $blog_id );
 
1944
        my $ts = sprintf "%04d-%02d-%02d %02d:%02d:%02d", $ts[5] + 1900,
 
1945
          $ts[4] + 1, @ts[ 3, 2, 1, 0 ];
 
1946
 
 
1947
        my $val = ( $tmpl->identifier ? $tmpl_ids->{ $tmpl->identifier() } : undef )
 
1948
          || $tmpl_types->{ $tmpl->type() }
 
1949
          || $tmpls->{ $tmpl->type() }{ $tmpl->name };
 
1950
        if ( !$val ) {
 
1951
            push @msg,
 
1952
              $app->translate(
 
1953
"Skipping template '[_1]' since it appears to be a custom template.",
 
1954
                $tmpl->name
 
1955
              );
 
1956
            next;
 
1957
        }
 
1958
 
 
1959
        my $text = $tmpl->text;
 
1960
        $text =~ s/\s+//g;
 
1961
 
 
1962
        my $def_text = $val->{text};
 
1963
        $def_text =~ s/\s+//g;
 
1964
 
 
1965
        if ($text ne $def_text) {
 
1966
            # if it has been customized, back it up to a new tmpl record
 
1967
            my $backup = $tmpl->clone;
 
1968
            delete $backup->{column_values}
 
1969
              ->{id};    # make sure we don't overwrite original
 
1970
            delete $backup->{changed_cols}->{id};
 
1971
            $backup->name( $backup->name . ' (Backup from ' . $ts . ')' );
 
1972
            $backup->type('backup');
 
1973
            $backup->outfile('');
 
1974
            $backup->linked_file( $tmpl->linked_file );
 
1975
            $backup->rebuild_me(0);
 
1976
            $backup->build_dynamic(0);
 
1977
            $backup->identifier(undef);
 
1978
            $backup->save;
 
1979
            push @msg,
 
1980
              $app->translate(
 
1981
    'Refreshing template <strong>[_3]</strong> with <a href="?__mode=view&amp;blog_id=[_1]&amp;_type=template&amp;id=[_2]">backup</a>',
 
1982
                  $blog_id, $backup->id, $tmpl->name );
 
1983
 
 
1984
            # we found that the previous template had not been
 
1985
            # altered, so replace it with new default template...
 
1986
            $tmpl->text( $val->{text} );
 
1987
            $tmpl->identifier( $val->{identifier} );
 
1988
            $tmpl->linked_file('');
 
1989
            $tmpl->save;
 
1990
        } else {
 
1991
            push @msg, $app->translate("Skipping template '[_1]' since it has not been changed.", $tmpl->name);
 
1992
        }
 
1993
    }
 
1994
    my @msg_loop;
 
1995
    push @msg_loop, { message => $_ } foreach @msg;
 
1996
 
 
1997
    $app->build_page( 'refresh_results.tmpl',
 
1998
        { message_loop => \@msg_loop, return_url => $app->return_uri } );
 
1999
}
 
2000
 
 
2001
sub clone_templates {
 
2002
    my ($app) = @_;
 
2003
 
 
2004
    my $user = $app->user;
 
2005
    my $perms = $app->permissions;
 
2006
    return $app->error(
 
2007
        $app->translate(
 
2008
            "Permission denied.")
 
2009
      )
 
2010
      #TODO: system level-designer permission
 
2011
      unless $user->is_superuser() || $user->can_edit_templates()
 
2012
      || ( $perms
 
2013
        && ( $perms->can_edit_templates()
 
2014
          || $perms->can_administer_blog ) );
 
2015
 
 
2016
    my @id = $app->param('id');
 
2017
    require MT::Template;
 
2018
    foreach my $tmpl_id (@id) {
 
2019
        my $tmpl = MT::Template->load($tmpl_id);
 
2020
        next unless $tmpl;
 
2021
 
 
2022
        my $new_tmpl = $tmpl->clone({
 
2023
            Except => {
 
2024
                id => 1,
 
2025
                name => 1,
 
2026
                identifier => 1,
 
2027
            },
 
2028
        });
 
2029
 
 
2030
        my $new_basename = $app->translate("Copy of [_1]", $tmpl->name);
 
2031
        my $new_name = $new_basename;
 
2032
        my $i = 0;
 
2033
        while (MT::Template->exist({ name => $new_name, blog_id => $tmpl->blog_id })) {
 
2034
            $new_name = $new_basename . ' (' . ++$i . ')';
 
2035
        }
 
2036
 
 
2037
        $new_tmpl->name($new_name);
 
2038
        $new_tmpl->save;
 
2039
    }
 
2040
 
 
2041
    $app->add_return_arg( 'saved_copied' => 1 );
 
2042
    $app->call_return;
 
2043
}
 
2044
 
 
2045
sub publish_index_templates {
 
2046
    my $app = shift;
 
2047
    $app->validate_magic or return;
 
2048
 
 
2049
    # permission check
 
2050
    my $perms = $app->permissions;
 
2051
    return $app->errtrans("Permission denied.")
 
2052
        unless $app->user->is_superuser ||
 
2053
            $perms->can_administer_blog ||
 
2054
            $perms->can_rebuild;
 
2055
 
 
2056
    my $blog = $app->blog;
 
2057
    my $templates = MT->model('template')->lookup_multi([ $app->param('id') ]);
 
2058
    TEMPLATE: for my $tmpl (@$templates) {
 
2059
        next TEMPLATE if !defined $tmpl;
 
2060
        next TEMPLATE if $tmpl->blog_id != $blog->id;
 
2061
        next TEMPLATE unless $tmpl->build_type;
 
2062
 
 
2063
        $app->rebuild_indexes(
 
2064
            Blog     => $blog,
 
2065
            Template => $tmpl,
 
2066
            Force    => 1,
 
2067
        );
 
2068
    }
 
2069
 
 
2070
    $app->call_return( published => 1 );
 
2071
}
 
2072
 
 
2073
sub publish_archive_templates {
 
2074
    my $app = shift;
 
2075
    $app->validate_magic or return;
 
2076
 
 
2077
    # permission check
 
2078
    my $perms = $app->permissions;
 
2079
    return $app->errtrans("Permission denied.")
 
2080
      unless $app->user->is_superuser
 
2081
      || $perms->can_administer_blog
 
2082
      || $perms->can_rebuild;
 
2083
 
 
2084
    my @ids = $app->param('id');
 
2085
    if (scalar @ids == 1) {
 
2086
        # we also support a list of comma-delimited ids like this
 
2087
        @ids = split /,/, $ids[0];
 
2088
    }
 
2089
    return $app->error($app->translate("Invalid request."))
 
2090
        unless @ids;
 
2091
 
 
2092
    my $tmpl_id;
 
2093
    my %ats;
 
2094
    require MT::TemplateMap;
 
2095
    while (!$tmpl_id && @ids) {
 
2096
        $tmpl_id = shift @ids;
 
2097
        my @tmpl_maps = MT::TemplateMap->load( { template_id => $tmpl_id } );
 
2098
        foreach my $map (@tmpl_maps) {
 
2099
            next unless $map->build_type;
 
2100
            $ats{ $map->archive_type } = 1;
 
2101
        }
 
2102
        undef $tmpl_id unless keys %ats;
 
2103
    }
 
2104
 
 
2105
    # we have a template and archive types to publish!
 
2106
 
 
2107
    require MT::CMS::Blog;
 
2108
    my $return_args;
 
2109
    my $reedit = $app->param('reedit');
 
2110
    if (@ids) {
 
2111
        # we have more to do after this, so save the list
 
2112
        # of remaining archive templates...
 
2113
        $return_args = $app->uri_params(
 
2114
            mode => 'publish_archive_templates',
 
2115
            args => {
 
2116
                magic_token => $app->current_magic,
 
2117
                blog_id => scalar $app->param('blog_id'),
 
2118
                id => join(",", @ids),
 
2119
                reedit => $reedit,
 
2120
            }
 
2121
        );
 
2122
    } else {
 
2123
        my $mode = $reedit ? 'view' : 'list';
 
2124
        $return_args = $app->uri_params(
 
2125
            mode => $mode,
 
2126
            args => {
 
2127
                _type     => 'template',
 
2128
                blog_id   => scalar $app->param('blog_id'),
 
2129
                published => 1,
 
2130
                ( $reedit ? ( saved => 1 )       : () ),
 
2131
                ( $reedit ? ( id    => $reedit ) : () ),
 
2132
            }
 
2133
        );
 
2134
    }
 
2135
    $return_args =~ s/^\?//;
 
2136
 
 
2137
    $app->return_args( $return_args );
 
2138
    $app->param( 'template_id', $tmpl_id );
 
2139
    $app->param( 'single_template', 1 ); # forces fullscreen mode
 
2140
    $app->param( 'type', join(",", keys %ats) );
 
2141
    return MT::CMS::Blog::start_rebuild_pages($app);
 
2142
}
 
2143
 
 
2144
sub save_widget {
 
2145
    my $app = shift;
 
2146
    my $q   = $app->param;
 
2147
 
 
2148
    $app->validate_magic() or return;
 
2149
    my $author = $app->user;
 
2150
 
 
2151
    my $id = $q->param('id');
 
2152
 
 
2153
    if ( !$author->is_superuser ) {
 
2154
        $app->run_callbacks( 'cms_save_permission_filter.template', $app, $id )
 
2155
          || return $app->error(
 
2156
            $app->translate( "Permission denied: [_1]", $app->errstr() ) );
 
2157
    }
 
2158
 
 
2159
    my $filter_result = $app->run_callbacks( 'cms_save_filter.widgetset', $app );
 
2160
 
 
2161
    if ( !$filter_result ) {
 
2162
        return edit_widget( $app, { error => $app->translate( "Save failed: [_1]", $app->errstr ) } );
 
2163
    }
 
2164
 
 
2165
    my $class = $app->model('template');
 
2166
    my $obj;
 
2167
    if ( $id ) {
 
2168
        $obj = $class->load($id)
 
2169
            or return $app->error($app->translate("Invalid ID [_1]", $id));
 
2170
    }
 
2171
    else {
 
2172
        $obj = $class->new;
 
2173
    }
 
2174
 
 
2175
    my $original = $obj->clone();
 
2176
    $obj->name($q->param('name'));
 
2177
    $obj->type('widgetset');
 
2178
    $obj->blog_id( $q->param('blog_id') || 0 );
 
2179
    $obj->modulesets($q->param('modules'));
 
2180
 
 
2181
    unless (
 
2182
        $app->run_callbacks( 'cms_pre_save.template', $app, $obj, $original ) )
 
2183
    {
 
2184
        return edit_widget( $app, { error => $app->translate( "Save failed: [_1]", $app->errstr ) } );
 
2185
    }
 
2186
 
 
2187
    $obj->save
 
2188
      or return $app->error(
 
2189
        $app->translate( "Saving object failed: [_1]", $obj->errstr ) );
 
2190
 
 
2191
    $app->run_callbacks( 'cms_post_save.template', $app, $obj, $original )
 
2192
      or return $app->error( $app->errstr() );
 
2193
 
 
2194
    $app->redirect(
 
2195
        $app->uri(
 
2196
            'mode' => 'edit_widget',
 
2197
            args =>
 
2198
              { blog_id => $obj->blog_id, 'saved' => 1, rebuild => 1, id => $obj->id }
 
2199
        )
 
2200
    );
 
2201
}
 
2202
 
 
2203
sub edit_widget {
 
2204
    my $app = shift;
 
2205
    my (%opt) = @_;
 
2206
 
 
2207
    my $q       = $app->param();
 
2208
    my $id      = scalar($q->param('id')) || $opt{id};
 
2209
    my $name    = scalar($q->param('name'));
 
2210
    my $blog_id = scalar $q->param('blog_id') || 0;
 
2211
 
 
2212
    my $tmpl_class = $app->model('template');
 
2213
    require MT::Promise;
 
2214
    my $obj_promise = MT::Promise::delay(
 
2215
        sub {
 
2216
            return $tmpl_class->load($id) || undef;
 
2217
        }
 
2218
    );
 
2219
 
 
2220
    if ( !$app->user->is_superuser ) {
 
2221
        $app->run_callbacks( 'cms_view_permission_filter.template',
 
2222
            $app, $id, $obj_promise )
 
2223
          || return $app->error(
 
2224
            $app->translate( "Permission denied: [_1]", $app->errstr() ) );
 
2225
    }
 
2226
 
 
2227
    my $param = {
 
2228
        blog_id      => $blog_id,
 
2229
        search_type  => "template",
 
2230
        search_label => MT::Template->class_label_plural,
 
2231
        exists($opt{rebuild}) ? ( rebuild => $opt{rebuild} ) : (),
 
2232
        exists($opt{error}) ? ( error => $opt{error} ) : (),
 
2233
        exists($opt{saved}) ? ( saved => $opt{saved} ) : (),
 
2234
        $id
 
2235
          ? ( id => $id )
 
2236
          : $name
 
2237
            ? ( name => $name )
 
2238
            : (),
 
2239
    };
 
2240
    if ($blog_id) {
 
2241
        my $blog = $app->blog;
 
2242
        # include_system/include_cache are only applicable
 
2243
        # to blog-level templates
 
2244
        $param->{include_system} = $blog->include_system;
 
2245
        $param->{include_cache} = $blog->include_cache;
 
2246
        $param->{include_with_ssi}      = 0;
 
2247
        $param->{cache_path}            = '';
 
2248
        $param->{cache_enabled}         = 0;
 
2249
        $param->{cache_expire_type}     = 0;
 
2250
        $param->{cache_expire_period}   = '';
 
2251
        $param->{cache_expire_interval} = 0;
 
2252
        $param->{ssi_type} = uc $blog->include_system;
 
2253
    }
 
2254
    
 
2255
    my $iter = $tmpl_class->load_iter(
 
2256
        { type => 'widget', blog_id => $blog_id ? [ $blog_id, 0 ] : 0 },
 
2257
        { sort => 'name', direction => 'ascend' }
 
2258
    );
 
2259
 
 
2260
    my %all_widgets;
 
2261
    while (my $m = $iter->()) {
 
2262
        next unless $m;
 
2263
        $all_widgets{ $m->id }{name} = $m->name;
 
2264
        $all_widgets{ $m->id }{blog_id} = $m->blog_id;
 
2265
    }
 
2266
 
 
2267
    my @inst_modules;
 
2268
    my $wtmpl;
 
2269
    if ( $id ) {
 
2270
        $wtmpl = $obj_promise->force()
 
2271
          or return $app->error(
 
2272
            $app->translate(
 
2273
                "Load failed: [_1]",
 
2274
                $tmpl_class->errstr || $app->translate("(no reason given)")
 
2275
            )
 
2276
          );
 
2277
        return $app->return_to_dashboard( redirect => 1 )
 
2278
            if $wtmpl->blog_id ne $blog_id;
 
2279
        $param->{name} = $wtmpl->name;
 
2280
        $param->{include_with_ssi} = $wtmpl->include_with_ssi
 
2281
          if defined $wtmpl->include_with_ssi;
 
2282
        $param->{cache_path}       = $wtmpl->cache_path
 
2283
          if defined $wtmpl->cache_path;
 
2284
        $param->{cache_expire_type} = $wtmpl->cache_expire_type
 
2285
          if defined $wtmpl->cache_expire_type;
 
2286
        my ( $period, $interval ) =
 
2287
          _get_schedule( $wtmpl->cache_expire_interval );
 
2288
        $param->{cache_expire_period}   = $period   if defined $period;
 
2289
        $param->{cache_expire_interval} = $interval if defined $interval;
 
2290
        my @events = split ',', $wtmpl->cache_expire_event;
 
2291
        foreach my $name (@events) {
 
2292
            $param->{ 'cache_expire_event_' . $name } = 1;
 
2293
        }
 
2294
        my $modulesets = $wtmpl->modulesets;
 
2295
        if ( $modulesets ) {
 
2296
            my @modules = split ',', $modulesets;
 
2297
            foreach my $mid ( @modules ) {
 
2298
                push @inst_modules, {
 
2299
                    id => $mid,
 
2300
                    name => $all_widgets{$mid}{name},
 
2301
                    blog_id => $all_widgets{$mid}{blog_id},
 
2302
                };
 
2303
                delete $all_widgets{$mid};
 
2304
            }
 
2305
        }
 
2306
    }
 
2307
    $param->{installed} = \@inst_modules if @inst_modules;
 
2308
    my @avail_modules = map { {
 
2309
        id => $_, name => $all_widgets{$_}{name}, blog_id => $all_widgets{$_}{blog_id}
 
2310
    } } keys %all_widgets;
 
2311
    $param->{available} = \@avail_modules;
 
2312
 
 
2313
    my $res = $app->run_callbacks('cms_edit.widgetset', $app, $id, $wtmpl, $param);
 
2314
    if (!$res) {
 
2315
        return $app->error($app->callback_errstr());
 
2316
    }
 
2317
 
 
2318
    $app->load_tmpl('edit_widget.tmpl', $param);
 
2319
}
 
2320
 
 
2321
sub list_widget {
 
2322
    my $app = shift;
 
2323
    my (%opt) = @_;
 
2324
    my $q = $app->param;
 
2325
 
 
2326
    my $perms = $app->blog ? $app->permissions : $app->user->permissions;
 
2327
    return $app->return_to_dashboard( redirect => 1 )
 
2328
      unless $perms || $app->user->is_superuser;
 
2329
    if ( $perms && !$perms->can_edit_templates ) {
 
2330
        return $app->return_to_dashboard( permission => 1 );
 
2331
    }
 
2332
    my $blog_id = $q->param('blog_id') || 0;
 
2333
 
 
2334
    my $widget_loop = &build_template_table( $app,
 
2335
        load_args => [ 
 
2336
            { type => 'widget', blog_id => $blog_id ? [ $blog_id, 0 ] : 0 },
 
2337
            { sort => 'name', direction => 'ascend' }
 
2338
        ],
 
2339
    );
 
2340
 
 
2341
    my $iter = $app->model('template')->load_iter(
 
2342
        { type => 'widgetset', blog_id => $blog_id ? $blog_id : 0 },
 
2343
        { sort => 'name', direction => 'ascend' }
 
2344
    );
 
2345
    my @widgetmanagers;
 
2346
    while ( my $widgetset = $iter->() ) {
 
2347
        next unless $widgetset;
 
2348
        my $ws = { 
 
2349
            id => $widgetset->id,
 
2350
            widgetmanager => $widgetset->name,
 
2351
        };
 
2352
        if ( my $modulesets = $widgetset->modulesets ) {
 
2353
            $ws->{widgets} = $modulesets;
 
2354
            my @names;
 
2355
            foreach my $module ( split ',', $modulesets ) { 
 
2356
                my ( $widget ) = grep { $_->{id} eq $module } @$widget_loop;
 
2357
                push @names, $widget->{name} if $widget;
 
2358
            }
 
2359
            $ws->{names} = join(', ', @names) if @names;
 
2360
        }
 
2361
        push @widgetmanagers, $ws;
 
2362
    }
 
2363
 
 
2364
    my @widget_loop;
 
2365
    if ( $blog_id ) {
 
2366
        # Remove system level widgets from the listing
 
2367
        @widget_loop = grep { $_->{blog_id} == $blog_id } @$widget_loop;
 
2368
    }
 
2369
    else {
 
2370
        @widget_loop = @$widget_loop;
 
2371
    }
 
2372
 
 
2373
    my $param = {
 
2374
        @widgetmanagers ? ( object_loop  => \@widgetmanagers ) : (),
 
2375
        @widget_loop    ? ( widget_table => \@widget_loop ) : (),
 
2376
        object_type    => "template",
 
2377
        search_type    => "template",
 
2378
        search_label   => MT::Template->class_label_plural,
 
2379
        listing_screen => 1,
 
2380
        screen_id      => "list-widget-set",
 
2381
        $blog_id ? ( blog_view => 1, blog_id => $blog_id ) : (),
 
2382
        exists($opt{rebuild}) ? ( rebuild => $opt{rebuild} ) : (),
 
2383
        exists($opt{error}) ? ( error => $opt{error} ) : (),
 
2384
        exists($opt{deleted}) ? ( saved => $opt{deleted} ) : ()
 
2385
    };
 
2386
 
 
2387
    $app->load_tmpl('list_widget.tmpl', $param);
 
2388
}
 
2389
 
 
2390
sub delete_widget {
 
2391
    my $app  = shift;
 
2392
    my $q    = $app->param;
 
2393
    my $type = $q->param('_type');
 
2394
 
 
2395
    return $app->errtrans("Invalid request.")
 
2396
      unless $type;
 
2397
 
 
2398
    return $app->error( $app->translate("Invalid request.") )
 
2399
      if $app->request_method() ne 'POST';
 
2400
 
 
2401
    $app->validate_magic() or return;
 
2402
 
 
2403
    my $tmpl_class = $app->model('template');
 
2404
 
 
2405
    for my $id ( $q->param('id') ) {
 
2406
        next unless $id;    # avoid 'empty' ids
 
2407
 
 
2408
        my $obj = $tmpl_class->load($id);
 
2409
        next unless $obj;
 
2410
        $app->run_callbacks( 'cms_delete_permission_filter.template',
 
2411
            $app, $obj )
 
2412
          || return $app->error(
 
2413
            $app->translate( "Permission denied: [_1]", $app->errstr() ) );
 
2414
 
 
2415
        $obj->remove
 
2416
          or return $app->errtrans(
 
2417
            'Removing [_1] failed: [_2]',
 
2418
            $app->translate('template'),
 
2419
            $obj->errstr
 
2420
          );
 
2421
        $app->run_callbacks( 'cms_post_delete.template', $app, $obj );
 
2422
    }
 
2423
    $app->call_return;
 
2424
}
 
2425
 
 
2426
sub restore_widgetmanagers {
 
2427
    my ($cb, $objects, $deferred, $errors, $callback) = @_;
 
2428
    my @keys = grep { $_ =~ /^MT::Template#/ } keys( %$objects );
 
2429
    foreach my $key ( @keys ) {
 
2430
        my $tmpl = $objects->{$key};
 
2431
        next unless 'widgetset' eq $tmpl->type;
 
2432
        my $modulesets = $tmpl->modulesets;
 
2433
        next unless $modulesets;
 
2434
        $callback->( MT->translate( 'Restoring widget set [_1]... ', $tmpl->name ) );
 
2435
 
 
2436
        my @tmpl_ids = split ',', $modulesets;
 
2437
        my @new_ids;
 
2438
        foreach my $id ( @tmpl_ids ) {
 
2439
            my $new_tmpl = $objects->{"MT::Template#$id"};
 
2440
            next unless $new_tmpl;
 
2441
            push @new_ids, $new_tmpl->id;
 
2442
        }
 
2443
        if ( @new_ids ) {
 
2444
            $tmpl->modulesets( join(',', @new_ids) );
 
2445
            $tmpl->save;
 
2446
            $callback->( MT->translate("Done.") . "\n" );
 
2447
        }
 
2448
        else {
 
2449
            $callback->( MT->translate("Failed.") . "\n" );
 
2450
        }
 
2451
    }
 
2452
    1;
 
2453
}
 
2454
 
 
2455
{
 
2456
    my @period_options = (
 
2457
        {
 
2458
            name => 'minutes',
 
2459
            expr => 60,
 
2460
        },
 
2461
        {
 
2462
            name => 'hours',
 
2463
            expr => 60 * 60,
 
2464
        },
 
2465
        {
 
2466
            name => 'days',
 
2467
            expr => 24 * 60 * 60,
 
2468
        },
 
2469
    );
 
2470
 
 
2471
    sub _get_schedule {
 
2472
        my ($sec) = @_;
 
2473
        return unless defined $sec;
 
2474
        my ( $period, $interval );
 
2475
        for (@period_options) {
 
2476
            last if $sec % $_->{expr};
 
2477
            $period   = $_->{name};
 
2478
            $interval = $sec / $_->{expr};
 
2479
        }
 
2480
        ( $period, $interval );
 
2481
    }
 
2482
 
 
2483
    sub _get_interval {
 
2484
        my ( $period, $interval ) = @_;
 
2485
        return unless defined $period;
 
2486
        my $sec = 0;
 
2487
        for (@period_options) {
 
2488
            if ( $_->{name} eq $period ) {
 
2489
                $sec = $interval * $_->{expr};
 
2490
                last;
 
2491
            }
 
2492
        }
 
2493
        $sec;
 
2494
    }
 
2495
}
 
2496
 
 
2497
1;