tokenService = $tokenService; } public function getHandler(Request $request): JsonResponse { try { $tokenData = $this->tokenService->validateToken($request->input('access_token')); } catch (RequiredConstraintsViolated|InvalidTokenStructure) { $micropubResponses = new MicropubResponses; return $micropubResponses->invalidTokenResponse(); } if ($tokenData->claims()->has('scope') === false) { $micropubResponses = new MicropubResponses; return $micropubResponses->tokenHasNoScopeResponse(); } $scopes = $tokenData->claims()->get('scope'); if (is_string($scopes)) { $scopes = explode(' ', $scopes); } if (! in_array('create', $scopes)) { $micropubResponses = new MicropubResponses; return $micropubResponses->insufficientScopeResponse(); } if ($request->input('q') === 'last') { $media = Media::where('created_at', '>=', Carbon::now()->subMinutes(30)) ->where('token', $request->input('access_token')) ->latest() ->first(); $mediaUrl = $media?->url; return response()->json(['url' => $mediaUrl]); } if ($request->input('q') === 'source') { $limit = $request->input('limit', 10); $offset = $request->input('offset', 0); $media = Media::latest()->offset($offset)->limit($limit)->get(); $media->transform(function ($mediaItem) { return [ 'url' => $mediaItem->url, 'published' => $mediaItem->created_at->toW3cString(), 'mime_type' => $mediaItem->mimetype, ]; }); return response()->json(['items' => $media]); } if ($request->has('q')) { return response()->json([ 'error' => 'invalid_request', 'error_description' => sprintf( 'This server does not know how to handle this q parameter (%s)', $request->input('q') ), ], 400); } return response()->json(['status' => 'OK']); } /** * Process a media item posted to the media endpoint. * * @throws BindingResolutionException * @throws Exception */ public function media(Request $request): JsonResponse { try { $tokenData = $this->tokenService->validateToken($request->input('access_token')); } catch (RequiredConstraintsViolated|InvalidTokenStructure) { $micropubResponses = new MicropubResponses; return $micropubResponses->invalidTokenResponse(); } if ($tokenData->claims()->has('scope') === false) { $micropubResponses = new MicropubResponses; return $micropubResponses->tokenHasNoScopeResponse(); } $scopes = $tokenData->claims()->get('scope'); if (is_string($scopes)) { $scopes = explode(' ', $scopes); } if (! in_array('create', $scopes)) { $micropubResponses = new MicropubResponses; return $micropubResponses->insufficientScopeResponse(); } if ($request->hasFile('file') === false) { return response()->json([ 'response' => 'error', 'error' => 'invalid_request', 'error_description' => 'No file was sent with the request', ], 400); } /** @var UploadedFile $file */ $file = $request->file('file'); if ($file->isValid() === false) { return response()->json([ 'response' => 'error', 'error' => 'invalid_request', 'error_description' => 'The uploaded file failed validation', ], 400); } $filename = Storage::disk('local')->putFile('media', $file); /** @var ImageManager $manager */ $manager = resolve(ImageManager::class); try { $image = $manager->read($request->file('file')); $width = $image->width(); } catch (Exception) { // not an image $width = null; } $media = Media::create([ 'token' => $request->bearerToken(), 'path' => $filename, 'type' => $this->getFileTypeFromMimeType($request->file('file')->getMimeType()), 'image_widths' => $width, ]); ProcessMedia::dispatch($filename); return response()->json([ 'response' => 'created', 'location' => $media->url, ], 201)->header('Location', $media->url); } /** * Return the relevant CORS headers to a pre-flight OPTIONS request. */ public function mediaOptionsResponse(): Response { return response('OK', 200); } /** * Get the file type from the mime-type of the uploaded file. */ private function getFileTypeFromMimeType(string $mimeType): string { // try known images $imageMimeTypes = [ 'image/gif', 'image/jpeg', 'image/png', 'image/svg+xml', 'image/tiff', 'image/webp', ]; if (in_array($mimeType, $imageMimeTypes)) { return 'image'; } // try known video $videoMimeTypes = [ 'video/mp4', 'video/mpeg', 'video/ogg', 'video/quicktime', 'video/webm', ]; if (in_array($mimeType, $videoMimeTypes)) { return 'video'; } // try known audio types $audioMimeTypes = [ 'audio/midi', 'audio/mpeg', 'audio/ogg', 'audio/x-m4a', ]; if (in_array($mimeType, $audioMimeTypes)) { return 'audio'; } return 'download'; } /** * Save an uploaded file to the local disk. * * @throws Exception */ private function saveFileToLocal(UploadedFile $file): string { $filename = Uuid::uuid4()->toString() . '.' . $file->extension(); Storage::disk('local')->putFileAs('', $file, $filename); return $filename; } }