root/branches/release-36/lib/MT/Author.pm @ 2099

Revision 2099, 24.7 kB (checked in by bchoate, 19 months ago)

Handle special case where user has excessive permission records. BugId:79501

  • Property svn:keywords set to Author Date Id Revision
Line 
1# Movable Type (r) Open Source (C) 2001-2008 Six Apart, Ltd.
2# This program is distributed under the terms of the
3# GNU General Public License, version 2.
4#
5# $Id$
6
7package MT::Author;
8
9use strict;
10use base qw( MT::Object MT::Scorable );
11
12__PACKAGE__->install_properties({
13    column_defs => {
14        'id' => 'integer not null auto_increment',
15        'name' => 'string(255) not null',
16        'nickname' => 'string(255)',
17        'password' => 'string(60) not null',
18        'type' => 'smallint not null',
19        'email' => 'string(75)',
20        'url' => 'string(255)',
21        'hint' => 'string(75)',
22        'public_key' => 'text',
23        'preferred_language' => 'string(50)',
24        'api_password' => 'string(60)',
25        'remote_auth_username' => 'string(50)',
26        'remote_auth_token' => 'string(50)',
27        'entry_prefs' => 'string(255)',
28        'text_format' => 'string(30)',
29        'status' => 'integer',
30        'external_id' => 'string(255)',
31        #'last_login' => 'datetime',
32
33        # deprecated; permissions are in MT::Permission only now
34        'can_create_blog' => 'boolean',
35        'is_superuser' => 'boolean',
36        'can_view_log' => 'boolean',
37        'auth_type' => 'string(50)',
38        'userpic_asset_id' => 'integer',
39        'basename' => 'string(255)',
40
41        # meta properties
42        'widgets' => 'hash meta',
43        'favorite_blogs' => 'array meta',
44    },
45    defaults => {
46        type => 1,
47        status => 1,
48    },
49    indexes => {
50        created_on => 1,
51        name => 1,
52        email => 1,
53        type => 1,
54        status => 1,
55        external_id => 1,
56        auth_type_name => {
57            columns => ['auth_type', 'name', 'type'],
58        },
59        basename => 1,
60    },
61    meta => 1,
62    child_classes => ['MT::Permission', 'MT::Association'],
63    datasource => 'author',
64    primary_key => 'id',
65    audit => 1,
66});
67
68sub class_label {
69    MT->translate("User");
70}
71
72sub class_label_plural {
73    MT->translate("Users");
74}
75
76# Valid "type" codes:
77sub AUTHOR ()    { 1 }
78sub COMMENTER () { 2 }
79
80# Commenter statuses
81sub APPROVED () { 1 }
82sub BANNED ()   { 2 }
83sub BLOCKED ()  { 2 }  # alias for BANNED for backward compatibility
84sub PENDING ()  { 3 }
85
86# Author statuses
87sub ACTIVE ()   { 1 }
88sub INACTIVE () { 2 }
89#use constant PENDING => 3; # there *is* PENDING status for authors but it's the same name and value.
90
91use Exporter;
92*import = \&Exporter::import;
93use vars qw(@EXPORT_OK %EXPORT_TAGS);
94@EXPORT_OK = qw(AUTHOR COMMENTER ACTIVE INACTIVE APPROVED BANNED PENDING);
95%EXPORT_TAGS = (constants => [qw(AUTHOR COMMENTER ACTIVE INACTIVE APPROVED BANNED PENDING)]);
96
97sub set_defaults {
98    my $auth = shift;
99    my $cfg = MT->config;
100    $auth->SUPER::set_defaults(@_);
101    $auth->preferred_language($cfg->DefaultUserLanguage || $cfg->DefaultLanguage);
102}
103
104sub remove_sessions {
105    my $auth = shift;
106    require MT::Session;
107    my $sess_iter = MT::Session->load_iter({ kind => 'US' });
108    my @sess;
109    while (my $sess = $sess_iter->()) {
110        my $id = $sess->get('author_id');
111        next unless $id == $auth->id;
112        push @sess, $sess;
113    }
114    $_->remove foreach @sess;
115}
116
117sub set_password {
118    my $auth = shift;
119    my($pass) = @_;
120    my @alpha = ('a'..'z', 'A'..'Z', 0..9);
121    my $salt = join '', map $alpha[rand @alpha], 1..2;
122    # FIXME: use something besides 'crypt'
123    $auth->column('password', crypt $pass, $salt);
124}
125
126sub is_valid_password {
127    my $author = shift;
128    my($pass, $crypted, $error_ref) = @_;
129    $pass ||= '';
130    require MT::Auth;
131    return MT::Auth->is_valid_password($author, $pass, $crypted, $error_ref);
132}
133
134sub is_email_hidden {
135    my $auth = shift;
136    return 1 unless $auth->email =~ m/@/;
137    return ($auth->email =~ /^[0-9a-f]{40}$/i) ? 1 : 0;
138}
139
140# Existing comments of a user are made visible only if the
141# user is coming from "pending" status.
142
143sub set_commenter_perm {
144    my $this = shift;
145    my ($blog_id, $action) = @_;
146
147    require MT::Permission;
148    my %perm_spec = (
149        author_id => $this->id(),
150        blog_id => $blog_id
151    );
152    my $perm = MT::Permission->load(\%perm_spec);
153    if (!$perm) {
154        $perm = MT::Permission->new();
155        $perm->set_values(\%perm_spec);
156    }
157    if ($action eq 'approve') {
158        $perm->remove_restrictions('comment');
159        $perm->can_comment(1) if COMMENTER eq $this->type;
160    } elsif (($action eq 'ban') || ($action eq 'block')) {
161        $perm->set_these_restrictions('comment');
162        $perm->can_comment(0) if COMMENTER eq $this->type;
163    } elsif ($action eq 'pending') {
164        $perm->remove_restrictions('comment');
165        $perm->can_comment(0) if COMMENTER eq $this->type;
166    }
167    $perm->save()
168        or return $this->error(MT->translate("The approval could not be committed: [_1]", $perm->errstr));
169
170    return 1;
171}
172
173sub commenter_status {
174    my $this = shift;
175    return APPROVED if $this->is_superuser;
176    my ($blog_id) = @_;
177    require MT::Permission;
178    my $perm = MT::Permission->load(
179        { author_id=>$this->id, blog_id => $blog_id } );
180    return PENDING if !$perm;
181    return BANNED if $perm->is_restricted('comment');
182    return APPROVED if $perm->can_comment() || $perm->can_manage_feedback();
183    return PENDING;
184}
185
186sub is_active { shift->status() == ACTIVE; }
187sub is_trusted { shift->commenter_status(@_) == APPROVED; }
188sub is_banned { shift->commenter_status(@_) == BANNED; }
189*is_blocked = \&is_banned;
190sub is_not_trusted { shift->commenter_status(@_) == PENDING; }
191*is_untrusted = \&is_not_trusted;
192
193sub approve {
194    my $this = shift;
195    my ($blog_id) = @_;
196    $this->set_commenter_perm($blog_id, 'approve');
197}
198
199*trust = \&approve;
200
201sub pending {
202    $_[0]->set_commenter_perm($_[1], 'pending');
203}
204
205sub ban {
206    my $this = shift;
207    my ($blog_id) = @_;
208    $this->set_commenter_perm($blog_id, 'ban');
209}
210*block = \&ban;
211
212sub save {
213    my $auth = shift;
214
215    if ($auth->type == AUTHOR) {
216        if (!$auth->id) {
217            # New author, undefined API password. Generate one.
218            if (!defined $auth->api_password) {
219                my @pool = ('a'..'z', 0..9);
220                my $pass = '';
221                for (1..8) { $pass .= $pool[ rand @pool ] }
222                $auth->api_password($pass);
223            }
224        }
225        # Generate basename
226        my $basename = MT::Util::make_unique_author_basename($auth);
227        $auth->basename($basename);
228    }
229
230    my $privs;
231    if (exists $auth->permissions(0)->{changed_cols}->{permissions}) {
232         $privs = $auth->permissions(0)->permissions;
233    }
234    # delete new user's privilege from cache
235    delete MT::Request->instance->{__stash}->{'__perm_author_'} unless $auth->id;
236    $auth->SUPER::save(@_) or return $auth->error($auth->errstr);
237    if (defined $privs) {
238        my $perm = $auth->permissions(0);
239        $perm->permissions($privs);
240        $perm->save or return $auth->error("Error saving permission: " . $perm->errstr);
241    }
242    1;
243}
244
245sub remove {
246    my $auth = shift;
247    $auth->remove_sessions if ref $auth;
248    $auth->remove_children({ key => 'author_id' }) or return;
249    $auth->SUPER::remove(@_);
250}
251
252sub can_edit_entry {
253    my $author = shift;
254    die unless $author->isa('MT::Author');
255    return 1 if $author->is_superuser();
256    my($entry) = @_;
257    unless (ref $entry) {
258        require MT::Entry;
259        $entry = MT::Entry->load($entry);
260    }
261    die if !$entry || $entry->isa('MT::Entry');
262    my $perms = $author->permissions($entry->blog_id);
263    die unless $perms->isa('MT::Permission');
264    $perms->can_edit_all_posts ||
265        ($perms->can_create_post && $entry->author_id == $author->id);
266}
267
268sub is_superuser {
269    my $author = shift;
270    if (@_) {
271        $author->permissions(0)->can_administer(@_);
272        if ($_[0]) {
273            $author->permissions(0)->can_create_blog(@_);
274            $author->permissions(0)->can_view_log(@_);
275            $author->permissions(0)->can_manage_plugins(@_);
276            $author->permissions(0)->can_edit_templates(@_);
277        }
278    } else {
279        $author->permissions(0)->can_administer() ||
280            $author->SUPER::is_superuser();
281    }
282}
283
284sub can_create_blog {
285    my $author = shift;
286    if (@_) {
287        $author->permissions(0)->can_create_blog(@_);
288    } else {
289        $author->is_superuser() ||
290            $author->permissions(0)->can_create_blog(@_);
291    }
292}
293
294sub can_view_log {
295    my $author = shift;
296    if (@_) {
297        $author->permissions(0)->can_view_log(@_);
298    } else {
299        $author->is_superuser() ||
300            $author->permissions(0)->can_view_log(@_);
301    }
302}
303
304sub can_manage_plugins {
305    my $author = shift;
306    if (@_) {
307        $author->permissions(0)->can_manage_plugins(@_);
308    } else {
309        $author->is_superuser() ||
310            $author->permissions(0)->can_manage_plugins(@_);
311    }
312}
313
314sub can_edit_templates {
315    my $author = shift;
316    if (@_) {
317        $author->permissions(0)->can_edit_templates(@_);
318    } else {
319        $author->is_superuser() ||
320            $author->permissions(0)->can_edit_templates(@_);
321    }
322}
323
324sub blog_perm {
325    my $author = shift;
326    my ($blog_id) = @_;
327    $author->permissions($blog_id);
328}
329
330sub permissions {
331    my $author = shift;
332    my ($obj) = @_;
333    my $blog_id = $obj;
334
335    my $terms = { author_id => $author->id };
336    my $cache_key = "__perm_author_" . (defined($author->id) ? $author->id : q());
337    if ($obj) {
338        if ((ref $obj) && $obj->isa('MT::Blog')) {
339            $blog_id = $obj->id;
340        } elsif ($obj) {
341            $blog_id = $obj;
342            require MT::Blog;
343            $obj = MT::Blog->load($blog_id);
344        }
345        $cache_key .= "_blog_$blog_id";
346        $terms->{blog_id} = [ 0, $blog_id ];
347    } else {
348        $terms->{blog_id} = 0;
349    }
350
351    require MT::Request;
352    my $r = MT::Request->instance;
353    my $p = $r->stash($cache_key);
354    return $p if $p;
355
356    require MT::Permission;
357    my @perm = MT::Permission->load($terms);
358    my $perm;
359    if ($obj) {
360        if (@perm == 2) {
361            if (!$perm[0]->blog_id) {
362                @perm = reverse @perm;
363            }
364            ($perm, my $sys_perm) = @perm;
365            $perm->add_permissions($sys_perm);
366        } elsif (@perm == 1) {
367            $perm = $perm[0];
368            if (!$perm->blog_id) {
369                $perm->blog_id($obj->id);
370                delete $perm->{column_values}{blog_id};
371                delete $perm->{changed_cols}{blog_id};
372            }
373        } elsif (@perm > 2) {
374            # Condition sometimes caused by saving preferences. BugId:79501
375            # Handle by merging permissions and removing all but one
376            # Not ideal, but better than dying...
377            my ($sys_perm) = grep { ! $_->blog_id } @perm;
378            my @blog_perms = grep { $_->blog_id } sort { $b->modified_on cmp $a->modified_on } @perm;
379
380            my $new_perm = shift @blog_perms; # take last one saved
381            if (@blog_perms) {
382                foreach my $more_perms (@blog_perms) {
383                    $new_perm->add_permissions($more_perms);
384                    $new_perm->add_restrictions($more_perms);
385                    $more_perms->remove;
386                }
387                # save merged permission record
388                $new_perm->save;
389            }
390            $new_perm->add_permissions($sys_perm);
391            $new_perm->add_restrictions($sys_perm);
392            $perm = $new_perm;
393            @perm = ($perm);
394        }
395    } else {
396        $perm = $perm[0] if @perm;
397    }
398    unless (@perm) {
399        if ($blog_id || !@_) {
400            if ($author->is_superuser()) {
401                $perm = new MT::Permission;
402                $perm->author_id($author->id);
403                $perm->set_full_permissions;
404            }
405        }
406    }
407    unless ($perm) {
408        $perm = new MT::Permission;
409        $perm->author_id($author->id);
410        $perm->clear_full_permissions;
411    }
412    $r->stash($cache_key, $perm);
413    $perm;
414}
415
416sub common_blogs { # returns the blogs in the form of permission records of $this
417    die "This was removed";        # FIXME: this is to catch mistakes
418}
419sub can_administer {
420    die "This was removed";        # FIXME: this is to catch mistakes
421}
422
423sub entry_prefs {
424    my $author = shift;
425    my @prefs = split /,/, ($author->column('entry_prefs') || '');
426    my %prefs;
427    foreach (@prefs) {
428        my ($name, $value) = split /=/, $_, 2;
429        $prefs{$name} = $value;
430    }
431    if (@_) {
432        %prefs = (%prefs, @_);
433        my $pref = '';
434        foreach (keys %prefs) {
435            $pref .= ',' if $pref ne '';
436            $pref .= $_ . '=' . $prefs{$_};
437        }
438        $author->column('entry_prefs', $pref);
439    }
440
441    # default assignments for author entry preferences
442    $prefs{tag_delim} ||= MT->config->DefaultUserTagDelimiter;
443
444    \%prefs;
445}
446
447sub role_iter {
448    my $author = shift;
449    my ($terms, $args) = @_;
450    require MT::Association;
451    require MT::Role;
452    my $blog_id = delete $terms->{blog_id};
453    my $type;
454    if ($blog_id) {
455        $type = MT::Association::USER_BLOG_ROLE();
456    } else {
457        $type = MT::Association::USER_ROLE();
458    }
459    $args->{join} = MT::Association->join_on('role_id', {
460        type => $type,
461        author_id => $author->id,
462        $blog_id ? (blog_id => $blog_id) : (blog_id => 0),
463    });
464    MT::Role->load_iter($terms, $args);
465}
466
467sub blog_iter {
468    my $author = shift;
469    my ($terms, $args) = @_;
470    my $perm = $author->permissions;
471    if (!$author->is_superuser) {
472        require MT::Permission;
473        $args->{join} = MT::Permission->join_on('blog_id', {
474            author_id => $author->id,
475        });
476    }
477    require MT::Blog;
478    my $i = MT::Blog->load_iter($terms, $args);
479}
480
481sub group_iter {
482    my $author = shift;
483    my ($terms, $args) = @_;
484    my $grp_class = MT->model('group') or return undef;
485    require MT::Association;
486    $args->{join} = MT::Association->join_on('group_id', {
487        type => MT::Association::USER_GROUP(),
488        author_id => $author->id,
489    });
490    return $grp_class->load_iter($terms, $args);
491}
492
493sub group_role_iter {
494    my $author = shift;
495    my ($terms, $args) = @_;
496
497    my $grp_class = MT->model('group')
498        or return undef;
499    my @iters;
500    require MT::Association;
501    require MT::Role;
502    my $blog_id = delete $terms->{blog_id};
503    $args->{join} = MT::Association->join_on('role_id', {
504        type => $blog_id ? MT::Association::USER_BLOG_ROLE() : MT::Association::USER_ROLE(),
505        author_id => $author->id,
506        $blog_id ? (blog_id => $blog_id) : (),
507    });
508    my $user_iter = MT::Role->load_iter($terms, $args);
509    push @iters, $user_iter if $user_iter;
510
511    my @groups;
512    if (my $group_iter = $author->group_iter({ status => MT::Group::ACTIVE() })) {
513        while (my $g = $group_iter->()) {
514            push @groups, $g->id;
515        }
516    }
517    if (@groups) {
518        $args->{join} = MT::Association->join_on('role_id', {
519            type => $blog_id ? MT::Association::GROUP_BLOG_ROLE() : MT::Association::GROUP_ROLE(),
520            group_id => \@groups,
521            $blog_id ? (blog_id => $blog_id) : (),
522        });
523        my $group_iter = MT::Role->load_iter($terms, $args);
524        push @iters, $group_iter if $group_iter;
525    }
526    MT::Util::multi_iter(\@iters);
527}
528
529sub add_role {
530    my $author = shift;
531    my ($role, $blog) = @_;
532    $author->save unless $author->id;
533    $role->save unless $role->id;
534    $blog->save if $blog && !$blog->id;
535    require MT::Association;
536    MT::Association->link($author, @_);
537}
538
539sub add_group {
540    my $author = shift;
541    my ($group) = @_;
542    $author->save unless $author->id;
543    $group->save unless $group->id;
544    require MT::Association;
545    MT::Association->link($author, @_);
546}
547
548sub remove_role {
549    my $author = shift;
550    require MT::Association;
551    MT::Association->unlink($author, @_);
552}
553
554sub remove_group {
555    my $author = shift;
556    require MT::Association;
557    MT::Association->unlink($author, @_);
558}
559
560sub add_default_roles {
561    my $author = shift;
562    my $def = MT->config->DefaultAssignments;
563    return unless $def;
564
565    my $blog_class = MT->model('blog');
566    my $role_class = MT->model('role');
567
568    require MT::Association;
569    my @def = split ',', $def;
570    while (my $role_id = shift @def) {
571        my $blog_id = shift @def;
572        next unless $role_id && $blog_id;
573        my $blog = $blog_class->load($blog_id);
574        my $role = $role_class->load($role_id);
575        next unless ref $blog && ref $role;
576        MT::Association->link($author => $role => $blog);
577    }
578}
579
580sub to_hash {
581    my $author = shift;
582    my $hash = $author->SUPER::to_hash(@_);
583    my $app = MT->instance;
584    my $blog = $app->blog if $app->can('blog');
585    if ($blog) {
586        require MT::Permission;
587        if (my $perms = MT::Permission->load({ author_id => $author->id, blog_id => $blog->id })) {
588            my $perms_hash = $perms->to_hash;
589            $hash->{"author.$_"} = $perms_hash->{$_} foreach keys %$perms_hash;
590        }
591    }
592    $hash;
593}
594
595sub group_count {
596    my $author = shift;
597    require MT::Association;
598    MT::Association->count({
599        type => MT::Association::USER_GROUP(),
600        author_id => $author->id,
601    });
602}
603
604sub external_id {
605    my $author = shift;
606    if (@_) {
607        return $author->SUPER::external_id($author->unpack_external_id(@_));
608    }
609    my $value = $author->SUPER::external_id;
610    $value = $author->pack_external_id($value) if $value;
611}
612
613sub load {
614    my $author = shift;
615    my ($terms, $args) = @_;
616    if ((ref($terms) eq 'HASH') && exists($terms->{external_id})) {
617        $terms->{external_id} = $author->unpack_external_id($terms->{external_id});
618    }
619    $author->SUPER::load($terms, $args);
620}
621
622sub load_iter {
623    my $author = shift;
624    my ($terms, $args) = @_;
625    if ((ref($terms) eq 'HASH') && exists($terms->{external_id})) {
626        $terms->{external_id} = $author->unpack_external_id($terms->{external_id});
627    }
628    $author->SUPER::load_iter($terms, $args);
629}
630
631sub pack_external_id { return pack('H*', $_[1]); }
632sub unpack_external_id { return unpack('H*', $_[1]); }
633
634sub auth_icon_url {
635    my $author = shift;
636    my ($size) = @_;
637    $size ||= 'logo_small';
638
639    my $app = MT->instance;
640    my $static_path = $app->static_path;
641
642    my $auth_type = $author->auth_type;
643    return q() unless $auth_type;
644
645    if ( $author->type == MT::Author::AUTHOR() ) {
646        return $static_path . 'images/comment/mt_logo.png' ;
647    }
648   
649    my $authenticator = MT->commenter_authenticator( $auth_type );
650    return q() unless $authenticator;
651    return q() unless exists $authenticator->{$size};
652
653    my $logo = $authenticator->{$size};
654    if ( ( $logo !~ m!^https?://! ) || ( $logo !~ m!^/! ) ) {
655        $logo = $static_path . $logo;
656    }
657    return $logo;
658}
659
660sub userpic {
661    my $author = shift;
662
663    my $asset_id = $author->userpic_asset_id or return;
664    require MT::Asset;
665    my $asset = MT->model('asset.image')->load($asset_id) or return;
666
667    $asset;
668}
669
670sub userpic_thumbnail_options {
671    my $author = shift;
672
673    # Specify these to put an author's userpic thumbnail in a consistent
674    # place whenever userpic_url is called as an instance method on a
675    # particular author.
676    my %real_userpic_options = (
677        Path   => File::Spec->catdir( MT->config->AssetCacheDir, 'userpics' ),
678        Format => MT->translate('userpic-[_1]-%wx%h%x', $author->id),
679    ) if ref $author;
680
681    my $cfg = MT->config;
682    my $max_dim = $cfg->UserpicThumbnailSize;
683    my $square  = $cfg->UserpicAllowRect ? 0 : 1;
684    return (
685        Width  => $max_dim,
686        Height => $max_dim,
687        Square => $square,
688        Type   => 'png',
689        %real_userpic_options,
690    );
691}
692
693sub userpic_file {
694    my $author = shift;
695
696    my $asset = $author->userpic;
697    if (!$asset) {
698        $asset = MT->model('asset.image')->new;
699        $asset->file_name('userpic');
700    }
701
702    my %thumb_param = $author->userpic_thumbnail_options();
703    my $thumb_file = File::Spec->catfile(
704        $asset->thumbnail_path(%thumb_param),
705        $asset->thumbnail_filename(%thumb_param),
706    );
707
708    return $thumb_file;
709}
710
711sub userpic_url {
712    my $author = shift;
713    my (%param) = @_;
714
715    my $asset = delete $param{Asset};
716    if (!$asset && ref $author) {
717        $asset = $author->userpic;
718    }
719    return if !$asset;
720
721    my @info = $asset->thumbnail_url(
722        $author->userpic_thumbnail_options(),
723        %param,
724    );
725    if ($info[0] !~ m!^https?://!) {
726        my $static_host = MT->instance->static_path;
727        if ($static_host =~ m!^https?://!) {
728            $static_host =~ s!^(https?://[^/]+?)!$1!;
729            $info[0] = $static_host . $info[0];
730        }
731    }
732    return wantarray ? @info : $info[0];
733}
734
735sub userpic_html {
736    my $author = shift;
737    my ($thumb_url, $w, $h) = $author->userpic_url(@_) or return;
738    return unless $thumb_url;
739    sprintf q{<img src="%s" width="%d" height="%d" alt="" />},
740        MT::Util::encode_html($thumb_url), $w, $h;
741}
742
7431;
744
745__END__
746
747=head1 NAME
748
749MT::Author - Movable Type author record
750
751=head1 SYNOPSIS
752
753    use MT::Author;
754    my $author = MT::Author->new;
755    $author->name('Foo Bar');
756    $author->set_password('secret');
757    $author->save
758        or die $author->errstr;
759
760    my $author = MT::Author->load($author_id);
761
762=head1 DESCRIPTION
763
764An I<MT::Author> object represents a user in the Movable Type system. It
765contains profile information (name, nickname, email address, etc.), global
766permissions settings (blog creation, activity log viewing), and authentication
767information (password, public key). It does not contain any per-blog
768permissions settings--for those, look at the I<MT::Permission> object.
769
770=head1 USAGE
771
772As a subclass of I<MT::Object>, I<MT::Author> inherits all of the
773data-management and -storage methods from that class; thus you should look
774at the I<MT::Object> documentation for details about creating a new object,
775loading an existing object, saving an object, etc.
776
777The following methods are unique to the I<MT::Author> interface:
778
779=head2 $author->set_password($pass)
780
781One-way encrypts I<$pass> with a randomly-generated salt, using the Unix
782I<crypt> function, and sets the I<password> data field in the I<MT::Author>
783object I<$author>.
784
785Because the password is one-way encrypted, there is B<no way> of recovering
786the initial password.
787
788=head2 $author->is_valid_password($check_pass)
789
790Tests whether I<$check_pass> is a valid password for the I<MT::Author> object
791I<$author> (ie, whether it matches the password originally set using
792I<set_password>). This check is done by one-way encrypting I<$check_pass>,
793using the same salt used to encrypt the original password, then comparing the
794two encrypted strings for equality.
795
796=head1 DATA ACCESS METHODS
797
798The I<MT::Author> object holds the following pieces of data. These fields can
799be accessed and set using the standard data access methods described in the
800I<MT::Object> documentation.
801
802=over 4
803
804=item * id
805
806The numeric ID of the author.
807
808=item * name
809
810The username of the author. This is the username used to log in to the system.
811
812=item * nickname
813
814The author nickname (or "display" name). This is the preferred name used for publishing the author's name.
815
816=item * password
817
818The author's password, one-way encrypted. If you wish to check the validity of
819a password, you should use the I<is_valid_password> method, above.
820
821=item * type
822
823The type of author record. Currently, MT stores authenticated commenters in the author table. The type column can be one of AUTHOR or COMMENTER (constants defined in this package).
824
825=item * status
826
827A column that defines whether the records of an AUTHOR type are ACTIVE, INACTIVE or PENDING (constants declared in this package).
828
829=item * commenter_status
830
831This method requires a blog id to be passed as the argument and a value of APPROVED, BANNED or PENDING (constants declared in this package) is returned.
832
833=item * email
834
835The author's email address.
836
837=item * url
838
839The author's homepage URL.
840
841=item * hint
842
843The answer to the question used when recovering the user's password.
844
845=item * external_id
846
847A column for holding a value used to synchronize the MT author record with an external record.
848
849=item * can_create_blog
850
851A boolean flag specifying whether the author has permission to create a new
852blog in the system.
853
854=item * can_view_log
855
856A boolean flag specifying whether the author has permission to view the global
857system activity log.
858
859=item * created_by
860
861The author ID of the author who created this author. If the author was created by a process where no user was logged in to Movable Type, the created_by column will be empty.
862
863=item * public_key
864
865The author's ASCII-armoured public key, to be used in the future for verifying
866incoming email messages.
867
868=back
869
870=head1 DATA LOOKUP
871
872In addition to numeric ID lookup, you can look up or sort records by any
873combination of the following fields. See the I<load> documentation in
874I<MT::Object> for more information.
875
876=over 4
877
878=item * name
879
880=item * email
881
882=back
883
884=head1 NOTES
885
886=over 4
887
888=item *
889
890When you remove an author using I<MT::Author::remove>, in addition to removing
891the author record, all of the author's permissions (I<MT::Permission> objects)
892will be removed, as well.
893
894=back
895
896=head1 AUTHOR & COPYRIGHTS
897
898Please see the I<MT> manpage for author, copyright, and license information.
899
900=cut
Note: See TracBrowser for help on using the browser.