ImportPostController.php 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  1. <?php
  2. namespace App\Http\Controllers;
  3. use Illuminate\Http\Request;
  4. use App\Models\ImportPost;
  5. use App\Services\ImportService;
  6. use App\Services\StatusService;
  7. use App\Http\Resources\ImportStatus;
  8. use App\Follower;
  9. use App\User;
  10. class ImportPostController extends Controller
  11. {
  12. public function __construct()
  13. {
  14. $this->middleware('auth');
  15. }
  16. public function getConfig(Request $request)
  17. {
  18. return [
  19. 'enabled' => config('import.instagram.enabled'),
  20. 'limits' => [
  21. 'max_posts' => config('import.instagram.limits.max_posts'),
  22. 'max_attempts' => config('import.instagram.limits.max_attempts'),
  23. ],
  24. 'allow_video_posts' => config('import.instagram.allow_video_posts'),
  25. 'permissions' => [
  26. 'admins_only' => config('import.instagram.permissions.admins_only'),
  27. 'admin_follows_only' => config('import.instagram.permissions.admin_follows_only'),
  28. 'min_account_age' => config('import.instagram.permissions.min_account_age'),
  29. 'min_follower_count' => config('import.instagram.permissions.min_follower_count'),
  30. ],
  31. 'allowed' => $this->checkPermissions($request, false)
  32. ];
  33. }
  34. public function getProcessingCount(Request $request)
  35. {
  36. abort_unless(config('import.instagram.enabled'), 404);
  37. $processing = ImportPost::whereProfileId($request->user()->profile_id)
  38. ->whereNull('status_id')
  39. ->whereSkipMissingMedia(false)
  40. ->count();
  41. $finished = ImportPost::whereProfileId($request->user()->profile_id)
  42. ->whereNotNull('status_id')
  43. ->whereSkipMissingMedia(false)
  44. ->count();
  45. return response()->json([
  46. 'processing_count' => $processing,
  47. 'finished_count' => $finished,
  48. ]);
  49. }
  50. public function getImportedFiles(Request $request)
  51. {
  52. abort_unless(config('import.instagram.enabled'), 404);
  53. return response()->json(
  54. ImportService::getImportedFiles($request->user()->profile_id),
  55. 200,
  56. [],
  57. JSON_UNESCAPED_SLASHES
  58. );
  59. }
  60. public function getImportedPosts(Request $request)
  61. {
  62. abort_unless(config('import.instagram.enabled'), 404);
  63. return ImportStatus::collection(
  64. ImportPost::whereProfileId($request->user()->profile_id)
  65. ->has('status')
  66. ->cursorPaginate(9)
  67. );
  68. }
  69. public function store(Request $request)
  70. {
  71. abort_unless(config('import.instagram.enabled'), 404);
  72. $this->checkPermissions($request);
  73. $uid = $request->user()->id;
  74. $pid = $request->user()->profile_id;
  75. foreach($request->input('files') as $file) {
  76. $media = $file['media'];
  77. $c = collect($media);
  78. $postHash = hash('sha256', $c->toJson());
  79. $exts = $c->map(function($m) {
  80. $fn = last(explode('/', $m['uri']));
  81. return last(explode('.', $fn));
  82. });
  83. $postType = 'photo';
  84. if($exts->count() > 1) {
  85. if($exts->contains('mp4')) {
  86. if($exts->contains('jpg', 'png')) {
  87. $postType = 'photo:video:album';
  88. } else {
  89. $postType = 'video:album';
  90. }
  91. } else {
  92. $postType = 'photo:album';
  93. }
  94. } else {
  95. if(in_array($exts[0], ['jpg', 'png'])) {
  96. $postType = 'photo';
  97. } else if(in_array($exts[0], ['mp4'])) {
  98. $postType = 'video';
  99. }
  100. }
  101. $ip = new ImportPost;
  102. $ip->user_id = $uid;
  103. $ip->profile_id = $pid;
  104. $ip->post_hash = $postHash;
  105. $ip->service = 'instagram';
  106. $ip->post_type = $postType;
  107. $ip->media_count = $c->count();
  108. $ip->media = $c->map(function($m) {
  109. return [
  110. 'uri' => $m['uri'],
  111. 'title' => $m['title'],
  112. 'creation_timestamp' => $m['creation_timestamp']
  113. ];
  114. })->toArray();
  115. $ip->caption = $c->count() > 1 ? $file['title'] : $ip->media[0]['title'];
  116. $ip->filename = last(explode('/', $ip->media[0]['uri']));
  117. $ip->metadata = $c->map(function($m) {
  118. return [
  119. 'uri' => $m['uri'],
  120. 'media_metadata' => isset($m['media_metadata']) ? $m['media_metadata'] : null
  121. ];
  122. })->toArray();
  123. $ip->creation_date = $c->count() > 1 ? now()->parse($file['creation_timestamp']) : now()->parse($media[0]['creation_timestamp']);
  124. $ip->creation_year = now()->parse($ip->creation_date)->format('y');
  125. $ip->creation_month = now()->parse($ip->creation_date)->format('m');
  126. $ip->creation_day = now()->parse($ip->creation_date)->format('d');
  127. $ip->save();
  128. ImportService::getImportedFiles($pid, true);
  129. ImportService::getPostCount($pid, true);
  130. }
  131. return [
  132. 'msg' => 'Success'
  133. ];
  134. }
  135. public function storeMedia(Request $request)
  136. {
  137. abort_unless(config('import.instagram.enabled'), 404);
  138. $this->checkPermissions($request);
  139. $mimes = config('import.instagram.allow_video_posts') ? 'mimetypes:image/png,image/jpeg,video/mp4' : 'mimetypes:image/png,image/jpeg';
  140. $this->validate($request, [
  141. 'file' => 'required|array|max:10',
  142. 'file.*' => [
  143. 'required',
  144. 'file',
  145. $mimes,
  146. 'max:' . config('pixelfed.max_photo_size')
  147. ]
  148. ]);
  149. foreach($request->file('file') as $file) {
  150. $fileName = $file->getClientOriginalName();
  151. $file->storeAs('imports/' . $request->user()->id . '/', $fileName);
  152. }
  153. ImportService::getImportedFiles($request->user()->profile_id, true);
  154. return [
  155. 'msg' => 'Success'
  156. ];
  157. }
  158. protected function checkPermissions($request, $abortOnFail = true)
  159. {
  160. $user = $request->user();
  161. if($abortOnFail) {
  162. abort_unless(config('import.instagram.enabled'), 404);
  163. }
  164. if($user->is_admin) {
  165. if(!$abortOnFail) {
  166. return true;
  167. } else {
  168. return;
  169. }
  170. }
  171. $admin = User::whereIsAdmin(true)->first();
  172. if(config('import.instagram.permissions.admins_only')) {
  173. if($abortOnFail) {
  174. abort_unless($user->is_admin, 404, 'Only admins can use this feature.');
  175. } else {
  176. if(!$user->is_admin) {
  177. return false;
  178. }
  179. }
  180. }
  181. if(config('import.instagram.permissions.admin_follows_only')) {
  182. $exists = Follower::whereProfileId($admin->profile_id)
  183. ->whereFollowingId($user->profile_id)
  184. ->exists();
  185. if($abortOnFail) {
  186. abort_unless(
  187. $exists,
  188. 404,
  189. 'Only admins, and accounts they follow can use this feature'
  190. );
  191. } else {
  192. if(!$exists) {
  193. return false;
  194. }
  195. }
  196. }
  197. if(config('import.instagram.permissions.min_account_age')) {
  198. $res = $user->created_at->lt(
  199. now()->subDays(config('import.instagram.permissions.min_account_age'))
  200. );
  201. if($abortOnFail) {
  202. abort_unless(
  203. $res,
  204. 404,
  205. 'Your account is too new to use this feature'
  206. );
  207. } else {
  208. if(!$res) {
  209. return false;
  210. }
  211. }
  212. }
  213. if(config('import.instagram.permissions.min_follower_count')) {
  214. $res = Follower::whereFollowingId($user->profile_id)->count() >= config('import.instagram.permissions.min_follower_count');
  215. if($abortOnFail) {
  216. abort_unless(
  217. $res,
  218. 404,
  219. 'You don\'t have enough followers to use this feature'
  220. );
  221. } else {
  222. if(!$res) {
  223. return false;
  224. }
  225. }
  226. }
  227. if(intval(config('import.instagram.limits.max_posts')) > 0) {
  228. $res = ImportService::getPostCount($user->profile_id) >= intval(config('import.instagram.limits.max_posts'));
  229. if($abortOnFail) {
  230. abort_if(
  231. $res,
  232. 404,
  233. 'You have reached the limit of post imports and cannot import any more posts'
  234. );
  235. } else {
  236. if($res) {
  237. return false;
  238. }
  239. }
  240. }
  241. if(intval(config('import.instagram.limits.max_attempts')) > 0) {
  242. $res = ImportService::getAttempts($user->profile_id) >= intval(config('import.instagram.limits.max_attempts'));
  243. if($abortOnFail) {
  244. abort_if(
  245. $res,
  246. 404,
  247. 'You have reached the limit of post import attempts and cannot import any more posts'
  248. );
  249. } else {
  250. if($res) {
  251. return false;
  252. }
  253. }
  254. }
  255. if(!$abortOnFail) {
  256. return true;
  257. }
  258. }
  259. }