Exemplo n.º 1
0
 public function onEndPersonalGroupNav(Menu $menu, Profile $target, Profile $scoped = null)
 {
     $menu->out->menuItem(common_local_url('showfavorites', array('nickname' => $target->getNickname())), _m('MENU', 'Favorites'), sprintf(_('%s\'s favorite notices'), $target->getBestName()), $scoped instanceof Profile && $target->id === $scoped->id && $menu->actionName == 'showfavorites', 'nav_timeline_favorites');
 }
Exemplo n.º 2
0
 static function saveActivity(Activity $act, Profile $actor, array $options = array())
 {
     // First check if we're going to let this Activity through from the specific actor
     if (!$actor->hasRight(Right::NEWNOTICE)) {
         common_log(LOG_WARNING, "Attempted post from user disallowed to post: " . $actor->getNickname());
         // TRANS: Client exception thrown when a user tries to post while being banned.
         throw new ClientException(_m('You are banned from posting notices on this site.'), 403);
     }
     if (common_config('throttle', 'enabled') && !self::checkEditThrottle($actor->id)) {
         common_log(LOG_WARNING, 'Excessive posting by profile #' . $actor->id . '; throttled.');
         // TRANS: Client exception thrown when a user tries to post too many notices in a given time frame.
         throw new ClientException(_m('Too many notices too fast; take a breather ' . 'and post again in a few minutes.'));
     }
     // Get ActivityObject properties
     $actobj = null;
     if (!empty($act->id)) {
         // implied object
         $options['uri'] = $act->id;
         $options['url'] = $act->link;
     } else {
         $actobj = count($act->objects) == 1 ? $act->objects[0] : null;
         if (!is_null($actobj) && !empty($actobj->id)) {
             $options['uri'] = $actobj->id;
             if ($actobj->link) {
                 $options['url'] = $actobj->link;
             } elseif (preg_match('!^https?://!', $actobj->id)) {
                 $options['url'] = $actobj->id;
             }
         }
     }
     $defaults = array('groups' => array(), 'is_local' => $actor->isLocal() ? self::LOCAL_PUBLIC : self::REMOTE, 'mentions' => array(), 'reply_to' => null, 'repeat_of' => null, 'scope' => null, 'source' => 'unknown', 'tags' => array(), 'uri' => null, 'url' => null, 'urls' => array(), 'distribute' => true);
     // options will have default values when nothing has been supplied
     $options = array_merge($defaults, $options);
     foreach (array_keys($defaults) as $key) {
         // Only convert the keynames we specify ourselves from 'defaults' array into variables
         ${$key} = $options[$key];
     }
     extract($options, EXTR_SKIP);
     // dupe check
     $stored = new Notice();
     if (!empty($uri) && !ActivityUtils::compareVerbs($act->verb, array(ActivityVerb::DELETE))) {
         $stored->uri = $uri;
         if ($stored->find()) {
             common_debug('cannot create duplicate Notice URI: ' . $stored->uri);
             // I _assume_ saving a Notice with a colliding URI means we're really trying to
             // save the same notice again...
             throw new AlreadyFulfilledException('Notice URI already exists');
         }
     }
     $autosource = common_config('public', 'autosource');
     // Sandboxed are non-false, but not 1, either
     if (!$actor->hasRight(Right::PUBLICNOTICE) || $source && $autosource && in_array($source, $autosource)) {
         // FIXME: ...what about remote nonpublic? Hmmm. That is, if we sandbox remote profiles...
         $stored->is_local = Notice::LOCAL_NONPUBLIC;
     } else {
         $stored->is_local = intval($is_local);
     }
     if (!$stored->isLocal()) {
         // Only do these checks for non-local notices. Local notices will generate these values later.
         if (!common_valid_http_url($url)) {
             common_debug('Bad notice URL: [' . $url . '], URI: [' . $uri . ']. Cannot link back to original! This is normal for shared notices etc.');
         }
         if (empty($uri)) {
             throw new ServerException('No URI for remote notice. Cannot accept that.');
         }
     }
     $stored->profile_id = $actor->id;
     $stored->source = $source;
     $stored->uri = $uri;
     $stored->url = $url;
     $stored->verb = $act->verb;
     // Notice content. We trust local users to provide HTML we like, but of course not remote users.
     // FIXME: What about local users importing feeds? Mirror functions must filter out bad HTML first...
     $content = $act->content ?: $act->summary;
     if (is_null($content) && !is_null($actobj)) {
         $content = $actobj->content ?: $actobj->summary;
     }
     $stored->rendered = $actor->isLocal() ? $content : common_purify($content);
     // yeah, just don't use getRendered() here since it's not inserted yet ;)
     $stored->content = common_strip_html($stored->rendered);
     // Maybe a missing act-time should be fatal if the actor is not local?
     if (!empty($act->time)) {
         $stored->created = common_sql_date($act->time);
     } else {
         $stored->created = common_sql_now();
     }
     $reply = null;
     if ($act->context instanceof ActivityContext && !empty($act->context->replyToID)) {
         $reply = self::getKV('uri', $act->context->replyToID);
     }
     if (!$reply instanceof Notice && $act->target instanceof ActivityObject) {
         $reply = self::getKV('uri', $act->target->id);
     }
     if ($reply instanceof Notice) {
         if (!$reply->inScope($actor)) {
             // TRANS: Client error displayed when trying to reply to a notice a the target has no access to.
             // TRANS: %1$s is a user nickname, %2$d is a notice ID (number).
             throw new ClientException(sprintf(_m('%1$s has no right to reply to notice %2$d.'), $actor->getNickname(), $reply->id), 403);
         }
         $stored->reply_to = $reply->id;
         $stored->conversation = $reply->conversation;
         // If the original is private to a group, and notice has no group specified,
         // make it to the same group(s)
         if (empty($groups) && $reply->scope & Notice::GROUP_SCOPE) {
             $replyGroups = $reply->getGroups();
             foreach ($replyGroups as $group) {
                 if ($actor->isMember($group)) {
                     $groups[] = $group->id;
                 }
             }
         }
         if (is_null($scope)) {
             $scope = $reply->scope;
         }
     } else {
         // If we don't know the reply, we might know the conversation!
         // This will happen if a known remote user replies to an
         // unknown remote user - within a known conversation.
         if (empty($stored->conversation) and !empty($act->context->conversation)) {
             $conv = Conversation::getKV('uri', $act->context->conversation);
             if ($conv instanceof Conversation) {
                 common_debug('Conversation stitched together from (probably) a reply activity to unknown remote user. Activity creation time (' . $stored->created . ') should maybe be compared to conversation creation time (' . $conv->created . ').');
             } else {
                 // Conversation entry with specified URI was not found, so we must create it.
                 common_debug('Conversation URI not found, so we will create it with the URI given in the context of the activity: ' . $act->context->conversation);
                 // The insert in Conversation::create throws exception on failure
                 $conv = Conversation::create($act->context->conversation, $stored->created);
             }
             $stored->conversation = $conv->getID();
             unset($conv);
         }
     }
     // If it's not part of a conversation, it's the beginning of a new conversation.
     if (empty($stored->conversation)) {
         $conv = Conversation::create();
         $stored->conversation = $conv->getID();
         unset($conv);
     }
     $notloc = null;
     if ($act->context instanceof ActivityContext) {
         if ($act->context->location instanceof Location) {
             $notloc = Notice_location::fromLocation($act->context->location);
         }
     } else {
         $act->context = new ActivityContext();
     }
     $stored->scope = self::figureOutScope($actor, $groups, $scope);
     foreach ($act->categories as $cat) {
         if ($cat->term) {
             $term = common_canonical_tag($cat->term);
             if (!empty($term)) {
                 $tags[] = $term;
             }
         }
     }
     foreach ($act->enclosures as $href) {
         // @todo FIXME: Save these locally or....?
         $urls[] = $href;
     }
     if (ActivityUtils::compareVerbs($stored->verb, array(ActivityVerb::POST))) {
         if (empty($act->objects[0]->type)) {
             // Default type for the post verb is 'note', but we know it's
             // a 'comment' if it is in reply to something.
             $stored->object_type = empty($stored->reply_to) ? ActivityObject::NOTE : ActivityObject::COMMENT;
         } else {
             //TODO: Is it safe to always return a relative URI? The
             // JSON version of ActivityStreams always use it, so we
             // should definitely be able to handle it...
             $stored->object_type = ActivityUtils::resolveUri($act->objects[0]->type, true);
         }
     }
     if (Event::handle('StartNoticeSave', array(&$stored))) {
         // XXX: some of these functions write to the DB
         try {
             $result = $stored->insert();
             // throws exception on error
             if ($notloc instanceof Notice_location) {
                 $notloc->notice_id = $stored->getID();
                 $notloc->insert();
             }
             $orig = clone $stored;
             // for updating later in this try clause
             $object = null;
             Event::handle('StoreActivityObject', array($act, $stored, $options, &$object));
             if (empty($object)) {
                 throw new ServerException('Unsuccessful call to StoreActivityObject ' . $stored->getUri() . ': ' . $act->asString());
             }
             // If something changed in the Notice during StoreActivityObject
             $stored->update($orig);
         } catch (Exception $e) {
             if (empty($stored->id)) {
                 common_debug('Failed to save stored object entry in database (' . $e->getMessage() . ')');
             } else {
                 common_debug('Failed to store activity object in database (' . $e->getMessage() . '), deleting notice id ' . $stored->id);
                 $stored->delete();
             }
             throw $e;
         }
     }
     if (!$stored instanceof Notice) {
         throw new ServerException('StartNoticeSave did not give back a Notice');
     }
     // Only save 'attention' and metadata stuff (URLs, tags...) stuff if
     // the activityverb is a POST (since stuff like repeat, favorite etc.
     // reasonably handle notifications themselves.
     if (ActivityUtils::compareVerbs($stored->verb, array(ActivityVerb::POST))) {
         if (!empty($tags)) {
             $stored->saveKnownTags($tags);
         } else {
             $stored->saveTags();
         }
         // Note: groups may save tags, so must be run after tags are saved
         // to avoid errors on duplicates.
         $stored->saveAttentions($act->context->attention);
         if (!empty($urls)) {
             $stored->saveKnownUrls($urls);
         } else {
             $stored->saveUrls();
         }
     }
     if ($distribute) {
         // Prepare inbox delivery, may be queued to background.
         $stored->distribute();
     }
     return $stored;
 }
