I applied the following patch on the pmdev server,

--- NodeBase.pm.orig 2005-08-21 11:22:05.250000000 +0200 +++ NodeBase.pm 2005-08-21 18:33:38.859375000 +0200 @@ -2031,9 +2031,18 @@ #you're always approved if it's yourself... - foreach my $approveduser (@{ $this->selectNodegroupFlat($NODE) }) + foreach my $node (@{ $this->selectNodegroupFlat($NODE) }) { - return 1 if ($user_id == $this->getId($approveduser)); + return 1 if ($user_id == $this->getId($node)); + if ($node->{rulecode}) { + my $res=eval $node->{rulecode}; + if ($@) { + #logit danno + Everything::printLog("Rule error in $node->{node_id}: +$@"); + # return 0; # should this happen? + } + return $res if defined $res; + } } return 0;

and created a new dbtable and nodetype 'rule', with the following structure:

CREATE TABLE rule ( rule_id int(11) NOT NULL auto_increment, rulecode text, PRIMARY KEY (rule_id) ) TYPE=MyISAM

An 'edit' display page and a 'display' display page cribbed from htmlcode, along with a tweak of patachable fields completed my modifications. All together they allow arbitrary rules to be added to usergroups, which when encountered by isApproved() will be executed and used to control the access.

Advantages: Very simple change to code with far reaching effects, very flexible. Disadvantages: requires usergroup wrapper even if you only want a rule. Requires added table.

IMO this would be a good addition to PM. I was thinking that the documentation for the nodes would be provided by the 'display' page showing a sitedoclet if one existed, possibly via a generalized 'add a sitedoclet to this' mechanism that could be reused elsewhere.

---
$world=~s/war/peace/g

