| 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 | |
|---|
| 7 | package MT::Permission; |
|---|
| 8 | |
|---|
| 9 | use strict; |
|---|
| 10 | |
|---|
| 11 | use MT::Blog; |
|---|
| 12 | use MT::Object; |
|---|
| 13 | @MT::Permission::ISA = qw(MT::Object); |
|---|
| 14 | |
|---|
| 15 | __PACKAGE__->install_properties( |
|---|
| 16 | { |
|---|
| 17 | column_defs => { |
|---|
| 18 | 'id' => 'integer not null auto_increment', |
|---|
| 19 | 'author_id' => 'integer not null', |
|---|
| 20 | 'blog_id' => 'integer not null', |
|---|
| 21 | 'role_mask' => 'integer', |
|---|
| 22 | |
|---|
| 23 | # These were only declared for MTE 1.5x; dropping them |
|---|
| 24 | # has no ill effect since they were never actually used. |
|---|
| 25 | # 'role_mask2' => 'integer', # for upgrades... |
|---|
| 26 | # 'role_mask3' => 'integer', |
|---|
| 27 | # 'role_mask4' => 'integer', |
|---|
| 28 | 'permissions' => 'text', |
|---|
| 29 | 'entry_prefs' => 'text', |
|---|
| 30 | 'blog_prefs' => 'string(255)', |
|---|
| 31 | 'template_prefs' => 'string(255)', |
|---|
| 32 | 'restrictions' => 'text', |
|---|
| 33 | }, |
|---|
| 34 | child_of => 'MT::Blog', |
|---|
| 35 | indexes => { |
|---|
| 36 | blog_id => 1, |
|---|
| 37 | author_id => 1, |
|---|
| 38 | role_mask => 1, |
|---|
| 39 | }, |
|---|
| 40 | defaults => { |
|---|
| 41 | author_id => 0, |
|---|
| 42 | blog_id => 0, |
|---|
| 43 | role_mask => 0, |
|---|
| 44 | }, |
|---|
| 45 | audit => 1, |
|---|
| 46 | datasource => 'permission', |
|---|
| 47 | primary_key => 'id', |
|---|
| 48 | } |
|---|
| 49 | ); |
|---|
| 50 | |
|---|
| 51 | sub class_label { |
|---|
| 52 | MT->translate("Permission"); |
|---|
| 53 | } |
|---|
| 54 | |
|---|
| 55 | sub class_label_plural { |
|---|
| 56 | MT->translate("Permissions"); |
|---|
| 57 | } |
|---|
| 58 | |
|---|
| 59 | |
|---|
| 60 | sub user { |
|---|
| 61 | my $perm = shift; |
|---|
| 62 | |
|---|
| 63 | #xxx Beware of circular references |
|---|
| 64 | return undef unless $perm->author_id; |
|---|
| 65 | $perm->cache_property( |
|---|
| 66 | 'user', |
|---|
| 67 | sub { |
|---|
| 68 | require MT::Author; |
|---|
| 69 | MT::Author->load( $perm->author_id ); |
|---|
| 70 | } |
|---|
| 71 | ); |
|---|
| 72 | } |
|---|
| 73 | *author = *user; |
|---|
| 74 | |
|---|
| 75 | sub blog { |
|---|
| 76 | my $perm = shift; |
|---|
| 77 | return undef unless $perm->blog_id; |
|---|
| 78 | $perm->cache_property( |
|---|
| 79 | 'blog', |
|---|
| 80 | sub { |
|---|
| 81 | require MT::Blog; |
|---|
| 82 | MT::Blog->load( $perm->blog_id ); |
|---|
| 83 | } |
|---|
| 84 | ); |
|---|
| 85 | } |
|---|
| 86 | |
|---|
| 87 | # Legend: |
|---|
| 88 | # author_id || blog_id || permissions |
|---|
| 89 | # N || 0 || System level privilege |
|---|
| 90 | # N || N || Author's Weblog level permissions |
|---|
| 91 | # 0 || N || Weblog default preferences of Entry Display (TBRemoved) |
|---|
| 92 | # 0 || 0 || !!BUG!! |
|---|
| 93 | # Permissions are stored in database like 'Perm1','Perm_2','Pe_rm_3'. |
|---|
| 94 | { |
|---|
| 95 | my @Perms; |
|---|
| 96 | |
|---|
| 97 | sub init_permissions { |
|---|
| 98 | my $pkg = shift; |
|---|
| 99 | $pkg->perms() unless @Perms; |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | sub _all_perms { |
|---|
| 103 | my ($scope) = @_; |
|---|
| 104 | my @perms; |
|---|
| 105 | if ( my $perms = MT->registry("permissions") ) { |
|---|
| 106 | foreach my $p (%$perms) { |
|---|
| 107 | my ( $s, $name ) = split /\./, $p; |
|---|
| 108 | next unless $s && $name; |
|---|
| 109 | next unless $s eq $scope; |
|---|
| 110 | push @perms, "'$name'"; |
|---|
| 111 | } |
|---|
| 112 | } |
|---|
| 113 | return join ',', @perms; |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | sub add_permissions { |
|---|
| 117 | my $perms = shift; |
|---|
| 118 | |
|---|
| 119 | # This parameter can be any MT::Object that provides the |
|---|
| 120 | # permission field. So it works with MT::Permission and MT::Role. |
|---|
| 121 | my ($more_perm) = @_; |
|---|
| 122 | if ( my $more = $more_perm->permissions ) { |
|---|
| 123 | if ( $more =~ /'administer_blog'/ ) { |
|---|
| 124 | $more = _all_perms('blog'); |
|---|
| 125 | } |
|---|
| 126 | my $cur_perm = $perms->permissions; |
|---|
| 127 | my @newperms; |
|---|
| 128 | for my $p ( split ',', $more ) { |
|---|
| 129 | $p =~ s/'(.+)'/$1/; |
|---|
| 130 | next if $perms->has($p); |
|---|
| 131 | push @newperms, $p; |
|---|
| 132 | } |
|---|
| 133 | return unless @newperms; |
|---|
| 134 | my $newperm = "'" . join( "','", @newperms ) . "'"; |
|---|
| 135 | $newperm = "$cur_perm,$newperm" if $cur_perm; |
|---|
| 136 | $perms->permissions($newperm); |
|---|
| 137 | } |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | sub add_restrictions { |
|---|
| 141 | my $perms = shift; |
|---|
| 142 | my ($more_perm) = @_; |
|---|
| 143 | if ( my $more = $more_perm->restrictions ) { |
|---|
| 144 | if ( $more =~ /'administer_blog'/ ) { |
|---|
| 145 | $more = _all_perms('blog'); |
|---|
| 146 | } |
|---|
| 147 | my $cur_perm = $perms->restrictions; |
|---|
| 148 | my @newperms; |
|---|
| 149 | for my $p ( split ',', $more ) { |
|---|
| 150 | $p =~ s/'(.+)'/$1/; |
|---|
| 151 | next if $perms->has($p); |
|---|
| 152 | push @newperms, $p; |
|---|
| 153 | } |
|---|
| 154 | return unless @newperms; |
|---|
| 155 | my $newperm = "'" . join( "','", @newperms ) . "'"; |
|---|
| 156 | $newperm = "$cur_perm,$newperm" if $cur_perm; |
|---|
| 157 | $perms->restrictions($newperm); |
|---|
| 158 | } |
|---|
| 159 | } |
|---|
| 160 | |
|---|
| 161 | # Sets permissions of those in a particular set |
|---|
| 162 | sub set_full_permissions { |
|---|
| 163 | my $perms = shift; |
|---|
| 164 | $perms->set_permissions('blog'); |
|---|
| 165 | } |
|---|
| 166 | |
|---|
| 167 | sub set_permissions { |
|---|
| 168 | my $perms = shift; |
|---|
| 169 | __PACKAGE__->_set_these( $perms, 'permissions', @_ ); |
|---|
| 170 | } |
|---|
| 171 | |
|---|
| 172 | sub set_restrictions { |
|---|
| 173 | my $perms = shift; |
|---|
| 174 | __PACKAGE__->_set_these( $perms, 'restrictions', @_ ); |
|---|
| 175 | } |
|---|
| 176 | |
|---|
| 177 | sub _set_these { |
|---|
| 178 | my $pkg = shift; |
|---|
| 179 | my $perms = shift; |
|---|
| 180 | my ( $column, $set ) = @_; |
|---|
| 181 | my @permissions; |
|---|
| 182 | for my $ref ( @{ perms() } ) { |
|---|
| 183 | next if $set && ( $set ne '*' ) && ( $ref->[2] ne $set ); |
|---|
| 184 | push @permissions, $ref->[0]; |
|---|
| 185 | } |
|---|
| 186 | $perms->$column( "'" . join( "','", @permissions ) . "'" ); |
|---|
| 187 | } |
|---|
| 188 | |
|---|
| 189 | sub remove_restrictions { |
|---|
| 190 | my $perms = shift; |
|---|
| 191 | my (@perms) = @_; |
|---|
| 192 | my $cur_rest = $perms->restrictions; |
|---|
| 193 | return unless $cur_rest; |
|---|
| 194 | for my $perm_name (@perms) { |
|---|
| 195 | $cur_rest =~ s/'$perm_name',?//i; |
|---|
| 196 | } |
|---|
| 197 | $perms->restrictions($cur_rest); |
|---|
| 198 | } |
|---|
| 199 | |
|---|
| 200 | # Clears all permissions or those in a particular set |
|---|
| 201 | sub clear_full_permissions { |
|---|
| 202 | my $perms = shift; |
|---|
| 203 | $perms->clear_permissions('blog'); |
|---|
| 204 | } |
|---|
| 205 | |
|---|
| 206 | sub clear_permissions { |
|---|
| 207 | my $perms = shift; |
|---|
| 208 | __PACKAGE__->_clear_these( $perms, 'permissions', @_ ); |
|---|
| 209 | } |
|---|
| 210 | |
|---|
| 211 | sub clear_restrictions { |
|---|
| 212 | my $perms = shift; |
|---|
| 213 | __PACKAGE__->_clear_these( $perms, 'restrictions', @_ ); |
|---|
| 214 | } |
|---|
| 215 | |
|---|
| 216 | sub _clear_these { |
|---|
| 217 | my $pkg = shift; |
|---|
| 218 | my $perms = shift; |
|---|
| 219 | my ( $column, $set ) = @_; |
|---|
| 220 | my $cur_perm = $perms->$column; |
|---|
| 221 | return unless $cur_perm; |
|---|
| 222 | for my $ref ( @{ perms() } ) { |
|---|
| 223 | next if $set && ( $set ne '*' ) && ( $ref->[2] ne $set ); |
|---|
| 224 | my $perm_name = $ref->[0]; |
|---|
| 225 | $cur_perm =~ s/'$perm_name',?//i; |
|---|
| 226 | } |
|---|
| 227 | $perms->$column($cur_perm); |
|---|
| 228 | } |
|---|
| 229 | |
|---|
| 230 | sub perms { |
|---|
| 231 | my $pkg = shift; |
|---|
| 232 | unless (@Perms) { |
|---|
| 233 | if ( my $perms = MT->registry("permissions") ) { |
|---|
| 234 | foreach my $pk (%$perms) { |
|---|
| 235 | my ( $scope, $name ) = split /\./, $pk; |
|---|
| 236 | next unless $scope && $name; |
|---|
| 237 | my $label = |
|---|
| 238 | 'CODE' eq ref( $perms->{$pk}{label} ) |
|---|
| 239 | ? $perms->{$pk}{label}->() |
|---|
| 240 | : $perms->{$pk}{label}; |
|---|
| 241 | push @Perms, [ $name, $label || '', $scope ]; |
|---|
| 242 | } |
|---|
| 243 | __mk_perm($_) foreach @Perms; |
|---|
| 244 | } |
|---|
| 245 | } |
|---|
| 246 | if (@_) { |
|---|
| 247 | my $set = shift; |
|---|
| 248 | my @perms = grep { $_->[2] eq $set } @Perms; |
|---|
| 249 | \@perms; |
|---|
| 250 | } |
|---|
| 251 | else { |
|---|
| 252 | \@Perms; |
|---|
| 253 | } |
|---|
| 254 | } |
|---|
| 255 | |
|---|
| 256 | my %Perms; |
|---|
| 257 | |
|---|
| 258 | sub __mk_perm { |
|---|
| 259 | no strict 'refs'; |
|---|
| 260 | my $ref = shift; |
|---|
| 261 | my $meth = 'can_' . $ref->[0]; |
|---|
| 262 | |
|---|
| 263 | $Perms{ $ref->[0] } = $ref; |
|---|
| 264 | my $set = $ref->[2]; |
|---|
| 265 | |
|---|
| 266 | return if defined *$meth; |
|---|
| 267 | |
|---|
| 268 | *$meth = sub { |
|---|
| 269 | my $cur_perm = $_[0]->permissions; |
|---|
| 270 | return undef if !$cur_perm && ( @_ < 2 ); |
|---|
| 271 | my $perm = substr $meth, 4; #remove 'can_' |
|---|
| 272 | if ( @_ == 2 ) { |
|---|
| 273 | if ( $_[1] ) { |
|---|
| 274 | return 1 if $_[0]->has($perm); |
|---|
| 275 | $cur_perm .= ',' if $cur_perm; |
|---|
| 276 | $cur_perm .= "'$perm'"; |
|---|
| 277 | } |
|---|
| 278 | else { |
|---|
| 279 | |
|---|
| 280 | # arg == 0 - remove it |
|---|
| 281 | $cur_perm =~ s/'$perm',?// if defined $cur_perm; |
|---|
| 282 | } |
|---|
| 283 | $_[0]->permissions($cur_perm); |
|---|
| 284 | } |
|---|
| 285 | else { |
|---|
| 286 | if ( my $author = $_[0]->author ) { |
|---|
| 287 | return 1 |
|---|
| 288 | if ( ( $meth ne 'can_administer' ) |
|---|
| 289 | && $author->is_superuser ); |
|---|
| 290 | return 1 |
|---|
| 291 | if ( ( $set eq 'blog' ) |
|---|
| 292 | && $_[0]->has('administer_blog') ); |
|---|
| 293 | } |
|---|
| 294 | } |
|---|
| 295 | return undef |
|---|
| 296 | if $_[0]->restrictions && $_[0]->restrictions =~ /'$perm'/i; |
|---|
| 297 | ( defined($cur_perm) && $cur_perm =~ /'$perm'/i ) ? 1 : undef; |
|---|
| 298 | }; |
|---|
| 299 | } |
|---|
| 300 | |
|---|
| 301 | sub set_these_permissions { |
|---|
| 302 | my $perms = shift; |
|---|
| 303 | __PACKAGE__->_set_these_list( $perms, 'permissions', @_ ); |
|---|
| 304 | } |
|---|
| 305 | |
|---|
| 306 | sub set_these_restrictions { |
|---|
| 307 | my $perms = shift; |
|---|
| 308 | __PACKAGE__->_set_these_list( $perms, 'restrictions', @_ ); |
|---|
| 309 | } |
|---|
| 310 | |
|---|
| 311 | sub _set_these_list { |
|---|
| 312 | my $pkg = shift; |
|---|
| 313 | my $perms = shift; |
|---|
| 314 | my ( $column, @list ) = @_; |
|---|
| 315 | if ( ( ref $list[0] ) eq 'ARRAY' ) { |
|---|
| 316 | @list = @{ $list[0] }; |
|---|
| 317 | } |
|---|
| 318 | foreach (@list) { |
|---|
| 319 | my $ref = $Perms{$_}; |
|---|
| 320 | die "invalid permission" unless $ref; |
|---|
| 321 | next if $pkg->_check_if($perms, $column, $_); |
|---|
| 322 | my $val = $perms->$column || ''; |
|---|
| 323 | $val .= ',' if $val ne ''; |
|---|
| 324 | $val .= "'" . $ref->[0] . "'"; |
|---|
| 325 | $perms->$column($val); |
|---|
| 326 | } |
|---|
| 327 | } |
|---|
| 328 | |
|---|
| 329 | sub add_permission { |
|---|
| 330 | my $pkg = shift; |
|---|
| 331 | my ($perm) = @_; |
|---|
| 332 | if ( ref $perm eq 'HASH' ) { |
|---|
| 333 | return unless $perm->{key} && $perm->{set}; |
|---|
| 334 | my $ref = [ $perm->{key}, $perm->{label} || '', $perm->{set} ]; |
|---|
| 335 | push @Perms, $ref; |
|---|
| 336 | __mk_perm($ref); |
|---|
| 337 | } |
|---|
| 338 | elsif ( ref $perm eq 'ARRAY' ) { |
|---|
| 339 | push @Perms, $perm; |
|---|
| 340 | __mk_perm($perm); |
|---|
| 341 | } |
|---|
| 342 | } |
|---|
| 343 | |
|---|
| 344 | # $perm->has() and $perm->is_restricted skips any fancy logic, |
|---|
| 345 | # returning true or false depending only on whether the bit is |
|---|
| 346 | # set in this record. |
|---|
| 347 | sub has { |
|---|
| 348 | my $this = shift; |
|---|
| 349 | __PACKAGE__->_check_if( $this, 'permissions', @_ ); |
|---|
| 350 | } |
|---|
| 351 | |
|---|
| 352 | sub is_restricted { |
|---|
| 353 | my $this = shift; |
|---|
| 354 | __PACKAGE__->_check_if( $this, 'restrictions', @_ ); |
|---|
| 355 | } |
|---|
| 356 | |
|---|
| 357 | sub _check_if { |
|---|
| 358 | my $pkg = shift; |
|---|
| 359 | my $this = shift; |
|---|
| 360 | my ( $column, $perm_name ) = @_; |
|---|
| 361 | my $cur_perm = $this->$column; |
|---|
| 362 | return 0 unless $cur_perm; |
|---|
| 363 | my $r = ( $cur_perm =~ /'$perm_name'/i ) ? 1 : 0; |
|---|
| 364 | return $r; |
|---|
| 365 | } |
|---|
| 366 | } |
|---|
| 367 | |
|---|
| 368 | sub can_post { |
|---|
| 369 | my $perms = shift; |
|---|
| 370 | if ( my ($val) = @_ ) { |
|---|
| 371 | $perms->can_create_post($val); |
|---|
| 372 | $perms->can_publish_post($val); |
|---|
| 373 | return $val; |
|---|
| 374 | } |
|---|
| 375 | $perms->can_create_post && $perms->can_publish_post; |
|---|
| 376 | } |
|---|
| 377 | |
|---|
| 378 | sub can_edit_authors { |
|---|
| 379 | my $perms = shift; |
|---|
| 380 | my $author = $perms->user; |
|---|
| 381 | $perms->can_administer_blog || ( $author && $author->is_superuser() ); |
|---|
| 382 | } |
|---|
| 383 | |
|---|
| 384 | sub can_edit_entry { |
|---|
| 385 | my $perms = shift; |
|---|
| 386 | my ( $entry, $author, $status ) = @_; |
|---|
| 387 | die unless $author->isa('MT::Author'); |
|---|
| 388 | return 1 if $author->is_superuser(); |
|---|
| 389 | unless ( ref $entry ) { |
|---|
| 390 | require MT::Entry; |
|---|
| 391 | $entry = MT::Entry->load($entry) |
|---|
| 392 | or die; |
|---|
| 393 | } |
|---|
| 394 | die unless $entry->isa('MT::Entry'); |
|---|
| 395 | if ( 'page' eq $entry->class ) { |
|---|
| 396 | return $perms->can_manage_pages; |
|---|
| 397 | } |
|---|
| 398 | return $perms->can_edit_all_posts |
|---|
| 399 | || ( |
|---|
| 400 | defined $status |
|---|
| 401 | ? ( $perms->can_publish_post && $entry->author_id == $author->id ) |
|---|
| 402 | : ( $perms->can_create_post && $entry->author_id == $author->id ) |
|---|
| 403 | ); |
|---|
| 404 | } |
|---|
| 405 | |
|---|
| 406 | sub can_upload { |
|---|
| 407 | my $perms = shift; |
|---|
| 408 | if (@_) { |
|---|
| 409 | if (my $can = shift) { |
|---|
| 410 | $perms->set_these_permissions('upload'); |
|---|
| 411 | } else { |
|---|
| 412 | $perms->clear_permissions('upload'); |
|---|
| 413 | } |
|---|
| 414 | } |
|---|
| 415 | return $perms->can_edit_assets || $perms->has('upload'); |
|---|
| 416 | } |
|---|
| 417 | |
|---|
| 418 | sub can_view_feedback { |
|---|
| 419 | my $perms = shift; |
|---|
| 420 | $perms->can_edit_all_posts |
|---|
| 421 | || $perms->can_create_post |
|---|
| 422 | || $perms->can_publish_post |
|---|
| 423 | || $perms->can_manage_feedback; |
|---|
| 424 | } |
|---|
| 425 | |
|---|
| 426 | sub is_empty { |
|---|
| 427 | my $perms = shift; |
|---|
| 428 | !( defined( $perms->permissions ) && $perms->permissions ); |
|---|
| 429 | } |
|---|
| 430 | |
|---|
| 431 | sub _static_rebuild { |
|---|
| 432 | my $pkg = shift; |
|---|
| 433 | my ($obj) = @_; |
|---|
| 434 | |
|---|
| 435 | if ( $obj->isa('MT::Association') ) { |
|---|
| 436 | my $assoc = $obj; |
|---|
| 437 | if ( $assoc->role_id && $assoc->blog_id ) { |
|---|
| 438 | if ( $assoc->group_id ) { |
|---|
| 439 | my $grp = $assoc->group or return; |
|---|
| 440 | my $iter = $grp->user_iter; |
|---|
| 441 | while ( my $user = $iter->() ) { |
|---|
| 442 | my $perm = MT::Permission->get_by_key( |
|---|
| 443 | { |
|---|
| 444 | author_id => $user->id, |
|---|
| 445 | blog_id => $assoc->blog_id |
|---|
| 446 | } |
|---|
| 447 | ); |
|---|
| 448 | $perm->rebuild; |
|---|
| 449 | } |
|---|
| 450 | } |
|---|
| 451 | elsif ( $assoc->author_id ) { |
|---|
| 452 | my $user = $assoc->user or return; |
|---|
| 453 | my $perm = MT::Permission->get_by_key( |
|---|
| 454 | { |
|---|
| 455 | author_id => $user->id, |
|---|
| 456 | blog_id => $assoc->blog_id |
|---|
| 457 | } |
|---|
| 458 | ); |
|---|
| 459 | $perm->rebuild; |
|---|
| 460 | } |
|---|
| 461 | } |
|---|
| 462 | elsif ( $assoc->author_id && $assoc->group_id ) { |
|---|
| 463 | |
|---|
| 464 | # rebuild permissions for author |
|---|
| 465 | my $grp = $assoc->group or return; |
|---|
| 466 | my $blog_iter = $grp->blog_iter; |
|---|
| 467 | my @blogs; |
|---|
| 468 | if ($blog_iter) { |
|---|
| 469 | while ( my $blog = $blog_iter->() ) { |
|---|
| 470 | push @blogs, $blog->id; |
|---|
| 471 | } |
|---|
| 472 | } |
|---|
| 473 | if (@blogs) { |
|---|
| 474 | foreach my $blog_id (@blogs) { |
|---|
| 475 | my $perm = MT::Permission->get_by_key( |
|---|
| 476 | { |
|---|
| 477 | author_id => $assoc->author_id, |
|---|
| 478 | blog_id => $blog_id, |
|---|
| 479 | } |
|---|
| 480 | ); |
|---|
| 481 | $perm->rebuild; |
|---|
| 482 | } |
|---|
| 483 | } |
|---|
| 484 | } |
|---|
| 485 | } |
|---|
| 486 | 1; |
|---|
| 487 | } |
|---|
| 488 | |
|---|
| 489 | sub rebuild { |
|---|
| 490 | my $perm = shift; |
|---|
| 491 | if ( !ref $perm ) { |
|---|
| 492 | return $perm->_static_rebuild(@_); |
|---|
| 493 | } |
|---|
| 494 | |
|---|
| 495 | # rebuild permissions for this user / blog |
|---|
| 496 | my $user_id = $perm->author_id; |
|---|
| 497 | my $blog_id = $perm->blog_id; |
|---|
| 498 | |
|---|
| 499 | return unless $user_id && $blog_id; |
|---|
| 500 | |
|---|
| 501 | # clean slate |
|---|
| 502 | $perm->clear_full_permissions; |
|---|
| 503 | my $has_permissions = 0; |
|---|
| 504 | |
|---|
| 505 | # find all blogs for this user |
|---|
| 506 | my $user = MT::Author->load($user_id) or return; |
|---|
| 507 | |
|---|
| 508 | my $role_iter = $user->role_iter( { blog_id => $blog_id } ); |
|---|
| 509 | if ($role_iter) { |
|---|
| 510 | while ( my $role = $role_iter->() ) { |
|---|
| 511 | $perm->add_permissions($role); |
|---|
| 512 | $has_permissions = 1; |
|---|
| 513 | } |
|---|
| 514 | } |
|---|
| 515 | |
|---|
| 516 | # find all blogs for this user through groups |
|---|
| 517 | $role_iter = $user->group_role_iter( { blog_id => $blog_id } ); |
|---|
| 518 | if ($role_iter) { |
|---|
| 519 | while ( my $role = $role_iter->() ) { |
|---|
| 520 | $perm->add_permissions($role); |
|---|
| 521 | $has_permissions = 1; |
|---|
| 522 | } |
|---|
| 523 | } |
|---|
| 524 | |
|---|
| 525 | if ($has_permissions) { |
|---|
| 526 | $perm->save; |
|---|
| 527 | } |
|---|
| 528 | else { |
|---|
| 529 | $perm->remove if $perm->id; |
|---|
| 530 | } |
|---|
| 531 | } |
|---|
| 532 | |
|---|
| 533 | sub load_same { |
|---|
| 534 | my $pkg = shift; |
|---|
| 535 | my ( $terms, $args, $exact, @list ) = @_; |
|---|
| 536 | if ( ( ref $list[0] ) eq 'ARRAY' ) { |
|---|
| 537 | @list = @{ $list[0] }; |
|---|
| 538 | } |
|---|
| 539 | foreach (@list) { |
|---|
| 540 | $_ =~ s/^([^'].+[^'])$/'$1'/; |
|---|
| 541 | } |
|---|
| 542 | |
|---|
| 543 | my %terms = map { $_ => $terms->{$_} } keys %$terms; |
|---|
| 544 | my %args = map { $_ => $args->{$_} } keys %$args; |
|---|
| 545 | $args{like} = { 'permissions' => 1 }; |
|---|
| 546 | my @ids; |
|---|
| 547 | my @roles = (); |
|---|
| 548 | for my $key (@list) { |
|---|
| 549 | $terms{permissions} = "%" . $key . "%"; |
|---|
| 550 | $terms{id} = \@ids if scalar(@ids); |
|---|
| 551 | |
|---|
| 552 | my @tmp_roles = $pkg->load( \%terms, \%args ); |
|---|
| 553 | unless ( scalar @tmp_roles ) { |
|---|
| 554 | @roles = (); |
|---|
| 555 | last; |
|---|
| 556 | } |
|---|
| 557 | delete $args{not}; # not is used only the first time |
|---|
| 558 | @ids = map { $_->id } @tmp_roles; |
|---|
| 559 | @roles = @tmp_roles; |
|---|
| 560 | } |
|---|
| 561 | return ( wantarray ? () : undef ) unless scalar(@roles); |
|---|
| 562 | if ($exact) { |
|---|
| 563 | my $base_len = length( join( ',', @list ) ); |
|---|
| 564 | @roles = grep { length( $_->permissions ) == $base_len } @roles; |
|---|
| 565 | } |
|---|
| 566 | return wantarray ? @roles : ( ( scalar @roles ) ? $roles[0] : undef ); |
|---|
| 567 | } |
|---|
| 568 | |
|---|
| 569 | sub to_hash { |
|---|
| 570 | my $perms = shift; |
|---|
| 571 | my $hash = {}; # $perms->SUPER::to_hash(@_); |
|---|
| 572 | my $all_perms = MT::Permission->perms(); |
|---|
| 573 | foreach (@$all_perms) { |
|---|
| 574 | my $perm = $_->[0]; |
|---|
| 575 | $perm = 'can_' . $perm; |
|---|
| 576 | $hash->{"permission.$perm"} = $perms->$perm(); |
|---|
| 577 | } |
|---|
| 578 | $hash; |
|---|
| 579 | } |
|---|
| 580 | |
|---|
| 581 | 1; |
|---|
| 582 | __END__ |
|---|
| 583 | |
|---|
| 584 | =head1 NAME |
|---|
| 585 | |
|---|
| 586 | MT::Permission - Movable Type permissions record |
|---|
| 587 | |
|---|
| 588 | =head1 SYNOPSIS |
|---|
| 589 | |
|---|
| 590 | use MT::Permission; |
|---|
| 591 | my $perms = MT::Permission->load({ blog_id => $blog->id, |
|---|
| 592 | author_id => $author->id }) |
|---|
| 593 | or die "User has no permissions for blog"; |
|---|
| 594 | $perms->can_create_post |
|---|
| 595 | or die "User cannot publish to blog"; |
|---|
| 596 | |
|---|
| 597 | $perms->can_edit_config(0); |
|---|
| 598 | $perms->save |
|---|
| 599 | or die $perms->errstr; |
|---|
| 600 | |
|---|
| 601 | =head1 DESCRIPTION |
|---|
| 602 | |
|---|
| 603 | An I<MT::Permission> object represents the permissions settings for a user |
|---|
| 604 | in a particular blog. Permissions are set on a role basis, and each permission |
|---|
| 605 | is either on or off for an user-blog combination; permissions are stored as |
|---|
| 606 | a bitmask. |
|---|
| 607 | |
|---|
| 608 | Note: The I<MT::Permission> object is not meant to be modified or created |
|---|
| 609 | directly. Permissions should be assigned to users through role associations, |
|---|
| 610 | or through MT::Author's can_xxx methods for system level privileges. |
|---|
| 611 | The I<MT::Permission> object is actually managed by Movable Type purely, and |
|---|
| 612 | is a flattened view of all the permissions a particular user has for a single |
|---|
| 613 | blog. Users' system level privileges are also stored in MT::Permission record |
|---|
| 614 | with blog_id = 0. |
|---|
| 615 | |
|---|
| 616 | =head1 USAGE |
|---|
| 617 | |
|---|
| 618 | As a subclass of I<MT::Object>, I<MT::Permission> inherits all of the |
|---|
| 619 | data-management and -storage methods from that class; thus you should look |
|---|
| 620 | at the I<MT::Object> documentation for details about creating a new object, |
|---|
| 621 | loading an existing object, saving an object, etc. |
|---|
| 622 | |
|---|
| 623 | The following methods are unique to the I<MT::Permission> interface. Each of |
|---|
| 624 | these methods, B<except> for I<set_full_permissions>, can be called with an |
|---|
| 625 | optional argument to turn the permission on or off. If the argument is some |
|---|
| 626 | true value, the permission is enabled; otherwise, the permission is disabled. |
|---|
| 627 | If no argument is provided at all, the existing permission setting is |
|---|
| 628 | returned. |
|---|
| 629 | |
|---|
| 630 | =head2 MT::Permission->perms( [ $set ] ) |
|---|
| 631 | |
|---|
| 632 | Returns an array reference containing the list of available permissions. The |
|---|
| 633 | array is a list of permissions, each of which is an array reference with |
|---|
| 634 | the following items: |
|---|
| 635 | |
|---|
| 636 | [ key, label, set ] |
|---|
| 637 | |
|---|
| 638 | The 'key' element is the value of that permission and is also a unique |
|---|
| 639 | identifier that is used to identify the permission. Declared permissions |
|---|
| 640 | may be tested through a 'can' method that is added to the MT::Permission |
|---|
| 641 | namespace when registering them. So if you register with a 'key' value |
|---|
| 642 | of 'foo', this creates a method 'can_foo', which may be tested for like this: |
|---|
| 643 | |
|---|
| 644 | my $perm = $app->permissions; |
|---|
| 645 | if ($perm->can_foo) { |
|---|
| 646 | $app->foo; |
|---|
| 647 | } |
|---|
| 648 | |
|---|
| 649 | The 'label' element is a phrase that identifies the permission. |
|---|
| 650 | |
|---|
| 651 | The 'set' element identifies which group or category of permissions the |
|---|
| 652 | permission is associated with. Currently, there are two sets of |
|---|
| 653 | permissions: 'blog' and 'system'. |
|---|
| 654 | |
|---|
| 655 | If you call the perms method with the $set parameter, it will only return |
|---|
| 656 | permissions declared with that 'set' identifier. |
|---|
| 657 | |
|---|
| 658 | =head2 MT::Permission->add_permission( \%perm ) |
|---|
| 659 | |
|---|
| 660 | =head2 MT::Permission->add_permission( \@perm ) |
|---|
| 661 | |
|---|
| 662 | Both of these methods can be used to register a new permission with |
|---|
| 663 | Movable Type. |
|---|
| 664 | |
|---|
| 665 | Note: It is not advisable to call these method to register custom permissions |
|---|
| 666 | without having preregistered for one from Six Apart, Ltd. This will |
|---|
| 667 | reserve your permission and allow it to coexist with other plugins and |
|---|
| 668 | future permissions defined by Movable Type itself. |
|---|
| 669 | |
|---|
| 670 | When calling add_permission with a hashref, you should specify these |
|---|
| 671 | elements in the hash: |
|---|
| 672 | |
|---|
| 673 | =over 4 |
|---|
| 674 | |
|---|
| 675 | =item * key |
|---|
| 676 | |
|---|
| 677 | =item * label |
|---|
| 678 | |
|---|
| 679 | =item * set |
|---|
| 680 | |
|---|
| 681 | =back |
|---|
| 682 | |
|---|
| 683 | See the 'perms' method documentation for more information on these |
|---|
| 684 | elements. |
|---|
| 685 | |
|---|
| 686 | If calling the add_permission method with an arrayref, you should |
|---|
| 687 | specify the elements of the array in the same order as given by |
|---|
| 688 | the 'perms' method. You may only register one permission per call |
|---|
| 689 | to the add_permission method. |
|---|
| 690 | |
|---|
| 691 | =head2 $perms->set_full_permissions() |
|---|
| 692 | |
|---|
| 693 | Turns on all blog-level permissions. |
|---|
| 694 | |
|---|
| 695 | =head2 $perms->clear_full_permissions() |
|---|
| 696 | |
|---|
| 697 | Turns off all permissions. |
|---|
| 698 | |
|---|
| 699 | =head2 $perms->set_permissions($set) |
|---|
| 700 | |
|---|
| 701 | Sets all permissions identified by the group C<$set> (use '*' to include |
|---|
| 702 | all permissions regardless of grouping). |
|---|
| 703 | |
|---|
| 704 | =head2 $perms->clear_permissions($set) |
|---|
| 705 | |
|---|
| 706 | Clears all permissions identified by the group C<$set> (use '*' to include |
|---|
| 707 | all permissions regardless of grouping). |
|---|
| 708 | |
|---|
| 709 | =head2 $perms->add_permissions($more_perms) |
|---|
| 710 | |
|---|
| 711 | Adds C<$more_perms> to C<$perms>. |
|---|
| 712 | |
|---|
| 713 | =head2 $perms->set_these_permissions(@permission_names) |
|---|
| 714 | |
|---|
| 715 | Adds permissions (enabling them) to the existing permission object. |
|---|
| 716 | |
|---|
| 717 | $perms->set_these_permissions('view_blog_log', 'create_post'); |
|---|
| 718 | |
|---|
| 719 | =head2 MT::Permission->rebuild($assoc) |
|---|
| 720 | |
|---|
| 721 | Rebuilds permission objects affected by the given L<MT::Association> object. |
|---|
| 722 | |
|---|
| 723 | =head2 $perms->rebuild() |
|---|
| 724 | |
|---|
| 725 | Rebuilds the single permission object based on the user/group/role/blog |
|---|
| 726 | relationships that can be found for the author and blog tied to the |
|---|
| 727 | permission. |
|---|
| 728 | |
|---|
| 729 | =head2 $perms->has($permission_name) |
|---|
| 730 | |
|---|
| 731 | Returns true or false depending only on whether the bit identified by |
|---|
| 732 | C<$permission_name> is set in this permission object. |
|---|
| 733 | |
|---|
| 734 | =head2 $perms->can_administer_blog |
|---|
| 735 | |
|---|
| 736 | Returns true if the user can administer the blog. This is a blog-level |
|---|
| 737 | "superuser" capability. |
|---|
| 738 | |
|---|
| 739 | =head2 $perms->can_create_post |
|---|
| 740 | |
|---|
| 741 | Returns true if the user can post to the blog , and edit the entries that |
|---|
| 742 | he/she has posted; false otherwise. |
|---|
| 743 | |
|---|
| 744 | =head2 $perms->can_publish_post |
|---|
| 745 | |
|---|
| 746 | Returns true if the user can publish his/her post; false otherwise. |
|---|
| 747 | |
|---|
| 748 | =head2 $perms->can_post |
|---|
| 749 | |
|---|
| 750 | (Backward compatibility API) Returns true if the user can post to the blog, |
|---|
| 751 | and edit the entries that he/she has posted and publish the post; false otherwise. |
|---|
| 752 | |
|---|
| 753 | =head2 $perms->can_upload |
|---|
| 754 | |
|---|
| 755 | Returns true if the user can upload files to the blog directories specified |
|---|
| 756 | for this blog, false otherwise. |
|---|
| 757 | |
|---|
| 758 | =head2 $perms->can_edit_all_posts |
|---|
| 759 | |
|---|
| 760 | Returns true if the user can edit B<all> entries posted to this blog (even |
|---|
| 761 | entries that he/she did not write), false otherwise. |
|---|
| 762 | |
|---|
| 763 | =head2 $perms->can_edit_templates |
|---|
| 764 | |
|---|
| 765 | Returns true if the user can edit the blog's templates, false otherwise. |
|---|
| 766 | |
|---|
| 767 | =head2 $perms->can_send_notifications |
|---|
| 768 | |
|---|
| 769 | Returns true if the user can send messages to the notification list, false |
|---|
| 770 | otherwise. |
|---|
| 771 | |
|---|
| 772 | =head2 $perms->can_edit_categories |
|---|
| 773 | |
|---|
| 774 | Returns true if the user can edit the categories defined for the blog, false |
|---|
| 775 | otherwise. |
|---|
| 776 | |
|---|
| 777 | =head2 $perms->can_edit_tags |
|---|
| 778 | |
|---|
| 779 | Returns true if the user can edit the tags defined for the blog, false |
|---|
| 780 | otherwise. |
|---|
| 781 | |
|---|
| 782 | =head2 $perms->can_edit_notifications |
|---|
| 783 | |
|---|
| 784 | Returns true if the user can edit the notification list for the blog, false |
|---|
| 785 | otherwise. |
|---|
| 786 | |
|---|
| 787 | =head2 $perms->can_view_blog_log |
|---|
| 788 | |
|---|
| 789 | Returns true if the user can view the activity log for the blog, false |
|---|
| 790 | otherwise. |
|---|
| 791 | |
|---|
| 792 | =head2 $perms->can_rebuild |
|---|
| 793 | |
|---|
| 794 | Returns true if the user can edit the rebuild the blog, false otherwise. |
|---|
| 795 | |
|---|
| 796 | =head2 $perms->can_edit_config |
|---|
| 797 | |
|---|
| 798 | Returns true if the user can edit the blog configuration, false otherwise. |
|---|
| 799 | |
|---|
| 800 | (Backward compatibility warning) can_edit_config no longer means the user |
|---|
| 801 | can set and modify publishing paths (site_path, site_url, archive_path and |
|---|
| 802 | archive_url) for the weblog. Use can_set_publish_paths. |
|---|
| 803 | |
|---|
| 804 | =head2 $perms->can_set_publish_paths |
|---|
| 805 | |
|---|
| 806 | Returns true if the user can set publishing paths, false otherwise. |
|---|
| 807 | |
|---|
| 808 | =head2 $perms->can_edit_authors() |
|---|
| 809 | |
|---|
| 810 | Returns true if the 'administer_blog' permission is set or the associated |
|---|
| 811 | author has superuser rights. |
|---|
| 812 | |
|---|
| 813 | =head2 $perms->can_edit_entry($entry, $author) |
|---|
| 814 | |
|---|
| 815 | Returns true if the C<$author> has rights to edit entry C<$entry>. This |
|---|
| 816 | is always true if C<$author> is a superuser or can edit all posts or |
|---|
| 817 | is a blog administrator for the blog that contains the entry. Otherwise, |
|---|
| 818 | it returns true if the author has permission to post and the entry was |
|---|
| 819 | authored by that author, false otherwise. |
|---|
| 820 | |
|---|
| 821 | The C<$entry> parameter can either be a I<MT::Entry> object or an entry id. |
|---|
| 822 | |
|---|
| 823 | =head2 $perms->can_manage_feedback |
|---|
| 824 | |
|---|
| 825 | Returns true if the C<$author> has rights to manage feedbacks (comments |
|---|
| 826 | and trackbacks) as well as IP ban list. |
|---|
| 827 | |
|---|
| 828 | =head2 $perms->can_view_feedback |
|---|
| 829 | |
|---|
| 830 | TODO Returns true if permission indicates the user can list comments and trackbacks. |
|---|
| 831 | |
|---|
| 832 | =head2 $perms->can_administer |
|---|
| 833 | |
|---|
| 834 | Returns true if the user in question is a system administrator, false otherwise. |
|---|
| 835 | |
|---|
| 836 | =head2 $perms->can_view_log |
|---|
| 837 | |
|---|
| 838 | Returns true if the user can view system level activity log, false otherwise. |
|---|
| 839 | |
|---|
| 840 | =head2 $perms->can_create_blog |
|---|
| 841 | |
|---|
| 842 | Returns true if the user can create a new weblog, false otherwise. |
|---|
| 843 | |
|---|
| 844 | =head2 $perms->can_manage_plugins |
|---|
| 845 | |
|---|
| 846 | Returns true if the user can enable/disable, and configure plugins in system level, |
|---|
| 847 | false otherwise. |
|---|
| 848 | |
|---|
| 849 | =head2 $perms->can_not_comment |
|---|
| 850 | |
|---|
| 851 | Returns true if the user has been banned from commenting on the blog. |
|---|
| 852 | This permission is used for authenticated commenters. |
|---|
| 853 | |
|---|
| 854 | =head2 $perms->can_comment |
|---|
| 855 | |
|---|
| 856 | Returns true if the user has been approved for commenting on the blog. |
|---|
| 857 | This permission is used for authenticated commenters. |
|---|
| 858 | |
|---|
| 859 | =head2 $perms->blog |
|---|
| 860 | |
|---|
| 861 | Returns the I<MT::Blog> object for this permission object. |
|---|
| 862 | |
|---|
| 863 | =head2 $perms->user |
|---|
| 864 | |
|---|
| 865 | =head2 $perms->author |
|---|
| 866 | |
|---|
| 867 | Returns the I<MT::Author> object for this permission object. The C<author> |
|---|
| 868 | method is deprecated in favor of C<user>. |
|---|
| 869 | |
|---|
| 870 | =head2 $perms->to_hash |
|---|
| 871 | |
|---|
| 872 | Returns a hashref that represents the contents of the permission object. |
|---|
| 873 | Elements are in the form of (enabled permissions are set, disabled |
|---|
| 874 | permissions are set to 0): |
|---|
| 875 | |
|---|
| 876 | { 'permission.can_edit_templates' => 16, |
|---|
| 877 | 'permission.can_rebuild' => 0, |
|---|
| 878 | # .... |
|---|
| 879 | 'permission.can_create_post' => 2 } |
|---|
| 880 | |
|---|
| 881 | =head2 $class->load_same($terms, $args, $exact, @list) |
|---|
| 882 | |
|---|
| 883 | Returns an array or an object depending on context, of permission records |
|---|
| 884 | which have specified list of permissions. If $exact is set to True, permission |
|---|
| 885 | records which have exact match to the list are returned. $terms and $args |
|---|
| 886 | can be used to further narrow down results. |
|---|
| 887 | |
|---|
| 888 | =head1 DATA ACCESS METHODS |
|---|
| 889 | |
|---|
| 890 | The I<MT::Comment> object holds the following pieces of data. These fields can |
|---|
| 891 | be accessed and set using the standard data access methods described in the |
|---|
| 892 | I<MT::Object> documentation. |
|---|
| 893 | |
|---|
| 894 | =over 4 |
|---|
| 895 | |
|---|
| 896 | =item * id |
|---|
| 897 | |
|---|
| 898 | The numeric ID of this permissions record. |
|---|
| 899 | |
|---|
| 900 | =item * author_id |
|---|
| 901 | |
|---|
| 902 | The numeric ID of the user associated with this permissions record. |
|---|
| 903 | |
|---|
| 904 | =item * blog_id |
|---|
| 905 | |
|---|
| 906 | The numeric ID of the blog associated with this permissions record. |
|---|
| 907 | |
|---|
| 908 | =item * role_mask |
|---|
| 909 | |
|---|
| 910 | =item * role_mask2 |
|---|
| 911 | |
|---|
| 912 | =item * role_mask3 |
|---|
| 913 | |
|---|
| 914 | =item * role_mask4 |
|---|
| 915 | |
|---|
| 916 | These bitmask fields are deprecated in favor of text based permissions |
|---|
| 917 | column. |
|---|
| 918 | |
|---|
| 919 | =item * permissions |
|---|
| 920 | |
|---|
| 921 | Permissions are stored in this column like 'Perm1','Perm_2','Pe_rm_3'. |
|---|
| 922 | |
|---|
| 923 | =item * entry_prefs |
|---|
| 924 | |
|---|
| 925 | The setting of display fields of "edit entry" page. The value |
|---|
| 926 | at author_id 0 means default setting of a blog. |
|---|
| 927 | |
|---|
| 928 | =item * template_prefs |
|---|
| 929 | |
|---|
| 930 | The setting of display "edit template" page. The value |
|---|
| 931 | at author_id 0 means default setting of a blog. |
|---|
| 932 | |
|---|
| 933 | =back |
|---|
| 934 | |
|---|
| 935 | =head1 DATA LOOKUP |
|---|
| 936 | |
|---|
| 937 | In addition to numeric ID lookup, you can look up or sort records by any |
|---|
| 938 | combination of the following fields. See the I<load> documentation in |
|---|
| 939 | I<MT::Object> for more information. |
|---|
| 940 | |
|---|
| 941 | =over 4 |
|---|
| 942 | |
|---|
| 943 | =item * blog_id |
|---|
| 944 | |
|---|
| 945 | =item * author_id |
|---|
| 946 | |
|---|
| 947 | =back |
|---|
| 948 | |
|---|
| 949 | =head1 AUTHOR & COPYRIGHTS |
|---|
| 950 | |
|---|
| 951 | Please see the I<MT> manpage for user, copyright, and license information. |
|---|
| 952 | |
|---|
| 953 | =cut |
|---|