AdminAutospamController.php 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255
  1. <?php
  2. namespace App\Http\Controllers\Admin;
  3. use DB, Cache;
  4. use App\{
  5. AccountInterstitial,
  6. DiscoverCategory,
  7. DiscoverCategoryHashtag,
  8. Hashtag,
  9. Media,
  10. Profile,
  11. Status,
  12. StatusHashtag,
  13. User
  14. };
  15. use App\Models\ConfigCache;
  16. use App\Models\AutospamCustomTokens;
  17. use App\Services\AccountService;
  18. use App\Services\ConfigCacheService;
  19. use App\Services\StatusService;
  20. use Carbon\Carbon;
  21. use Illuminate\Http\Request;
  22. use Illuminate\Validation\Rule;
  23. use League\ISO3166\ISO3166;
  24. use Illuminate\Support\Str;
  25. use Illuminate\Support\Facades\Storage;
  26. use Illuminate\Support\Facades\Validator;
  27. use Illuminate\Support\Facades\Http;
  28. use App\Http\Controllers\PixelfedDirectoryController;
  29. use \DateInterval;
  30. use \DatePeriod;
  31. use App\Http\Resources\AdminSpamReport;
  32. use App\Util\Lexer\Classifier;
  33. use App\Jobs\AutospamPipeline\AutospamPretrainPipeline;
  34. use App\Jobs\AutospamPipeline\AutospamPretrainNonSpamPipeline;
  35. use App\Jobs\AutospamPipeline\AutospamUpdateCachedDataPipeline;
  36. use Illuminate\Support\Facades\URL;
  37. use App\Services\AutospamService;
  38. trait AdminAutospamController
  39. {
  40. public function autospamHome(Request $request)
  41. {
  42. return view('admin.autospam.home');
  43. }
  44. public function getAutospamConfigApi(Request $request)
  45. {
  46. $open = Cache::remember('admin-dash:reports:spam-count', 3600, function() {
  47. return AccountInterstitial::whereType('post.autospam')->whereNull('appeal_handled_at')->count();
  48. });
  49. $closed = Cache::remember('admin-dash:reports:spam-count-closed', 3600, function() {
  50. return AccountInterstitial::whereType('post.autospam')->whereNotNull('appeal_handled_at')->count();
  51. });
  52. $thisWeek = Cache::remember('admin-dash:reports:spam-count-stats-this-week ', 86400, function() {
  53. $sr = config('database.default') == 'pgsql' ? "to_char(created_at, 'MM-YYYY')" : "DATE_FORMAT(created_at, '%m-%Y')";
  54. $gb = config('database.default') == 'pgsql' ? [DB::raw($sr)] : DB::raw($sr);
  55. $s = AccountInterstitial::select(
  56. DB::raw('count(id) as count'),
  57. DB::raw($sr . " as month_year")
  58. )
  59. ->where('created_at', '>=', now()->subWeeks(52))
  60. ->groupBy($gb)
  61. ->get()
  62. ->map(function($s) {
  63. $dt = now()->parse('01-' . $s->month_year);
  64. return [
  65. 'id' => $dt->format('Ym'),
  66. 'x' => $dt->format('M Y'),
  67. 'y' => $s->count
  68. ];
  69. })
  70. ->sortBy('id')
  71. ->values()
  72. ->toArray();
  73. return $s;
  74. });
  75. $files = [
  76. 'spam' => [
  77. 'exists' => Storage::exists(AutospamService::MODEL_SPAM_PATH),
  78. 'size' => 0
  79. ],
  80. 'ham' => [
  81. 'exists' => Storage::exists(AutospamService::MODEL_HAM_PATH),
  82. 'size' => 0
  83. ],
  84. 'combined' => [
  85. 'exists' => Storage::exists(AutospamService::MODEL_FILE_PATH),
  86. 'size' => 0
  87. ]
  88. ];
  89. if($files['spam']['exists']) {
  90. $files['spam']['size'] = Storage::size(AutospamService::MODEL_SPAM_PATH);
  91. }
  92. if($files['ham']['exists']) {
  93. $files['ham']['size'] = Storage::size(AutospamService::MODEL_HAM_PATH);
  94. }
  95. if($files['combined']['exists']) {
  96. $files['combined']['size'] = Storage::size(AutospamService::MODEL_FILE_PATH);
  97. }
  98. return [
  99. 'autospam_enabled' => (bool) config_cache('pixelfed.bouncer.enabled') ?? false,
  100. 'nlp_enabled' => (bool) AutospamService::active(),
  101. 'files' => $files,
  102. 'open' => $open,
  103. 'closed' => $closed,
  104. 'graph' => collect($thisWeek)->map(fn($s) => $s['y'])->values(),
  105. 'graphLabels' => collect($thisWeek)->map(fn($s) => $s['x'])->values()
  106. ];
  107. }
  108. public function getAutospamReportsClosedApi(Request $request)
  109. {
  110. $appeals = AdminSpamReport::collection(
  111. AccountInterstitial::orderBy('id', 'desc')
  112. ->whereType('post.autospam')
  113. ->whereIsSpam(true)
  114. ->whereNotNull('appeal_handled_at')
  115. ->cursorPaginate(6)
  116. ->withQueryString()
  117. );
  118. return $appeals;
  119. }
  120. public function postAutospamTrainSpamApi(Request $request)
  121. {
  122. $aiCount = AccountInterstitial::whereItemType('App\Status')
  123. ->whereIsSpam(true)
  124. ->count();
  125. abort_if($aiCount < 100, 422, 'You don\'t have enough data to pre-train against.');
  126. $existing = Cache::get('pf:admin:autospam:pretrain:recent');
  127. abort_if($existing, 422, 'You\'ve already run this recently, please wait 30 minutes before pre-training again');
  128. AutospamPretrainPipeline::dispatch();
  129. Cache::put('pf:admin:autospam:pretrain:recent', 1, 1440);
  130. return [
  131. 'msg' => 'Success!'
  132. ];
  133. }
  134. public function postAutospamTrainNonSpamSearchApi(Request $request)
  135. {
  136. $this->validate($request, [
  137. 'q' => 'required|string|min:1'
  138. ]);
  139. $q = $request->input('q');
  140. $res = Profile::whereNull(['status', 'domain'])
  141. ->where('username', 'like', '%' . $q . '%')
  142. ->orderByDesc('followers_count')
  143. ->take(10)
  144. ->get()
  145. ->map(function($p) {
  146. $acct = AccountService::get($p->id, true);
  147. return [
  148. 'id' => (string) $p->id,
  149. 'avatar' => $acct['avatar'],
  150. 'username' => $p->username
  151. ];
  152. })
  153. ->values();
  154. return $res;
  155. }
  156. public function postAutospamTrainNonSpamSubmitApi(Request $request)
  157. {
  158. $this->validate($request, [
  159. 'accounts' => 'required|array|min:1|max:10'
  160. ]);
  161. $accts = $request->input('accounts');
  162. $accounts = Profile::whereNull(['domain', 'status'])->find(collect($accts)->map(function($a) { return $a['id'];}));
  163. abort_if(!$accounts || !$accounts->count(), 422, 'One or more of the selected accounts are not valid');
  164. AutospamPretrainNonSpamPipeline::dispatch($accounts);
  165. return $accounts;
  166. }
  167. public function getAutospamCustomTokensApi(Request $request)
  168. {
  169. return AutospamCustomTokens::latest()->cursorPaginate(6);
  170. }
  171. public function saveNewAutospamCustomTokensApi(Request $request)
  172. {
  173. $this->validate($request, [
  174. 'token' => 'required|unique:autospam_custom_tokens,token',
  175. ]);
  176. $ct = new AutospamCustomTokens;
  177. $ct->token = $request->input('token');
  178. $ct->weight = $request->input('weight');
  179. $ct->category = $request->input('category') === 'spam' ? 'spam' : 'ham';
  180. $ct->note = $request->input('note');
  181. $ct->active = $request->input('active');
  182. $ct->save();
  183. AutospamUpdateCachedDataPipeline::dispatch();
  184. return $ct;
  185. }
  186. public function updateAutospamCustomTokensApi(Request $request)
  187. {
  188. $this->validate($request, [
  189. 'id' => 'required',
  190. 'token' => 'required',
  191. 'category' => 'required|in:spam,ham',
  192. 'active' => 'required|boolean'
  193. ]);
  194. $ct = AutospamCustomTokens::findOrFail($request->input('id'));
  195. $ct->weight = $request->input('weight');
  196. $ct->category = $request->input('category');
  197. $ct->note = $request->input('note');
  198. $ct->active = $request->input('active');
  199. $ct->save();
  200. AutospamUpdateCachedDataPipeline::dispatch();
  201. return $ct;
  202. }
  203. public function exportAutospamCustomTokensApi(Request $request)
  204. {
  205. abort_if(!Storage::exists(AutospamService::MODEL_SPAM_PATH), 422, 'Autospam Dataset does not exist, please train spam before attempting to export');
  206. return Storage::download(AutospamService::MODEL_SPAM_PATH);
  207. }
  208. public function enableAutospamApi(Request $request)
  209. {
  210. ConfigCacheService::put('autospam.nlp.enabled', true);
  211. Cache::forget(AutospamService::CHCKD_CACHE_KEY);
  212. return ['msg' => 'Success'];
  213. }
  214. public function disableAutospamApi(Request $request)
  215. {
  216. ConfigCacheService::put('autospam.nlp.enabled', false);
  217. Cache::forget(AutospamService::CHCKD_CACHE_KEY);
  218. return ['msg' => 'Success'];
  219. }
  220. }