Exemplo n.º 3
0
 */
define('INSTALLDIR', realpath(dirname(__FILE__) . '/..'));
$shortoptions = 'y';
$longoptions = array('yes');
$helptext = <<<END_OF_HELP
clean_profiles.php [options]
Deletes all profile table entries where the profile does not occur in the
notice table, is not a group and is not a local user. Very MySQL specific I think.

WARNING: This has not been tested thoroughly. Maybe we've missed a table to compare somewhere.

  -y --yes      do not wait for confirmation

END_OF_HELP;
require_once INSTALLDIR . '/scripts/commandline.inc';
if (!have_option('y', 'yes')) {
    print "About to delete profiles that we think are useless to save. Are you sure? [y/N] ";
    $response = fgets(STDIN);
    if (strtolower(trim($response)) != 'y') {
        print "Aborting.\n";
        exit(0);
    }
}
print "Deleting";
$profile = new Profile();
$profile->query('SELECT * FROM profile WHERE ' . 'NOT (SELECT COUNT(*) FROM notice WHERE profile_id=profile.id) ' . 'AND NOT (SELECT COUNT(*) FROM user WHERE user.id=profile.id) ' . 'AND NOT (SELECT COUNT(*) FROM user_group WHERE user_group.profile_id=profile.id) ' . 'AND NOT (SELECT COUNT(*) FROM subscription WHERE subscriber=profile.id OR subscribed=profile.id) ');
while ($profile->fetch()) {
    echo ' ' . $profile->getID() . ':' . $profile->getNickname();
    $profile->delete();
}
print "\nDONE.\n";
Exemplo n.º 4
0
 function relationshipDetailsArray(Profile $source, Profile $target)
 {
     $details = array();
     $details['screen_name'] = $source->getNickname();
     $details['followed_by'] = $target->isSubscribed($source);
     try {
         $sub = Subscription::getSubscription($source, $target);
         $details['following'] = true;
         $details['notifications_enabled'] = $sub->jabber || $sub->sms;
     } catch (NoResultException $e) {
         $details['following'] = false;
         $details['notifications_enabled'] = false;
     }
     $details['blocking'] = $source->hasBlocked($target);
     $details['id'] = intval($source->id);
     return $details;
 }