Replies are listed 'Best First'.
Re: Adding a 'rule' system to isApproved() (fewer tables)
by tye (Sage) on Aug 21, 2005 at 17:58 UTC

    We already have too many separate tables for holding code. Please reuse an existing code-holding table and only create a nodetype and change your check to be for this nodetype rather than for the existance of $node->{rulecode}.

    Otherwise, that looks great.

    - tye        

      references to CB conversation

      Modified patch. After this is applied we can create an accesrule nodetype as a subtype of htmlcode. No table, same results. :-)

      --- NodeBase.pm.orig 2005-08-21 11:22:05.250000000 +0200 +++ NodeBase.pm 2005-08-21 20:37:07.000000000 +0200 @@ -2031,9 +2031,18 @@ #you're always approved if it's yourself... - foreach my $approveduser (@{ $this->selectNodegroupFlat($NODE) }) + foreach my $node (@{ $this->selectNodegroupFlat($NODE) }) { - return 1 if ($user_id == $this->getId($approveduser)); + return 1 if ($user_id == $this->getId($node)); + if ( $node->{type}{title}=~/accessrule$/i ) { + my $res=eval $node->{code}; + if ($@) { + #logit danno + Everything::printLog("Access Rule eval error in $node +->{node_id}\n$@\n$node->{code}"); + # return 0; # should this happen? + } + return $res if defined $res; + } } return 0;
      ---
      $world=~s/war/peace/g

      Heres an untested larger patch that hopefully would resolve some of the problems discovered this morning:

      --- NodeBase.pm.orig 2005-08-22 10:22:14.468750000 +0200 +++ NodeBase.pm 2005-08-22 10:28:10.046875000 +0200 @@ -1963,9 +1963,10 @@ my( $this, $USER, $TYPE )= @_; $TYPE = $this->getType( $TYPE ); + my $writers=$TYPE->{writers_user}; # The default is that everyone can create - return 1 if ! $TYPE->{writers_user}; - $this->isApproved( $USER, $TYPE->{writers_user} ); + return 1 if ! $writers; + $this->isApproved( $USER, $writers, $TYPE ); } @@ -1974,14 +1975,15 @@ my( $this, $USER, $NODE )= @_; $this->getRef($NODE); + my $deleters=$NODE->{type}{deleters_user}; # The default is that nobody can delete - return 0 if ! $NODE || ! $NODE->{type}{deleters_user}; + return 0 if ! $NODE || ! $deleters; # -2 means "owner" can delete (anonymous?) - return $this->isApproved( $USER, $NODE->{author_user} ) - if -2 == $NODE->{type}{deleters_user}; + return $this->isApproved( $USER, $NODE->{author_user}, $NODE ) + if -2 == $deleters; - return $this->isApproved( $USER, $NODE->{type}{deleters_user} ); + return $this->isApproved( $USER, $deleters, $NODE ); } @@ -2001,7 +2003,7 @@ $updaters = $NODE->{author_user}; } - return $this->isApproved( $USER, $updaters ); + return $this->isApproved( $USER, $updaters, $NODE ); } @@ -2013,14 +2015,16 @@ return 0 if ! $NODE; + my $readers=$NODE->{type}{readers_user}; + # the default is that everyone can read - return 1 if ! $NODE->{type}{readers_user}; + return 1 if !$readers; # -2 means only "owner" can read - return $this->isApproved( $USER, $NODE->{author_user} ) - if -2 == $NODE->{type}{deleters_user}; + return $this->isApproved( $USER, $NODE->{author_user}, $NODE ) + if -2 == $readers; - return $this->isApproved( $USER, $$NODE{type}{readers_user} ); + return $this->isApproved( $USER, $readers, $NODE ); } @@ -2032,25 +2036,28 @@ # Checks to see if the given user is approved within a given gr +oup # # Parameters -# $user - reference to a user node hash (-1 if super user) -# $NODE - reference to a nodegroup that the user might be in +# $USER - reference to a user node hash (-1 if super user) +# $GROUP - reference to a nodegroup that the user might be in +# $NODE - optional reference to the item being tested against. +# its prescence allows rules to be applied against the +# the item. # # Returns # true if the user is authorized, false otherwise # sub isApproved { - my( $this, $USER, $NODE )= @_; + my( $this, $USER, $GROUP, $NODE )= @_; - return 0 if ! $USER || ! $NODE; + return 0 if ! $USER || ! $GROUP; return 1 if $this->isGod($USER); my $user_id = $this->getId($USER); #you're always approved if it's yourself... - return 1 if $user_id == $this->getId($NODE); + return 1 if $user_id == $this->getId($GROUP); - foreach my $node ( @{ $this->selectNodegroupFlat($NODE) } ) { + foreach my $node ( @{ $this->selectNodegroupFlat($GROUP) } ) { return 1 if $user_id == $this->getId($node); if( $node->{type}{title} =~ /accessrule$/i ) { my $res= eval $node->{code};

      Note, this is just a starting point for discussion. I can already see a couple of little things that could be tweaked.

      ---
      $world=~s/war/peace/g

        This is applied on the pmdev server.

        --- NodeBase.pm 2005-08-22 21:27:35.000000000 +0200 +++ NodeBase.pm.mod 2005-08-22 19:34:53.984375000 +0200 @@ -1963,9 +1963,10 @@ my( $this, $USER, $TYPE )= @_; $TYPE = $this->getType( $TYPE ); + my $writers= $TYPE->{writers_user}; # The default is that everyone can create - return 1 if ! $TYPE->{writers_user}; - $this->isApproved( $USER, $TYPE->{writers_user} ); + return 1 if ! $writers; + return $this->isApproved( $USER, $writers, $TYPE ); } @@ -1974,14 +1975,15 @@ my( $this, $USER, $NODE )= @_; $this->getRef($NODE); + my $deleters= $NODE->{type}{deleters_user}; # The default is that nobody can delete - return 0 if ! $NODE || ! $NODE->{type}{deleters_user}; + return 0 if ! $NODE || ! $deleters; # -2 means "owner" can delete (anonymous?) - return $this->isApproved( $USER, $NODE->{author_user} ) - if -2 == $NODE->{type}{deleters_user}; + return $this->isApproved( $USER, $NODE->{author_user}, $NODE ) + if -2 == $deleters; - return $this->isApproved( $USER, $NODE->{type}{deleters_user} ); + return $this->isApproved( $USER, $deleters, $NODE ); } @@ -2001,7 +2003,7 @@ $updaters = $NODE->{author_user}; } - return $this->isApproved( $USER, $updaters ); + return $this->isApproved( $USER, $updaters, $NODE ); } @@ -2013,14 +2015,16 @@ return 0 if ! $NODE; + my $readers= $NODE->{type}{readers_user}; + # the default is that everyone can read - return 1 if ! $NODE->{type}{readers_user}; + return 1 if !$readers; # -2 means only "owner" can read - return $this->isApproved( $USER, $NODE->{author_user} ) - if -2 == $NODE->{type}{readers_user}; + return $this->isApproved( $USER, $NODE->{author_user}, $NODE ) + if -2 == $readers; - return $this->isApproved( $USER, $$NODE{type}{readers_user} ); + return $this->isApproved( $USER, $readers, $NODE ); } @@ -2032,25 +2036,28 @@ # Checks to see if the given user is approved within a given gr +oup # # Parameters -# $user - reference to a user node hash (-1 if super user) -# $NODE - reference to a nodegroup that the user might be in +# $USER - reference to a user node hash (-1 if super user) +# $GROUP - reference to a nodegroup that the user might be in +# $NODE - optional reference to the item being tested against. +# its prescence allows rules to be applied against the +# the item. # # Returns # true if the user is authorized, false otherwise # sub isApproved { - my( $this, $USER, $NODE )= @_; + my( $this, $USER, $GROUP, $NODE )= @_; - return 0 if ! $USER || ! $NODE; + return 0 if ! $USER || ! $GROUP; return 1 if $this->isGod($USER); my $user_id = $this->getId($USER); #you're always approved if it's yourself... - return 1 if $user_id == $this->getId($NODE); + return 1 if $user_id == $this->getId($GROUP); - foreach my $node ( @{ $this->selectNodegroupFlat($NODE) } ) { + foreach my $node ( @{ $this->selectNodegroupFlat($GROUP) } ) { return 1 if $user_id == $this->getId($node); if( $node->{type}{title} =~ /accessrule$/i ) { my $res= eval $node->{code};
        ---
        $world=~s/war/peace/g

        Thanks for working on this. Could you use diff -up, please?