SearchApiV2Service.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. <?php
  2. namespace App\Services;
  3. use Cache;
  4. use Illuminate\Support\Facades\Redis;
  5. use App\{Hashtag, Profile, Status};
  6. use App\Transformer\Api\AccountTransformer;
  7. use App\Transformer\Api\StatusTransformer;
  8. use League\Fractal;
  9. use League\Fractal\Serializer\ArraySerializer;
  10. use League\Fractal\Pagination\IlluminatePaginatorAdapter;
  11. use App\Util\ActivityPub\Helpers;
  12. use Illuminate\Support\Str;
  13. class SearchApiV2Service
  14. {
  15. private $query;
  16. public static function query($query)
  17. {
  18. return (new self)->run($query);
  19. }
  20. protected function run($query)
  21. {
  22. $this->query = $query;
  23. if($query->has('resolve') &&
  24. $query->resolve == true &&
  25. Helpers::validateUrl(urldecode($query->input('q')))
  26. ) {
  27. return $this->resolve();
  28. }
  29. if($query->has('type')) {
  30. switch ($query->input('type')) {
  31. case 'accounts':
  32. return [
  33. 'accounts' => $this->accounts(),
  34. 'hashtags' => [],
  35. 'statuses' => []
  36. ];
  37. break;
  38. case 'hashtags':
  39. return [
  40. 'accounts' => [],
  41. 'hashtags' => $this->hashtags(),
  42. 'statuses' => []
  43. ];
  44. break;
  45. case 'statuses':
  46. return [
  47. 'accounts' => [],
  48. 'hashtags' => [],
  49. 'statuses' => $this->statuses()
  50. ];
  51. break;
  52. }
  53. }
  54. if($query->has('account_id')) {
  55. return [
  56. 'accounts' => [],
  57. 'hashtags' => [],
  58. 'statuses' => $this->statusesById()
  59. ];
  60. }
  61. return [
  62. 'accounts' => $this->accounts(),
  63. 'hashtags' => $this->hashtags(),
  64. 'statuses' => $this->statuses()
  65. ];
  66. }
  67. protected function resolve()
  68. {
  69. $query = urldecode($this->query->input('q'));
  70. if(Str::startsWith($query, '@') == true) {
  71. return WebfingerService::lookup($this->query->input('q'));
  72. } else if (Str::startsWith($query, 'https://') == true) {
  73. return $this->resolveQuery();
  74. }
  75. }
  76. protected function accounts()
  77. {
  78. $limit = $this->query->input('limit') ?? 20;
  79. $offset = $this->query->input('offset') ?? 0;
  80. $query = '%' . $this->query->input('q') . '%';
  81. $results = Profile::whereNull('status')
  82. ->where('username', 'like', $query)
  83. ->offset($offset)
  84. ->limit($limit)
  85. ->get();
  86. $fractal = new Fractal\Manager();
  87. $fractal->setSerializer(new ArraySerializer());
  88. $resource = new Fractal\Resource\Collection($results, new AccountTransformer());
  89. return $fractal->createData($resource)->toArray();
  90. }
  91. protected function hashtags()
  92. {
  93. $limit = $this->query->input('limit') ?? 20;
  94. $offset = $this->query->input('offset') ?? 0;
  95. $query = '%' . $this->query->input('q') . '%';
  96. return Hashtag::whereIsBanned(false)
  97. ->where('name', 'like', $query)
  98. ->offset($offset)
  99. ->limit($limit)
  100. ->get()
  101. ->map(function($tag) {
  102. return [
  103. 'name' => $tag->name,
  104. 'url' => $tag->url(),
  105. 'history' => []
  106. ];
  107. });
  108. }
  109. protected function statuses()
  110. {
  111. // Removed until we provide more relevent sorting/results
  112. return [];
  113. }
  114. protected function statusesById()
  115. {
  116. $accountId = $this->query->input('account_id');
  117. $limit = $this->query->input('limit', 20);
  118. $query = '%' . $this->query->input('q') . '%';
  119. $results = Status::where('caption', 'like', $query)
  120. ->whereProfileId($accountId)
  121. ->limit($limit)
  122. ->get();
  123. $fractal = new Fractal\Manager();
  124. $fractal->setSerializer(new ArraySerializer());
  125. $resource = new Fractal\Resource\Collection($results, new StatusTransformer());
  126. return $fractal->createData($resource)->toArray();
  127. }
  128. protected function resolveQuery()
  129. {
  130. $query = urldecode($this->query->input('q'));
  131. if(Helpers::validateLocalUrl($query)) {
  132. if(Str::contains($query, '/p/')) {
  133. return $this->resolveLocalStatus();
  134. } else {
  135. return $this->resolveLocalProfile();
  136. }
  137. } else {
  138. return [
  139. 'accounts' => [],
  140. 'hashtags' => [],
  141. 'statuses' => []
  142. ];
  143. }
  144. }
  145. protected function resolveLocalStatus()
  146. {
  147. $query = urldecode($this->query->input('q'));
  148. $query = last(explode('/', $query));
  149. $status = Status::whereNull('uri')
  150. ->whereScope('public')
  151. ->find($query);
  152. if(!$status) {
  153. return [
  154. 'accounts' => [],
  155. 'hashtags' => [],
  156. 'statuses' => []
  157. ];
  158. }
  159. $fractal = new Fractal\Manager();
  160. $fractal->setSerializer(new ArraySerializer());
  161. $resource = new Fractal\Resource\Item($status, new StatusTransformer());
  162. return [
  163. 'accounts' => [],
  164. 'hashtags' => [],
  165. 'statuses' => $fractal->createData($resource)->toArray()
  166. ];
  167. }
  168. protected function resolveLocalProfile()
  169. {
  170. $query = urldecode($this->query->input('q'));
  171. $query = last(explode('/', $query));
  172. $profile = Profile::whereNull('status')
  173. ->whereNull('domain')
  174. ->whereUsername($query)
  175. ->first();
  176. if(!$profile) {
  177. return [
  178. 'accounts' => [],
  179. 'hashtags' => [],
  180. 'statuses' => []
  181. ];
  182. }
  183. $fractal = new Fractal\Manager();
  184. $fractal->setSerializer(new ArraySerializer());
  185. $resource = new Fractal\Resource\Item($profile, new AccountTransformer());
  186. return [
  187. 'accounts' => $fractal->createData($resource)->toArray(),
  188. 'hashtags' => [],
  189. 'statuses' => []
  190. ];
  191. }
  192. }