Exemplo n.º 5
0
 function onEndPersonalGroupNav(Menu $menu, Profile $target, Profile $scoped = null)
 {
     $menu->menuItem(common_local_url('events', array('nickname' => $target->getNickname())), _m('Happenings'), _m('A list of your events'), false, 'nav_timeline_events');
     return true;
 }
 public function onEndPersonalGroupNav(Menu $menu, Profile $target, Profile $scoped = null)
 {
     if ($scoped instanceof Profile && $scoped->id == $target->id && !common_config('singleuser', 'enabled')) {
         $menu->out->menuItem(common_local_url('inbox', array('nickname' => $target->getNickname())), _m('MENU', 'Messages'), _('Your incoming messages'), $scoped->id === $target->id && $menu->actionName == 'inbox');
     }
 }
Exemplo n.º 7
0
 static function filename(Profile $profile, $origname, $mimetype)
 {
     $ext = self::guessMimeExtension($mimetype);
     // Normalize and make the original filename more URL friendly.
     $origname = basename($origname, ".{$ext}");
     if (class_exists('Normalizer')) {
         // http://php.net/manual/en/class.normalizer.php
         // http://www.unicode.org/reports/tr15/
         $origname = Normalizer::normalize($origname, Normalizer::FORM_KC);
     }
     $origname = preg_replace('/[^A-Za-z0-9\\.\\_]/', '_', $origname);
     $nickname = $profile->getNickname();
     $datestamp = strftime('%Y%m%d', time());
     do {
         // generate new random strings until we don't run into a filename collision.
         $random = strtolower(common_confirmation_code(16));
         $filename = "{$nickname}-{$datestamp}-{$origname}-{$random}.{$ext}";
     } while (file_exists(self::path($filename)));
     return $filename;
 }
