Profile.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. <?php
  2. namespace App;
  3. use App\Util\Lexer\PrettyNumber;
  4. use Auth;
  5. use Cache;
  6. use Illuminate\Database\Eloquent\Model;
  7. use Illuminate\Database\Eloquent\SoftDeletes;
  8. use Storage;
  9. class Profile extends Model
  10. {
  11. use SoftDeletes;
  12. /**
  13. * The attributes that should be mutated to dates.
  14. *
  15. * @var array
  16. */
  17. protected $dates = ['deleted_at'];
  18. protected $hidden = [
  19. 'private_key',
  20. ];
  21. protected $visible = ['username', 'name'];
  22. public function user()
  23. {
  24. return $this->belongsTo(User::class);
  25. }
  26. public function url($suffix = '')
  27. {
  28. if ($this->remote_url) {
  29. return $this->remote_url;
  30. } else {
  31. return url($this->username.$suffix);
  32. }
  33. }
  34. public function localUrl($suffix = '')
  35. {
  36. return url($this->username.$suffix);
  37. }
  38. public function permalink($suffix = '')
  39. {
  40. if($this->remote_url) {
  41. return $this->remote_url;
  42. }
  43. return url('users/'.$this->username.$suffix);
  44. }
  45. public function emailUrl()
  46. {
  47. if($this->domain) {
  48. return $this->username;
  49. }
  50. $domain = parse_url(config('app.url'), PHP_URL_HOST);
  51. return $this->username.'@'.$domain;
  52. }
  53. public function statuses()
  54. {
  55. return $this->hasMany(Status::class);
  56. }
  57. public function followingCount($short = false)
  58. {
  59. $count = $this->following()->count();
  60. if ($short) {
  61. return PrettyNumber::convert($count);
  62. } else {
  63. return $count;
  64. }
  65. }
  66. public function followerCount($short = false)
  67. {
  68. $count = $this->followers()->count();
  69. if ($short) {
  70. return PrettyNumber::convert($count);
  71. } else {
  72. return $count;
  73. }
  74. }
  75. public function following()
  76. {
  77. return $this->belongsToMany(
  78. self::class,
  79. 'followers',
  80. 'profile_id',
  81. 'following_id'
  82. );
  83. }
  84. public function followers()
  85. {
  86. return $this->belongsToMany(
  87. self::class,
  88. 'followers',
  89. 'following_id',
  90. 'profile_id'
  91. );
  92. }
  93. public function follows($profile) : bool
  94. {
  95. return Follower::whereProfileId($this->id)->whereFollowingId($profile->id)->exists();
  96. }
  97. public function followedBy($profile) : bool
  98. {
  99. return Follower::whereProfileId($profile->id)->whereFollowingId($this->id)->exists();
  100. }
  101. public function bookmarks()
  102. {
  103. return $this->belongsToMany(
  104. Status::class,
  105. 'bookmarks',
  106. 'profile_id',
  107. 'status_id'
  108. );
  109. }
  110. public function likes()
  111. {
  112. return $this->hasMany(Like::class);
  113. }
  114. public function avatar()
  115. {
  116. return $this->hasOne(Avatar::class)->withDefault([
  117. 'media_path' => 'public/avatars/default.png',
  118. ]);
  119. }
  120. public function avatarUrl()
  121. {
  122. $url = Cache::remember("avatar:{$this->id}", 1440, function () {
  123. $path = optional($this->avatar)->media_path;
  124. $version = hash('sha1', $this->avatar->updated_at);
  125. $path = "{$path}?v={$version}";
  126. return url(Storage::url($path));
  127. });
  128. return $url;
  129. }
  130. public function statusCount()
  131. {
  132. return $this->statuses()
  133. ->whereHas('media')
  134. ->whereNull('in_reply_to_id')
  135. ->whereNull('reblog_of_id')
  136. ->count();
  137. }
  138. public function recommendFollowers()
  139. {
  140. $follows = $this->following()->pluck('followers.id');
  141. $following = $this->following()
  142. ->orderByRaw('rand()')
  143. ->take(3)
  144. ->pluck('following_id');
  145. $following->push(Auth::id());
  146. $following = Follower::whereNotIn('profile_id', $follows)
  147. ->whereNotIn('following_id', $following)
  148. ->whereNotIn('following_id', $follows)
  149. ->whereIn('profile_id', $following)
  150. ->orderByRaw('rand()')
  151. ->distinct('id')
  152. ->limit(3)
  153. ->pluck('following_id');
  154. $recommended = [];
  155. foreach ($following as $follow) {
  156. $recommended[] = self::findOrFail($follow);
  157. }
  158. return $recommended;
  159. }
  160. public function keyId()
  161. {
  162. if ($this->remote_url) {
  163. return;
  164. }
  165. return $this->permalink('#main-key');
  166. }
  167. public function mutedIds()
  168. {
  169. return UserFilter::whereUserId($this->id)
  170. ->whereFilterableType('App\Profile')
  171. ->whereFilterType('mute')
  172. ->pluck('filterable_id');
  173. }
  174. public function blockedIds()
  175. {
  176. return UserFilter::whereUserId($this->id)
  177. ->whereFilterableType('App\Profile')
  178. ->whereFilterType('block')
  179. ->pluck('filterable_id');
  180. }
  181. public function mutedProfileUrls()
  182. {
  183. $ids = $this->mutedIds();
  184. return $this->whereIn('id', $ids)->get()->map(function($i) {
  185. return $i->url();
  186. });
  187. }
  188. public function blockedProfileUrls()
  189. {
  190. $ids = $this->blockedIds();
  191. return $this->whereIn('id', $ids)->get()->map(function($i) {
  192. return $i->url();
  193. });
  194. }
  195. public function reports()
  196. {
  197. return $this->hasMany(Report::class, 'profile_id');
  198. }
  199. public function media()
  200. {
  201. return $this->hasMany(Media::class, 'profile_id');
  202. }
  203. public function inboxUrl()
  204. {
  205. return $this->inbox_url ?? $this->permalink('/inbox');
  206. }
  207. public function outboxUrl()
  208. {
  209. return $this->outbox_url ?? $this->permalink('/outbox');
  210. }
  211. public function sharedInbox()
  212. {
  213. return $this->sharedInbox ?? $this->inboxUrl();
  214. }
  215. public function getDefaultScope()
  216. {
  217. return $this->is_private == true ? 'private' : 'public';
  218. }
  219. public function getAudience($scope = false)
  220. {
  221. if($this->remote_url) {
  222. return [];
  223. }
  224. $scope = $scope ?? $this->getDefaultScope();
  225. $audience = [];
  226. switch ($scope) {
  227. case 'public':
  228. $audience = [
  229. 'to' => [
  230. 'https://www.w3.org/ns/activitystreams#Public'
  231. ],
  232. 'cc' => [
  233. $this->permalink('/followers')
  234. ]
  235. ];
  236. break;
  237. }
  238. return $audience;
  239. }
  240. public function getAudienceInbox($scope = 'public')
  241. {
  242. return $this
  243. ->followers()
  244. ->whereLocalProfile(false)
  245. ->get()
  246. ->map(function($follow) {
  247. return $follow->sharedInbox ?? $follow->inbox_url;
  248. })
  249. ->unique()
  250. ->toArray();
  251. }
  252. }