Bouncer.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. <?php
  2. namespace App\Util\Sentiment;
  3. use App\AccountInterstitial;
  4. use App\Status;
  5. use Cache;
  6. use Illuminate\Support\Str;
  7. class Bouncer {
  8. public static function get(Status $status)
  9. {
  10. if($status->uri || $status->scope != 'public') {
  11. return;
  12. }
  13. if($status->profile->user->is_admin == true) {
  14. return;
  15. }
  16. $exemptionKey = 'pf:bouncer_v0:exemption_by_pid:' . $status->profile_id;
  17. $exemptionTtl = now()->addDays(12);
  18. if( $status->in_reply_to_id != null &&
  19. $status->in_reply_to_profile_id == $status->profile_id
  20. ) {
  21. return;
  22. }
  23. $exemption = Cache::remember($exemptionKey, $exemptionTtl, function() use($status) {
  24. $uid = $status->profile->user_id;
  25. $ids = AccountInterstitial::whereUserId($uid)
  26. ->whereType('post.autospam')
  27. ->whereItemType('App\Status')
  28. ->whereNotNull('appeal_handled_at')
  29. ->latest()
  30. ->take(5)
  31. ->pluck('item_id');
  32. if($ids->count() == 0) {
  33. return false;
  34. }
  35. $count = Status::select('id', 'scope')
  36. ->whereScope('public')
  37. ->find($ids)
  38. ->count();
  39. return $count >= 1 ? true : false;
  40. });
  41. if($exemption == true) {
  42. return;
  43. }
  44. if( $status->profile->created_at->gt(now()->subMonths(6)) &&
  45. $status->profile->bio &&
  46. $status->profile->website
  47. ) {
  48. return (new self)->handle($status);
  49. }
  50. $recentKey = 'pf:bouncer_v0:recent_by_pid:' . $status->profile_id;
  51. $recentTtl = now()->addHours(28);
  52. $recent = Cache::remember($recentKey, $recentTtl, function() use($status) {
  53. return $status
  54. ->profile
  55. ->created_at
  56. ->gt(now()->subMonths(6)) ||
  57. $status
  58. ->profile
  59. ->statuses()
  60. ->whereScope('public')
  61. ->count() == 0;
  62. });
  63. if(!$recent) {
  64. return;
  65. }
  66. if($status->profile->followers()->count() > 100) {
  67. return;
  68. }
  69. if(!Str::contains($status->caption, [
  70. 'https://',
  71. 'http://',
  72. 'hxxps://',
  73. 'hxxp://',
  74. 'www.',
  75. '.com',
  76. '.net',
  77. '.org'
  78. ])) {
  79. return;
  80. }
  81. return (new self)->handle($status);
  82. }
  83. protected function handle($status)
  84. {
  85. $media = $status->media;
  86. $ai = new AccountInterstitial;
  87. $ai->user_id = $status->profile->user_id;
  88. $ai->type = 'post.autospam';
  89. $ai->view = 'account.moderation.post.autospam';
  90. $ai->item_type = 'App\Status';
  91. $ai->item_id = $status->id;
  92. $ai->has_media = (bool) $media->count();
  93. $ai->blurhash = $media->count() ? $media->first()->blurhash : null;
  94. $ai->meta = json_encode([
  95. 'caption' => $status->caption,
  96. 'created_at' => $status->created_at,
  97. 'type' => $status->type,
  98. 'url' => $status->url(),
  99. 'is_nsfw' => $status->is_nsfw,
  100. 'scope' => $status->scope,
  101. 'reblog' => $status->reblog_of_id,
  102. 'likes_count' => $status->likes_count,
  103. 'reblogs_count' => $status->reblogs_count,
  104. ]);
  105. $ai->save();
  106. $u = $status->profile->user;
  107. $u->has_interstitial = true;
  108. $u->save();
  109. $status->scope = 'unlisted';
  110. $status->visibility = 'unlisted';
  111. // $status->is_nsfw = true;
  112. $status->save();
  113. Cache::forget('pf:bouncer_v0:exemption_by_pid:' . $status->profile_id);
  114. Cache::forget('pf:bouncer_v0:recent_by_pid:' . $status->profile_id);
  115. }
  116. }