Exemplo n.º 8
0
 static function saveActivity(Activity $act, Profile $actor, array $options = array())
 {
     // First check if we're going to let this Activity through from the specific actor
     if (!$actor->hasRight(Right::NEWNOTICE)) {
         common_log(LOG_WARNING, "Attempted post from user disallowed to post: " . $actor->getNickname());
         // TRANS: Client exception thrown when a user tries to post while being banned.
         throw new ClientException(_m('You are banned from posting notices on this site.'), 403);
     }
     if (common_config('throttle', 'enabled') && !self::checkEditThrottle($actor->id)) {
         common_log(LOG_WARNING, 'Excessive posting by profile #' . $actor->id . '; throttled.');
         // TRANS: Client exception thrown when a user tries to post too many notices in a given time frame.
         throw new ClientException(_m('Too many notices too fast; take a breather ' . 'and post again in a few minutes.'));
     }
     // Get ActivityObject properties
     if (!empty($act->id)) {
         // implied object
         $options['uri'] = $act->id;
         $options['url'] = $act->link;
     } else {
         $actobj = count($act->objects) == 1 ? $act->objects[0] : null;
         if (!is_null($actobj) && !empty($actobj->id)) {
             $options['uri'] = $actobj->id;
             if ($actobj->link) {
                 $options['url'] = $actobj->link;
             } elseif (preg_match('!^https?://!', $actobj->id)) {
                 $options['url'] = $actobj->id;
             }
         }
     }
     $defaults = array('groups' => array(), 'is_local' => self::LOCAL_PUBLIC, 'mentions' => array(), 'reply_to' => null, 'repeat_of' => null, 'scope' => null, 'source' => 'unknown', 'tags' => array(), 'uri' => null, 'url' => null, 'urls' => array(), 'distribute' => true);
     // options will have default values when nothing has been supplied
     $options = array_merge($defaults, $options);
     foreach (array_keys($defaults) as $key) {
         // Only convert the keynames we specify ourselves from 'defaults' array into variables
         ${$key} = $options[$key];
     }
     extract($options, EXTR_SKIP);
     $stored = new Notice();
     if (!empty($uri)) {
         $stored->uri = $uri;
         if ($stored->find()) {
             common_debug('cannot create duplicate Notice URI: ' . $stored->uri);
             throw new Exception('Notice URI already exists');
         }
     }
     $stored->profile_id = $actor->id;
     $stored->source = $source;
     $stored->uri = $uri;
     $stored->url = $url;
     $stored->verb = $act->verb;
     // Use the local user's shortening preferences, if applicable.
     $stored->rendered = $actor->isLocal() ? $actor->shortenLinks($act->content) : $act->content;
     $stored->content = common_strip_html($stored->rendered);
     $autosource = common_config('public', 'autosource');
     // Sandboxed are non-false, but not 1, either
     if (!$actor->hasRight(Right::PUBLICNOTICE) || $source && $autosource && in_array($source, $autosource)) {
         $stored->is_local = Notice::LOCAL_NONPUBLIC;
     }
     // Maybe a missing act-time should be fatal if the actor is not local?
     if (!empty($act->time)) {
         $stored->created = common_sql_date($act->time);
     } else {
         $stored->created = common_sql_now();
     }
     $reply = null;
     if ($act->context instanceof ActivityContext && !empty($act->context->replyToID)) {
         $reply = self::getKV('uri', $act->context->replyToID);
     }
     if (!$reply instanceof Notice && $act->target instanceof ActivityObject) {
         $reply = self::getKV('uri', $act->target->id);
     }
     if ($reply instanceof Notice) {
         if (!$reply->inScope($actor)) {
             // TRANS: Client error displayed when trying to reply to a notice a the target has no access to.
             // TRANS: %1$s is a user nickname, %2$d is a notice ID (number).
             throw new ClientException(sprintf(_m('%1$s has no right to reply to notice %2$d.'), $actor->getNickname(), $reply->id), 403);
         }
         $stored->reply_to = $reply->id;
         $stored->conversation = $reply->conversation;
         // If the original is private to a group, and notice has no group specified,
         // make it to the same group(s)
         if (empty($groups) && $reply->scope & Notice::GROUP_SCOPE) {
             $groups = array();
             $replyGroups = $reply->getGroups();
             foreach ($replyGroups as $group) {
                 if ($actor->isMember($group)) {
                     $groups[] = $group->id;
                 }
             }
         }
         if (is_null($scope)) {
             $scope = $reply->scope;
         }
     }
     if ($act->context instanceof ActivityContext) {
         $location = $act->context->location;
         if ($location) {
             $stored->lat = $location->lat;
             $stored->lon = $location->lon;
             if ($location->location_id) {
                 $stored->location_ns = $location->location_ns;
                 $stored->location_id = $location->location_id;
             }
         }
     } else {
         $act->context = new ActivityContext();
     }
     $stored->scope = self::figureOutScope($actor, $groups, $scope);
     foreach ($act->categories as $cat) {
         if ($cat->term) {
             $term = common_canonical_tag($cat->term);
             if (!empty($term)) {
                 $tags[] = $term;
             }
         }
     }
     foreach ($act->enclosures as $href) {
         // @todo FIXME: Save these locally or....?
         $urls[] = $href;
     }
     if (Event::handle('StartNoticeSave', array(&$stored))) {
         // XXX: some of these functions write to the DB
         try {
             $stored->insert();
             // throws exception on error
             $orig = clone $stored;
             // for updating later in this try clause
             $object = null;
             Event::handle('StoreActivityObject', array($act, $stored, $options, &$object));
             if (empty($object)) {
                 throw new ServerException('Unsuccessful call to StoreActivityObject ' . $stored->uri . ': ' . $act->asString());
             }
             // If it's not part of a conversation, it's
             // the beginning of a new conversation.
             if (empty($stored->conversation)) {
                 // $act->context->conversation will be null if it was not provided
                 $conv = Conversation::create($stored, $act->context->conversation);
                 $stored->conversation = $conv->id;
             }
             $stored->update($orig);
         } catch (Exception $e) {
             if (empty($stored->id)) {
                 common_debug('Failed to save stored object entry in database (' . $e->getMessage() . ')');
             } else {
                 common_debug('Failed to store activity object in database (' . $e->getMessage() . '), deleting notice id ' . $stored->id);
                 $stored->delete();
             }
             throw $e;
         }
     }
     if (!$stored instanceof Notice) {
         throw new ServerException('StartNoticeSave did not give back a Notice');
     }
     // Save per-notice metadata...
     $mentions = array();
     $groups = array();
     // This event lets plugins filter out non-local recipients (attentions we don't care about)
     // Used primarily for OStatus (and if we don't federate, all attentions would be local anyway)
     Event::handle('GetLocalAttentions', array($actor, $act->context->attention, &$mentions, &$groups));
     if (!empty($mentions)) {
         $stored->saveKnownReplies($mentions);
     } else {
         $stored->saveReplies();
     }
     if (!empty($tags)) {
         $stored->saveKnownTags($tags);
     } else {
         $stored->saveTags();
     }
     // Note: groups may save tags, so must be run after tags are saved
     // to avoid errors on duplicates.
     // Note: groups should always be set.
     $stored->saveKnownGroups($groups);
     if (!empty($urls)) {
         $stored->saveKnownUrls($urls);
     } else {
         $stored->saveUrls();
     }
     if ($distribute) {
         // Prepare inbox delivery, may be queued to background.
         $stored->distribute();
     }
     return $stored;
 }
