root/branches/release-34/lib/MT/CMS/Category.pm @ 1823

Revision 1823, 13.9 kB (checked in by takayama, 20 months ago)

Fixed BugId:67959
* Added check for result of object loading

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