DirectMessageController.php 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. <?php
  2. namespace App\Http\Controllers;
  3. use App\DirectMessage;
  4. use App\Jobs\DirectPipeline\DirectDeletePipeline;
  5. use App\Jobs\DirectPipeline\DirectDeliverPipeline;
  6. use App\Jobs\StatusPipeline\StatusDelete;
  7. use App\Media;
  8. use App\Models\Conversation;
  9. use App\Notification;
  10. use App\Profile;
  11. use App\Services\AccountService;
  12. use App\Services\MediaBlocklistService;
  13. use App\Services\MediaPathService;
  14. use App\Services\MediaService;
  15. use App\Services\StatusService;
  16. use App\Services\UserFilterService;
  17. use App\Services\UserRoleService;
  18. use App\Services\UserStorageService;
  19. use App\Services\WebfingerService;
  20. use App\Status;
  21. use App\UserFilter;
  22. use App\Util\ActivityPub\Helpers;
  23. use App\Util\Lexer\Autolink;
  24. use Illuminate\Http\Request;
  25. use Illuminate\Support\Str;
  26. class DirectMessageController extends Controller
  27. {
  28. public function __construct()
  29. {
  30. $this->middleware('auth');
  31. }
  32. public function browse(Request $request)
  33. {
  34. $this->validate($request, [
  35. 'a' => 'nullable|string|in:inbox,sent,filtered',
  36. 'page' => 'nullable|integer|min:1|max:99',
  37. ]);
  38. $user = $request->user();
  39. if ($user->has_roles && ! UserRoleService::can('can-direct-message', $user->id)) {
  40. return [];
  41. }
  42. $profile = $user->profile_id;
  43. $action = $request->input('a', 'inbox');
  44. $page = $request->input('page', 1);
  45. $limit = 8;
  46. $offset = ($page - 1) * $limit;
  47. $baseQuery = DirectMessage::select(
  48. 'id', 'type', 'to_id', 'from_id', 'status_id',
  49. 'is_hidden', 'meta', 'created_at', 'read_at'
  50. )->with(['author', 'status', 'recipient']);
  51. if (config('database.default') == 'pgsql') {
  52. $query = match ($action) {
  53. 'inbox' => $baseQuery->whereToId($profile)
  54. ->whereIsHidden(false)
  55. ->orderBy('created_at', 'desc'),
  56. 'sent' => $baseQuery->whereFromId($profile)
  57. ->orderBy('created_at', 'desc'),
  58. 'filtered' => $baseQuery->whereToId($profile)
  59. ->whereIsHidden(true)
  60. ->orderBy('created_at', 'desc'),
  61. default => throw new \InvalidArgumentException('Invalid action')
  62. };
  63. $dms = $query->offset($offset)
  64. ->limit($limit)
  65. ->get();
  66. $dms = $action === 'sent' ?
  67. $dms->unique('to_id') :
  68. $dms->unique('from_id');
  69. } else {
  70. $query = match ($action) {
  71. 'inbox' => $baseQuery->whereToId($profile)
  72. ->whereIsHidden(false)
  73. ->groupBy('from_id', 'id', 'type', 'to_id', 'status_id',
  74. 'is_hidden', 'meta', 'created_at', 'read_at')
  75. ->orderBy('created_at', 'desc'),
  76. 'sent' => $baseQuery->whereFromId($profile)
  77. ->groupBy('to_id', 'id', 'type', 'from_id', 'status_id',
  78. 'is_hidden', 'meta', 'created_at', 'read_at')
  79. ->orderBy('created_at', 'desc'),
  80. 'filtered' => $baseQuery->whereToId($profile)
  81. ->whereIsHidden(true)
  82. ->groupBy('from_id', 'id', 'type', 'to_id', 'status_id',
  83. 'is_hidden', 'meta', 'created_at', 'read_at')
  84. ->orderBy('created_at', 'desc'),
  85. default => throw new \InvalidArgumentException('Invalid action')
  86. };
  87. $dms = $query->offset($offset)
  88. ->limit($limit)
  89. ->get();
  90. }
  91. $mappedDms = $dms->map(function ($r) use ($action) {
  92. if ($action === 'sent') {
  93. return [
  94. 'id' => (string) $r->to_id,
  95. 'name' => $r->recipient->name,
  96. 'username' => $r->recipient->username,
  97. 'avatar' => $r->recipient->avatarUrl(),
  98. 'url' => $r->recipient->url(),
  99. 'isLocal' => (bool) ! $r->recipient->domain,
  100. 'domain' => $r->recipient->domain,
  101. 'timeAgo' => $r->created_at->diffForHumans(null, true, true),
  102. 'lastMessage' => $r->status->caption,
  103. 'messages' => [],
  104. ];
  105. }
  106. return [
  107. 'id' => (string) $r->from_id,
  108. 'name' => $r->author->name,
  109. 'username' => $r->author->username,
  110. 'avatar' => $r->author->avatarUrl(),
  111. 'url' => $r->author->url(),
  112. 'isLocal' => (bool) ! $r->author->domain,
  113. 'domain' => $r->author->domain,
  114. 'timeAgo' => $r->created_at->diffForHumans(null, true, true),
  115. 'lastMessage' => $r->status->caption,
  116. 'messages' => [],
  117. ];
  118. });
  119. return response()->json($mappedDms->values());
  120. }
  121. public function create(Request $request)
  122. {
  123. $this->validate($request, [
  124. 'to_id' => 'required',
  125. 'message' => 'required|string|min:1|max:500',
  126. 'type' => 'required|in:text,emoji',
  127. ]);
  128. $user = $request->user();
  129. abort_if($user->has_roles && ! UserRoleService::can('can-direct-message', $user->id), 403, 'Invalid permissions for this action');
  130. if (! $user->is_admin) {
  131. abort_if($user->created_at->gt(now()->subHours(72)), 400, 'You need to wait a bit before you can DM another account');
  132. }
  133. $profile = $user->profile;
  134. $recipient = Profile::where('id', '!=', $profile->id)->findOrFail($request->input('to_id'));
  135. abort_if(in_array($profile->id, $recipient->blockedIds()->toArray()), 403);
  136. $msg = $request->input('message');
  137. if ((! $recipient->domain && $recipient->user->settings->public_dm == false) || $recipient->is_private) {
  138. if ($recipient->follows($profile) == true) {
  139. $hidden = false;
  140. } else {
  141. $hidden = true;
  142. }
  143. } else {
  144. $hidden = false;
  145. }
  146. $status = new Status;
  147. $status->profile_id = $profile->id;
  148. $status->caption = $msg;
  149. $status->visibility = 'direct';
  150. $status->scope = 'direct';
  151. $status->in_reply_to_profile_id = $recipient->id;
  152. $status->save();
  153. $dm = new DirectMessage;
  154. $dm->to_id = $recipient->id;
  155. $dm->from_id = $profile->id;
  156. $dm->status_id = $status->id;
  157. $dm->is_hidden = $hidden;
  158. $dm->type = $request->input('type');
  159. $dm->save();
  160. Conversation::updateOrInsert(
  161. [
  162. 'to_id' => $recipient->id,
  163. 'from_id' => $profile->id,
  164. ],
  165. [
  166. 'type' => $dm->type,
  167. 'status_id' => $status->id,
  168. 'dm_id' => $dm->id,
  169. 'is_hidden' => $hidden,
  170. ]
  171. );
  172. if (filter_var($msg, FILTER_VALIDATE_URL)) {
  173. if (Helpers::validateUrl($msg)) {
  174. $dm->type = 'link';
  175. $dm->meta = [
  176. 'domain' => parse_url($msg, PHP_URL_HOST),
  177. 'local' => parse_url($msg, PHP_URL_HOST) ==
  178. parse_url(config('app.url'), PHP_URL_HOST),
  179. ];
  180. $dm->save();
  181. }
  182. }
  183. $nf = UserFilter::whereUserId($recipient->id)
  184. ->whereFilterableId($profile->id)
  185. ->whereFilterableType('App\Profile')
  186. ->whereFilterType('dm.mute')
  187. ->exists();
  188. if ($recipient->domain == null && $hidden == false && ! $nf) {
  189. $notification = new Notification;
  190. $notification->profile_id = $recipient->id;
  191. $notification->actor_id = $profile->id;
  192. $notification->action = 'dm';
  193. $notification->item_id = $dm->id;
  194. $notification->item_type = "App\DirectMessage";
  195. $notification->save();
  196. }
  197. if ($recipient->domain) {
  198. $this->remoteDeliver($dm);
  199. }
  200. $res = [
  201. 'id' => (string) $dm->id,
  202. 'isAuthor' => $profile->id == $dm->from_id,
  203. 'reportId' => (string) $dm->status_id,
  204. 'hidden' => (bool) $dm->is_hidden,
  205. 'type' => $dm->type,
  206. 'text' => $dm->status->caption,
  207. 'media' => null,
  208. 'timeAgo' => $dm->created_at->diffForHumans(null, null, true),
  209. 'seen' => $dm->read_at != null,
  210. 'meta' => $dm->meta,
  211. ];
  212. return response()->json($res);
  213. }
  214. public function thread(Request $request)
  215. {
  216. $this->validate($request, [
  217. 'pid' => 'required',
  218. 'max_id' => 'sometimes|integer',
  219. 'min_id' => 'sometimes|integer',
  220. ]);
  221. $user = $request->user();
  222. abort_if(
  223. $user->has_roles && ! UserRoleService::can('can-direct-message', $user->id),
  224. 403,
  225. 'Invalid permissions for this action'
  226. );
  227. $uid = $user->profile_id;
  228. $pid = $request->input('pid');
  229. $max_id = $request->input('max_id');
  230. $min_id = $request->input('min_id');
  231. $profile = Profile::findOrFail($pid);
  232. $query = DirectMessage::select(
  233. 'id',
  234. 'is_hidden',
  235. 'from_id',
  236. 'to_id',
  237. 'type',
  238. 'status_id',
  239. 'meta',
  240. 'created_at',
  241. 'read_at'
  242. )->with(['status' => function ($q) {
  243. $q->select('id', 'caption', 'profile_id');
  244. }])->where(function ($q) use ($pid, $uid) {
  245. $q->where(function ($query) use ($pid, $uid) {
  246. $query->where('from_id', $pid)
  247. ->where('to_id', $uid)
  248. ->where('is_hidden', false);
  249. })->orWhere(function ($query) use ($pid, $uid) {
  250. $query->where('from_id', $uid)
  251. ->where('to_id', $pid);
  252. });
  253. });
  254. if ($min_id) {
  255. $res = $query->where('id', '>', $min_id)
  256. ->orderBy('id', 'asc')
  257. ->take(8)
  258. ->get()
  259. ->reverse();
  260. } elseif ($max_id) {
  261. $res = $query->where('id', '<', $max_id)
  262. ->orderBy('id', 'desc')
  263. ->take(8)
  264. ->get();
  265. } else {
  266. $res = $query->orderBy('id', 'desc')
  267. ->take(8)
  268. ->get();
  269. }
  270. $messages = $res->filter(function ($message) {
  271. return $message && $message->status;
  272. })->map(function ($message) use ($uid) {
  273. return [
  274. 'id' => (string) $message->id,
  275. 'hidden' => (bool) $message->is_hidden,
  276. 'isAuthor' => $uid == $message->from_id,
  277. 'type' => $message->type,
  278. 'text' => $message->status->caption,
  279. 'media' => $message->status->firstMedia() ? $message->status->firstMedia()->url() : null,
  280. 'carousel' => MediaService::get($message->status_id),
  281. 'created_at' => $message->created_at->format('c'),
  282. 'timeAgo' => $message->created_at->diffForHumans(null, null, true),
  283. 'seen' => $message->read_at != null,
  284. 'reportId' => (string) $message->status_id,
  285. 'meta' => is_string($message->meta) ? json_decode($message->meta, true) : $message->meta,
  286. ];
  287. })->values();
  288. $filters = UserFilterService::mutes($uid);
  289. return response()->json([
  290. 'id' => (string) $profile->id,
  291. 'name' => $profile->name,
  292. 'username' => $profile->username,
  293. 'avatar' => $profile->avatarUrl(),
  294. 'url' => $profile->url(),
  295. 'muted' => in_array($profile->id, $filters),
  296. 'isLocal' => (bool) ! $profile->domain,
  297. 'domain' => $profile->domain,
  298. 'created_at' => $profile->created_at->format('c'),
  299. 'updated_at' => $profile->updated_at->format('c'),
  300. 'timeAgo' => $profile->created_at->diffForHumans(null, true, true),
  301. 'lastMessage' => '',
  302. 'messages' => $messages,
  303. ], 200, [], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
  304. }
  305. public function delete(Request $request)
  306. {
  307. $this->validate($request, [
  308. 'id' => 'required',
  309. ]);
  310. $sid = $request->input('id');
  311. $pid = $request->user()->profile_id;
  312. $dm = DirectMessage::whereFromId($pid)
  313. ->whereStatusId($sid)
  314. ->firstOrFail();
  315. $status = Status::whereProfileId($pid)
  316. ->findOrFail($dm->status_id);
  317. $recipient = AccountService::get($dm->to_id);
  318. if (! $recipient) {
  319. return response('', 422);
  320. }
  321. if ($recipient['local'] == false) {
  322. $dmc = $dm;
  323. $this->remoteDelete($dmc);
  324. } else {
  325. StatusDelete::dispatch($status)->onQueue('high');
  326. }
  327. if (Conversation::whereStatusId($sid)->count()) {
  328. $latest = DirectMessage::where(['from_id' => $dm->from_id, 'to_id' => $dm->to_id])
  329. ->orWhere(['to_id' => $dm->from_id, 'from_id' => $dm->to_id])
  330. ->latest()
  331. ->first();
  332. if ($latest->status_id == $sid) {
  333. Conversation::where(['to_id' => $dm->from_id, 'from_id' => $dm->to_id])
  334. ->update([
  335. 'updated_at' => $latest->updated_at,
  336. 'status_id' => $latest->status_id,
  337. 'type' => $latest->type,
  338. 'is_hidden' => false,
  339. ]);
  340. Conversation::where(['to_id' => $dm->to_id, 'from_id' => $dm->from_id])
  341. ->update([
  342. 'updated_at' => $latest->updated_at,
  343. 'status_id' => $latest->status_id,
  344. 'type' => $latest->type,
  345. 'is_hidden' => false,
  346. ]);
  347. } else {
  348. Conversation::where([
  349. 'status_id' => $sid,
  350. 'to_id' => $dm->from_id,
  351. 'from_id' => $dm->to_id,
  352. ])->delete();
  353. Conversation::where([
  354. 'status_id' => $sid,
  355. 'from_id' => $dm->from_id,
  356. 'to_id' => $dm->to_id,
  357. ])->delete();
  358. }
  359. }
  360. StatusService::del($status->id, true);
  361. $status->forceDeleteQuietly();
  362. return [200];
  363. }
  364. public function get(Request $request, $id)
  365. {
  366. $user = $request->user();
  367. abort_if($user->has_roles && ! UserRoleService::can('can-direct-message', $user->id), 403, 'Invalid permissions for this action');
  368. $pid = $request->user()->profile_id;
  369. $dm = DirectMessage::whereStatusId($id)->firstOrFail();
  370. abort_if($pid !== $dm->to_id && $pid !== $dm->from_id, 404);
  371. return response()->json($dm, 200, [], JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES);
  372. }
  373. public function mediaUpload(Request $request)
  374. {
  375. $this->validate($request, [
  376. 'file' => function () {
  377. return [
  378. 'required',
  379. 'mimetypes:'.config_cache('pixelfed.media_types'),
  380. 'max:'.config_cache('pixelfed.max_photo_size'),
  381. ];
  382. },
  383. 'to_id' => 'required',
  384. ]);
  385. $user = $request->user();
  386. abort_if($user->has_roles && ! UserRoleService::can('can-direct-message', $user->id), 403, 'Invalid permissions for this action');
  387. $profile = $user->profile;
  388. $recipient = Profile::where('id', '!=', $profile->id)->findOrFail($request->input('to_id'));
  389. abort_if(in_array($profile->id, $recipient->blockedIds()->toArray()), 403);
  390. if ((! $recipient->domain && $recipient->user->settings->public_dm == false) || $recipient->is_private) {
  391. if ($recipient->follows($profile) == true) {
  392. $hidden = false;
  393. } else {
  394. $hidden = true;
  395. }
  396. } else {
  397. $hidden = false;
  398. }
  399. $accountSize = UserStorageService::get($user->id);
  400. abort_if($accountSize === -1, 403, 'Invalid request.');
  401. $photo = $request->file('file');
  402. $fileSize = $photo->getSize();
  403. $sizeInKbs = (int) ceil($fileSize / 1000);
  404. $updatedAccountSize = (int) $accountSize + (int) $sizeInKbs;
  405. if ((bool) config_cache('pixelfed.enforce_account_limit') == true) {
  406. $limit = (int) config_cache('pixelfed.max_account_size');
  407. if ($updatedAccountSize >= $limit) {
  408. abort(403, 'Account size limit reached.');
  409. }
  410. }
  411. $mimes = explode(',', config_cache('pixelfed.media_types'));
  412. if (in_array($photo->getMimeType(), $mimes) == false) {
  413. abort(403, 'Invalid or unsupported mime type.');
  414. }
  415. $storagePath = MediaPathService::get($user, 2).Str::random(8);
  416. $path = $photo->storePublicly($storagePath);
  417. $hash = \hash_file('sha256', $photo);
  418. abort_if(MediaBlocklistService::exists($hash) == true, 451);
  419. $status = new Status;
  420. $status->profile_id = $profile->id;
  421. $status->caption = null;
  422. $status->visibility = 'direct';
  423. $status->scope = 'direct';
  424. $status->in_reply_to_profile_id = $recipient->id;
  425. $status->save();
  426. $media = new Media;
  427. $media->status_id = $status->id;
  428. $media->profile_id = $profile->id;
  429. $media->user_id = $user->id;
  430. $media->media_path = $path;
  431. $media->original_sha256 = $hash;
  432. $media->size = $photo->getSize();
  433. $media->mime = $photo->getMimeType();
  434. $media->caption = null;
  435. $media->filter_class = null;
  436. $media->filter_name = null;
  437. $media->save();
  438. $dm = new DirectMessage;
  439. $dm->to_id = $recipient->id;
  440. $dm->from_id = $profile->id;
  441. $dm->status_id = $status->id;
  442. $dm->type = array_first(explode('/', $media->mime)) == 'video' ? 'video' : 'photo';
  443. $dm->is_hidden = $hidden;
  444. $dm->save();
  445. Conversation::updateOrInsert(
  446. [
  447. 'to_id' => $recipient->id,
  448. 'from_id' => $profile->id,
  449. ],
  450. [
  451. 'type' => $dm->type,
  452. 'status_id' => $status->id,
  453. 'dm_id' => $dm->id,
  454. 'is_hidden' => $hidden,
  455. ]
  456. );
  457. $user->storage_used = (int) $updatedAccountSize;
  458. $user->storage_used_updated_at = now();
  459. $user->save();
  460. if ($recipient->domain) {
  461. $this->remoteDeliver($dm);
  462. }
  463. return [
  464. 'id' => $dm->id,
  465. 'reportId' => (string) $dm->status_id,
  466. 'type' => $dm->type,
  467. 'url' => $media->url(),
  468. ];
  469. }
  470. public function composeLookup(Request $request)
  471. {
  472. $this->validate($request, [
  473. 'q' => 'required|string|min:2|max:50',
  474. 'remote' => 'nullable',
  475. ]);
  476. $user = $request->user();
  477. if ($user->has_roles && ! UserRoleService::can('can-direct-message', $user->id)) {
  478. return [];
  479. }
  480. $q = $request->input('q');
  481. $r = $request->input('remote', false);
  482. if ($r && ! Str::of($q)->contains('.')) {
  483. return [];
  484. }
  485. if ($r && Helpers::validateUrl($q)) {
  486. Helpers::profileFetch($q);
  487. }
  488. if (Str::of($q)->startsWith('@')) {
  489. if (strlen($q) < 3) {
  490. return [];
  491. }
  492. if (substr_count($q, '@') == 2) {
  493. WebfingerService::lookup($q);
  494. }
  495. $q = mb_substr($q, 1);
  496. }
  497. $blocked = UserFilter::whereFilterableType('App\Profile')
  498. ->whereFilterType('block')
  499. ->whereFilterableId($request->user()->profile_id)
  500. ->pluck('user_id');
  501. $blocked->push($request->user()->profile_id);
  502. $results = Profile::select('id', 'domain', 'username')
  503. ->whereNotIn('id', $blocked)
  504. ->where('username', 'like', '%'.$q.'%')
  505. ->orderBy('domain')
  506. ->limit(8)
  507. ->get()
  508. ->map(function ($r) {
  509. $acct = AccountService::get($r->id);
  510. return [
  511. 'local' => (bool) ! $r->domain,
  512. 'id' => (string) $r->id,
  513. 'name' => $r->username,
  514. 'privacy' => true,
  515. 'avatar' => $r->avatarUrl(),
  516. 'account' => $acct,
  517. ];
  518. });
  519. return $results;
  520. }
  521. public function read(Request $request)
  522. {
  523. $this->validate($request, [
  524. 'pid' => 'required',
  525. 'sid' => 'required',
  526. ]);
  527. $pid = $request->input('pid');
  528. $sid = $request->input('sid');
  529. $user = $request->user();
  530. abort_if($user->has_roles && ! UserRoleService::can('can-direct-message', $user->id), 403, 'Invalid permissions for this action');
  531. $dms = DirectMessage::whereToId($request->user()->profile_id)
  532. ->whereFromId($pid)
  533. ->where('status_id', '>=', $sid)
  534. ->get();
  535. $now = now();
  536. foreach ($dms as $dm) {
  537. $dm->read_at = $now;
  538. $dm->save();
  539. }
  540. return response()->json($dms->pluck('id'));
  541. }
  542. public function mute(Request $request)
  543. {
  544. $this->validate($request, [
  545. 'id' => 'required',
  546. ]);
  547. $user = $request->user();
  548. abort_if($user->has_roles && ! UserRoleService::can('can-direct-message', $user->id), 403, 'Invalid permissions for this action');
  549. $fid = $request->input('id');
  550. $pid = $request->user()->profile_id;
  551. UserFilter::firstOrCreate(
  552. [
  553. 'user_id' => $pid,
  554. 'filterable_id' => $fid,
  555. 'filterable_type' => 'App\Profile',
  556. 'filter_type' => 'dm.mute',
  557. ]
  558. );
  559. return [200];
  560. }
  561. public function unmute(Request $request)
  562. {
  563. $this->validate($request, [
  564. 'id' => 'required',
  565. ]);
  566. $user = $request->user();
  567. abort_if($user->has_roles && ! UserRoleService::can('can-direct-message', $user->id), 403, 'Invalid permissions for this action');
  568. $fid = $request->input('id');
  569. $pid = $request->user()->profile_id;
  570. $f = UserFilter::whereUserId($pid)
  571. ->whereFilterableId($fid)
  572. ->whereFilterableType('App\Profile')
  573. ->whereFilterType('dm.mute')
  574. ->firstOrFail();
  575. $f->delete();
  576. return [200];
  577. }
  578. public function remoteDeliver($dm)
  579. {
  580. $profile = $dm->author;
  581. $url = $dm->recipient->sharedInbox ?? $dm->recipient->inbox_url;
  582. $status = $dm->status;
  583. if (! $status) {
  584. return;
  585. }
  586. $tags = [
  587. [
  588. 'type' => 'Mention',
  589. 'href' => $dm->recipient->permalink(),
  590. 'name' => $dm->recipient->emailUrl(),
  591. ],
  592. ];
  593. $content = $status->caption ? Autolink::create()->autolink($status->caption) : null;
  594. $body = [
  595. '@context' => [
  596. 'https://w3id.org/security/v1',
  597. 'https://www.w3.org/ns/activitystreams',
  598. ],
  599. 'id' => $dm->status->permalink(),
  600. 'type' => 'Create',
  601. 'actor' => $dm->status->profile->permalink(),
  602. 'published' => $dm->status->created_at->toAtomString(),
  603. 'to' => [$dm->recipient->permalink()],
  604. 'cc' => [],
  605. 'object' => [
  606. 'id' => $dm->status->url(),
  607. 'type' => 'Note',
  608. 'summary' => null,
  609. 'content' => $content,
  610. 'inReplyTo' => null,
  611. 'published' => $dm->status->created_at->toAtomString(),
  612. 'url' => $dm->status->url(),
  613. 'attributedTo' => $dm->status->profile->permalink(),
  614. 'to' => [$dm->recipient->permalink()],
  615. 'cc' => [],
  616. 'sensitive' => (bool) $dm->status->is_nsfw,
  617. 'attachment' => $dm->status->media()->orderBy('order')->get()->map(function ($media) {
  618. return [
  619. 'type' => $media->activityVerb(),
  620. 'mediaType' => $media->mime,
  621. 'url' => $media->url(),
  622. 'name' => $media->caption,
  623. ];
  624. })->toArray(),
  625. 'tag' => $tags,
  626. ],
  627. ];
  628. DirectDeliverPipeline::dispatch($profile, $url, $body)->onQueue('high');
  629. }
  630. public function remoteDelete($dm)
  631. {
  632. $profile = $dm->author;
  633. $url = $dm->recipient->sharedInbox ?? $dm->recipient->inbox_url;
  634. $body = [
  635. '@context' => [
  636. 'https://www.w3.org/ns/activitystreams',
  637. ],
  638. 'id' => $dm->status->permalink('#delete'),
  639. 'to' => [
  640. 'https://www.w3.org/ns/activitystreams#Public',
  641. ],
  642. 'type' => 'Delete',
  643. 'actor' => $dm->status->profile->permalink(),
  644. 'object' => [
  645. 'id' => $dm->status->url(),
  646. 'type' => 'Tombstone',
  647. ],
  648. ];
  649. DirectDeletePipeline::dispatch($profile, $url, $body)->onQueue('high');
  650. }
  651. }