root/branches/release-26/lib/MT/Author.pm @ 1174

Revision 1174, 23.3 kB (checked in by bchoate, 23 months ago)

Updated copyright year for source.

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