diff --git a/classes/Notice.php b/classes/Notice.php index 114119bfc9..83507f3bc0 100644 --- a/classes/Notice.php +++ b/classes/Notice.php @@ -73,6 +73,7 @@ class Notice extends Memcached_DataObject public $location_ns; // int(4) public $repeat_of; // int(4) public $object_type; // varchar(255) + public $scope; // int(4) /* Static get */ function staticGet($k,$v=NULL) @@ -89,6 +90,11 @@ class Notice extends Memcached_DataObject const LOCAL_NONPUBLIC = -1; const GATEWAY = -2; + const SITE_SCOPE = 1; + const ADDRESSEE_SCOPE = 2; + const GROUP_SCOPE = 4; + const FOLLOWER_SCOPE = 8; + function getProfile() { $profile = Profile::staticGet('id', $this->profile_id); @@ -2011,4 +2017,84 @@ class Notice extends Memcached_DataObject ($this->is_local != Notice::GATEWAY)); } } + + /** + * Check that the given profile is allowed to read, respond to, or otherwise + * act on this notice. + * + * The $scope member is a bitmask of scopes, representing a logical AND of the + * scope requirement. So, 0x03 (Notice::ADDRESSEE_SCOPE | Notice::SITE_SCOPE) means + * "only visible to people who are mentioned in the notice AND are users on this site." + * Users on the site who are not mentioned in the notice will not be able to see the + * notice. + * + * @param Profile $profile The profile to check + * + * @return boolean whether the profile is in the notice's scope + */ + + function inScope($profile) + { + // If there's any scope, and there's no logged-in user, + // not allowed. + + if ($this->scope > 0 && empty($profile)) { + return false; + } + + // Only for users on this site + + if ($this->scope & Notice::SITE_SCOPE) { + $user = $profile->getUser(); + if (empty($user)) { + return false; + } + } + + // Only for users mentioned in the notice + + if ($this->scope & Notice::ADDRESSEE_SCOPE) { + + // XXX: just query for the single reply + + $replies = $this->getReplies(); + + if (!in_array($profile->id, $replies)) { + return false; + } + } + + // Only for members of the given group + + if ($this->scope & Notice::GROUP_SCOPE) { + + // XXX: just query for the single membership + + $groups = $this->getGroups(); + + $foundOne = false; + + foreach ($groups as $group) { + if ($profile->isMember($group)) { + $foundOne = true; + break; + } + } + + if (!$foundOne) { + return false; + } + } + + // Only for followers of the author + + if ($this->scope & Notice::FOLLOWER_SCOPE) { + $author = $this->getProfile(); + if (!Subscription::exists($profile, $author)) { + return false; + } + } + + return true; + } } diff --git a/classes/Profile.php b/classes/Profile.php index b582451350..b6b05f6a4f 100644 --- a/classes/Profile.php +++ b/classes/Profile.php @@ -1090,4 +1090,44 @@ class Profile extends Memcached_DataObject return $profile; } + + function canRead(Notice $notice) + { + if ($notice->scope & Notice::SITE_SCOPE) { + $user = $this->getUser(); + if (empty($user)) { + return false; + } + } + + if ($notice->scope & Notice::ADDRESSEE_SCOPE) { + $replies = $notice->getReplies(); + + if (!in_array($this->id, $replies)) { + $groups = $notice->getGroups(); + + $foundOne = false; + + foreach ($groups as $group) { + if ($this->isMember($group)) { + $foundOne = true; + break; + } + } + + if (!$foundOne) { + return false; + } + } + } + + if ($notice->scope & Notice::FOLLOWER_SCOPE) { + $author = $notice->getProfile(); + if (!Subscription::exists($this, $author)) { + return false; + } + } + + return true; + } } diff --git a/classes/statusnet.ini b/classes/statusnet.ini index f648fb3fbf..12c59daae0 100644 --- a/classes/statusnet.ini +++ b/classes/statusnet.ini @@ -337,6 +337,7 @@ location_id = 1 location_ns = 1 repeat_of = 1 object_type = 2 +scope = 1 [notice__keys] id = N diff --git a/db/core.php b/db/core.php index 928186d94d..3e439e5010 100644 --- a/db/core.php +++ b/db/core.php @@ -202,6 +202,9 @@ $schema['notice'] = array( 'location_ns' => array('type' => 'int', 'description' => 'namespace for location'), 'repeat_of' => array('type' => 'int', 'description' => 'notice this is a repeat of'), 'object_type' => array('type' => 'varchar', 'length' => 255, 'description' => 'URI representing activity streams object type', 'default' => 'http://activitystrea.ms/schema/1.0/note'), + 'scope' => array('type' => 'int', + 'default' => '1', + 'description' => 'bit map for distribution scope; 0 = everywhere; 1 = this server only; 2 = addressees; 4 = followers'), ), 'primary key' => array('id'), 'unique keys' => array(