|
@@ -15,104 +15,104 @@ use Illuminate\Support\Str;
|
|
|
|
|
|
class Status extends Model
|
|
class Status extends Model
|
|
{
|
|
{
|
|
- use HasSnowflakePrimary, SoftDeletes;
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * Indicates if the IDs are auto-incrementing.
|
|
|
|
- *
|
|
|
|
- * @var bool
|
|
|
|
- */
|
|
|
|
- public $incrementing = false;
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * The attributes that should be mutated to dates.
|
|
|
|
- *
|
|
|
|
- * @var array
|
|
|
|
- */
|
|
|
|
- protected $casts = [
|
|
|
|
- 'deleted_at' => 'datetime',
|
|
|
|
- 'edited_at' => 'datetime'
|
|
|
|
- ];
|
|
|
|
-
|
|
|
|
- protected $guarded = [];
|
|
|
|
-
|
|
|
|
- const STATUS_TYPES = [
|
|
|
|
- 'text',
|
|
|
|
- 'photo',
|
|
|
|
- 'photo:album',
|
|
|
|
- 'video',
|
|
|
|
- 'video:album',
|
|
|
|
- 'photo:video:album',
|
|
|
|
- 'share',
|
|
|
|
- 'reply',
|
|
|
|
- 'story',
|
|
|
|
- 'story:reply',
|
|
|
|
- 'story:reaction',
|
|
|
|
- 'story:live',
|
|
|
|
- 'loop'
|
|
|
|
- ];
|
|
|
|
-
|
|
|
|
- const MAX_MENTIONS = 20;
|
|
|
|
-
|
|
|
|
- const MAX_HASHTAGS = 60;
|
|
|
|
-
|
|
|
|
- const MAX_LINKS = 5;
|
|
|
|
-
|
|
|
|
- public function profile()
|
|
|
|
- {
|
|
|
|
- return $this->belongsTo(Profile::class);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function media()
|
|
|
|
- {
|
|
|
|
- return $this->hasMany(Media::class);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function firstMedia()
|
|
|
|
- {
|
|
|
|
- return $this->hasMany(Media::class)->orderBy('order', 'asc')->first();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function viewType()
|
|
|
|
- {
|
|
|
|
- if($this->type) {
|
|
|
|
- return $this->type;
|
|
|
|
- }
|
|
|
|
- return $this->setType();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function setType()
|
|
|
|
- {
|
|
|
|
- if(in_array($this->type, self::STATUS_TYPES)) {
|
|
|
|
- return $this->type;
|
|
|
|
- }
|
|
|
|
- $mimes = $this->media->pluck('mime')->toArray();
|
|
|
|
- $type = StatusController::mimeTypeCheck($mimes);
|
|
|
|
- if($type) {
|
|
|
|
- $this->type = $type;
|
|
|
|
- $this->save();
|
|
|
|
- return $type;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function thumb($showNsfw = false)
|
|
|
|
- {
|
|
|
|
- $entity = StatusService::get($this->id, false);
|
|
|
|
-
|
|
|
|
- if(!$entity || !isset($entity['media_attachments']) || empty($entity['media_attachments'])) {
|
|
|
|
- return url(Storage::url('public/no-preview.png'));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if((!isset($entity['sensitive']) || $entity['sensitive']) && !$showNsfw) {
|
|
|
|
- return url(Storage::url('public/no-preview.png'));
|
|
|
|
- }
|
|
|
|
|
|
+ use HasSnowflakePrimary, SoftDeletes;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * Indicates if the IDs are auto-incrementing.
|
|
|
|
+ *
|
|
|
|
+ * @var bool
|
|
|
|
+ */
|
|
|
|
+ public $incrementing = false;
|
|
|
|
+
|
|
|
|
+ /**
|
|
|
|
+ * The attributes that should be mutated to dates.
|
|
|
|
+ *
|
|
|
|
+ * @var array
|
|
|
|
+ */
|
|
|
|
+ protected $casts = [
|
|
|
|
+ 'deleted_at' => 'datetime',
|
|
|
|
+ 'edited_at' => 'datetime'
|
|
|
|
+ ];
|
|
|
|
+
|
|
|
|
+ protected $guarded = [];
|
|
|
|
+
|
|
|
|
+ const STATUS_TYPES = [
|
|
|
|
+ 'text',
|
|
|
|
+ 'photo',
|
|
|
|
+ 'photo:album',
|
|
|
|
+ 'video',
|
|
|
|
+ 'video:album',
|
|
|
|
+ 'photo:video:album',
|
|
|
|
+ 'share',
|
|
|
|
+ 'reply',
|
|
|
|
+ 'story',
|
|
|
|
+ 'story:reply',
|
|
|
|
+ 'story:reaction',
|
|
|
|
+ 'story:live',
|
|
|
|
+ 'loop'
|
|
|
|
+ ];
|
|
|
|
+
|
|
|
|
+ const MAX_MENTIONS = 20;
|
|
|
|
+
|
|
|
|
+ const MAX_HASHTAGS = 60;
|
|
|
|
+
|
|
|
|
+ const MAX_LINKS = 5;
|
|
|
|
+
|
|
|
|
+ public function profile()
|
|
|
|
+ {
|
|
|
|
+ return $this->belongsTo(Profile::class);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function media()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasMany(Media::class);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function firstMedia()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasMany(Media::class)->orderBy('order', 'asc')->first();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function viewType()
|
|
|
|
+ {
|
|
|
|
+ if($this->type) {
|
|
|
|
+ return $this->type;
|
|
|
|
+ }
|
|
|
|
+ return $this->setType();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function setType()
|
|
|
|
+ {
|
|
|
|
+ if(in_array($this->type, self::STATUS_TYPES)) {
|
|
|
|
+ return $this->type;
|
|
|
|
+ }
|
|
|
|
+ $mimes = $this->media->pluck('mime')->toArray();
|
|
|
|
+ $type = StatusController::mimeTypeCheck($mimes);
|
|
|
|
+ if($type) {
|
|
|
|
+ $this->type = $type;
|
|
|
|
+ $this->save();
|
|
|
|
+ return $type;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function thumb($showNsfw = false)
|
|
|
|
+ {
|
|
|
|
+ $entity = StatusService::get($this->id, false);
|
|
|
|
+
|
|
|
|
+ if(!$entity || !isset($entity['media_attachments']) || empty($entity['media_attachments'])) {
|
|
|
|
+ return url(Storage::url('public/no-preview.png'));
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if((!isset($entity['sensitive']) || $entity['sensitive']) && !$showNsfw) {
|
|
|
|
+ return url(Storage::url('public/no-preview.png'));
|
|
|
|
+ }
|
|
|
|
|
|
if(!isset($entity['visibility']) || !in_array($entity['visibility'], ['public', 'unlisted'])) {
|
|
if(!isset($entity['visibility']) || !in_array($entity['visibility'], ['public', 'unlisted'])) {
|
|
return url(Storage::url('public/no-preview.png'));
|
|
return url(Storage::url('public/no-preview.png'));
|
|
}
|
|
}
|
|
|
|
|
|
- return collect($entity['media_attachments'])
|
|
|
|
- ->filter(fn($media) => $media['type'] == 'image' && in_array($media['mime'], ['image/jpeg', 'image/png']))
|
|
|
|
|
|
+ return collect($entity['media_attachments'])
|
|
|
|
+ ->filter(fn($media) => $media['type'] == 'image' && in_array($media['mime'], ['image/jpeg', 'image/png', 'image/jpg']))
|
|
->map(function($media) {
|
|
->map(function($media) {
|
|
if(!Str::endsWith($media['preview_url'], ['no-preview.png', 'no-preview.jpg'])) {
|
|
if(!Str::endsWith($media['preview_url'], ['no-preview.png', 'no-preview.jpg'])) {
|
|
return $media['preview_url'];
|
|
return $media['preview_url'];
|
|
@@ -121,259 +121,259 @@ class Status extends Model
|
|
return $media['url'];
|
|
return $media['url'];
|
|
})
|
|
})
|
|
->first() ?? url(Storage::url('public/no-preview.png'));
|
|
->first() ?? url(Storage::url('public/no-preview.png'));
|
|
- }
|
|
|
|
-
|
|
|
|
- public function url($forceLocal = false)
|
|
|
|
- {
|
|
|
|
- if($this->uri) {
|
|
|
|
- return $forceLocal ? "/i/web/post/_/{$this->profile_id}/{$this->id}" : $this->uri;
|
|
|
|
- } else {
|
|
|
|
- $id = $this->id;
|
|
|
|
- $account = AccountService::get($this->profile_id, true);
|
|
|
|
- if(!$account || !isset($account['username'])) {
|
|
|
|
- return '/404';
|
|
|
|
- }
|
|
|
|
- $path = url(config('app.url')."/p/{$account['username']}/{$id}");
|
|
|
|
- return $path;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function permalink($suffix = '/activity')
|
|
|
|
- {
|
|
|
|
- $id = $this->id;
|
|
|
|
- $username = $this->profile->username;
|
|
|
|
- $path = config('app.url')."/p/{$username}/{$id}{$suffix}";
|
|
|
|
-
|
|
|
|
- return url($path);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function editUrl()
|
|
|
|
- {
|
|
|
|
- return $this->url().'/edit';
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function mediaUrl()
|
|
|
|
- {
|
|
|
|
- $media = $this->firstMedia();
|
|
|
|
- $path = $media->media_path;
|
|
|
|
- $hash = is_null($media->processed_at) ? md5('unprocessed') : md5($media->created_at);
|
|
|
|
- $url = $media->cdn_url ? $media->cdn_url . "?v={$hash}" : url(Storage::url($path)."?v={$hash}");
|
|
|
|
-
|
|
|
|
- return $url;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function likes()
|
|
|
|
- {
|
|
|
|
- return $this->hasMany(Like::class);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function liked() : bool
|
|
|
|
- {
|
|
|
|
- if(!Auth::check()) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- $pid = Auth::user()->profile_id;
|
|
|
|
-
|
|
|
|
- return Like::select('status_id', 'profile_id')
|
|
|
|
- ->whereStatusId($this->id)
|
|
|
|
- ->whereProfileId($pid)
|
|
|
|
- ->exists();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function likedBy()
|
|
|
|
- {
|
|
|
|
- return $this->hasManyThrough(
|
|
|
|
- Profile::class,
|
|
|
|
- Like::class,
|
|
|
|
- 'status_id',
|
|
|
|
- 'id',
|
|
|
|
- 'id',
|
|
|
|
- 'profile_id'
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function comments()
|
|
|
|
- {
|
|
|
|
- return $this->hasMany(self::class, 'in_reply_to_id');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function bookmarked()
|
|
|
|
- {
|
|
|
|
- if (!Auth::check()) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- $profile = Auth::user()->profile;
|
|
|
|
-
|
|
|
|
- return Bookmark::whereProfileId($profile->id)->whereStatusId($this->id)->count();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function shares()
|
|
|
|
- {
|
|
|
|
- return $this->hasMany(self::class, 'reblog_of_id');
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function shared() : bool
|
|
|
|
- {
|
|
|
|
- if(!Auth::check()) {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- $pid = Auth::user()->profile_id;
|
|
|
|
-
|
|
|
|
- return $this->select('profile_id', 'reblog_of_id')
|
|
|
|
- ->whereProfileId($pid)
|
|
|
|
- ->whereReblogOfId($this->id)
|
|
|
|
- ->exists();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function sharedBy()
|
|
|
|
- {
|
|
|
|
- return $this->hasManyThrough(
|
|
|
|
- Profile::class,
|
|
|
|
- Status::class,
|
|
|
|
- 'reblog_of_id',
|
|
|
|
- 'id',
|
|
|
|
- 'id',
|
|
|
|
- 'profile_id'
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function parent()
|
|
|
|
- {
|
|
|
|
- $parent = $this->in_reply_to_id ?? $this->reblog_of_id;
|
|
|
|
- if (!empty($parent)) {
|
|
|
|
- return $this->findOrFail($parent);
|
|
|
|
- } else {
|
|
|
|
- return false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function conversation()
|
|
|
|
- {
|
|
|
|
- return $this->hasOne(Conversation::class);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function hashtags()
|
|
|
|
- {
|
|
|
|
- return $this->hasManyThrough(
|
|
|
|
- Hashtag::class,
|
|
|
|
- StatusHashtag::class,
|
|
|
|
- 'status_id',
|
|
|
|
- 'id',
|
|
|
|
- 'id',
|
|
|
|
- 'hashtag_id'
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function mentions()
|
|
|
|
- {
|
|
|
|
- return $this->hasManyThrough(
|
|
|
|
- Profile::class,
|
|
|
|
- Mention::class,
|
|
|
|
- 'status_id',
|
|
|
|
- 'id',
|
|
|
|
- 'id',
|
|
|
|
- 'profile_id'
|
|
|
|
- );
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function reportUrl()
|
|
|
|
- {
|
|
|
|
- return route('report.form')."?type=post&id={$this->id}";
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function toActivityStream()
|
|
|
|
- {
|
|
|
|
- $media = $this->media;
|
|
|
|
- $mediaCollection = [];
|
|
|
|
- foreach ($media as $image) {
|
|
|
|
- $mediaCollection[] = [
|
|
|
|
- 'type' => 'Link',
|
|
|
|
- 'href' => $image->url(),
|
|
|
|
- 'mediaType' => $image->mime,
|
|
|
|
- ];
|
|
|
|
- }
|
|
|
|
- $obj = [
|
|
|
|
- '@context' => 'https://www.w3.org/ns/activitystreams',
|
|
|
|
- 'type' => 'Image',
|
|
|
|
- 'name' => null,
|
|
|
|
- 'url' => $mediaCollection,
|
|
|
|
- ];
|
|
|
|
-
|
|
|
|
- return $obj;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function recentComments()
|
|
|
|
- {
|
|
|
|
- return $this->comments()->orderBy('created_at', 'desc')->take(3);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function scopeToAudience($audience)
|
|
|
|
- {
|
|
|
|
- if(!in_array($audience, ['to', 'cc']) || $this->local == false) {
|
|
|
|
- return;
|
|
|
|
- }
|
|
|
|
- $res = [];
|
|
|
|
- $res['to'] = [];
|
|
|
|
- $res['cc'] = [];
|
|
|
|
- $scope = $this->scope;
|
|
|
|
- $mentions = $this->mentions->map(function ($mention) {
|
|
|
|
- return $mention->permalink();
|
|
|
|
- })->toArray();
|
|
|
|
-
|
|
|
|
- if($this->in_reply_to_id != null) {
|
|
|
|
- $parent = $this->parent();
|
|
|
|
- if($parent) {
|
|
|
|
- $mentions = array_merge([$parent->profile->permalink()], $mentions);
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- switch ($scope) {
|
|
|
|
- case 'public':
|
|
|
|
- $res['to'] = [
|
|
|
|
- "https://www.w3.org/ns/activitystreams#Public"
|
|
|
|
- ];
|
|
|
|
- $res['cc'] = array_merge([$this->profile->permalink('/followers')], $mentions);
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case 'unlisted':
|
|
|
|
- $res['to'] = array_merge([$this->profile->permalink('/followers')], $mentions);
|
|
|
|
- $res['cc'] = [
|
|
|
|
- "https://www.w3.org/ns/activitystreams#Public"
|
|
|
|
- ];
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- case 'private':
|
|
|
|
- $res['to'] = array_merge([$this->profile->permalink('/followers')], $mentions);
|
|
|
|
- $res['cc'] = [];
|
|
|
|
- break;
|
|
|
|
-
|
|
|
|
- // TODO: Update scope when DMs are supported
|
|
|
|
- case 'direct':
|
|
|
|
- $res['to'] = [];
|
|
|
|
- $res['cc'] = [];
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
- return $res[$audience];
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function place()
|
|
|
|
- {
|
|
|
|
- return $this->belongsTo(Place::class);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function directMessage()
|
|
|
|
- {
|
|
|
|
- return $this->hasOne(DirectMessage::class);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function poll()
|
|
|
|
- {
|
|
|
|
- return $this->hasOne(Poll::class);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public function edits()
|
|
|
|
- {
|
|
|
|
- return $this->hasMany(StatusEdit::class);
|
|
|
|
- }
|
|
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function url($forceLocal = false)
|
|
|
|
+ {
|
|
|
|
+ if($this->uri) {
|
|
|
|
+ return $forceLocal ? "/i/web/post/_/{$this->profile_id}/{$this->id}" : $this->uri;
|
|
|
|
+ } else {
|
|
|
|
+ $id = $this->id;
|
|
|
|
+ $account = AccountService::get($this->profile_id, true);
|
|
|
|
+ if(!$account || !isset($account['username'])) {
|
|
|
|
+ return '/404';
|
|
|
|
+ }
|
|
|
|
+ $path = url(config('app.url')."/p/{$account['username']}/{$id}");
|
|
|
|
+ return $path;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function permalink($suffix = '/activity')
|
|
|
|
+ {
|
|
|
|
+ $id = $this->id;
|
|
|
|
+ $username = $this->profile->username;
|
|
|
|
+ $path = config('app.url')."/p/{$username}/{$id}{$suffix}";
|
|
|
|
+
|
|
|
|
+ return url($path);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function editUrl()
|
|
|
|
+ {
|
|
|
|
+ return $this->url().'/edit';
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function mediaUrl()
|
|
|
|
+ {
|
|
|
|
+ $media = $this->firstMedia();
|
|
|
|
+ $path = $media->media_path;
|
|
|
|
+ $hash = is_null($media->processed_at) ? md5('unprocessed') : md5($media->created_at);
|
|
|
|
+ $url = $media->cdn_url ? $media->cdn_url . "?v={$hash}" : url(Storage::url($path)."?v={$hash}");
|
|
|
|
+
|
|
|
|
+ return $url;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function likes()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasMany(Like::class);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function liked() : bool
|
|
|
|
+ {
|
|
|
|
+ if(!Auth::check()) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ $pid = Auth::user()->profile_id;
|
|
|
|
+
|
|
|
|
+ return Like::select('status_id', 'profile_id')
|
|
|
|
+ ->whereStatusId($this->id)
|
|
|
|
+ ->whereProfileId($pid)
|
|
|
|
+ ->exists();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function likedBy()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasManyThrough(
|
|
|
|
+ Profile::class,
|
|
|
|
+ Like::class,
|
|
|
|
+ 'status_id',
|
|
|
|
+ 'id',
|
|
|
|
+ 'id',
|
|
|
|
+ 'profile_id'
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function comments()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasMany(self::class, 'in_reply_to_id');
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function bookmarked()
|
|
|
|
+ {
|
|
|
|
+ if (!Auth::check()) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ $profile = Auth::user()->profile;
|
|
|
|
+
|
|
|
|
+ return Bookmark::whereProfileId($profile->id)->whereStatusId($this->id)->count();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function shares()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasMany(self::class, 'reblog_of_id');
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function shared() : bool
|
|
|
|
+ {
|
|
|
|
+ if(!Auth::check()) {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ $pid = Auth::user()->profile_id;
|
|
|
|
+
|
|
|
|
+ return $this->select('profile_id', 'reblog_of_id')
|
|
|
|
+ ->whereProfileId($pid)
|
|
|
|
+ ->whereReblogOfId($this->id)
|
|
|
|
+ ->exists();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function sharedBy()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasManyThrough(
|
|
|
|
+ Profile::class,
|
|
|
|
+ Status::class,
|
|
|
|
+ 'reblog_of_id',
|
|
|
|
+ 'id',
|
|
|
|
+ 'id',
|
|
|
|
+ 'profile_id'
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function parent()
|
|
|
|
+ {
|
|
|
|
+ $parent = $this->in_reply_to_id ?? $this->reblog_of_id;
|
|
|
|
+ if (!empty($parent)) {
|
|
|
|
+ return $this->findOrFail($parent);
|
|
|
|
+ } else {
|
|
|
|
+ return false;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function conversation()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasOne(Conversation::class);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function hashtags()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasManyThrough(
|
|
|
|
+ Hashtag::class,
|
|
|
|
+ StatusHashtag::class,
|
|
|
|
+ 'status_id',
|
|
|
|
+ 'id',
|
|
|
|
+ 'id',
|
|
|
|
+ 'hashtag_id'
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function mentions()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasManyThrough(
|
|
|
|
+ Profile::class,
|
|
|
|
+ Mention::class,
|
|
|
|
+ 'status_id',
|
|
|
|
+ 'id',
|
|
|
|
+ 'id',
|
|
|
|
+ 'profile_id'
|
|
|
|
+ );
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function reportUrl()
|
|
|
|
+ {
|
|
|
|
+ return route('report.form')."?type=post&id={$this->id}";
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function toActivityStream()
|
|
|
|
+ {
|
|
|
|
+ $media = $this->media;
|
|
|
|
+ $mediaCollection = [];
|
|
|
|
+ foreach ($media as $image) {
|
|
|
|
+ $mediaCollection[] = [
|
|
|
|
+ 'type' => 'Link',
|
|
|
|
+ 'href' => $image->url(),
|
|
|
|
+ 'mediaType' => $image->mime,
|
|
|
|
+ ];
|
|
|
|
+ }
|
|
|
|
+ $obj = [
|
|
|
|
+ '@context' => 'https://www.w3.org/ns/activitystreams',
|
|
|
|
+ 'type' => 'Image',
|
|
|
|
+ 'name' => null,
|
|
|
|
+ 'url' => $mediaCollection,
|
|
|
|
+ ];
|
|
|
|
+
|
|
|
|
+ return $obj;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function recentComments()
|
|
|
|
+ {
|
|
|
|
+ return $this->comments()->orderBy('created_at', 'desc')->take(3);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function scopeToAudience($audience)
|
|
|
|
+ {
|
|
|
|
+ if(!in_array($audience, ['to', 'cc']) || $this->local == false) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
|
|
|
+ $res = [];
|
|
|
|
+ $res['to'] = [];
|
|
|
|
+ $res['cc'] = [];
|
|
|
|
+ $scope = $this->scope;
|
|
|
|
+ $mentions = $this->mentions->map(function ($mention) {
|
|
|
|
+ return $mention->permalink();
|
|
|
|
+ })->toArray();
|
|
|
|
+
|
|
|
|
+ if($this->in_reply_to_id != null) {
|
|
|
|
+ $parent = $this->parent();
|
|
|
|
+ if($parent) {
|
|
|
|
+ $mentions = array_merge([$parent->profile->permalink()], $mentions);
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ switch ($scope) {
|
|
|
|
+ case 'public':
|
|
|
|
+ $res['to'] = [
|
|
|
|
+ "https://www.w3.org/ns/activitystreams#Public"
|
|
|
|
+ ];
|
|
|
|
+ $res['cc'] = array_merge([$this->profile->permalink('/followers')], $mentions);
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 'unlisted':
|
|
|
|
+ $res['to'] = array_merge([$this->profile->permalink('/followers')], $mentions);
|
|
|
|
+ $res['cc'] = [
|
|
|
|
+ "https://www.w3.org/ns/activitystreams#Public"
|
|
|
|
+ ];
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ case 'private':
|
|
|
|
+ $res['to'] = array_merge([$this->profile->permalink('/followers')], $mentions);
|
|
|
|
+ $res['cc'] = [];
|
|
|
|
+ break;
|
|
|
|
+
|
|
|
|
+ // TODO: Update scope when DMs are supported
|
|
|
|
+ case 'direct':
|
|
|
|
+ $res['to'] = [];
|
|
|
|
+ $res['cc'] = [];
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ return $res[$audience];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function place()
|
|
|
|
+ {
|
|
|
|
+ return $this->belongsTo(Place::class);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function directMessage()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasOne(DirectMessage::class);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function poll()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasOne(Poll::class);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public function edits()
|
|
|
|
+ {
|
|
|
|
+ return $this->hasMany(StatusEdit::class);
|
|
|
|
+ }
|
|
}
|
|
}
|