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

« back to all changes in this revision

Viewing changes to lib/MT/CMS/Category.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
package MT::CMS::Category;
 
2
 
 
3
use strict;
 
4
use MT::Util qw( encode_url encode_js );
 
5
 
 
6
sub edit {
 
7
    my $cb = shift;
 
8
    my ($app, $id, $obj, $param) = @_;
 
9
 
 
10
    my $blog = $app->blog;
 
11
 
 
12
    if ($id) {
 
13
        $param->{nav_categories} = 1;
 
14
 
 
15
        #$param{ "tab_" . ( $app->param('tab') || 'details' ) } = 1;
 
16
 
 
17
        # $app->add_breadcrumb($app->translate('Categories'),
 
18
        #                      $app->uri( 'mode' => 'list_cat',
 
19
        #                          args => { blog_id => $obj->blog_id }));
 
20
        # $app->add_breadcrumb($obj->label);
 
21
        my $parent   = $obj->parent_category;
 
22
        my $site_url = $blog->site_url;
 
23
        $site_url .= '/' unless $site_url =~ m!/$!;
 
24
        $param->{path_prefix} =
 
25
          $site_url . ( $parent ? $parent->publish_path : '' );
 
26
        $param->{path_prefix} .= '/' unless $param->{path_prefix} =~ m!/$!;
 
27
        require MT::Trackback;
 
28
        my $tb = MT::Trackback->load( { category_id => $obj->id } );
 
29
 
 
30
        if ($tb) {
 
31
            my $list_pref = $app->list_pref('ping');
 
32
            %$param = ( %$param, %$list_pref );
 
33
            my $path = $app->config('CGIPath');
 
34
            $path .= '/' unless $path =~ m!/$!;
 
35
            if ($path =~ m!^/!) {
 
36
                my ($blog_domain) = $blog->archive_url =~ m|(.+://[^/]+)|;
 
37
                $path = $blog_domain . $path;
 
38
            }
 
39
 
 
40
            my $script = $app->config('TrackbackScript');
 
41
            $param->{tb}     = 1;
 
42
            $param->{tb_url} = $path . $script . '/' . $tb->id;
 
43
            if ( $param->{tb_passphrase} = $tb->passphrase ) {
 
44
                $param->{tb_url} .= '/' . encode_url( $param->{tb_passphrase} );
 
45
            }
 
46
            $app->load_list_actions( 'ping', $param->{ping_table}[0],
 
47
                'pings' );
 
48
        }
 
49
    }
 
50
    1;
 
51
}
 
52
 
 
53
sub list {
 
54
    my $app   = shift;
 
55
    my $q     = $app->param;
 
56
    my $type  = $q->param('_type') || 'category';
 
57
    my $class = $app->model($type);
 
58
 
 
59
    my $perms = $app->permissions;
 
60
    my $entry_class;
 
61
    my $entry_type;
 
62
    if ( $type eq 'category' ) {
 
63
        $entry_type = 'entry';
 
64
        return $app->return_to_dashboard( redirect => 1 )
 
65
          unless $perms && $perms->can_edit_categories;
 
66
    }
 
67
    elsif ( $type eq 'folder' ) {
 
68
        $entry_type = 'page';
 
69
        return $app->return_to_dashboard( redirect => 1 )
 
70
          unless $perms && $perms->can_manage_pages;
 
71
    }
 
72
    $entry_class = $app->model($entry_type);
 
73
    my $blog_id = scalar $q->param('blog_id');
 
74
    require MT::Blog;
 
75
    my $blog = MT::Blog->load($blog_id)
 
76
      or return $app->errtrans("Invalid request.");
 
77
    my %param;
 
78
    my %authors;
 
79
    my $data = $app->_build_category_list(
 
80
        blog_id    => $blog_id,
 
81
        counts     => 1,
 
82
        new_cat_id => scalar $q->param('new_cat_id'),
 
83
        type       => $type
 
84
    );
 
85
    if ( $blog->site_url =~ /\/$/ ) {
 
86
        $param{blog_site_url} = $blog->site_url;
 
87
    }
 
88
    else {
 
89
        $param{blog_site_url} = $blog->site_url . '/';
 
90
    }
 
91
    $param{object_loop} = $param{category_loop} = $data;
 
92
    $param{saved} = $q->param('saved');
 
93
    $param{saved_deleted} = $q->param('saved_deleted');
 
94
    $app->load_list_actions( $type, \%param );
 
95
 
 
96
    #$param{nav_categories} = 1;
 
97
    $param{sub_object_label} =
 
98
        $type eq 'folder'
 
99
      ? $app->translate('Subfolder')
 
100
      : $app->translate('Subcategory');
 
101
    $param{object_label}        = $class->class_label;
 
102
    $param{object_label_plural} = $class->class_label_plural;
 
103
    $param{object_type}         = $type;
 
104
    $param{entry_label_plural}  = $entry_class->class_label_plural;
 
105
    $param{entry_label}         = $entry_class->class_label;
 
106
    $param{search_label}        = $param{entry_label_plural};
 
107
    $param{search_type}         = $entry_type;
 
108
    $param{screen_id} =
 
109
        $type eq 'folder'
 
110
      ? 'list-folder'
 
111
      : 'list-category';
 
112
    $param{listing_screen}      = 1;
 
113
    $app->add_breadcrumb( $param{object_label_plural} );
 
114
 
 
115
    $param{screen_class} = "list-${type}";
 
116
    $param{screen_class} .= " list-category"
 
117
      if $type eq 'folder';    # to piggyback on list-category styles
 
118
    my $tmpl_file = 'list_' . $type . '.tmpl';
 
119
    $app->load_tmpl( $tmpl_file, \%param );
 
120
}
 
121
 
 
122
sub save {
 
123
    my $app   = shift;
 
124
    my $q     = $app->param;
 
125
    my $perms = $app->permissions;
 
126
    my $type  = $q->param('_type');
 
127
    my $class = $app->model($type)
 
128
      or return $app->errtrans("Invalid request.");
 
129
 
 
130
    if ( $type eq 'category' ) {
 
131
        return $app->errtrans("Permission denied.")
 
132
          unless $perms && $perms->can_edit_categories;
 
133
    }
 
134
    elsif ( $type eq 'folder' ) {
 
135
        return $app->errtrans("Permission denied.")
 
136
          unless $perms && $perms->can_manage_pages;
 
137
    }
 
138
 
 
139
    $app->validate_magic() or return;
 
140
 
 
141
    my $blog_id = $q->param('blog_id');
 
142
    my $cat;
 
143
    if ( my $moved_cat_id = $q->param('move_cat_id') ) {
 
144
        $cat = $class->load( $q->param('move_cat_id') )
 
145
            or return;
 
146
        move_category($app) or return;
 
147
    }
 
148
    else {
 
149
        for my $p ( $q->param ) {
 
150
            my ($parent) = $p =~ /^category-new-parent-(\d+)$/;
 
151
            next unless ( defined $parent );
 
152
 
 
153
            my $label = $q->param($p);
 
154
            $label =~ s/(^\s+|\s+$)//g;
 
155
            next unless ( $label ne '' );
 
156
 
 
157
            $cat = $class->new;
 
158
            my $original = $cat->clone;
 
159
            $cat->blog_id($blog_id);
 
160
            $cat->label($label);
 
161
            $cat->author_id( $app->user->id );
 
162
            $cat->parent($parent);
 
163
 
 
164
            $app->run_callbacks( 'cms_pre_save.' . $type,
 
165
                $app, $cat, $original )
 
166
              || return $app->errtrans( "Saving [_1] failed: [_2]", $type,
 
167
                $app->errstr );
 
168
 
 
169
            $cat->save
 
170
              or return $app->error(
 
171
                $app->translate(
 
172
                    "Saving [_1] failed: [_2]",
 
173
                    $type, $cat->errstr
 
174
                )
 
175
              );
 
176
 
 
177
            # Now post-process it.
 
178
            $app->run_callbacks( 'cms_post_save.' . $type,
 
179
                $app, $cat, $original );
 
180
        }
 
181
    }
 
182
 
 
183
    return $app->errtrans( "The [_1] must be given a name!", $type )
 
184
      if !$cat;
 
185
 
 
186
    $app->redirect(
 
187
        $app->uri(
 
188
            'mode' => 'list_cat',
 
189
            args   => {
 
190
                _type      => $type,
 
191
                blog_id    => $blog_id,
 
192
                saved      => 1,
 
193
                new_cat_id => $cat->id
 
194
            }
 
195
        )
 
196
    );
 
197
}
 
198
 
 
199
sub category_add {
 
200
    my $app  = shift;
 
201
    my $q    = $app->param;
 
202
    my $type = $q->param('_type') || 'category';
 
203
    my $pkg  = $app->model($type);
 
204
    my $data = $app->_build_category_list(
 
205
        blog_id => scalar $q->param('blog_id'),
 
206
        type    => $type
 
207
    );
 
208
    my %param;
 
209
    $param{'category_loop'} = $data;
 
210
    $app->add_breadcrumb( $app->translate( 'Add a [_1]', $pkg->class_label ) );
 
211
    $param{object_type}  = $type;
 
212
    $param{object_label} = $pkg->class_label;
 
213
    $app->load_tmpl( 'popup/category_add.tmpl', \%param );
 
214
}
 
215
 
 
216
sub category_do_add {
 
217
    my $app    = shift;
 
218
    my $q      = $app->param;
 
219
    my $type   = $q->param('_type') || 'category';
 
220
    my $author = $app->user;
 
221
    my $pkg    = $app->model($type);
 
222
    $app->validate_magic() or return;
 
223
    my $name = $q->param('label')
 
224
      or return $app->error( $app->translate("No label") );
 
225
    $name =~ s/(^\s+|\s+$)//g;
 
226
    return $app->errtrans("Category name cannot be blank.")
 
227
      if $name eq '';
 
228
    my $parent   = $q->param('parent') || '0';
 
229
    my $cat      = $pkg->new;
 
230
    my $original = $cat->clone;
 
231
    $cat->blog_id( scalar $q->param('blog_id') );
 
232
    $cat->author_id( $app->user->id );
 
233
    $cat->label($name);
 
234
    $cat->parent($parent);
 
235
 
 
236
    if ( !$author->is_superuser ) {
 
237
        $app->run_callbacks( 'cms_save_permission_filter.' . $type,
 
238
            $app, undef )
 
239
          || return $app->error(
 
240
            $app->translate( "Permission denied: [_1]", $app->errstr() ) );
 
241
    }
 
242
 
 
243
    my $filter_result = $app->run_callbacks( 'cms_save_filter.' . $type, $app )
 
244
      || return;
 
245
 
 
246
    $app->run_callbacks( 'cms_pre_save.' . $type, $app, $cat, $original )
 
247
      || return;
 
248
 
 
249
    $cat->save or return $app->error( $cat->errstr );
 
250
 
 
251
    # Now post-process it.
 
252
    $app->run_callbacks( 'cms_post_save.' . $type, $app, $cat, $original )
 
253
      or return;
 
254
 
 
255
    my $id = $cat->id;
 
256
    $name = encode_js($name);
 
257
    my %param = ( javascript => <<SCRIPT);
 
258
    o.doAddCategoryItem('$name', '$id');
 
259
SCRIPT
 
260
    $app->load_tmpl( 'reload_opener.tmpl', \%param );
 
261
}
 
262
 
 
263
sub js_add_category {
 
264
    my $app = shift;
 
265
    unless ( $app->validate_magic ) {
 
266
        return $app->json_error( $app->translate("Invalid request.") );
 
267
    }
 
268
    my $user    = $app->user;
 
269
    my $blog_id = $app->param('blog_id');
 
270
    my $perms   = $app->permissions;
 
271
    my $type    = $app->param('_type') || 'category';
 
272
    my $class   = $app->model($type);
 
273
    if ( !$class ) {
 
274
        return $app->json_error( $app->translate("Invalid request.") );
 
275
    }
 
276
 
 
277
    my $label = $app->param('label');
 
278
    my $enc   = $app->config->PublishCharset;
 
279
 
 
280
    # XMLHttpRequest always send text in UTF-8... right?
 
281
    if ( 'utf-8' ne lc($enc) ) {
 
282
        $label = MT::I18N::encode_text( $label, 'utf-8', $enc );
 
283
    }
 
284
    my $basename = $app->param('basename');
 
285
    if ( !defined($label) || ( $label =~ m/^\s*$/ ) ) {
 
286
        return $app->json_error( $app->translate("Invalid request.") );
 
287
    }
 
288
 
 
289
    my $blog = $app->blog;
 
290
    if ( !$blog ) {
 
291
        return $app->json_error( $app->translate("Invalid request.") );
 
292
    }
 
293
 
 
294
    my $parent;
 
295
    if ( my $parent_id = $app->param('parent') ) {
 
296
        if ( $parent_id != -1 ) {    # special case for 'root' folder
 
297
            $parent = $class->load( { id => $parent_id, blog_id => $blog_id } );
 
298
            if ( !$parent ) {
 
299
                return $app->json_error( $app->translate("Invalid request.") );
 
300
            }
 
301
        }
 
302
    }
 
303
 
 
304
    my $obj      = $class->new;
 
305
    my $original = $obj->clone;
 
306
 
 
307
    if (
 
308
        !$app->run_callbacks(
 
309
            'cms_save_permission.' . $type,
 
310
            $app, $obj, $original
 
311
        )
 
312
      )
 
313
    {
 
314
        return $app->json_error( $app->translate("Permission denied.") );
 
315
    }
 
316
 
 
317
    $obj->label($label);
 
318
    $obj->basename($basename)   if $basename;
 
319
    $obj->parent( $parent->id ) if $parent;
 
320
    $obj->blog_id($blog_id);
 
321
    $obj->author_id( $user->id );
 
322
    $obj->created_by( $user->id );
 
323
 
 
324
    if (
 
325
        !$app->run_callbacks( 'cms_pre_save.' . $type, $app, $obj, $original ) )
 
326
    {
 
327
        return $app->json_error( $app->errstr );
 
328
    }
 
329
 
 
330
    $obj->save;
 
331
 
 
332
    $app->run_callbacks( 'cms_post_save.' . $type, $app, $obj, $original );
 
333
 
 
334
    return $app->json_result(
 
335
        {
 
336
            id       => $obj->id,
 
337
            basename => $obj->basename
 
338
        }
 
339
    );
 
340
}
 
341
 
 
342
sub can_view {
 
343
    my ( $eh, $app, $id ) = @_;
 
344
    my $perms = $app->permissions;
 
345
    return $perms->can_edit_categories();
 
346
}
 
347
 
 
348
sub can_save {
 
349
    my ( $eh, $app, $id ) = @_;
 
350
    my $perms = $app->permissions;
 
351
    return $perms->can_edit_categories();
 
352
}
 
353
 
 
354
sub can_delete {
 
355
    my ( $eh, $app, $obj ) = @_;
 
356
    return 1 if $app->user->is_superuser();
 
357
    my $perms = $app->permissions;
 
358
    return $perms && $perms->can_edit_categories();
 
359
}
 
360
 
 
361
sub pre_save {
 
362
    my $eh = shift;
 
363
    my ( $app, $obj ) = @_;
 
364
    my $pkg = $app->model('category');
 
365
    if ( defined( my $pass = $app->param('tb_passphrase') ) ) {
 
366
        $obj->{__tb_passphrase} = $pass;
 
367
    }
 
368
    my @siblings = $pkg->load(
 
369
        {
 
370
            parent  => $obj->parent,
 
371
            blog_id => $obj->blog_id
 
372
        }
 
373
    );
 
374
    foreach (@siblings) {
 
375
        next if $obj->id && ( $_->id == $obj->id );
 
376
        return $eh->error(
 
377
            $app->translate(
 
378
"The category name '[_1]' conflicts with another category. Top-level categories and sub-categories with the same parent must have unique names.",
 
379
                $_->label
 
380
            )
 
381
        ) if $_->label eq $obj->label;
 
382
        return $eh->error(
 
383
            $app->translate(
 
384
"The category basename '[_1]' conflicts with another category. Top-level categories and sub-categories with the same parent must have unique basenames.",
 
385
                $_->label
 
386
            )
 
387
        ) if $_->basename eq $obj->basename;
 
388
    }
 
389
    1;
 
390
}
 
391
 
 
392
sub post_save {
 
393
    my $eh = shift;
 
394
    my ( $app, $obj, $original ) = @_;
 
395
 
 
396
    if ( !$original->id ) {
 
397
        $app->log(
 
398
            {
 
399
                message => $app->translate(
 
400
                    "Category '[_1]' created by '[_2]'", $obj->label,
 
401
                    $app->user->name
 
402
                ),
 
403
                level    => MT::Log::INFO(),
 
404
                class    => 'category',
 
405
                category => 'new',
 
406
            }
 
407
        );
 
408
    }
 
409
    1;
 
410
}
 
411
 
 
412
sub save_filter {
 
413
    my $eh = shift;
 
414
    my ($app) = @_;
 
415
    return $app->errtrans( "The name '[_1]' is too long!",
 
416
        $app->param('label') )
 
417
      if ( length( $app->param('label') ) > 100 );
 
418
    return 1;
 
419
}
 
420
 
 
421
sub post_delete {
 
422
    my ( $eh, $app, $obj ) = @_;
 
423
 
 
424
    $app->log(
 
425
        {
 
426
            message => $app->translate(
 
427
                "Category '[_1]' (ID:[_2]) deleted by '[_3]'",
 
428
                $obj->label, $obj->id, $app->user->name
 
429
            ),
 
430
            level    => MT::Log::INFO(),
 
431
            class    => 'system',
 
432
            category => 'delete'
 
433
        }
 
434
    );
 
435
}
 
436
 
 
437
sub move_category {
 
438
    my $app   = shift;
 
439
    my $type  = $app->param('_type');
 
440
    my $class = $app->model($type)
 
441
      or return $app->errtrans("Invalid request.");
 
442
    $app->validate_magic() or return;
 
443
 
 
444
    my $cat        = $class->load( $app->param('move_cat_id') )
 
445
        or return;
 
446
    my $new_parent = $app->param('move-radio');
 
447
 
 
448
    return 1 if ( $new_parent == $cat->parent );
 
449
 
 
450
    $cat->parent($new_parent);
 
451
    my @siblings = $class->load(
 
452
        {
 
453
            parent  => $cat->parent,
 
454
            blog_id => $cat->blog_id
 
455
        }
 
456
    );
 
457
    foreach (@siblings) {
 
458
 
 
459
        # FIXME: Language should support both category / folder
 
460
        return $app->errtrans(
 
461
"The category name '[_1]' conflicts with another category. Top-level categories and sub-categories with the same parent must have unique names.",
 
462
            $_->label
 
463
        ) if $_->label eq $cat->label;
 
464
    }
 
465
 
 
466
    $cat->save
 
467
      or return $app->error(
 
468
        $app->translate( "Saving category failed: [_1]", $cat->errstr ) );
 
469
}
 
470
 
 
471
1;