feat: image feature added

This commit is contained in:
2025-09-26 11:42:31 +03:30
parent 0b52638e7d
commit 535e73c4c9
6 changed files with 632 additions and 2 deletions
+123
View File
@@ -0,0 +1,123 @@
<?php
// app/Http/Controllers/ImageController.php
namespace App\Http\Controllers;
use App\Models\Image;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;
class ImageController extends Controller
{
public function store(Request $request)
{
$data = $request->validate([
'image' => 'required|image|max:2048',
'title' => 'nullable|string|max:255',
'description' => 'nullable|string|max:500',
'type' => 'nullable|in:public,private',
]);
$path = $request->file('image')->store('images', 'public');
$image = Image::create([
'user_id' => auth()->id(),
'path' => $path,
'title' => $data['title'] ?? null,
'description' => $data['description'] ?? null,
'type' => $data['type'] ?? 'private', // default private
]);
return response()->json([
'message' => 'Image uploaded successfully',
'image' => $image,
'url' => asset('storage/' . $path),
]);
}
public function publicImages()
{
$images = Image::where('type', 'public')->get();
return response()->json($images->map(function ($image) {
$image->url = asset('storage/' . $image->path);
return $image;
}));
}
public function userImages()
{
$images = Image::where('user_id', auth()->id())
->where('type', 'private')
->get();
return response()->json($images->map(function ($image) {
$image->url = asset('storage/' . $image->path);
return $image;
}));
}
public function allImages()
{
$userId = auth()->id();
$images = Image::where('type', 'public')
->orWhere(function ($query) use ($userId) {
$query->where('type', 'private')
->where('user_id', $userId);
})
->get();
return response()->json($images->map(function ($image) {
$image->url = asset('storage/' . $image->path);
return $image;
}));
}
// ✅ Update image
public function update(Request $request, $id)
{
$image = Image::where('id', $id)
->where('user_id', auth()->id()) // only owner can update
->firstOrFail();
$data = $request->validate([
'title' => 'nullable|string|max:255',
'description' => 'nullable|string|max:500',
'type' => 'nullable|in:public,private',
'image' => 'nullable|image|max:2048',
]);
if ($request->hasFile('image')) {
// delete old image
Storage::disk('public')->delete($image->path);
// store new one
$path = $request->file('image')->store('images', 'public');
$image->path = $path;
}
$image->title = $data['title'] ?? $image->title;
$image->description = $data['description'] ?? $image->description;
$image->type = $data['type'] ?? $image->type;
$image->save();
return response()->json([
'message' => 'Image updated successfully',
'image' => $image,
'url' => asset('storage/' . $image->path),
]);
}
// ✅ Delete image
public function destroy($id)
{
$image = Image::where('id', $id)
->where('user_id', auth()->id()) // only owner can delete
->firstOrFail();
Storage::disk('public')->delete($image->path);
$image->delete();
return response()->json(['message' => 'Image deleted successfully']);
}
}
+14
View File
@@ -0,0 +1,14 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Image extends Model
{
protected $fillable = ['user_id', 'path', 'title', 'description','type',];
public function user() {
return $this->belongsTo(User::class);
}
}
+1
View File
@@ -20,6 +20,7 @@
},
"require-dev": {
"fakerphp/faker": "^1.23",
"knuckleswtf/scribe": "*",
"laravel/pail": "^1.2.2",
"laravel/pint": "^1.13",
"laravel/sail": "^1.41",
Generated
+448 -1
View File
@@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "b2928ef8514c9c8819a75d8ef288dcb2",
"content-hash": "a424d7cee6af46482fa10c8efef94a43",
"packages": [
{
"name": "brick/math",
@@ -7259,6 +7259,56 @@
}
],
"packages-dev": [
{
"name": "erusev/parsedown",
"version": "1.7.4",
"source": {
"type": "git",
"url": "https://github.com/erusev/parsedown.git",
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/erusev/parsedown/zipball/cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"reference": "cb17b6477dfff935958ba01325f2e8a2bfa6dab3",
"shasum": ""
},
"require": {
"ext-mbstring": "*",
"php": ">=5.3.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35"
},
"type": "library",
"autoload": {
"psr-0": {
"Parsedown": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Emanuil Rusev",
"email": "hello@erusev.com",
"homepage": "http://erusev.com"
}
],
"description": "Parser for Markdown.",
"homepage": "http://parsedown.org",
"keywords": [
"markdown",
"parser"
],
"support": {
"issues": "https://github.com/erusev/parsedown/issues",
"source": "https://github.com/erusev/parsedown/tree/1.7.x"
},
"time": "2019-12-30T22:54:17+00:00"
},
{
"name": "fakerphp/faker",
"version": "v1.24.1",
@@ -7444,6 +7494,100 @@
},
"time": "2020-07-09T08:09:16+00:00"
},
{
"name": "knuckleswtf/scribe",
"version": "5.3.0",
"source": {
"type": "git",
"url": "https://github.com/knuckleswtf/scribe.git",
"reference": "380f9cd6de6d65d2e92930a8613d8a682e83e8c7"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/knuckleswtf/scribe/zipball/380f9cd6de6d65d2e92930a8613d8a682e83e8c7",
"reference": "380f9cd6de6d65d2e92930a8613d8a682e83e8c7",
"shasum": ""
},
"require": {
"erusev/parsedown": "1.7.4",
"ext-fileinfo": "*",
"ext-json": "*",
"ext-pdo": "*",
"fakerphp/faker": "^1.23.1",
"laravel/framework": "^9.0|^10.0|^11.0|^12.0",
"league/flysystem": "^3.0",
"mpociot/reflection-docblock": "^1.0.1",
"nikic/php-parser": "^5.0",
"nunomaduro/collision": "^6.0|^7.0|^8.0",
"php": ">=8.1",
"ramsey/uuid": "^4.2.2",
"shalvah/clara": "^3.1.0",
"shalvah/upgrader": ">=0.6.0",
"spatie/data-transfer-object": "^2.6|^3.0",
"symfony/var-exporter": "^6.0|^7.0",
"symfony/yaml": "^6.0|^7.0"
},
"replace": {
"mpociot/laravel-apidoc-generator": "*"
},
"require-dev": {
"dms/phpunit-arraysubset-asserts": "^v0.5.0",
"laravel/legacy-factories": "^1.3.0",
"league/fractal": "^0.20",
"nikic/fast-route": "^1.3",
"orchestra/testbench": "^7.0|^8.0|^v9.10.0|^10.0",
"pestphp/pest": "^1.21|^2.0|^3.0",
"phpstan/phpstan": "^2.1.5",
"phpunit/phpunit": "^9.0|^10.0|^11.0",
"spatie/ray": "^1.41",
"symfony/css-selector": "^6.0|^7.0",
"symfony/dom-crawler": "^6.0|^7.0"
},
"type": "library",
"extra": {
"laravel": {
"providers": [
"Knuckles\\Scribe\\ScribeServiceProvider"
]
}
},
"autoload": {
"files": [
"src/Config/helpers.php"
],
"psr-4": {
"Knuckles\\Camel\\": "camel/",
"Knuckles\\Scribe\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Shalvah"
}
],
"description": "Generate API documentation for humans from your Laravel codebase.✍",
"homepage": "http://github.com/knuckleswtf/scribe",
"keywords": [
"api",
"documentation",
"laravel"
],
"support": {
"issues": "https://github.com/knuckleswtf/scribe/issues",
"source": "https://github.com/knuckleswtf/scribe/tree/5.3.0"
},
"funding": [
{
"url": "https://patreon.com/shalvah",
"type": "patreon"
}
],
"time": "2025-07-28T22:27:25+00:00"
},
{
"name": "laravel/pail",
"version": "v1.2.2",
@@ -7734,6 +7878,59 @@
},
"time": "2024-05-16T03:13:13+00:00"
},
{
"name": "mpociot/reflection-docblock",
"version": "1.0.1",
"source": {
"type": "git",
"url": "https://github.com/mpociot/reflection-docblock.git",
"reference": "c8b2e2b1f5cebbb06e2b5ccbf2958f2198867587"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/mpociot/reflection-docblock/zipball/c8b2e2b1f5cebbb06e2b5ccbf2958f2198867587",
"reference": "c8b2e2b1f5cebbb06e2b5ccbf2958f2198867587",
"shasum": ""
},
"require": {
"php": ">=5.3.3"
},
"require-dev": {
"phpunit/phpunit": "~4.0"
},
"suggest": {
"dflydev/markdown": "~1.0",
"erusev/parsedown": "~1.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "2.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Mpociot": [
"src/"
]
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Mike van Riel",
"email": "mike.vanriel@naenius.com"
}
],
"support": {
"issues": "https://github.com/mpociot/reflection-docblock/issues",
"source": "https://github.com/mpociot/reflection-docblock/tree/master"
},
"time": "2016-06-20T20:53:12+00:00"
},
{
"name": "myclabs/deep-copy",
"version": "1.13.0",
@@ -9369,6 +9566,175 @@
],
"time": "2024-10-09T05:16:32+00:00"
},
{
"name": "shalvah/clara",
"version": "3.2.0",
"source": {
"type": "git",
"url": "https://github.com/shalvah/clara.git",
"reference": "cdbb5737cbdd101756d97dd2279a979a1af7710b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/shalvah/clara/zipball/cdbb5737cbdd101756d97dd2279a979a1af7710b",
"reference": "cdbb5737cbdd101756d97dd2279a979a1af7710b",
"shasum": ""
},
"require": {
"php": ">=7.4",
"symfony/console": "^4.0|^5.0|^6.0|^7.0"
},
"require-dev": {
"eloquent/phony-phpunit": "^7.0",
"phpunit/phpunit": "^9.1"
},
"type": "library",
"autoload": {
"files": [
"helpers.php"
],
"psr-4": {
"Shalvah\\Clara\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "🔊 Simple, pretty, testable console output for CLI apps.",
"keywords": [
"cli",
"log",
"logging"
],
"support": {
"issues": "https://github.com/shalvah/clara/issues",
"source": "https://github.com/shalvah/clara/tree/3.2.0"
},
"time": "2024-02-27T20:30:59+00:00"
},
{
"name": "shalvah/upgrader",
"version": "0.6.0",
"source": {
"type": "git",
"url": "https://github.com/shalvah/upgrader.git",
"reference": "d95ed17fe9f5e1ee7d47ad835595f1af080a867f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/shalvah/upgrader/zipball/d95ed17fe9f5e1ee7d47ad835595f1af080a867f",
"reference": "d95ed17fe9f5e1ee7d47ad835595f1af080a867f",
"shasum": ""
},
"require": {
"illuminate/support": ">=8.0",
"nikic/php-parser": "^5.0",
"php": ">=8.0"
},
"require-dev": {
"dms/phpunit-arraysubset-asserts": "^0.2.0",
"pestphp/pest": "^1.21",
"phpstan/phpstan": "^1.0",
"spatie/ray": "^1.33"
},
"type": "library",
"autoload": {
"psr-4": {
"Shalvah\\Upgrader\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Shalvah",
"email": "hello@shalvah.me"
}
],
"description": "Create automatic upgrades for your package.",
"homepage": "http://github.com/shalvah/upgrader",
"keywords": [
"upgrade"
],
"support": {
"issues": "https://github.com/shalvah/upgrader/issues",
"source": "https://github.com/shalvah/upgrader/tree/0.6.0"
},
"funding": [
{
"url": "https://patreon.com/shalvah",
"type": "patreon"
}
],
"time": "2024-02-20T11:51:46+00:00"
},
{
"name": "spatie/data-transfer-object",
"version": "3.9.1",
"source": {
"type": "git",
"url": "https://github.com/spatie/data-transfer-object.git",
"reference": "1df0906c4e9e3aebd6c0506fd82c8b7d5548c1c8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/spatie/data-transfer-object/zipball/1df0906c4e9e3aebd6c0506fd82c8b7d5548c1c8",
"reference": "1df0906c4e9e3aebd6c0506fd82c8b7d5548c1c8",
"shasum": ""
},
"require": {
"php": "^8.0"
},
"require-dev": {
"illuminate/collections": "^8.36",
"jetbrains/phpstorm-attributes": "^1.0",
"larapack/dd": "^1.1",
"phpunit/phpunit": "^9.5.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Spatie\\DataTransferObject\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Brent Roose",
"email": "brent@spatie.be",
"homepage": "https://spatie.be",
"role": "Developer"
}
],
"description": "Data transfer objects with batteries included",
"homepage": "https://github.com/spatie/data-transfer-object",
"keywords": [
"data-transfer-object",
"spatie"
],
"support": {
"issues": "https://github.com/spatie/data-transfer-object/issues",
"source": "https://github.com/spatie/data-transfer-object/tree/3.9.1"
},
"funding": [
{
"url": "https://spatie.be/open-source/support-us",
"type": "custom"
},
{
"url": "https://github.com/spatie",
"type": "github"
}
],
"abandoned": "spatie/laravel-data",
"time": "2022-09-16T13:34:38+00:00"
},
{
"name": "staabm/side-effects-detector",
"version": "1.0.5",
@@ -9421,6 +9787,87 @@
],
"time": "2024-10-20T05:08:20+00:00"
},
{
"name": "symfony/var-exporter",
"version": "v7.3.3",
"source": {
"type": "git",
"url": "https://github.com/symfony/var-exporter.git",
"reference": "d4dfcd2a822cbedd7612eb6fbd260e46f87b7137"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/var-exporter/zipball/d4dfcd2a822cbedd7612eb6fbd260e46f87b7137",
"reference": "d4dfcd2a822cbedd7612eb6fbd260e46f87b7137",
"shasum": ""
},
"require": {
"php": ">=8.2",
"symfony/deprecation-contracts": "^2.5|^3"
},
"require-dev": {
"symfony/property-access": "^6.4|^7.0",
"symfony/serializer": "^6.4|^7.0",
"symfony/var-dumper": "^6.4|^7.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\VarExporter\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Allows exporting any serializable PHP data structure to plain PHP code",
"homepage": "https://symfony.com",
"keywords": [
"clone",
"construct",
"export",
"hydrate",
"instantiate",
"lazy-loading",
"proxy",
"serialize"
],
"support": {
"source": "https://github.com/symfony/var-exporter/tree/v7.3.3"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://github.com/nicolas-grekas",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2025-08-18T13:10:53+00:00"
},
{
"name": "symfony/yaml",
"version": "v7.2.5",
@@ -0,0 +1,32 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('images', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained()->onDelete('cascade');
$table->string('path'); // مسیر ذخیره فایل
$table->string('title')->nullable();
$table->string('description')->nullable();
$table->enum('type', ['public', 'private'])->default('private'); // 🔑 type of image
$table->timestamps();
});
}
/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('images');
}
};
+14 -1
View File
@@ -12,6 +12,7 @@
use Illuminate\Support\Facades\Hash;
use App\Http\Controllers\QuestionController;
use App\Http\Controllers\SliderController;
use App\Http\Controllers\ImageController;
Route::get('/test-hash', function() {
$plain = 'amnk1380';
@@ -105,7 +106,19 @@
/// slider feature
Route::get('/slider', [SliderController::class, 'index']);
/// images
Route::post('/images', [ImageController::class, 'store']);
Route::get('/images/private', [ImageController::class, 'userImages']);
Route::get('/images/all', [ImageController::class, 'allImages']);
Route::get('/images/public', [ImageController::class, 'publicImages']);
Route::put('/images/{id}', [ImageController::class, 'update']); // ✅ update
Route::delete('/images/{id}', [ImageController::class, 'destroy']); // ✅ delete
});