root/branches/release-33/lib/MT/CMS/User.pm @ 1752

Revision 1752, 58.0 kB (checked in by fumiakiy, 20 months ago)

Do not double-translate the name of permissions. They are labels and automatically translated.

  • Property svn:keywords set to Id Revision
Line 
1package MT::CMS::User;
2
3use strict;
4
5use MT::Util qw( format_ts relative_date is_url );
6use MT::Author;
7
8sub edit {
9    my $cb = shift;
10    my ($app, $id, $obj, $param) = @_;
11
12    my $author = $app->user;
13
14    if ($id) {
15        # TODO: Populate permissions / blogs for this user
16        # populate blog_loop, permission_loop
17        $param->{is_me} = 1 if $id == $author->id;
18        $param->{editing_other_profile} = 1
19          if !$param->{is_me} && $author->is_superuser;
20
21        $param->{userpic} = $obj->userpic_html();
22
23        require MT::Permission;
24
25        # General permissions...
26        my $sys_perms = MT::Permission->perms('system');
27        foreach (@$sys_perms) {
28            $param->{ 'perm_can_' . $_->[0] } =
29              ($obj->is_superuser || $obj->permissions(0)->has( $_->[0] )) ? 1 : 0;
30        }
31        $param->{perm_is_superuser} = $obj->is_superuser;
32
33        require MT::Auth;
34        if ( $app->user->is_superuser ) {
35            $param->{search_label} = $app->translate('Users');
36            $param->{object_type}  = 'author';
37            $param->{can_edit_username} = 1;
38        }
39        $param->{status_enabled} = $obj->is_active ? 1 : 0;
40        $param->{status_pending} =
41          $obj->status == MT::Author::PENDING() ? 1 : 0;
42        $param->{can_modify_password} =
43          ( $param->{editing_other_profile} || $param->{is_me} )
44          && MT::Auth->password_exists;
45        $param->{can_recover_password} = MT::Auth->can_recover_password;
46        $param->{languages} = $app->languages_list( $obj->preferred_language )
47          unless exists $param->{langauges};
48    } else {
49        $param->{create_personal_weblog} =
50          $app->config->NewUserAutoProvisioning ? 1 : 0
51          unless exists $param->{create_personal_weblog};
52        $param->{can_modify_password}  = MT::Auth->password_exists;
53        $param->{can_recover_password} = MT::Auth->can_recover_password;
54    }
55
56    $app->add_breadcrumb( $app->translate("Users"),
57          $app->user->is_superuser
58        ? $app->uri( mode => 'list_authors' )
59        : undef );
60    my $auth_prefs;
61    if ($obj) {
62        $app->add_breadcrumb( $obj->name );
63        $param->{languages} =
64          $app->languages_list( $obj->preferred_language );
65        $auth_prefs = $obj->entry_prefs;
66    }
67    else {
68        $app->add_breadcrumb( $app->translate("Create User") );
69        $param->{languages} =
70          $app->languages_list( $app->config('DefaultUserLanguage') )
71          unless ( exists $param->{languages} );
72        $auth_prefs = { tag_delim => $app->config->DefaultUserTagDelimiter }
73          unless ( exists $param->{'auth_pref_tag_delim'} );
74    }
75    $param->{text_filters} =
76      $app->load_text_filters( $obj ? $obj->text_format : undef,
77        'comment' );
78    unless ( exists $param->{'auth_pref_tag_delim'} ) {
79        my $delim = chr( $auth_prefs->{tag_delim} );
80        if ( $delim eq ',' ) {
81            $param->{'auth_pref_tag_delim_comma'} = 1;
82        }
83        elsif ( $delim eq ' ' ) {
84            $param->{'auth_pref_tag_delim_space'} = 1;
85        }
86        else {
87            $param->{'auth_pref_tag_delim_other'} = 1;
88        }
89        $param->{'auth_pref_tag_delim'} = $delim;
90    }
91    $param->{'nav_authors'} = 1;
92}
93
94sub edit_role {
95    my $app = shift;
96
97    $app->return_to_dashboard( redirect => 1 ) if $app->param('blog_id');
98
99    my %param  = $_[0] ? %{ $_[0] } : ();
100    my $q      = $app->param;
101    my $author = $app->user;
102    my $id     = $q->param('id');
103
104    require MT::Permission;
105    if ( !$author->is_superuser ) {
106        return $app->error( $app->translate("Invalid request.") );
107    }
108    my $role;
109    require MT::Role;
110    if ($id) {
111        $role = MT::Role->load($id);
112
113        # $param{is_enabled} = $role->is_active;
114        $param{is_enabled}  = 1;
115        $param{name}        = $role->name;
116        $param{description} = $role->description;
117        $param{id}          = $role->id;
118        my $creator = MT::Author->load( $role->created_by )
119          if $role->created_by;
120        $param{created_by} = $creator ? $creator->name : '';
121
122        my $permissions = $role->permissions;
123        if ( defined($permissions) && $permissions ) {
124            my @perms = split ',', $permissions;
125
126            my @roles = MT::Role->load_same(
127                { 'id' => [$id] },
128                { not  => { id => 1 } },
129                1,    # exact match
130                @perms
131            );
132            my @same_perms;
133            for my $other_role (@roles) {
134                push @same_perms,
135                  {
136                    name => $other_role->name,
137                    id   => $other_role->id,
138                  };
139            }
140            $param{same_perm_loop} = \@same_perms if @same_perms;
141        }
142        require MT::Association;
143        $param{user_count} = MT::Author->count( undef, { join  => MT::Association->join_on( 'author_id', { role_id => $id }, { unique => 1 } ) } );
144    }
145
146    my $all_perm_flags = MT::Permission->perms('blog');
147
148    my @p_data;
149    for my $ref (@$all_perm_flags) {
150        $param{ 'have_access-' . $ref->[0] } =
151          ( $role && $role->has( $ref->[0] ) ) ? 1 : 0;
152        $param{ 'prompt-' . $ref->[0] } = $ref->[1];
153    }
154    $param{saved}          = $q->param('saved');
155    $param{nav_privileges} = 1;
156    $app->add_breadcrumb( $app->translate('Roles'),
157        $app->uri( mode => 'list_roles' ) );
158    if ($id) {
159        $app->add_breadcrumb( $role->name );
160    }
161    else {
162        $app->add_breadcrumb( $app->translate('Create Role') );
163    }
164    $param{screen_class}        = "settings-screen edit-role";
165    $param{object_type}         = 'role';
166    $param{object_label}        = MT::Role->class_label;
167    $param{object_label_plural} = MT::Role->class_label_plural;
168    $param{search_label}        = $app->translate('Users');
169    $app->load_tmpl( 'edit_role.tmpl', \%param );
170}
171
172sub list {
173    my $app = shift;
174    my (%param) = @_;
175
176    $app->return_to_dashboard( redirect => 1 )
177      if $app->param('blog_id');
178
179    my $this_author = $app->user;
180    return $app->return_to_dashboard( permission => 1 )
181      unless $this_author->is_superuser();
182
183    my $this_author_id = $this_author->id;
184    my $list_pref      = $app->list_pref('author');
185    %param             = (%param, %$list_pref);
186    my $limit          = $list_pref->{rows};
187    my $offset         = $app->param('offset') || 0;
188    my $args           = { offset => $offset, sort => 'name' };
189    $args->{limit} = $limit + 1;
190    my %author_entry_count;
191    $param{tab_users} = 1;
192    my ( $filter_col, $val );
193    $param{filter_args} = "";
194    my %terms = ( type => MT::Author::AUTHOR() );
195
196    my $filter_key = $app->param('filter_key');
197    if (   ( $filter_col = $app->param('filter') )
198        && ( $val = $app->param('filter_val') ) )
199    {
200        if ( !exists( $terms{$filter_col} ) ) {
201            $terms{$filter_col} = $val;
202            $param{filter}      = $filter_col;
203            $param{filter_val}  = $val;
204            $param{filter_args} = "&filter=" . encode_url($filter_col) . "&filter_val=" . encode_url($val);
205        }
206    } elsif ($filter_key) {
207        my $filters = $app->registry("list_filters", "sys_user") || {};
208        if ( my $filter = $filters->{$filter_key} ) {
209            if ( my $code = $filter->{code}
210                || $app->handler_to_coderef( $filter->{handler} ) )
211            {
212                $param{filter} = 1;
213                $param{filter_key}   = $filter_key;
214                $param{filter_label} = $filter->{label};
215                $code->( \%terms, $args );
216            }
217        }
218    }
219    $param{can_create_user}           = $this_author->is_superuser;
220    $param{synchronized}              = 1 if $app->param('synchronized');
221    $param{error}                     = 1 if $app->param('error');
222    my $author_iter = MT::Author->load_iter( \%terms, $args );
223    my ( @data, %authors, %entry_count_refs );
224    my $entry_class = $app->model('entry');
225    while ( my $au = $author_iter->() ) {
226        my $row = $au->column_values;
227        $row->{name} = '(unnamed)' if !$row->{name};
228        $authors{ $au->id } ||= $au;
229        $row->{id}    = $au->id;
230        $row->{email} = ''
231          unless ( !defined $au->email )
232          or ( $au->email =~ /@/ );
233        $row->{entry_count}          = 0;
234        $entry_count_refs{ $au->id } = \$row->{entry_count};
235        $row->{is_me}                = $au->id == $this_author_id;
236        $row->{has_edit_access}      = $this_author->is_superuser;
237        $row->{status_enabled}       = $au->is_active;
238        $row->{status_pending}       = $au->status == MT::Author::PENDING();
239
240        if ( $row->{created_by} ) {
241            my $parent_author = $authors{ $au->created_by } ||=
242              MT::Author->load( $au->created_by )
243              if $au->created_by;
244            if ($parent_author) {
245                $row->{created_by_name} = $parent_author->name;
246            }
247            else {
248                $row->{created_by_name} = $app->translate('(user deleted)');
249            }
250        }
251        push @data, $row;
252        last if scalar @data == $limit;
253    }
254    if ( keys %entry_count_refs ) {
255        my $author_entry_count_iter =
256          MT::Entry->count_group_by(
257            { author_id => [ keys %entry_count_refs ] },
258            { group     => ['author_id'] } );
259        while ( my ( $count, $author_id ) = $author_entry_count_iter->() ) {
260            ${ $entry_count_refs{$author_id} } = $count;
261        }
262    }
263    $param{object_loop} = \@data;
264    $param{object_type} = 'author';
265    $param{object_label} = $app->model('author')->class_label;
266    $param{object_label_plural} = $app->model('author')->class_label_plural;
267    if ( $this_author->is_superuser() ) {
268        $param{search_label} = $app->translate('Users');
269        $param{is_superuser} = 1;
270    }
271
272    $param{limit}      = $limit;
273    $param{list_start} = $offset + 1;
274    delete $args->{limit};
275    delete $args->{offset};
276    $param{list_total} = MT::Author->count( \%terms, $args );
277    $param{list_end}        = $offset + ( scalar @data );
278    $param{next_offset_val} = $offset + ( scalar @data );
279    $param{next_offset} = $param{next_offset_val} < $param{list_total} ? 1 : 0;
280    $param{next_max}    = $param{list_total} - $limit;
281    $param{next_max}    = 0 if ( $param{next_max} || 0 ) < $offset + 1;
282    if ( $offset > 0 ) {
283        $param{prev_offset}     = 1;
284        $param{prev_offset_val} = $offset - $limit;
285        $param{prev_offset_val} = 0 if $param{prev_offset_val} < 0;
286    }
287    $param{offset}            = $offset;
288    $param{list_filters}      = $app->list_filters("sys_user");
289    $param{list_noncron}      = 1;
290    $param{saved_deleted}     = $app->param('saved_deleted');
291    $param{saved_removed}     = $app->param('saved_removed');
292    $param{author_ldap_found} = $app->param('author_ldap_found');
293    $param{saved}             = $app->param('saved');
294    my $status = $app->param('saved_status');
295    $param{"saved_status_$status"} = 1 if $status;
296    $param{unchanged} = $app->param('unchanged');
297    $app->load_list_actions( 'author', \%param );
298    $param{page_actions} =
299      $app->page_actions('list_authors');
300
301    $param{nav_authors} = 1;
302    $param{listing_screen} = 1;
303    $param{screen_id} = "list-author";
304    my $tmpl_file = $param{output} || 'list_author.tmpl';
305    $app->load_tmpl( $tmpl_file, \%param );
306}
307
308# list of all users, regardless of commenter/author on a blog
309sub list_member {
310    my $app = shift;
311
312    my $blog_id = $app->param('blog_id');
313    $app->return_to_dashboard( redirect => 1 )
314      unless $blog_id;
315
316    my $blog  = $app->blog;
317    my $user  = $app->user;
318    my $perms = $app->permissions;
319    return $app->return_to_dashboard( permission => 1 )
320      unless $user->is_superuser() || ($perms && $perms->can_administer_blog());
321
322    my $super_user = 1 if $user->is_superuser();
323    my $args       = {};
324    my $terms      = {};
325    my $param = { list_noncron => 1 };
326    $args->{join} =
327      MT::Permission->join_on( 'author_id', { blog_id => $blog_id, } );
328
329    $args->{sort_order} = 'created_on';
330    $args->{direction}  = 'descend';
331
332    $param->{saved} = 1 if $app->param('saved');
333    $param->{search_label} = $app->translate('Users');
334    $param->{object_type} = 'author';
335
336    require MT::Association;
337    require MT::Role;
338    my @all_roles = MT::Role->load( undef, { sort => 'name' });
339
340    my $sel_role = 0;
341    my $filter = $app->param('filter') || '';
342    if ($filter eq 'role') {
343        my $val = scalar $app->param('filter_val');
344        if ($val) {
345            $sel_role = $val;
346            $args->{join} = MT::Association->join_on('author_id', { blog_id => $blog_id, role_id => $val });
347        }
348    }
349    elsif ($filter eq 'status') {
350        my $val = $app->param('filter_val');
351        if ($val eq 'disabled') {
352            $terms->{status} = 2;
353        }
354        elsif ($val eq 'pending') {
355            $terms->{status} = 3;
356        }
357        else {
358            $terms->{status} = 1;
359        }
360    }
361
362    my @role_loop;
363    foreach my $r (@all_roles) {
364        push @role_loop, { role_id => $r->id, role_name => $r->name, selected => $r->id == $sel_role };
365    }
366    $param->{role_loop} = \@role_loop;
367    my $hasher = sub {
368        my ( $obj, $row ) = @_;
369        if ( ( $row->{email} || '' ) !~ m/@/ ) {
370            $row->{email} = '';
371        }
372        if ( $row->{created_by} ) {
373            if ( my $created_by = MT::Author->load( $row->{created_by} ) ) {
374                $row->{created_by} = $created_by->name;
375            }
376            else {
377                $row->{created_by} = $app->translate('*User deleted*');
378            }
379        }
380        $row->{is_me}           = $row->{id} == $user->id;
381        $row->{has_edit_access} = 1 if $super_user;
382        $row->{usertype_author} = 1 if $obj->type == MT::Author::AUTHOR();
383        if ( $obj->type == MT::Author::COMMENTER() ) {
384            $row->{usertype_commenter} = 1;
385            $row->{status_trusted} = 1 if $obj->is_trusted($blog_id);
386            if ($row->{name} =~ m/^[a-f0-9]{32}$/) {
387                $row->{name} = $row->{nickname} || $row->{url};
388            }
389        }
390        $row->{status_enabled} = 1 if $obj->status == 1;
391        my @roles = MT::Role->load(undef, { join => MT::Association->join_on('role_id', { author_id => $row->{id}, blog_id => $blog_id }, { unique => 1 })});
392        my @role_loop;
393        foreach my $role (@roles) {
394            my @perms;
395            my @all_perms = @{ MT::Permission->perms() };
396            foreach (@all_perms) {
397                next unless length( $_->[1] || '' );
398                push @perms, $_->[1]
399                  if $role->has( $_->[0] );
400            }
401            my $role_perms = join(", ", @perms);
402            push @role_loop, { role_name => $role->name, role_id => $role->id, role_perms => $role_perms };
403        }
404        $row->{role_loop} = \@role_loop;
405        $row->{auth_icon_url} = $obj->auth_icon_url;
406    };
407    $param->{screen_id} = "list-member";
408
409    return $app->listing(
410        {
411            type     => 'user',
412            template => 'list_member.tmpl',
413            terms    => $terms,
414            params   => $param,
415            args     => $args,
416            code     => $hasher,
417        }
418    );
419}
420
421sub list_association {
422    my $app = shift;
423
424    my $blog_id   = $app->param('blog_id');
425    my $author_id = $app->param('author_id');
426    my $role_id   = $app->param('role_id');
427
428    my $this_user = $app->user;
429    if ( !$this_user->is_superuser ) {
430        if (
431            (
432                   !$blog_id
433                || !$this_user->permissions($blog_id)->can_administer_blog
434            )
435            && ( !$author_id || ( $author_id != $this_user->id ) )
436          )
437        {
438            return $app->errtrans("Permission denied.");
439        }
440    }
441
442    my ( $user, $role );
443    $app->error(undef);
444
445    if ($author_id) {
446        $app->add_breadcrumb( $app->translate('Users'),
447              $app->user->is_superuser
448            ? $app->uri( mode => 'list_authors' )
449            : undef );
450        if ( 'PSEUDO' ne $author_id ) {
451            my $author_class = $app->model('author');
452            $user = $author_class->load($author_id);
453            $app->add_breadcrumb(
454                $user->name,
455                $app->uri(
456                    mode => 'view',
457                    args => { _type => 'author', id => $author_id }
458                )
459            );
460        }
461        else {
462            $app->add_breadcrumb( $app->translate('(newly created user)') );
463        }
464        $app->add_breadcrumb( $app->translate('User Associations') );
465    }
466    if ($role_id) {
467        my $role_class = $app->model('role') or return;
468        $role = $role_class->load($role_id);
469        $app->add_breadcrumb( $app->translate("Roles"),
470            $app->uri( mode => "list_roles" ) );
471        $app->add_breadcrumb(
472            $role->name,
473            $app->uri(
474                mode => 'edit_role',
475                args => { _type => 'role', id => $role_id }
476            )
477        );
478        $app->add_breadcrumb( $app->translate("Role Users & Groups") );
479    }
480    if ( !$role_id  && !$author_id ) {
481        if ($blog_id) {
482            $app->add_breadcrumb( $app->translate("Users") );
483        }
484        else {
485            $app->add_breadcrumb( $app->translate("Associations") );
486        }
487    }
488
489    my $pref = $app->list_pref('association');
490
491    # Supplies additional parameters for the row being listed
492    my %users;
493    $users{ $this_user->id } = $this_user;
494    my $hasher = sub {
495        my ( $obj, $row ) = @_;
496        if ( my $user = $obj->user ) {
497            $row->{user_id}   = $user->id;
498            $row->{user_name} = $user->name;
499        }
500        if ( my $role = $obj->role ) {
501            $row->{role_name} = $role->name;
502
503            # populate permissions for the expanded view
504            if ( $pref->{view_expanded} ) {
505                my @perms;
506                my @all_perms = @{ MT::Permission->perms() };
507                foreach (@all_perms) {
508                    next unless length( $_->[1] || '' );
509                    push @perms, { name => $_->[1] }
510                      if $role->has( $_->[0] );
511                }
512                $row->{perm_loop} = \@perms;
513            }
514        }
515        else {
516            $row->{role_name} = $app->translate("(Custom)");
517        }
518        if ( my $blog = $obj->blog ) {
519            $row->{blog_name} = $blog->name;
520        }
521        if ( my $ts = $obj->created_on ) {
522            $row->{created_on_formatted} =
523              format_ts( MT::App::CMS::LISTING_DATE_FORMAT(), $ts, $obj->blog, $app->user ? $app->user->preferred_language : undef );
524            $row->{created_on_time_formatted} =
525              format_ts( MT::App::CMS::LISTING_TIMESTAMP_FORMAT(), $ts, $obj->blog, $app->user ? $app->user->preferred_language : undef );
526            $row->{created_on_relative} =
527              relative_date( $ts, time, $obj->blog );
528        }
529        if ( $row->{created_by} ) {
530            my $created_user = $users{ $row->{created_by} } ||=
531              MT::Author->load( $row->{created_by} );
532            if ($created_user) {
533                $row->{created_by} = $created_user->name;
534            }
535            else {
536                $row->{created_by} = $app->translate('(user deleted)');
537            }
538        }
539    };
540    $app->model('association') or return;
541    my $types;
542    if ( !$author_id && !$blog_id ) {
543        $types = [
544            MT::Association::USER_BLOG_ROLE(),
545            MT::Association::USER_ROLE(),
546        ];
547    }
548    elsif ( !$author_id ) {
549        $types = [
550            MT::Association::USER_BLOG_ROLE(),
551        ];
552    }
553    elsif ($author_id) {
554        $types =
555          [ MT::Association::USER_BLOG_ROLE(), MT::Association::USER_ROLE() ];
556    }
557
558    my $pre_build = sub {
559        my ($param) = @_;
560        my $data = $param->{object_loop} || [];
561
562        #TODO: handle group_view
563        if ( $param->{user_view}
564            && ( 'PSEUDO' ne $param->{edit_author_id} ) )
565        {
566
567            # don't merge
568        }
569        elsif ( $param->{role_view} ) {
570            _merge_default_assignments( $app, $data, $hasher, 'role',
571                $param->{role_id} );
572        }
573        elsif ( $param->{blog_view} ) {
574            _merge_default_assignments( $app, $data, $hasher, 'blog',
575                $param->{blog_id} );
576        }
577        else {
578            _merge_default_assignments( $app, $data, $hasher, 'all' );
579        }
580    };
581
582    return $app->listing(
583        {
584            args  => { sort => 'created_on', direction => 'descend' },
585            type  => 'association',
586            code  => $hasher,
587            terms => {
588                type => $types,
589                $author_id ? ( author_id => $author_id ) : (),
590                $blog_id   ? ( blog_id   => $blog_id )   : (),
591                $role_id   ? ( role_id   => $role_id )   : (),
592            },
593            pre_build => $pre_build,
594            params => {
595                can_create_association => $app->user->is_superuser || ( $blog_id
596                    && $app->user->permissions($blog_id)->can_administer_blog ),
597                has_expanded_mode => 1,
598                nav_privileges =>
599                  ( $author_id || $blog_id ? 0 : 1 ) || $role_id,
600                nav_authors => ( $author_id || $blog_id ? 1 : 0 )
601                  && !$role_id,
602                blog_view     => $blog_id   ? 1 : 0,
603                user_view     => $author_id ? 1 : 0,
604                role_view     => $role_id   ? 1 : 0,
605                $role_id
606                ? (
607                    role_id   => $role_id,
608                    role_name => $role->name,
609                  )
610                : (),
611                $author_id
612                ? (
613                    edit_author_id   => $author_id,
614                    edit_name => $user
615                    ? ( $user->nickname ? $user->nickname : $user->name )
616                    : $app->translate('(newly created user)'),
617                    edit_object => $app->translate('The user'),
618                    group_count => $user ? $user->group_count() : 0,
619                    status_enabled => $user ? ( $user->is_active ? 1 : 0 ) : 0,
620                    status_pending => $user
621                    ? ( $user->status == MT::Author::PENDING() ? 1 : 0 )
622                    : 0,
623                  )
624                : (),
625                saved         => $app->param('saved')         || 0,
626                saved_deleted => $app->param('saved_deleted') || 0,
627                usergroup_view => !$author_id  && !$role_id,
628                blog_id => $blog_id,
629                search_label => $app->translate('Users'),
630                object_type  => 'association',
631                pt_name => $app->translate('User'),
632                screen_id => "list-associations",
633            },
634        }
635    );
636}
637
638sub list_role {
639    my $app = shift;
640
641    $app->return_to_dashboard( redirect => 1 ) if $app->param('blog_id');
642
643    my $pref = $app->list_pref('role');
644
645    my $author_class = $app->model('author');
646    my $assoc_class  = $app->model('association');
647    my $hasher       = sub {
648        my ( $obj, $row ) = @_;
649        my $user_count = $assoc_class->count(
650            {
651                role_id   => $obj->id,
652                author_id => [ 1, undef ],
653            },
654            {
655                unique     => 'author_id',
656                range_incl => { author_id => 1 },
657            }
658        );
659        $row->{members} = $user_count;
660        $row->{weblogs} = $assoc_class->count(
661            {
662                role_id => $obj->id,
663                blog_id => [ 1, undef ],
664            },
665            {
666                unique     => 'blog_id',
667                range_incl => { blog_id => 1 },
668            }
669        );
670        if ( $obj->created_by ) {
671            my $user = $author_class->load( $obj->created_by );
672            $row->{created_by} = $user ? $user->name : '';
673        }
674        else {
675            $row->{created_by} = '';
676        }
677
678        # populate permissions for the expanded view
679        if ( $pref->{view_expanded} ) {
680            my @perms;
681            my @all_perms = @{ MT::Permission->perms() };
682            foreach (@all_perms) {
683                next unless length( $_->[1] || '' );
684                push @perms, { name => $_->[1] }
685                  if $obj->has( $_->[0] );
686            }
687            $row->{perm_loop} = \@perms;
688        }
689    };
690    unless ( $app->user->is_superuser() ) {
691        return $app->errtrans("Permission denied.");
692    }
693    $app->add_breadcrumb( $app->translate("Roles") );
694    $app->listing(
695        {
696            args   => { sort => 'name' },
697            type   => 'role',
698            code   => $hasher,
699            params => {
700                nav_privileges    => 1,
701                list_noncron      => 1,
702                can_create_role   => $app->user->is_superuser,
703                has_expanded_mode => 1,
704                search_label      => $app->translate('Users'),
705                object_type       => 'role',
706                screen_id         => 'list-role',
707            },
708        }
709    );
710}
711
712sub save_role {
713    my $app = shift;
714    my $q   = $app->param;
715    $app->validate_magic()   or return;
716    $app->user->is_superuser or return $app->errtrans("Invalid request.");
717
718    my $id    = $q->param('id');
719    my @perms = $q->param('permission');
720    my $role;
721    require MT::Role;
722    $role = $id ? MT::Role->load($id) : MT::Role->new;
723    my $name = $q->param('name') || '';
724    $name =~ s/(^\s+|\s+$)//g;
725    return $app->errtrans("Role name cannot be blank.")
726      if $name eq '';
727
728    my $role_by_name = MT::Role->load( { name => $name } );
729    if ( $role_by_name && ( ( $id && ( $role->id != $id ) ) || !$id ) ) {
730        return $app->errtrans("Another role already exists by that name.");
731    }
732    if ( !@perms ) {
733        return $app->errtrans("You cannot define a role without permissions.");
734    }
735
736    $role->name( $q->param('name') );
737    $role->description( $q->param('description') );
738    $role->clear_full_permissions;
739    $role->set_these_permissions(@perms);
740    if ( $role->id ) {
741        $role->modified_by( $app->user->id );
742    }
743    else {
744        $role->created_by( $app->user->id );
745    }
746    $role->save or return $app->error( $role->errstr );
747
748    my $url;
749    $url = $app->uri(
750        'mode' => 'edit_role',
751        args   => { id => $role->id, saved => 1 }
752    );
753    $app->redirect($url);
754}
755
756sub enable_object {
757    my $app = shift;
758    set_object_status( $app, MT::Author::ACTIVE() );
759}
760
761sub disable_object {
762    my $app = shift;
763    set_object_status( $app, MT::Author::INACTIVE() );
764}
765
766sub set_object_status {
767    my ($app, $new_status) = @_;
768
769    $app->validate_magic() or return;
770    return $app->error( $app->translate('Permission denied.') )
771      unless $app->user->is_superuser;
772    return $app->error( $app->translate("Invalid request.") )
773      if $app->request_method ne 'POST';
774
775    my $q    = $app->param;
776    my $type = $q->param('_type');
777    return $app->error( $app->translate('Invalid type') )
778      unless ( $type eq 'user' )
779      || ( $type eq 'author' )
780      || ( $type eq 'group' );
781
782    my $class = $app->model($type);
783
784    my @sync;
785    my $saved = 0;
786    for my $id ( $q->param('id') ) {
787        next unless $id;    # avoid 'empty' ids
788        my $obj = $class->load($id);
789        next unless $obj;
790        if ( ( $obj->id == $app->user->id ) && ( $type eq 'author' ) ) {
791            next;
792        }
793        next if $new_status == $obj->status;
794        $obj->status($new_status);
795        $obj->save;
796        $saved++;
797        if ( $type eq 'author' ) {
798            if ( $new_status == MT::Author::ACTIVE() ) {
799                push @sync, $obj;
800            }
801        }
802    }
803    my $unchanged = 0;
804    if (@sync) {
805        MT::Auth->synchronize_author( User => \@sync );
806        foreach (@sync) {
807            if ( $_->status != MT::Author::ACTIVE() ) {
808                $unchanged++;
809            }
810        }
811    }
812    if ( $saved && ( $saved > $unchanged ) ) {
813        $app->add_return_arg(
814            saved_status => ( $new_status == MT::Author::ACTIVE() )
815            ? 'enabled'
816            : 'disabled'
817        );
818    }
819    $app->add_return_arg( is_power_edit => 1 )
820      if $q->param('is_power_edit');
821    $app->add_return_arg( unchanged => $unchanged )
822      if $unchanged;
823    $app->call_return;
824}
825
826sub upload_userpic {
827    my $app = shift;
828
829    my ($asset, $bytes) = $app->_upload_file(
830        @_,
831        require_type => 'image',
832    );
833    return if !defined $asset;
834    return $asset if !defined $bytes;  # whatever it is
835
836    ## TODO: should this be layered into _upload_file somehow, so we don't
837    ## save the asset twice?
838    my $user_id = $app->param('user_id');
839
840    $asset->tags('@userpic');
841    $asset->created_by($user_id);
842    $asset->save;
843
844    $app->forward( 'asset_userpic', { asset => $asset, user_id => $user_id } );
845}
846
847sub cfg_system_users {
848    my $app = shift;
849    my %param;
850    if ( $app->param('blog_id') ) {
851        return $app->return_to_dashboard( redirect => 1 );
852    }
853
854    return $app->errtrans("Permission denied.")
855      unless $app->user->is_superuser();
856    my $cfg = $app->config;
857    $app->add_breadcrumb( $app->translate('General Settings') );
858    $param{nav_config}   = 1;
859
860    $param{nav_settings} = 1;
861    $param{languages} =
862      $app->languages_list( $app->config('DefaultUserLanguage') );
863    my $tag_delim = $app->config('DefaultUserTagDelimiter') || ord(',');
864    if ( $tag_delim eq ord(',') ) {
865        $tag_delim = 'comma';
866    }
867    elsif ( $tag_delim eq ord(' ') ) {
868        $tag_delim = 'space';
869    }
870    else {
871        $tag_delim = 'comma';
872    }
873    $param{"tag_delim_$tag_delim"} = 1;
874
875    ( my $tz = $app->config('DefaultTimezone') ) =~ s![-\.]!_!g;
876    $tz =~ s!_00$!!;
877    $param{ 'server_offset_' . $tz } = 1;
878
879    $param{default_site_root} = $app->config('DefaultSiteRoot');
880    $param{default_site_url}  = $app->config('DefaultSiteURL');
881    $param{personal_weblog_readonly} =
882      $app->config->is_readonly('NewUserAutoProvisioning');
883    $param{personal_weblog} = $app->config->NewUserAutoProvisioning ? 1 : 0;
884    if ( my $id = $param{new_user_template_blog_id} =
885        $app->config('NewUserTemplateBlogId') || '' )
886    {
887        my $blog = MT::Blog->load($id);
888        if ($blog) {
889            $param{new_user_template_blog_name} = $blog->name;
890        }
891        else {
892            $app->config( 'NewUserTemplateBlogId', undef, 1 );
893            $cfg->save_config();
894            delete $param{new_user_template_blog_id};
895        }
896    }
897    $param{system_email_address} = $cfg->EmailAddressMain;
898    $param{saved}                = $app->param('saved');
899    $param{error}                = $app->param('error');
900    $param{screen_class}         = "settings-screen system-general-settings";
901    my $registration = $cfg->CommenterRegistration;
902    if ( $registration->{Allow} ) {
903        $param{registration} = 1;
904        if ( my $ids = $registration->{Notify} ) {
905            my @ids = split ',', $ids;
906            my @sysadmins = MT::Author->load(
907                {
908                    id   => \@ids,
909                    type => MT::Author::AUTHOR()
910                },
911                {
912                    join => MT::Permission->join_on(
913                        'author_id',
914                        {
915                            permissions => "\%'administer'\%",
916                            blog_id     => '0',
917                        },
918                        { 'like' => { 'permissions' => 1 } }
919                    )
920                }
921            );
922            my @names;
923            foreach my $a (@sysadmins) {
924                push @names, $a->name . '(' . $a->id . ')';
925            }
926            $param{notify_user_id} = $ids;
927            $param{notify_user_name} = join ',', @names;
928        }
929    }
930    $app->load_tmpl( 'cfg_system_users.tmpl', \%param );
931}
932
933sub save_cfg_system_users {
934    my $app = shift;
935    $app->validate_magic or return;
936    return $app->errtrans("Permission denied.")
937      unless $app->user->is_superuser();
938
939    my $tmpl_blog_id = $app->param('new_user_template_blog_id') || '';
940    if ( $tmpl_blog_id =~ m/^\d+$/ ) {
941        MT::Blog->load($tmpl_blog_id)
942          or return $app->error(
943            $app->translate(
944                "Invalid ID given for personal blog clone source ID.")
945          );
946    }
947    else {
948        if ( $tmpl_blog_id ne '' ) {
949            return $app->error(
950                $app->translate(
951                    "Invalid ID given for personal blog clone source ID.")
952            );
953        }
954    }
955
956    my $cfg = $app->config;
957    my $tz  = $app->param('default_time_zone');
958    $app->config( 'DefaultTimezone', $tz || undef, 1 );
959    $app->config( 'DefaultSiteRoot', $app->param('default_site_root') || undef,
960        1 );
961    $app->config( 'DefaultSiteURL', $app->param('default_site_url') || undef,
962        1 );
963    $app->config( 'NewUserAutoProvisioning',
964        $app->param('personal_weblog') ? 1 : 0, 1 );
965    $app->config( 'NewUserTemplateBlogId', $tmpl_blog_id || undef, 1 );
966    $app->config( 'DefaultUserLanguage', $app->param('default_language'), 1 );
967    $app->config( 'DefaultUserTagDelimiter',
968        $app->param('default_user_tag_delimiter') || undef, 1 );
969    my $registration = $cfg->CommenterRegistration;
970    if ( my $reg = $app->param('registration') ) {
971        $registration->{Allow} = $reg ? 1 : 0;
972        $registration->{Notify} = $app->param('notify_user_id');
973        $cfg->CommenterRegistration( $registration, 1 );
974    }
975    elsif ( $registration->{Allow} ) {
976        $registration->{Allow} = 0;
977        $cfg->CommenterRegistration( $registration, 1 );
978    }
979    $cfg->save_config();
980
981    my $args = ();
982
983    if ( $app->config->NewUserAutoProvisioning() ne
984        ( $app->param('personal_weblog') ? 1 : 0 ) )
985    {
986        $args->{error} =
987          $app->translate(
988'If personal blog is set, the default site URL and root are required.'
989          );
990    }
991    else {
992        $args->{saved} = 1;
993    }
994
995    $app->redirect(
996        $app->uri(
997            'mode' => 'cfg_system_users',
998            args   => $args
999        )
1000    );
1001}
1002
1003sub remove_user_assoc {
1004    my $app = shift;
1005    $app->validate_magic or return;
1006
1007    my $user = $app->user;
1008    my $perms = $app->permissions;
1009    return $app->errtrans("Permission denied.")
1010        unless $perms->can_administer_blog;
1011
1012    my $blog_id = $app->param('blog_id');
1013    my @ids = $app->param('id');
1014    return $app->errtrans("Invalid request.")
1015        unless $blog_id && @ids;
1016
1017    require MT::Association;
1018    require MT::Permission;
1019    foreach my $id (@ids) {
1020        next unless $id;
1021        MT::Association->remove({ blog_id => $blog_id, author_id => $id });
1022        # these too, just in case there are no real associations
1023        # (ie, commenters)
1024        MT::Permission->remove({ blog_id => $blog_id, author_id => $id });
1025    }
1026
1027    $app->add_return_arg( saved => 1 );
1028    $app->call_return;
1029}
1030
1031sub revoke_role {
1032    my $app = shift;
1033    $app->validate_magic or return;
1034
1035    my $user = $app->user;
1036    my $perms = $app->permissions;
1037    return $app->errtrans("Permission denied.")
1038        unless $perms->can_administer_blog;
1039
1040    my $blog_id = $app->param('blog_id');
1041    my $role_id = $app->param('role_id');
1042    my $user_id = $app->param('author_id');
1043    return $app->errtrans("Invalid request.")
1044        unless $blog_id && $role_id && $user_id;
1045
1046    require MT::Association;
1047    require MT::Role;
1048    require MT::Blog;
1049
1050    my $author = MT::Author->load( $user_id );
1051    my $role = MT::Role->load( $role_id );
1052    my $blog = MT::Blog->load( $blog_id );
1053    return $app->errtrans("Invalid request.")
1054        unless $blog && $role && $author;
1055
1056    MT::Association->unlink( $blog => $role => $author );
1057
1058    $app->add_return_arg( saved => 1 );
1059    $app->call_return;
1060}
1061
1062sub grant_role {
1063    my $app = shift;
1064
1065    my $user = $app->user;
1066
1067    my $blogs   = $app->param('blog')   || '';
1068    my $authors = $app->param('author') || '';
1069    my $roles   = $app->param('role')   || '';
1070    my $author_id = $app->param('author_id');
1071    my $blog_id   = $app->param('blog_id');
1072    my $role_id   = $app->param('role_id');
1073
1074    my @blogs   = split /,/, $blogs;
1075    my @authors = split /,/, $authors;
1076    my @roles   = split /,/, $roles;
1077
1078    require MT::Blog;
1079    require MT::Role;
1080
1081    foreach (@blogs) {
1082        my $id = $_;
1083        $id =~ s/\D//g;
1084        $_ = MT::Blog->load($id);
1085    }
1086    foreach (@roles) {
1087        my $id = $_;
1088        $id =~ s/\D//g;
1089        $_ = MT::Role->load($id);
1090    }
1091    my $add_pseudo_new_user = 0;
1092    foreach (@authors) {
1093        my $id = $_;
1094        if ( 'author-PSEUDO' eq $id ) {
1095            $add_pseudo_new_user = 1;
1096            next;
1097        }
1098        $id =~ s/\D//g;
1099        $_ = MT::Author->load($id);
1100    }
1101    $app->error(undef);
1102
1103    if ($author_id) {
1104        if ( $author_id eq 'PSEUDO' ) {
1105            $add_pseudo_new_user = 1;
1106        }
1107        else {
1108            push @authors, MT::Author->load($author_id);
1109        }
1110    }
1111    push @blogs,   MT::Blog->load($blog_id)     if $blog_id;
1112    push @roles,   MT::Role->load($role_id)     if $role_id;
1113
1114    if ( !$user->is_superuser ) {
1115        if (   ( scalar @blogs != 1 )
1116            || ( !$user->permissions( $blogs[0] )->can_administer_blog ) )
1117        {
1118            return $app->errtrans("Permission denied.");
1119        }
1120    }
1121
1122    require MT::Association;
1123
1124    my @default_assignments;
1125
1126    # TBD: handle case for associating system roles to users/groups
1127    foreach my $blog (@blogs) {
1128        next unless ref $blog;
1129        foreach my $role (@roles) {
1130            next unless ref $role;
1131            if ($add_pseudo_new_user) {
1132                push @default_assignments, $role->id . ',' . $blog->id;
1133            }
1134            foreach my $ug ( @authors ) {
1135                next unless ref $ug;
1136                MT::Association->link( $ug => $role => $blog );
1137            }
1138        }
1139    }
1140
1141    if ( $add_pseudo_new_user && @default_assignments ) {
1142        my $da = $app->config('DefaultAssignments');
1143        $da .= ',' if $da;
1144        $app->config( 'DefaultAssignments',
1145            $da . join( ',', @default_assignments ), 1 );
1146        $app->config->save_config;
1147    }
1148
1149    $app->add_return_arg( saved => 1 );
1150    $app->call_return;
1151}
1152
1153sub dialog_select_author {
1154    my $app = shift;
1155
1156    my $hasher = sub {
1157        my ( $obj, $row ) = @_;
1158        $row->{label}       = $row->{name};
1159        $row->{description} = $row->{nickname};
1160    };
1161
1162    $app->listing(
1163        {
1164            type  => 'author',
1165            terms => {
1166                type   => MT::Author::AUTHOR(),
1167                status => MT::Author::ACTIVE(),
1168            },
1169            args => {
1170                sort => 'name',
1171                join => MT::Permission->join_on(
1172                    'author_id',
1173                    {
1174                        permissions => "\%'create_post'\%",
1175                        blog_id     => $app->blog->id,
1176                    },
1177                    { 'like' => { 'permissions' => 1 } }
1178                ),
1179            },
1180            code     => $hasher,
1181            template => 'dialog/select_users.tmpl',
1182            params   => {
1183                dialog_title =>
1184                  $app->translate("Select a entry author"),
1185                items_prompt =>
1186                  $app->translate("Selected author"),
1187                search_prompt => $app->translate(
1188                    "Type a username to filter the choices below."),
1189                panel_label       => $app->translate("Entry author"),
1190                panel_description => $app->translate("Name"),
1191                panel_type        => 'author',
1192                panel_multi       => defined $app->param('multi')
1193                ? $app->param('multi')
1194                : 0,
1195                panel_searchable => 1,
1196                panel_first      => 1,
1197                panel_last       => 1,
1198                list_noncron     => 1,
1199                idfield          => $app->param('idfield'),
1200                namefield        => $app->param('namefield'),
1201            },
1202        }
1203    );
1204}
1205
1206sub dialog_select_sysadmin {
1207    my $app = shift;
1208    return $app->errtrans("Permission denied.")
1209      unless $app->user->is_superuser;
1210
1211    my $hasher = sub {
1212        my ( $obj, $row ) = @_;
1213        $row->{label}       = $row->{name};
1214        $row->{description} = $row->{nickname};
1215    };
1216
1217    $app->listing(
1218        {
1219            type  => 'author',
1220            terms => {
1221                type   => MT::Author::AUTHOR(),
1222                status => MT::Author::ACTIVE(),
1223            },
1224            args => {
1225                sort => 'name',
1226                join => MT::Permission->join_on(
1227                    'author_id',
1228                    {
1229                        permissions => "\%'administer'\%",
1230                        blog_id     => '0',
1231                    },
1232                    { 'like' => { 'permissions' => 1 } }
1233                ),
1234            },
1235            code     => $hasher,
1236            template => 'dialog/select_users.tmpl',
1237            params   => {
1238                dialog_title =>
1239                  $app->translate("Select a System Administrator"),
1240                items_prompt =>
1241                  $app->translate("Selected System Administrator"),
1242                search_prompt => $app->translate(
1243                    "Type a username to filter the choices below."),
1244                panel_label       => $app->translate("System Administrator"),
1245                panel_description => $app->translate("Name"),
1246                panel_type        => 'author',
1247                panel_multi       => defined $app->param('multi')
1248                ? $app->param('multi')
1249                : 0,
1250                panel_searchable => 1,
1251                panel_first      => 1,
1252                panel_last       => 1,
1253                list_noncron     => 1,
1254                idfield          => $app->param('idfield'),
1255                namefield        => $app->param('namefield'),
1256            },
1257        }
1258    );
1259}
1260
1261# This mode can be called to service a number of views
1262# Adding roles->blogs for a user
1263# Adding roles->blogs for a group
1264# Adding users->roles->blogs
1265# Adding groups->roles->blogs
1266sub dialog_grant_role {
1267    my $app = shift;
1268
1269    my $author_id = $app->param('author_id');
1270    my $blog_id   = $app->param('blog_id');
1271    my $role_id   = $app->param('role_id');
1272
1273    my $this_user = $app->user;
1274    if ( !$this_user->is_superuser ) {
1275        if (   !$blog_id
1276            || !$this_user->permissions($blog_id)->can_administer_blog )
1277        {
1278            return $app->errtrans("Permission denied.");
1279        }
1280    }
1281
1282    my $type = $app->param('_type');
1283    my ( $user, $role );
1284    if ($author_id) {
1285        $user = MT::Author->load($author_id);
1286    }
1287    if ($role_id) {
1288        require MT::Role;
1289        $role = MT::Role->load($role_id);
1290    }
1291
1292    my $hasher = sub {
1293        my ( $obj, $row ) = @_;
1294        $row->{label} = $row->{name};
1295        $row->{description} = $row->{nickname} if exists $row->{nickname};
1296    };
1297
1298    # Only show active users who are not commenters.
1299    my $terms = {};
1300    if ( $type && ( $type eq 'author' ) ) {
1301        $terms->{status} = MT::Author::ACTIVE();
1302        $terms->{type}   = MT::Author::AUTHOR();
1303    }
1304
1305    my $pseudo_user_row = {
1306        id    => 'PSEUDO',
1307        label => $app->translate('(newly created user)'),
1308        description =>
1309          $app->translate('represents a user who will be created afterwards'),
1310    };
1311
1312    if ( $app->param('search') || $app->param('json') ) {
1313        my $params = {
1314            panel_type   => $type,
1315            list_noncron => 1,
1316            panel_multi  => 1,
1317        };
1318        $app->listing(
1319            {
1320                terms    => $terms,
1321                type     => $type,
1322                code     => $hasher,
1323                params   => $params,
1324                template => 'include/listing_panel.tmpl',
1325                $app->param('search') ? () : (
1326                    pre_build => sub {
1327                        my ($param) = @_;
1328                        if ( $type && $type eq 'author' ) {
1329                            if ( !$app->param('offset') ) {
1330                                my $objs = $param->{object_loop} ||= [];
1331                                unshift @$objs, $pseudo_user_row;
1332                            }
1333                        }
1334                    }
1335                ),
1336            }
1337        );
1338    }
1339    else {
1340
1341        # traditional, full-screen listing
1342        my $params = {
1343            ($author_id || 0) eq 'PSEUDO'
1344            ? (
1345                edit_author_name => $app->translate('(newly created user)'),
1346                edit_author_id   => 'PSEUDO'
1347              )
1348            : $author_id
1349              ? (
1350                  edit_author_name => $user->nickname
1351                  ? $user->nickname
1352                  : $user->name,
1353                  edit_author_id => $user->id,
1354                )
1355              : (),
1356            $role_id
1357            ? (
1358                role_name => $role->name,
1359                role_id   => $role->id,
1360              )
1361            : (),
1362        };
1363
1364        my @panels;
1365        if ( !$role_id ) {
1366            push @panels, 'role';
1367        }
1368        if ( !$blog_id ) {
1369            push @panels, 'blog';
1370        }
1371        if ( !$author_id ) {
1372            if ( $type eq 'user' ) {
1373                unshift @panels, 'author';
1374            }
1375        }
1376
1377        my $panel_info = {
1378            'blog' => {
1379                panel_title       => $app->translate("Select Blogs"),
1380                panel_label       => $app->translate("Blog Name"),
1381                items_prompt      => $app->translate("Blogs Selected"),
1382                search_label      => $app->translate("Search Blogs"),
1383                panel_description => $app->translate("Description"),
1384            },
1385            'author' => {
1386                panel_title       => $app->translate("Select Users"),
1387                panel_label       => $app->translate("Username"),
1388                items_prompt      => $app->translate("Users Selected"),
1389                search_label      => $app->translate("Search Users"),
1390                panel_description => $app->translate("Name"),
1391            },
1392            'role' => {
1393                panel_title       => $app->translate("Select Roles"),
1394                panel_label       => $app->translate("Role Name"),
1395                items_prompt      => $app->translate("Roles Selected"),
1396                search_label      => $app->translate(""),
1397                panel_description => $app->translate("Description"),
1398            },
1399        };
1400
1401        $params->{blog_id}      = $blog_id;
1402        $params->{dialog_title} = $app->translate("Grant Permissions");
1403        $params->{panel_loop}   = [];
1404        $params->{panel_multi}  = 1;
1405
1406        for ( my $i = 0 ; $i <= $#panels ; $i++ ) {
1407            my $source       = $panels[$i];
1408            my $panel_params = {
1409                panel_type => $source,
1410                %{ $panel_info->{$source} },
1411                list_noncron     => 1,
1412                panel_last       => $i == $#panels,
1413                panel_first      => $i == 0,
1414                panel_number     => $i + 1,
1415                panel_total      => $#panels + 1,
1416                panel_has_steps  => ( $#panels == '0' ? 0 : 1 ),
1417                panel_searchable => ( $source eq 'role' ? 0 : 1 ),
1418            };
1419
1420            # Only show active user/groups.
1421            my $terms = {};
1422            if ( $source eq 'author' ) {
1423                $terms->{status} = MT::Author::ACTIVE();
1424                $terms->{type}   = MT::Author::AUTHOR();
1425            }
1426
1427            $app->listing(
1428                {
1429                    no_html => 1,
1430                    code    => $hasher,
1431                    type    => $source,
1432                    params  => $panel_params,
1433                    terms   => $terms,
1434                    args    => { sort => 'name' },
1435                }
1436            );
1437            if ( $source && ( $source eq 'author' ) ) {
1438                if ( !$app->param('offset') ) {
1439                    my $data = $panel_params->{object_loop} ||= [];
1440                    unshift @$data, $pseudo_user_row;
1441                }
1442            }
1443            if (
1444                !$panel_params->{object_loop}
1445                || ( $panel_params->{object_loop}
1446                    && @{ $panel_params->{object_loop} } < 1 )
1447              )
1448            {
1449                $params->{"missing_$source"} = 1;
1450                $params->{"missing_data"}    = 1;
1451            }
1452            push @{ $params->{panel_loop} }, $panel_params;
1453        }
1454
1455        # save the arguments from whence we came...
1456        $params->{return_args} = $app->return_args;
1457        $app->load_tmpl( 'dialog/create_association.tmpl', $params );
1458    }
1459}
1460
1461sub remove_userpic {
1462    my $app = shift;
1463    $app->validate_magic() or return;
1464    my $q  = $app->param;
1465    my $user_id = $q->param('user_id');
1466    my $user = $app->model('author')->load( { id => $user_id } )
1467        or return;
1468    if ($user->userpic_asset_id) {
1469        my $old_file = $user->userpic_file();
1470        my $fmgr = MT::FileMgr->new('Local');
1471        if ($fmgr->exists($old_file)) {
1472            $fmgr->delete($old_file);
1473        }
1474        $user->userpic_asset_id(0);
1475        $user->save;
1476    }
1477    return 'success';
1478}
1479
1480sub can_delete_association {
1481    my ( $eh, $app, $obj ) = @_;
1482
1483    my $blog_id = $app->param('blog_id');
1484    my $user    = $app->user;
1485    if ( !$user->is_superuser ) {
1486        if ( !$blog_id || !$user->permissions($blog_id)->can_administer_blog ) {
1487            return $eh->error( MT->translate("Permission denied.") );
1488        }
1489        if ( $obj->author_id == $user->id ) {
1490            return $eh->error(
1491                MT->translate("You cannot delete your own association.") );
1492        }
1493    }
1494    1;
1495}
1496
1497sub can_view {
1498    my ( $eh, $app, $id ) = @_;
1499    return $id && ( $app->user->id == $id );
1500}
1501
1502sub can_save {
1503    my ( $eh, $app, $id ) = @_;
1504    my $author = $app->user;
1505    if ( !$id ) {
1506        return $author->is_superuser;
1507    }
1508    else {
1509        return $author->id == $id;
1510    }
1511}
1512
1513sub can_delete {
1514    my ( $eh, $app, $obj ) = @_;
1515    my $author = $app->user;
1516    if ( $author->id == $obj->id ) {
1517        return $eh->error(
1518            MT->translate("You cannot delete your own user record.") );
1519    }
1520    return 1 if $author->is_superuser();
1521    if ( !( $obj->created_by && $obj->created_by == $author->id ) ) {
1522        return $eh->error(
1523            MT->translate(
1524                "You have no permission to delete the user [_1].", $obj->name
1525            )
1526        );
1527    }
1528}
1529
1530sub save_filter {
1531    my ( $eh, $app ) = @_;
1532
1533    my $status = $app->param('status');
1534    return 1 if $status and $status == MT::Author::INACTIVE();
1535
1536    require MT::Auth;
1537    my $auth_mode = $app->config('AuthenticationModule');
1538    my ($pref) = split /\s+/, $auth_mode;
1539
1540    my $name = $app->param('name');
1541    if ( $pref eq 'MT' ) {
1542        if ( defined $name ) {
1543            $name =~ s/(^\s+|\s+$)//g;
1544            $app->param( 'name', $name );
1545        }
1546        return $eh->error( $app->translate("User requires username") )
1547          if ( !$name );
1548    }
1549
1550    require MT::Author;
1551    my $existing = MT::Author->load(
1552        {
1553            name => $name,
1554            type => MT::Author::AUTHOR()
1555        }
1556    );
1557    my $id = $app->param('id');
1558    if ( $existing && ( ( $id && $existing->id ne $id ) || !$id ) ) {
1559        return $eh->error(
1560            $app->translate("A user with the same name already exists.") );
1561    }
1562
1563    return 1 if ( $pref ne 'MT' );
1564    if ( !$app->param('id') ) {    # it's a new object
1565        return $eh->error( $app->translate("User requires password") )
1566          if ( !$app->param('pass') );
1567        return $eh->error(
1568            $app->translate("User requires password recovery word/phrase") )
1569          if ( !$app->param('hint') );
1570    }
1571    return $eh->error(
1572        MT->translate("Email Address is required for password recovery") )
1573      unless $app->param('email');
1574    if ( $app->param('url') ) {
1575        my $url = $app->param('url');
1576        return $eh->error( MT->translate("Website URL is imperfect") )
1577          unless is_url($url);
1578    }
1579    1;
1580}
1581
1582sub pre_save {
1583    my $eh = shift;
1584    my ( $app, $obj, $original ) = @_;
1585
1586    # Authors should only be of type AUTHOR when created from
1587    # the CMS app; COMMENTERs are created from the Comments app.
1588    $obj->type( MT::Author::AUTHOR() );
1589
1590    my $pass = $app->param('pass');
1591    if ($pass) {
1592        $obj->set_password($pass);
1593    }
1594    elsif ( !$obj->id ) {
1595        $obj->password('(none)');
1596    }
1597
1598    my ( $delim, $delim2 ) = $app->param('tag_delim');
1599    $delim = $delim ? $delim : $delim2;
1600    if ( $delim =~ m/comma/i ) {
1601        $delim = ord(',');
1602    }
1603    elsif ( $delim =~ m/space/i ) {
1604        $delim = ord(' ');
1605    }
1606    else {
1607        $delim = ord(',');
1608    }
1609    $obj->entry_prefs( 'tag_delim' => $delim );
1610
1611    unless ( $obj->id ) {
1612        $obj->created_by( $app->user->id );
1613    }
1614    1;
1615}
1616
1617sub post_save {
1618    my $eh = shift;
1619    my ( $app, $obj, $original ) = @_;
1620
1621    if ( !$original->id ) {
1622        $app->log(
1623            {
1624                message => $app->translate(
1625                    "User '[_1]' (ID:[_2]) created by '[_3]'",
1626                    $obj->name, $obj->id, $app->user->name
1627                ),
1628                level    => MT::Log::INFO(),
1629                class    => 'author',
1630                category => 'new',
1631            }
1632        );
1633        $obj->add_default_roles;
1634
1635        my $author_id = $obj->id;
1636        if ( $app->param('create_personal_weblog') ) {
1637
1638            # provision new user with a personal blog
1639            $app->run_callbacks( 'new_user_provisioning', $obj );
1640        }
1641    }
1642    else {
1643        if ( $app->user->id == $obj->id ) {
1644            ## If this is a user editing his/her profile, $id will be
1645            ## some defined value; if so we should update the user's
1646            ## cookie to reflect any changes made to username and password.
1647            ## Otherwise, this is a new user, and we shouldn't update the
1648            ## cookie.
1649            $app->user($obj);
1650            if (   ( $obj->name ne $original->name )
1651                || ( $app->param('pass') ) )
1652            {
1653                $app->start_session();
1654            }
1655        }
1656    }
1657    1;
1658}
1659
1660sub post_delete {
1661    my ( $eh, $app, $obj ) = @_;
1662
1663    $app->log(
1664        {
1665            message => $app->translate(
1666                "User '[_1]' (ID:[_2]) deleted by '[_3]'",
1667                $obj->name, $obj->id, $app->user->name
1668            ),
1669            level    => MT::Log::INFO(),
1670            class    => 'system',
1671            category => 'delete'
1672        }
1673    );
1674}
1675
1676sub _merge_default_assignments {
1677    my $app = shift;
1678    my ( $data, $hasher, $type, $id ) = @_;
1679
1680    if ( my $def = MT->config->DefaultAssignments ) {
1681        my @def = split ',', $def;
1682        while ( my $role_id = shift @def ) {
1683            my $blog_id = shift @def;
1684            next unless $role_id && $blog_id;
1685            next if ( $type eq 'role' ) && ( $id != $role_id );
1686            next if ( $type eq 'blog' ) && ( $id != $blog_id );
1687            my $obj = MT::Association->new;
1688            $obj->role_id($role_id);
1689            $obj->blog_id($blog_id);
1690            $obj->id( 'PSEUDO-' . $role_id . '-' . $blog_id );
1691            my $row = $obj->column_values();
1692            $hasher->( $obj, $row ) if $hasher;
1693            $row->{user_id}   = 'PSEUDO';
1694            $row->{user_name} = MT->translate('(newly created user)');
1695            push @$data, $row;
1696        }
1697    }
1698}
1699
1700sub build_author_table {
1701    my $app = shift;
1702    my (%args) = @_;
1703
1704    my $i = 1;
1705    my @author;
1706    my $iter;
1707    if ( $args{load_args} ) {
1708        my $class = $app->model('author');
1709        $iter = $class->load_iter( @{ $args{load_args} } );
1710    }
1711    elsif ( $args{iter} ) {
1712        $iter = $args{iter};
1713    }
1714    elsif ( $args{items} ) {
1715        $iter = sub { pop @{ $args{items} } };
1716    }
1717    return [] unless $iter;
1718    my $blog_id = $app->param('blog_id');
1719    my $param = $args{param};
1720    $param->{has_edit_access}  = $app->user->is_superuser();
1721    $param->{is_administrator} = $app->user->is_superuser();
1722    my ( %blogs, %entry_count_refs );
1723    while ( my $author = $iter->() ) {
1724        my $row = {
1725            name           => $author->name,
1726            nickname       => $author->nickname,
1727            email          => $author->email,
1728            url            => $author->url,
1729            status_enabled => $author->is_active,
1730            status_pending => ( $author->status == MT::Author::PENDING() )
1731            ? 1
1732            : 0,
1733            id          => $author->id,
1734            entry_count => 0,
1735            is_me => ( $app->user->id == $author->id ? 1 : 0 )
1736        };
1737        $entry_count_refs{ $author->id } = \$row->{entry_count};
1738        if ( $author->created_by ) {
1739            if ( my $parent_author =
1740                $app->model('author')->load( $author->created_by ) )
1741            {
1742                $row->{created_by} = $parent_author->name;
1743            }
1744            else {
1745                $row->{created_by} = $app->translate('(user deleted)');
1746            }
1747        }
1748        $row->{object} = $author;
1749        $row->{usertype_author} = 1 if $author->type == MT::Author::AUTHOR();
1750        if ( $author->type == MT::Author::COMMENTER() ) {
1751            $row->{usertype_commenter} = 1;
1752            $row->{status_trusted} = 1 if $blog_id && $author->is_trusted($blog_id);
1753            if ($row->{name} =~ m/^[a-f0-9]{32}$/) {
1754                $row->{name} = $row->{nickname} || $row->{url};
1755            }
1756        }
1757        $row->{auth_icon_url} = $author->auth_icon_url;
1758        push @author, $row;
1759    }
1760    return [] unless @author;
1761    my $type = $app->param('entry_type') || 'entry';
1762    my $entry_class = $app->model($type);
1763    my $author_entry_count_iter =
1764      $entry_class->count_group_by( { author_id => [ keys %entry_count_refs ] },
1765        { group => ['author_id'] } );
1766    while ( my ( $count, $author_id ) = $author_entry_count_iter->() ) {
1767        ${ $entry_count_refs{$author_id} } = $count;
1768    }
1769    $param->{author_table}[0]{object_loop} = \@author;
1770
1771    $app->load_list_actions( 'author', $param->{author_table}[0] );
1772    $param->{page_actions} = $param->{author_table}[0]{page_actions} =
1773      $app->page_actions('list_authors');
1774    $param->{object_loop} = $param->{author_table}[0]{object_loop};
1775
1776    \@author;
1777}
1778
1779sub _delete_pseudo_association {
1780    my $app = shift;
1781    my ($pid, $bid) = @_;
1782    my $rid;
1783    if ($pid) {
1784        ( my $pseudo, $rid, $bid ) = split '-', $pid;
1785    }
1786    my @newdef;
1787    if ( my $def = $app->config->DefaultAssignments ) {
1788        my @def = split ',', $def;
1789        while ( my $role_id = shift @def ) {
1790            my $blog_id = shift @def;
1791            next unless $role_id && $blog_id;
1792            next
1793              if ( $rid && ( $role_id == $rid ) && ( $blog_id == $bid ) )
1794                || ( !defined($rid) && ( $blog_id == $bid ) );
1795            push @newdef, "$role_id,$blog_id";
1796        }
1797    }
1798    if (@newdef) {
1799        $app->config( 'DefaultAssignments', join( ',', @newdef ), 1 );
1800    }
1801    else {
1802        $app->config( 'DefaultAssignments', undef, 1 );
1803    }
1804    $app->config->save_config;
1805}
1806
18071;
Note: See TracBrowser for help on using the browser.