Exemplo n.º 9
0
 /**
  * Send a confirmation code to a user
  *
  * @param string $screenname screenname sending to
  * @param string $code the confirmation code
  * @param Profile $target For whom the code is valid for
  *
  * @return boolean success value
  */
 function sendConfirmationCode($screenname, $code, Profile $target)
 {
     // TRANS: Body text for confirmation code e-mail.
     // TRANS: %1$s is a user nickname, %2$s is the StatusNet sitename,
     // TRANS: %3$s is the display name of an IM plugin.
     $body = sprintf(_('User "%1$s" on %2$s has said that your %3$s screenname belongs to them. ' . 'If that is true, you can confirm by clicking on this URL: ' . '%4$s' . ' . (If you cannot click it, copy-and-paste it into the ' . 'address bar of your browser). If that user is not you, ' . 'or if you did not request this confirmation, just ignore this message.'), $target->getNickname(), common_config('site', 'name'), $this->getDisplayName(), common_local_url('confirmaddress', null, array('code' => $code)));
     return $this->sendMessage($screenname, $body);
 }
Exemplo n.º 10
0
 public function onStartChangePassword(Profile $target, $oldpassword, $newpassword)
 {
     if (!$this->checkPassword($target->getNickname(), $oldpassword)) {
         // if we ARE in overwrite mode, test password with common_check_user
         if (!$this->overwrite || !common_check_user($target->getNickname(), $oldpassword)) {
             // either we're not in overwrite mode, or the password was incorrect
             return !$this->authoritative;
         }
         // oldpassword was apparently ok
     }
     $changed = $this->changePassword($target->getNickname(), $oldpassword, $newpassword);
     return !$changed && empty($this->authoritative);
 }