$this->_profile[$this->profile_id] = $profile;
}
- function delete($useWhere=false)
+ public function deleteAs(Profile $actor, $delete_event=true)
{
- // For auditing purposes, save a record that the notice
- // was deleted.
-
- // @fixme we have some cases where things get re-run and so the
- // insert fails.
- $deleted = Deleted_notice::getKV('id', $this->id);
-
- if (!$deleted instanceof Deleted_notice) {
- $deleted = Deleted_notice::getKV('uri', $this->uri);
- }
-
- if (!$deleted instanceof Deleted_notice) {
- $deleted = new Deleted_notice();
-
- $deleted->id = $this->id;
- $deleted->profile_id = $this->profile_id;
- $deleted->uri = $this->uri;
- $deleted->created = $this->created;
- $deleted->deleted = common_sql_now();
-
- $deleted->insert();
+ if (!$this->getProfile()->sameAs($actor) && !$actor->hasRight(Right::DELETEOTHERSNOTICE)) {
+ throw new AuthorizationException(_('You are not allowed to delete another user\'s notice.'));
}
if (Event::handle('NoticeDeleteRelated', array($this))) {
-
// Clear related records
-
$this->clearReplies();
$this->clearLocation();
$this->clearRepeats();
$this->clearGroupInboxes();
$this->clearFiles();
$this->clearAttentions();
-
// NOTE: we don't clear queue items
}
+ $result = null;
+ if (!$delete_event || Event::handle('DeleteNoticeAsProfile', array($this, $actor, &$result))) {
+ // If $delete_event is true, we run the event. If the Event then
+ // returns false it is assumed everything was handled properly
+ // and the notice was deleted.
+ $result = $this->delete();
+ }
+ return $result;
+ }
+
+ public function delete($useWhere=false)
+ {
$result = parent::delete($useWhere);
$this->blowOnDelete();
return $this->content;
}
+ public function getRendered()
+ {
+ return $this->rendered;
+ }
+
/*
* Get the original representation URL of this notice.
*
}
}
- public function get_object_type($canonical=false) {
- return $canonical
- ? ActivityObject::canonicalType($this->object_type)
- : $this->object_type;
+ public function getObjectType($canonical=false) {
+ return ActivityUtils::resolveUri($this->object_type, $canonical);
}
public static function getByUri($uri)
$defaults = array(
'groups' => array(),
- 'is_local' => self::LOCAL_PUBLIC,
+ 'is_local' => $actor->isLocal() ? self::LOCAL_PUBLIC : self::REMOTE,
'mentions' => array(),
'reply_to' => null,
'repeat_of' => null,
}
extract($options, EXTR_SKIP);
+ // dupe check
$stored = new Notice();
- if (!empty($uri)) {
+ 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);
}
}
+ $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;
: $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);
$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.').');
- $stored->conversation = $conv->id;
+ $stored->conversation = $conv->getID();
} else {
// Conversation URI was not found, so we must create it. But we can't create it
// until we have a Notice ID because of the database layout...
$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 {
- $stored->insert(); // throws exception on error
+ $result = $stored->insert(); // throws exception on error
if ($notloc instanceof Notice_location) {
$notloc->notice_id = $stored->getID();
$object = null;
Event::handle('StoreActivityObject', array($act, $stored, $options, &$object));
if (empty($object)) {
- throw new ServerException('Unsuccessful call to StoreActivityObject '.$stored->uri . ': '.$act->asString());
+ throw new ServerException('Unsuccessful call to StoreActivityObject '.$stored->getUri() . ': '.$act->asString());
}
// If it's not part of a conversation, it's the beginning
// $act->context->conversation will be null if it was not provided
common_debug('Creating a new conversation for stored notice ID='.$stored->getID().' with URI: '.$act->context->conversation);
$conv = Conversation::create($stored, $act->context->conversation);
- $stored->conversation = $conv->id;
+ $stored->conversation = $conv->getID();
}
$stored->update($orig);
}
static public function figureOutScope(Profile $actor, array $groups, $scope=null) {
- if (is_null($scope)) {
- $scope = self::defaultScope();
- }
+ $scope = is_null($scope) ? self::defaultScope() : intval($scope);
// For private streams
try {
$user = $actor->getUser();
// FIXME: We can't do bit comparison with == (Legacy StatusNet thing. Let's keep it for now.)
- if ($user->private_stream && ($scope == Notice::PUBLIC_SCOPE || $scope == Notice::SITE_SCOPE)) {
+ if ($user->private_stream && ($scope === Notice::PUBLIC_SCOPE || $scope === Notice::SITE_SCOPE)) {
$scope |= Notice::FOLLOWER_SCOPE;
}
} catch (NoSuchUserException $e) {
}
} catch (NoParentNoticeException $e) {
// Latest notice has no parent
+ } catch (NoResultException $e) {
+ // Notice was not found, so we can't go further up in the tree.
+ // FIXME: Maybe we should do this in a more stable way where deleted
+ // notices won't break conversation chains?
}
// No parent, or parent out of scope
$root = $last;
self::blow('reply:stream:%d', $parentauthor->id);
} catch (NoParentNoticeException $e) {
// Not a reply, since it has no parent!
+ } catch (NoResultException $e) {
+ // Parent notice was probably deleted
}
// @todo ideally this parser information would only
$ctx->replyToUrl = $reply->getUrl(true); // true for fallback to local URL, less messy
} catch (NoParentNoticeException $e) {
// This is not a reply to something
+ } catch (NoResultException $e) {
+ // Parent notice was probably deleted
}
try {
$this->uri = sprintf('%s%s=%d:%s=%s',
TagURI::mint(),
'noticeId', $this->id,
- 'objectType', $this->get_object_type(true));
+ 'objectType', $this->getObjectType(true));
$changed = true;
}
public function isLocal()
{
- return ($this->is_local == Notice::LOCAL_PUBLIC ||
- $this->is_local == Notice::LOCAL_NONPUBLIC);
+ $is_local = intval($this->is_local);
+ return ($is_local === self::LOCAL_PUBLIC || $is_local === self::LOCAL_NONPUBLIC);
+ }
+
+ public function getScope()
+ {
+ return intval($this->scope);
}
public function isRepeat()
protected function _inScope($profile)
{
- if (!is_null($this->scope)) {
- $scope = $this->scope;
- } else {
- $scope = self::defaultScope();
- }
+ $scope = is_null($this->scope) ? self::defaultScope() : $this->getScope();
- if ($scope == 0 && !$this->getProfile()->isPrivateStream()) { // Not scoping, so it is public.
+ if ($scope === 0 && !$this->getProfile()->isPrivateStream()) { // Not scoping, so it is public.
return !$this->isHiddenSpam($profile);
}
public function getParent()
{
+ $reply_to_id = null;
+
if (empty($this->reply_to)) {
throw new NoParentNoticeException($this);
}
- return self::getByID($this->reply_to);
+
+ // The reply_to ID in the table Notice could exist with a number
+ // however, the replied to notice might not exist in the database.
+ // Thus we need to catch the exception and throw the NoParentNoticeException else
+ // the timeline will not display correctly.
+ try {
+ $reply_to_id = self::getByID($this->reply_to);
+ } catch(Exception $e){
+ throw new NoParentNoticeException($this);
+ }
+
+
+ return $reply_to_id;
}
/**