diff --git a/Dockerfile b/Dockerfile index 30f0138..311052a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,5 +10,3 @@ RUN apt-get -y update \ && apt-get -y install libvips-dev \ && pecl install vips \ && echo 'extension="vips.so"' > /usr/local/etc/php/conf.d/20-vips.ini - -COPY ./php.ini /usr/local/etc/php/php-vips.ini diff --git a/app/Http/Controllers/Controller.php b/app/Http/Controllers/Controller.php index 1af040a..6e92763 100644 --- a/app/Http/Controllers/Controller.php +++ b/app/Http/Controllers/Controller.php @@ -2,6 +2,7 @@ namespace App\Http\Controllers; +use App\Http\Controllers\Traits\FileTrait; use Illuminate\Foundation\Auth\Access\AuthorizesRequests; use Illuminate\Foundation\Bus\DispatchesJobs; use Illuminate\Foundation\Validation\ValidatesRequests; @@ -9,7 +10,7 @@ use Illuminate\Routing\Controller as BaseController; class Controller extends BaseController { - use AuthorizesRequests, DispatchesJobs, ValidatesRequests; + use AuthorizesRequests, DispatchesJobs, ValidatesRequests, FileTrait; protected function resourceAbilityMap() { diff --git a/app/Http/Controllers/FileController.php b/app/Http/Controllers/FileController.php index 136f81b..919db7a 100644 --- a/app/Http/Controllers/FileController.php +++ b/app/Http/Controllers/FileController.php @@ -4,11 +4,14 @@ namespace App\Http\Controllers; use App\Http\Requests\FileStoreRequest; use App\Http\Resources\FileResource; +use App\Image\ImageProcessor; use App\Jobs\FileConversionQueue; use App\Models\File; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Facades\Validator; +use Symfony\Component\Console\Input\Input; class FileController extends Controller { @@ -19,37 +22,71 @@ class FileController extends Controller public function private($collection, $path) { - Storage::disk(app()->collection->disk)->download($path); + // Storage::disk(app()->collection->disk)->download($path); } - public function store(Request $request) + public function store(Request $request, ImageProcessor $imageProcessor) { - // skip policy ---and first level---------- + if (!app()->collection->tmp_support && !$request->model_id) { + return abort(403); + } + + if (app()->collection->count !== 1 && (app()->collection->count <= File::where('model_id', auth()->id())->count()) && !app()->collection->tmp_support) { + return abort(403); + } - $validated = $request->validate([ - "file" => [ + if (!isset(app()->file) && is_null($request->file('file'))) { + return abort(403); + } + + $fieldsValidate = [ + "alts" => [app()->collection->alt_required ? "required" : "nullable", 'array'], + "alts.*" => [app()->collection->alt_required ? "required" : "nullable", 'max:1000'], + "description" => [app()->collection->description_required ? "required" : "nullable", 'max:300'], + 'original_name' => ["string", "nullable", 'max:300'], + 'public' => ['boolean', 'nullable'], + 'published_at' => ['date_format:Y-m-d H:i:s', 'nullable'], + ]; + + $fieldsValidate['file'] = + is_null($request->file('file')) ? + [ + 'string', + 'required', + 'max:300' + ] : + [ "mimes:" . app()->collection->getExts(), "mimetypes:" . app()->collection->getMimeTypes(), - "dimensions:min_width=" . app()->collection->min_width . ",min_height=" . app()->collection->min_height . ',max_width=' . app()->collection->max_width . ',max_height=' . app()->collection->max_height, - "max:" . app()->collection->max_size, - "min:" . app()->collection->min_size, - ], - "alts" => [app()->collection->alt_required ? "required" : "null", 'array'], - "alts.*" => [app()->collection->alt_required ? "required" : "null"], - "description" => [app()->collection->description_required ? "required" : "null"], - ]); + !$this->isImage($request->file->path()) ?: "dimensions:min_width=" . app()->collection->min_width . ",min_height=" . app()->collection->min_height . ',max_width=' . app()->collection->max_width . ',max_height=' . app()->collection->max_height, + "max:" . app()->collection->max_file_size, + "min:" . app()->collection->min_file_size, + ]; + $validated = $request->validate($fieldsValidate); + if (is_null($request->file('file'))) { + $storedImage = new \Illuminate\Http\File(Storage::disk('local')->path(app()->file->server_path)); + $validated = Validator::make(['file' => $storedImage], ["file" => [ + "mimes:" . app()->collection->getExts(), + "mimetypes:" . app()->collection->getMimeTypes(), + "dimensions:min_width=" . app()->collection->min_width . ",min_height=" . app()->collection->min_height . ',max_width=' . app()->collection->max_width . ',max_height=' . app()->collection->max_height, + "max:" . app()->collection->max_file_size, + "min:" . app()->collection->min_file_size + ]])->validate(); + } + if (!is_null(app()->collection->process)) { + $imageProcessor->process($request->file->path(), $request->file->path(), app()->collection->process); + } - DB::beginTransaction(); - $urlStorage = '/' . date('y') . '/' . date('m') . app()->getFileUuid; + DB::transaction(function () use ($request) { - try { - $file = File::create([ - 'uuid' => app()->getFileUuid, + $uuid = app()->uuid; + $request->resourceFile = File::create([ + 'uuid' => $uuid, 'original_name' => $request->name, 'public' => $request->public, 'ext' => $request->file->extension(), @@ -64,25 +101,19 @@ class FileController extends Controller 'ip' => $request->ip(), 'collection_id' => app()->collection->id, 'published_at' => $request->published_at, - 'server_path' => $urlStorage + 'server_path' => '/' . date('y') . '/' . date('m') . '/' . $uuid . '.' . app()->collection->ext, ]); if (!app()->collection->tmp_support && app()->collection->count == 1) { File::where('user_id', auth()->id())->delete(); } - $file = $request->file->storeAs($urlStorage, app()->getFileUuid, app()->collection->disk); + $storedImage = $request->file->storeAs($request->resourceFile->server_path, app()->uuid . '.' . app()->collection->ext, app()->collection->disk); if (app()->collection->public) { - Storage::setVisibility($file, 'public'); + Storage::setVisibility($storedImage, 'public'); } - - DB::commit(); - } catch (\Exception $e) { - DB::rollback(); - } - - FileConversionQueue::dispatch($file, app()->collection); - return new FileResource($file); + }); + return new FileResource($request->resourceFile); } diff --git a/app/Http/Controllers/Traits/FileTrait.php b/app/Http/Controllers/Traits/FileTrait.php new file mode 100644 index 0000000..097bb69 --- /dev/null +++ b/app/Http/Controllers/Traits/FileTrait.php @@ -0,0 +1,15 @@ +route()->action['as'] == 'api.file.store') { - app()->bind('collection', function () use ($request) { - return Collection::where('name', $request->route('collections_name'))->get(); - }); - - app()->singleton('getFileUuid', function () { - return Str::uuid(); + app()->singleton('collection', function () use ($request) { + return Collection::where('name', $request->route('collection_name'))->get()->first(); }); } if ($request->route()->action['as'] == 'api.file.private') { - app()->bind('collection', function () use ($request) { - return Collection::where('name', $request->route('collections_name'))->get(); + app()->singleton('collection', function () use ($request) { + return Collection::where('name', $request->route('collection_name'))->get()->first(); }); } diff --git a/app/Http/Middleware/BindFileModelMiddleware.php b/app/Http/Middleware/BindFileModelMiddleware.php new file mode 100644 index 0000000..e1289be --- /dev/null +++ b/app/Http/Middleware/BindFileModelMiddleware.php @@ -0,0 +1,31 @@ +route()->action['as'] == 'api.file.store') { + if(is_null($request->file('file'))){ + app()->bind('file', function () use ($request) { + return File::find($request->file); + }); + } + } + + return $next($request); + } +} diff --git a/app/Http/Resources/CollectionResource.php b/app/Http/Resources/CollectionResource.php index 24773b9..d98f5de 100644 --- a/app/Http/Resources/CollectionResource.php +++ b/app/Http/Resources/CollectionResource.php @@ -32,7 +32,7 @@ class CollectionResource extends JsonResource "description_required" => $this->description_required, "count" => $this->count, "exts" => $this->exts, - "avalible_exts" => $this->avalible_exts, + "ext" => $this->ext, "mimetypes" => $this->mimetypes, "model" => $this->model, "expire_date" => $this->expire_date, diff --git a/app/Http/Resources/FileResource.php b/app/Http/Resources/FileResource.php index 6eaf9fd..8b8205b 100644 --- a/app/Http/Resources/FileResource.php +++ b/app/Http/Resources/FileResource.php @@ -21,6 +21,7 @@ class FileResource extends JsonResource "mimetype" => $this->mimetype, "width" => $this->width, "height" => $this->height, + "server_path" => $this->server_path, "file_size" => $this->file_size, "sort" => $this->sort, "alts" => $this->alts, diff --git a/app/Image/ImageProcessor.php b/app/Image/ImageProcessor.php new file mode 100644 index 0000000..bc61664 --- /dev/null +++ b/app/Image/ImageProcessor.php @@ -0,0 +1,110 @@ +interpretation; + $hue %= 360; + if ($hue < 0) { + $hue = 360 + $hue; + } + if ($image->hasAlpha()) { + $imageWithoutAlpha = $image->extract_band(0, ['n' => $image->bands - 1]); + $alpha = $image->extract_band($image->bands - 1, ['n' => 1]); + return $imageWithoutAlpha + ->colourspace(Interpretation::LCH) + ->linear([$brightness, $saturation, 1.0], [0.0, 0.0, $hue]) + ->colourspace($oldInterpretation) + ->bandjoin($alpha); + } + return $image + ->colourspace(Interpretation::LCH) + ->linear([$brightness, $saturation, 1.0], [0.0, 0.0, $hue]) + ->colourspace($oldInterpretation); + } + + public function process(string $filename, string $target, array $options = ["w" => null, "h" => null, "r" => null,"flip" => null , "canv" => null,"rotation" => null],$saveOptions = ['Q' => 100]) + { + if (!isset($options['w']) && !isset($options['h'])) { + $image = Image::thumbnail($filename, getimagesize($filename)[0]); + } + + if (isset($options['r'])) { + $rArray = explode(':', $options['r']); + + if (isset($options['w']) && !isset($options['h'])) { + $options['h'] = $options['w'] * $rArray[1]; + $options['w'] = $options['w'] * $rArray[0]; + } + + + if (!isset($options['w']) && isset($options['h'])) { + $options['h'] = $options['h'] * $rArray[1]; + $options['w'] = $options['h'] * $rArray[0]; + } + if (!isset($options['w']) && !isset($options['h'])) { + $options['h'] = getimagesize($filename)[0] * $rArray[1]; + $options['w'] = getimagesize($filename)[0] * $rArray[0]; + } + } + + if (isset($options['w']) && !isset($options['h'])) { + $image = Image::thumbnail($filename, $options['w'], ['height' => getimagesize($filename)[1]]); + } + + if (!isset($options['w']) && isset($options['h'])) { + $image = Image::thumbnail($filename, getimagesize($filename)[0], ['height' => $options['h']]); + } + + + if (isset($options['w']) && isset($options['h']) && !($options['canv'] == true)) { + $image = Image::thumbnail($filename, $options['w'], ['height' => $options['h'], 'crop' => 'centre']); + } + + if (isset($options['w']) && isset($options['h']) && $options['canv'] == true) { + $image = Image::thumbnail($filename, $options['w'], ['height' => $options['h']]); + $widthH = ($options['h'] - $image->height) / 2; + $widthW = ($options['w'] - $image->width) / 2; + $image = $image->embed( + $widthW, + $widthH, + $options['w'], + $options['h'], + ['extend' => 'background', 'background' => 1024] + ); + } + + if (isset($options['brightness']) || isset($options['saturation']) || isset($options['hue'])) { + $image = $this->brightness($image, isset($options['brightness']) ? $options['brightness'] : 1.0, isset($options['saturation']) ? $options['saturation'] : 1.0, isset($options['hue']) ? $options['hue'] : 0.0); + } + + if (isset($options['rotation'])) { + $image = $image->rotate($options['rotation']); + } + + if (isset($options['flip'])) { + if ($options['flip'] == "h") { + $image = $image->fliphor(); + } + + if ($options['flip'] == "v") { + $image = $image->flipver(); + } + + if ($options['flip'] == "hv") { + $image = $image->fliphor(); + $image = $image->flipver(); + } + } + + $image->writeToFile($target,$saveOptions); + + return $target; + } +} diff --git a/app/Image/Processor.php b/app/Image/Processor.php deleted file mode 100644 index 969dc8d..0000000 --- a/app/Image/Processor.php +++ /dev/null @@ -1,28 +0,0 @@ -interpretation; - $hue %= 360; - if ($hue < 0) { - $hue = 360 + $hue; - } - if ($image->hasAlpha()) { - $imageWithoutAlpha = $image->extract_band(0, ['n' => $image->bands - 1]); - $alpha = $image->extract_band($image->bands - 1, ['n' => 1]); - return $imageWithoutAlpha - ->colourspace(Interpretation::LCH) - ->linear([$brightness, $saturation, 1.0], [0.0, 0.0, $hue]) - ->colourspace($oldInterpretation) - ->bandjoin($alpha); - } - return $image - ->colourspace(Interpretation::LCH) - ->linear([$brightness, $saturation, 1.0], [0.0, 0.0, $hue]) - ->colourspace($oldInterpretation); - } -} diff --git a/app/Models/Collection.php b/app/Models/Collection.php index 7fd6714..2f0cc3d 100644 --- a/app/Models/Collection.php +++ b/app/Models/Collection.php @@ -28,7 +28,7 @@ class Collection extends Model "alt_required", "description_required", "exts", - "avalible_exts", + "ext", "mimetypes", "model", "expire_date", @@ -36,7 +36,6 @@ class Collection extends Model protected $casts = [ 'exts' => 'array', - 'avalible_exts' => 'array', 'mimetypes' => 'array', ]; @@ -46,12 +45,7 @@ class Collection extends Model set: fn ($value) => json_encode($value), ); } - protected function avalible_exts(): Attribute - { - return Attribute::make( - set: fn ($value) => json_encode($value), - ); - } + protected function mimetypes(): Attribute { return Attribute::make( diff --git a/app/Models/File.php b/app/Models/File.php index 3df7b3b..69650ed 100644 --- a/app/Models/File.php +++ b/app/Models/File.php @@ -29,6 +29,7 @@ class File extends Model "description", "user_id", "ip", + "model_id", "collection_id", "published_at", ]; diff --git a/app/Providers/EventServiceProvider.php b/app/Providers/EventServiceProvider.php index ab8b2cf..97d03ea 100644 --- a/app/Providers/EventServiceProvider.php +++ b/app/Providers/EventServiceProvider.php @@ -2,10 +2,13 @@ namespace App\Providers; +use App\Models\File; +use App\Observers\FileObserver; use Illuminate\Auth\Events\Registered; use Illuminate\Auth\Listeners\SendEmailVerificationNotification; use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider; use Illuminate\Support\Facades\Event; +use PHPUnit\TextUI\XmlConfiguration\FileCollection; class EventServiceProvider extends ServiceProvider { diff --git a/app/Providers/UuidServiceProvider.php b/app/Providers/UuidServiceProvider.php new file mode 100644 index 0000000..235b289 --- /dev/null +++ b/app/Providers/UuidServiceProvider.php @@ -0,0 +1,31 @@ +app->bind('uuid', function () { + return Str::uuid(); + }); + } +} diff --git a/app/Utilities/Helpers/Image.php b/app/Utilities/Helpers/Image.php new file mode 100644 index 0000000..8be9b74 --- /dev/null +++ b/app/Utilities/Helpers/Image.php @@ -0,0 +1,193 @@ + 0 ? '?text=' . urlencode(implode(' ', $imageParts)) : '' + ); + } + + /** + * Download a remote random image to disk and return its location + * + * Requires curl, or allow_url_fopen to be on in php.ini. + * + * @example '/path/to/dir/13b73edae8443990be1aa8f1a483bc27.png' + * + * @return bool|string + */ + public static function image( + $dir = null, + $width = 640, + $height = 480, + $category = null, + $fullPath = true, + $randomize = true, + $word = null, + $gray = false, + $format = 'png' + ) { + trigger_deprecation( + 'fakerphp/faker', + '1.20', + 'Provider is deprecated and will no longer be available in Faker 2. Please use a custom provider instead' + ); + + $dir = null === $dir ? sys_get_temp_dir() : $dir; // GNU/Linux / OS X / Windows compatible + // Validate directory path + if (!is_dir($dir) || !is_writable($dir)) { + throw new \InvalidArgumentException(sprintf('Cannot write to directory "%s"', $dir)); + } + + // Generate a random filename. Use the server address so that a file + // generated at the same time on a different server won't have a collision. + $name = md5(uniqid(empty($_SERVER['SERVER_ADDR']) ? '' : $_SERVER['SERVER_ADDR'], true)); + $filename = sprintf('%s.%s', $name, $format); + $filepath = $dir . DIRECTORY_SEPARATOR . $filename; + + $url = static::imageUrl($width, $height, $category, $randomize, $word, $gray, $format); + + // save file + if (function_exists('curl_exec')) { + // use cURL + $fp = fopen($filepath, 'w'); + $ch = curl_init($url); + curl_setopt($ch, CURLOPT_FILE, $fp); + $success = curl_exec($ch) && curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200; + fclose($fp); + curl_close($ch); + + if (!$success) { + unlink($filepath); + + // could not contact the distant URL or HTTP error - fail silently. + return false; + } + } elseif (ini_get('allow_url_fopen')) { + // use remote fopen() via copy() + $success = copy($url, $filepath); + + if (!$success) { + // could not contact the distant URL or HTTP error - fail silently. + return false; + } + } else { + return new \RuntimeException('The image formatter downloads an image from a remote HTTP server. Therefore, it requires that PHP can request remote hosts, either via cURL or fopen()'); + } + + return $fullPath ? $filepath : $filename; + } + + public static function getFormats(): array + { + trigger_deprecation( + 'fakerphp/faker', + '1.20', + 'Provider is deprecated and will no longer be available in Faker 2. Please use a custom provider instead' + ); + + return array_keys(static::getFormatConstants()); + } + + public static function getFormatConstants(): array + { + trigger_deprecation( + 'fakerphp/faker', + '1.20', + 'Provider is deprecated and will no longer be available in Faker 2. Please use a custom provider instead' + ); + + return [ + static::FORMAT_JPG => constant('IMAGETYPE_JPEG'), + static::FORMAT_JPEG => constant('IMAGETYPE_JPEG'), + static::FORMAT_PNG => constant('IMAGETYPE_PNG'), + ]; + } +} diff --git a/config/app.php b/config/app.php index e8b5010..260a8a0 100644 --- a/config/app.php +++ b/config/app.php @@ -195,7 +195,8 @@ return [ App\Providers\EventServiceProvider::class, App\Providers\RouteServiceProvider::class, App\Providers\SettingServiceProvider::class, - // App\Providers\CollectionServiceProvider::class + App\Providers\UuidServiceProvider::class + ], /* diff --git a/database/factories/BaseFactory.php b/database/factories/BaseFactory.php index 319c837..912ed3c 100644 --- a/database/factories/BaseFactory.php +++ b/database/factories/BaseFactory.php @@ -3,7 +3,7 @@ namespace Database\Factories; - +use App\Image\ImageProcessor; use Illuminate\Support\Str; trait BaseFactory @@ -70,4 +70,15 @@ trait BaseFactory } + public function withImage() + { + return null; + } + + public function createImage($path, $saveOptions = ['Q' => 100],$options = ["w" => null, "h" => null, "r" => null,"flip" => null , "canv" => null,"rotation" => null]) + { + $imageProcessor = new ImageProcessor; + $image = $imageProcessor->process(storage_path('stub') . '/image.png',$path,$options,$saveOptions); + return $this; + } } diff --git a/database/factories/CollectionFactory.php b/database/factories/CollectionFactory.php index 1ca7151..4f853d3 100644 --- a/database/factories/CollectionFactory.php +++ b/database/factories/CollectionFactory.php @@ -38,17 +38,12 @@ class CollectionFactory extends Factory "png", "webp" ], - "avalible_exts" => [ - "jpg", - "jpeg", - "png", - "webp" - ], + "ext" => "webp", "mimetypes" => [ - "jpg", - "jpeg", - "png", - "webp" + "image/webp", + "image/png", + "image/jpeg", + "image/jpg" ], "model" => fake()->name(), "expire_date" => "2022-07-27 09:17:59" diff --git a/database/factories/FileFactory.php b/database/factories/FileFactory.php index 5ebfb9d..5949c0a 100644 --- a/database/factories/FileFactory.php +++ b/database/factories/FileFactory.php @@ -4,12 +4,15 @@ namespace Database\Factories; use App\Models\Collection; use Illuminate\Database\Eloquent\Factories\Factory; +use Illuminate\Support\Facades\App; +use Illuminate\Support\Str; /** * @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\File> */ class FileFactory extends Factory { + use BaseFactory; /** * Define the model's default state. * @@ -18,14 +21,13 @@ class FileFactory extends Factory public function definition() { return [ - "uuid" => 1, + "uuid" => app()->uuid, "original_name" => fake()->name(), "ext" => ['jpg', 'jpeg', 'png', 'webp'][rand(0, 3)], "mimetype" => 'image', "width" => rand(300, 2000), "height" => rand(300, 2000), "file_size" => rand(300, 2000), - "server_path" => date('y') . '/' . date('m'), "sort" => rand(0, 23), "alts" => [ 'hello wroldswdfouiwref iuwrhgf ow rgfaw ghfawej', @@ -34,8 +36,16 @@ class FileFactory extends Factory "description" => 'ajsfoisahjfoaspf asduf safsafjsh lh', "user_id" => rand(43724, 382348), "ip" => "127.0. 0.1", - "collection_id" => Collection::factory()->create()->id, + // "collection_id" => $collection->id, "published_at" => "2022-07-27 09:17:59", ]; } + + + public function dependencyProvider() + { + return [ + 'collection_id' => Collection::factory()->createQuietly() + ]; + } } diff --git a/database/migrations/2022_07_27_073858_create_files_table.php b/database/migrations/2022_07_27_073858_create_files_table.php index 570fb5a..74b41a8 100644 --- a/database/migrations/2022_07_27_073858_create_files_table.php +++ b/database/migrations/2022_07_27_073858_create_files_table.php @@ -24,6 +24,7 @@ return new class extends Migration $table->bigInteger("file_size")->nullable(); $table->bigInteger("sort")->nullable(); $table->json("alts")->nullable(); + $table->unsignedBigInteger("model_id")->nullable(); $table->string("description")->nullable(); $table->unsignedBigInteger("user_id")->nullable(); $table->string("ip")->nullable(); diff --git a/database/migrations/2022_07_27_073906_create_collections_table.php b/database/migrations/2022_07_27_073906_create_collections_table.php index 09a587a..dcf79b6 100644 --- a/database/migrations/2022_07_27_073906_create_collections_table.php +++ b/database/migrations/2022_07_27_073906_create_collections_table.php @@ -31,7 +31,8 @@ return new class extends Migration $table->boolean("alt_required")->nullable(); $table->boolean("description_required")->nullable(); $table->json("exts")->nullable(); - $table->json("avalible_exts")->nullable(); + $table->string("ext")->nullable(); + $table->json('image_processor')->nullable(); $table->json("mimetypes")->nullable(); $table->string("model")->unique()->nullable(); $table->time("expire_date")->nullable(); diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 22e5279..a406d7e 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -21,7 +21,28 @@ class DatabaseSeeder extends Seeder // 'email' => 'test@example.com', // ]); + \App\Models\Collection::factory()->create([ + "name" => "fuck", + "count" => 1, + "tmp_support" => 0, + "remove_tmp_time" => 132, + "max_file_size" => 100000000, + "min_file_size" => 10, + "max_width" =>2000, + "min_width" =>10, + "max_height" => 2000, + "min_height" =>10, + "alt_required" => 0, + "description_required" =>0, + "exts" => [ + "jpg", + "jpeg", + "png", + "webp" + ], + "ext" => "webp", + ]); \App\Models\Collection::factory(10)->create(); - \App\Models\File::factory(1)->create(); + \App\Models\File::factory()->create(); } } diff --git a/php.ini b/php.ini deleted file mode 100644 index bc849bf..0000000 --- a/php.ini +++ /dev/null @@ -1 +0,0 @@ -ffi.enable = "true" diff --git a/public/image-modified.webp b/public/image-modified.webp index fa30048..a3d801f 100644 Binary files a/public/image-modified.webp and b/public/image-modified.webp differ diff --git a/resources/views/welcome.blade.php b/resources/views/welcome.blade.php index f3ee5b1..643535d 100644 --- a/resources/views/welcome.blade.php +++ b/resources/views/welcome.blade.php @@ -16,13 +16,9 @@ -
+ @csrf -
- - -


@@ -36,6 +32,18 @@
+ + @dump($errors->any()) + @if($errors->any()) +
+

Opps Something went wrong

+ +
+@endif diff --git a/routes/api.php b/routes/api.php index f6d9471..62cc75d 100644 --- a/routes/api.php +++ b/routes/api.php @@ -24,5 +24,5 @@ Route::group(['as' => 'api.'], function () { Route::delete('collections/{collection}', [CollectionController::class, "destroy"])->withTrashed(); Route::get('{collection_name}/{uuid}.{extention}', [FileController::class, 'show'])->name('file.show'); Route::get('{collection_name}/{path}', [FileController::class, 'private'])->name('file.private'); - Route::post('{collection_name}', [FileController::class, 'store'])->name('file.store'); + Route::post('{collection_name}/{model_id?}', [FileController::class, 'store'])->name('file.store'); }); diff --git a/routes/web.php b/routes/web.php index 655f21f..0958771 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,7 +1,9 @@ $request->w, + 'h' => $request->h, + 'r' => $request->r, + 'canv' => $request->canv, + ]; + $imageProcessor->process(public_path('image.png'),public_path('image-modified.webp'),$option); + + return response()->file(public_path('image-modified.webp')); +}); Route::get('/', function (Request $request) { - // // $request->dddd = 'tesst'; - // dump($request->); + Collection::find(1)->getExts(); if (!isset($request->w) && !isset($request->h)) { $image = Image::thumbnail('../public/image.png', getimagesize('../public/image.png')[0]); @@ -95,7 +107,7 @@ Route::get('/', function (Request $request) { } - $image->writeToFile('image-modified.webp', [ + $image->writeToFile(storage_path('image-modified.webp'), [ 'Q' => isset($request->q) ? $request->q : 100 ]); @@ -103,8 +115,14 @@ Route::get('/', function (Request $request) { }); + Route::get('/upload',function(){ return view('welcome'); }); -Route::post('/upload',[FileController::class,'store']); +Route::post('/fuck',function(Request $request) +{ + $request->all(); + $storedImage = $request->file->storeAs('/addifsfsfsffuck', app()->uuid . '.' . 'webp', 'local'); + +}); diff --git a/storage/image-modified.webp b/storage/image-modified.webp new file mode 100644 index 0000000..fa30048 Binary files /dev/null and b/storage/image-modified.webp differ diff --git a/public/image.png b/storage/stub/image.png similarity index 100% rename from public/image.png rename to storage/stub/image.png diff --git a/tests/Base/FactoryMethodsTrait.php b/tests/Base/FactoryMethodsTrait.php index 1f939cf..ee28eca 100644 --- a/tests/Base/FactoryMethodsTrait.php +++ b/tests/Base/FactoryMethodsTrait.php @@ -21,7 +21,7 @@ trait FactoryMethodsTrait public function one($class, $attributes = []) { - return $class::factory()->createQuietly($attributes); + return $class::factory()->withDependency()->createQuietly($attributes); } public function randomOne($class) diff --git a/tests/Bootstrap.php b/tests/Bootstrap.php index 65a8ac0..7a5a5b8 100644 --- a/tests/Bootstrap.php +++ b/tests/Bootstrap.php @@ -2,7 +2,13 @@ namespace Tests; +use Tests\Base\AuthMethodsTrait; +use Tests\Base\DynamicPolicyAndModelTrait; +use Tests\Base\FactoryMethodsTrait; +use Tests\Base\FreshMongodbDatabase; +use Tests\Base\MockMethodsTrait; + class Bootstrap extends TestCase { - + use AuthMethodsTrait,DynamicPolicyAndModelTrait,FactoryMethodsTrait,FreshMongodbDatabase,MockMethodsTrait; } diff --git a/tests/Feature/FileStoreTest.php b/tests/Feature/FileStoreTest.php new file mode 100644 index 0000000..40f826f --- /dev/null +++ b/tests/Feature/FileStoreTest.php @@ -0,0 +1,138 @@ + UploadedFile::fake()->image('test.png'), + "alts" => ['1', '2', '3'], + "description" => 'lfjdsklfslfsdlfasdfsfhgsfgsdf', + "public" => 1 + ]; + $collection = Collection::factory()->create([ + 'tmp_support' => false + ]); + $response = $this->loginAs('dick')->postJson(route('api.file.store', ['collection_name' => $collection->name]), $data); + + $response->assertForbidden(); + } + + public function test_tmp_false_and_collection_is_full_forbidden() + { + $randomCount = rand(2, 10); + $collection = Collection::factory()->createQuietly([ + 'tmp_support' => false, + 'count' => $randomCount + ]); + for($i=$randomCount; $i > 0; $i--) { + $uuid = app()->uuid; + $this->one(File::class, [ + 'uuid' => $uuid, + 'user_id' => auth()->id(), + 'collection_id' => $collection->id, + 'server_path' => '/' . date('y') . '/' . date('m') . '/' . $uuid . '.' . $collection->ext, + ]); + } + + $data = [ + "file" => UploadedFile::fake()->image('test.png'), + "alts" => ['1', '2', '3'], + "description" => 'lfjdsklfslfsdlfasdfsfhgsfgsdf', + "public" => 1 + ]; + $response = $this->loginAs('dick')->postJson(route('api.file.store', ['collection_name' => $collection->name]), $data); + $response->assertForbidden(); + } + + public function test_file_is_not_isset_forbidden() + { + + $collection = Collection::factory()->create([ + 'tmp_support' => true + ]); + + $data = [ + "file" => app()->uuid, + "alts" => ['1', '2', '3'], + "description" => 'lfjdsklfslfsdlfasdfsfhgsfgsdf', + "public" => 1 + ]; + + $response = $this->loginAs('dick')->postJson(route('api.file.store', ['collection_name' => $collection->name]), $data); + + $response->assertForbidden(); + } + + + /** + * @dataProvider storeValidationTestProvider + */ + public function test_store_dynamic_validation_unprocessable($collectionFields, $dataFields) + { + $collection = Collection::factory()->create($collectionFields); + $response = $this->loginAs('dick')->postJson(route('api.file.store', ['collection_name' => $collection->name]), $dataFields); + $response->assertUnprocessable(); + } + + // /** + // * @testWith + // * ['email:gt'] + // * ['email:gt'] + // * ['email:gt'] + // * ['email:gt'] + // * ['email:gt'] + // */ + // public function test_store_static_validation_unprocessable($key) + // { + // File::factory()->smash($key); + // } + + + public function test_store_dynamic_validation_stored_file_unprocessable() + { + + $collection = Collection::factory()->create([ + 'alt_required' => false, + 'description_required' => false, + 'tmp_support' => true, + 'max_width' => 2000, + 'max_height' => 2000, + 'min_width' => 1, + 'min_height' => 1, + 'min_file_size' => 0 + ]); + $uuid = app()->uuid; + $file = File::factory()->createImage(storage_path('app/' . date('y') . '/' . date('m') . '/' . $uuid . '.' . $collection->ext))->create([ + 'uuid' => $uuid, + 'server_path' => '/' . date('y') . '/' . date('m') . '/', + 'collection_id' => $collection->id + ]); + + $data = [ + "file" => $file->uuid, + "alts" => ['1', '2', '3'], + "description" => 'lfjdsklfslfsdlfasdfsfhgsfgsdf', + "public" => 1 + ]; + + $response = $this->loginAs('dick')->postJson(route('api.file.store', ['collection_name' => $collection->name]), $data); + + $response->assertUnprocessable(); + } +} diff --git a/tests/Feature/Traits/FileTraits.php b/tests/Feature/Traits/FileTraits.php new file mode 100644 index 0000000..d9b9781 --- /dev/null +++ b/tests/Feature/Traits/FileTraits.php @@ -0,0 +1,63 @@ + false, + 'description_required' => false, + 'tmp_support' => true, + 'max_width' => 2000, + 'max_height' => 2000, + 'min_width' => 1, + 'min_height' => 1, + 'min_file_size' => 0 + ], + [ + "file" => UploadedFile::fake()->image('test.png', 400, 400), + "public" => 1 + ] + ]; + } + + private function changeDefaultArrayAndReturn($defaultArray, $key, $value): array + { + $defaultArray[$key[0]][$key[1]] = $value; + return $defaultArray; + } + + public function storeValidationTestProvider() + { + + $data = [ + $this->changeDefaultArrayAndReturn($this->defaultArray(), [0, 'alt_required'], true), + $this->changeDefaultArrayAndReturn($this->defaultArray(), [0, 'description_required'], true), + $this->changeDefaultArrayAndReturn($this->defaultArray(), [0, 'max_width'], 2), + $this->changeDefaultArrayAndReturn($this->defaultArray(), [0, 'max_height'], 2), + $this->changeDefaultArrayAndReturn($this->defaultArray(), [0, 'min_width'], 1500), + $this->changeDefaultArrayAndReturn($this->defaultArray(), [0, 'min_height'], 1500), + $this->changeDefaultArrayAndReturn($this->defaultArray(), [0, 'min_file_size'], 1000), + $this->changeDefaultArrayAndReturn($this->defaultArray(), [0, 'max_file_size'], 0), + $this->changeDefaultArrayAndReturn($this->defaultArray(), [0, 'exts'], ['jpg']), + $this->changeDefaultArrayAndReturn($this->defaultArray(), [0, 'mimetypes'], ['image/jpg']), + ]; + return $data; + } + + + public function storeValidationWithUuidTestProvider() + { + + $data = [ + $this->changeDefaultArrayAndReturn($this->defaultArray(), [0, 'alt_required'], true), + ]; + return $data; + } +}