create profile api's with tests
This commit is contained in:
107
app/Facades/File/File.php
Normal file
107
app/Facades/File/File.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace App\Facades\File;
|
||||
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Illuminate\Http\File as HttpFile;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class File
|
||||
{
|
||||
public function save(HttpFile|UploadedFile $file, string $path, string $name = null, string $disk = 'public'): string
|
||||
{
|
||||
return Storage::disk($disk)->putFileAs(
|
||||
$path,
|
||||
$file,
|
||||
$name ?? Str::uuid() . '.' . $file->extension()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $filePath
|
||||
* @param bool $url_is_absolute
|
||||
* @param string $disk
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException when filePath is empty.
|
||||
*/
|
||||
public function delete(string $filePath, bool $url_is_absolute = false, string $disk = 'public'): void
|
||||
{
|
||||
if (!$filePath){
|
||||
throw new \InvalidArgumentException('File path is invalid.');
|
||||
}
|
||||
|
||||
if ($url_is_absolute) {
|
||||
$needle = 'storage/';
|
||||
$pos = strpos($filePath, $needle);
|
||||
$filePath = substr($filePath, $pos + strlen($needle));
|
||||
}
|
||||
|
||||
if (Storage::disk($disk)->exists($filePath)) {
|
||||
Storage::disk($disk)->delete($filePath);
|
||||
}
|
||||
}
|
||||
|
||||
public function deleteContent($file_path): bool
|
||||
{
|
||||
if (file_exists($file_path)) {
|
||||
file_put_contents($file_path, '');
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function tail($file_path, $lines = 100, $buffer = 2048): bool|string
|
||||
{
|
||||
// Open file
|
||||
$file = @fopen($file_path, "rb");
|
||||
if ($file === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Jump to last character
|
||||
fseek($file, -1, SEEK_END);
|
||||
|
||||
// Read it and adjust line number if necessary
|
||||
// (Otherwise the result would be wrong if file doesn't end with a blank line)
|
||||
if (fread($file, 1) != "\n") {
|
||||
$lines -= 1;
|
||||
}
|
||||
|
||||
// Start reading
|
||||
$output = '';
|
||||
$chunk = '';
|
||||
|
||||
// While we would like more
|
||||
while (ftell($file) > 0 && $lines >= 0) {
|
||||
|
||||
// Figure out how far back we should jump
|
||||
$seek = min(ftell($file), $buffer);
|
||||
|
||||
// Do the jump (backwards, relative to where we are)
|
||||
fseek($file, -$seek, SEEK_CUR);
|
||||
|
||||
// Read a chunk and prepend it to our output
|
||||
$output = ($chunk = fread($file, $seek)) . $output;
|
||||
|
||||
// Jump back to where we started reading
|
||||
fseek($file, -mb_strlen($chunk, '8bit'), SEEK_CUR);
|
||||
|
||||
// Decrease our line counter
|
||||
$lines -= substr_count($chunk, "\n");
|
||||
}
|
||||
|
||||
// While we have too many lines
|
||||
// (Because of buffer size we might have read too many)
|
||||
while ($lines++ < 0) {
|
||||
|
||||
// Find first newline and remove all text before that
|
||||
$output = substr($output, strpos($output, "\n") + 1);
|
||||
}
|
||||
|
||||
// Close file and return
|
||||
fclose($file);
|
||||
return trim($output);
|
||||
}
|
||||
}
|
||||
13
app/Facades/File/FileFacade.php
Normal file
13
app/Facades/File/FileFacade.php
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace App\Facades\File;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
class FileFacade extends Facade
|
||||
{
|
||||
protected static function getFacadeAccessor(): string
|
||||
{
|
||||
return 'file';
|
||||
}
|
||||
}
|
||||
78
app/Http/Controllers/V3/ProfileController.php
Normal file
78
app/Http/Controllers/V3/ProfileController.php
Normal file
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\V3;
|
||||
|
||||
use App\Facades\File\FileFacade;
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Requests\V3\Profile\ChangePasswordRequest;
|
||||
use App\Http\Requests\V3\Profile\EditRequest;
|
||||
use App\Http\Traits\ApiResponse;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
|
||||
class ProfileController extends Controller
|
||||
{
|
||||
use ApiResponse;
|
||||
public function info(): JsonResponse
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
return $this->successResponse([
|
||||
'username' => $user->username,
|
||||
'first_name' => $user->first_name,
|
||||
'last_name' => $user->last_name,
|
||||
'name' => $user->name,
|
||||
'last_login' => $user->last_login,
|
||||
'major' => $user->major,
|
||||
'degree' => $user->degree,
|
||||
'mobile' => $user->mobile,
|
||||
'avatar' => $user->avatar,
|
||||
]);
|
||||
}
|
||||
|
||||
public function edit(EditRequest $request): JsonResponse
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
if ($request->has('avatar'))
|
||||
{
|
||||
if ($user->avatar) {
|
||||
FileFacade::delete($user->avatar);
|
||||
}
|
||||
$destinationPath = 'avatar/' . $user->username;
|
||||
$filename = time() .".". $request->file('avatar')->getClientOriginalExtension();
|
||||
$avatar = FileFacade::save($request->avatar, $destinationPath, $filename);
|
||||
}
|
||||
|
||||
$user->update([
|
||||
'first_name' => $request->first_name,
|
||||
'last_name' => $request->last_name,
|
||||
'major' => $request->major,
|
||||
'degree' => $request->degree,
|
||||
'mobile' => $request->mobile,
|
||||
'avatar' => $avatar ?? $user->avatar
|
||||
]);
|
||||
|
||||
return $this->successResponse();
|
||||
}
|
||||
|
||||
public function changePassword(ChangePasswordRequest $request): JsonResponse
|
||||
{
|
||||
$user = Auth::user();
|
||||
|
||||
if (! Hash::check($request->current_password, $user->password))
|
||||
{
|
||||
return $this->errorResponse(__('messages.incorrect_current_password'));
|
||||
}
|
||||
|
||||
$user->update([
|
||||
'password' => Hash::make($request->new_password)
|
||||
]);
|
||||
|
||||
return $this->successResponse();
|
||||
|
||||
}
|
||||
}
|
||||
29
app/Http/Requests/V3/Profile/ChangePasswordRequest.php
Normal file
29
app/Http/Requests/V3/Profile/ChangePasswordRequest.php
Normal file
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\V3\Profile;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class ChangePasswordRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'current_password' => 'required|string|regex:/^(?=.*[a-zA-Z])(?=.*\d).+$/|min:8',
|
||||
'new_password' => 'required|string|regex:/^(?=.*[a-zA-Z])(?=.*\d).+$/|min:8',
|
||||
];
|
||||
}
|
||||
}
|
||||
33
app/Http/Requests/V3/Profile/EditRequest.php
Normal file
33
app/Http/Requests/V3/Profile/EditRequest.php
Normal file
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Requests\V3\Profile;
|
||||
|
||||
use Illuminate\Foundation\Http\FormRequest;
|
||||
|
||||
class EditRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*
|
||||
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'first_name' => 'required|string',
|
||||
'last_name' => 'required|string',
|
||||
'degree' => 'required',
|
||||
'major' => 'required',
|
||||
'mobile' => 'required|regex:/^09\d{9}$/|numeric|digits:11',
|
||||
'avatar' => 'mimes:png,jpg,jpeg|max:2048'
|
||||
];
|
||||
}
|
||||
}
|
||||
30
app/Providers/FileServiceProvider.php
Normal file
30
app/Providers/FileServiceProvider.php
Normal file
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
namespace App\Providers;
|
||||
|
||||
use App\Facades\File\File;
|
||||
use Illuminate\Support\ServiceProvider;
|
||||
|
||||
class FileServiceProvider extends ServiceProvider
|
||||
{
|
||||
/**
|
||||
* Register services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register(): void
|
||||
{
|
||||
$this->app->bind('file', function () {
|
||||
return new File();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Bootstrap services.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function boot()
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -69,8 +69,8 @@ class RouteServiceProvider extends ServiceProvider
|
||||
->group(base_path('routes/v2.php'));
|
||||
|
||||
Route::prefix('api/v3')
|
||||
->name('v3')
|
||||
->middleware('web', 'auth', 'confirmUser')
|
||||
->name('v3.')
|
||||
->middleware(['web', 'auth', 'confirmUser'])
|
||||
->namespace($this->namespace)
|
||||
->group(base_path('routes/v3.php'));
|
||||
Route::prefix('api')
|
||||
|
||||
2
bootstrap/cache/services.php
vendored
2
bootstrap/cache/services.php
vendored
@@ -45,6 +45,7 @@
|
||||
41 => 'App\\Providers\\TelescopeServiceProvider',
|
||||
42 => 'Barryvdh\\Debugbar\\ServiceProvider',
|
||||
43 => 'App\\Providers\\DataTableServiceProvider',
|
||||
44 => 'App\\Providers\\FileServiceProvider',
|
||||
),
|
||||
'eager' =>
|
||||
array (
|
||||
@@ -78,6 +79,7 @@
|
||||
27 => 'App\\Providers\\TelescopeServiceProvider',
|
||||
28 => 'Barryvdh\\Debugbar\\ServiceProvider',
|
||||
29 => 'App\\Providers\\DataTableServiceProvider',
|
||||
30 => 'App\\Providers\\FileServiceProvider',
|
||||
),
|
||||
'deferred' =>
|
||||
array (
|
||||
|
||||
@@ -183,6 +183,7 @@ return [
|
||||
|
||||
// custom facades here..
|
||||
App\Providers\DataTableServiceProvider::class,
|
||||
App\Providers\FileServiceProvider::class,
|
||||
|
||||
],
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace Database\Factories;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
|
||||
/**
|
||||
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
|
||||
@@ -23,6 +24,8 @@ class UserFactory extends Factory
|
||||
'confirmed' => 1,
|
||||
'province_fa' => $this->faker->name,
|
||||
'city_fa' => $this->faker->name,
|
||||
'password' => Hash::make('password1234'),
|
||||
'avatar' => $this->faker->image
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
6
resources/lang/en/messages.php
Normal file
6
resources/lang/en/messages.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'successful' => 'The Operation was successful',
|
||||
'incorrect_current_password' => 'The current password is incorrect.',
|
||||
];
|
||||
6
resources/lang/fa/messages.php
Normal file
6
resources/lang/fa/messages.php
Normal file
@@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
return [
|
||||
'successful' => 'عملیات موفق آمیز بود',
|
||||
'incorrect_current_password' => 'رمز عبور فعلی اشتباه است',
|
||||
];
|
||||
@@ -174,6 +174,11 @@ return [
|
||||
"available" => "موجود",
|
||||
"size" => "اندازه",
|
||||
"file" => "فایل",
|
||||
"fullname" => "نام کامل"
|
||||
"fullname" => "نام کامل",
|
||||
'current_password' => 'رمز عبور فعلی',
|
||||
'new_password' => 'رمز عبور جدید',
|
||||
'degree' => 'مدرک تحصیلی',
|
||||
'major' => 'شغل',
|
||||
'avatar' => 'آواتار'
|
||||
],
|
||||
];
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
use App\Http\Controllers\V3\Harim\DivarkeshiController;
|
||||
use App\Http\Controllers\V3\ProfileController;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
|
||||
Route::prefix('harim')->name('harim')->group(function () {
|
||||
Route::prefix('divarkeshi')->name('divarkeshi')->controller(DivarkeshiController::class)->group(function () {
|
||||
@@ -21,3 +23,12 @@ Route::prefix('harim')->name('harim')->group(function () {
|
||||
// Route::get('/{contract}', 'V3\Dashboard\ContractController@detail')->name('V3.contract.detail');
|
||||
});
|
||||
});
|
||||
|
||||
Route::prefix('profile')
|
||||
->name('profile.')
|
||||
->controller(ProfileController::class)
|
||||
->group(function () {
|
||||
Route::get('info', 'info')->name('info');
|
||||
Route::post('edit', 'edit')->name('edit');
|
||||
Route::post('change_password', 'changePassword')->name('changePassword');
|
||||
});
|
||||
|
||||
115
tests/Feature/Facades/FileTest.php
Normal file
115
tests/Feature/Facades/FileTest.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\Facades;
|
||||
|
||||
use App\Facades\File\FileFacade;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
|
||||
class FileTest extends TestCase
|
||||
{
|
||||
use WithFaker;
|
||||
|
||||
/**
|
||||
* A basic feature test example.
|
||||
*/
|
||||
public function test_image_is_saved(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$inputFile = UploadedFile::fake()->image($this->faker->image);
|
||||
$path = FileFacade::save($inputFile, 'testDir');
|
||||
|
||||
Storage::disk('public')->assertExists($path);
|
||||
}
|
||||
|
||||
public function test_image_is_saved_with_specified_name(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$imageName = 'photo.png';
|
||||
$inputFile = UploadedFile::fake()->image($imageName);
|
||||
$actualPath = FileFacade::save($inputFile, 'testDir', $imageName);
|
||||
$expectedPath = 'testDir/photo.png';
|
||||
|
||||
Storage::disk('public')->assertExists($actualPath);
|
||||
$this->assertEquals($expectedPath, $actualPath);
|
||||
}
|
||||
|
||||
public function test_file_is_saved(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$fileName = 'fake' . '.' . $this->faker->fileExtension();
|
||||
$inputFile = UploadedFile::fake()->create($fileName);
|
||||
$path = FileFacade::save($inputFile, 'testDir');
|
||||
|
||||
Storage::disk('public')->assertExists($path);
|
||||
}
|
||||
|
||||
public function test_file_is_saved_with_specified_name(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$fileName = 'fake' . '.' . $this->faker->fileExtension();
|
||||
$inputFile = UploadedFile::fake()->create($fileName);
|
||||
$actualPath = FileFacade::save($inputFile, 'testDir', $fileName);
|
||||
$expectedPath = 'testDir/' . $fileName;
|
||||
|
||||
Storage::disk('public')->assertExists($actualPath);
|
||||
$this->assertEquals($expectedPath, $actualPath);
|
||||
}
|
||||
|
||||
public function test_file_is_saved_with_specified_disk(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
Storage::fake('p2');
|
||||
|
||||
$fileName = 'fake' . '.' . $this->faker->fileExtension();
|
||||
$inputFile = UploadedFile::fake()->create($fileName);
|
||||
$path = FileFacade::save($inputFile, 'testDir', disk: 'p2');
|
||||
|
||||
Storage::disk('p2')->assertExists($path);
|
||||
Storage::disk('public')->assertMissing($path);
|
||||
}
|
||||
|
||||
public function test_delete_throws_exception_with_empty_file_path(): void
|
||||
{
|
||||
$this->assertThrows(
|
||||
fn() => FileFacade::delete(''),
|
||||
\InvalidArgumentException::class
|
||||
);
|
||||
}
|
||||
|
||||
public function test_file_is_deleted(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$fileName = 'fake' . '.' . $this->faker->fileExtension();
|
||||
$inputFile = UploadedFile::fake()->create($fileName);
|
||||
|
||||
$path = Storage::disk('public')->putFile('testDir', $inputFile);
|
||||
|
||||
Storage::disk('public')->assertExists($path);
|
||||
FileFacade::delete($path);
|
||||
Storage::disk('public')->assertMissing($path);
|
||||
}
|
||||
|
||||
public function test_file_with_absolute_path_is_deleted(): void
|
||||
{
|
||||
Storage::fake('public');
|
||||
|
||||
$fileName = 'fake' . '.' . $this->faker->fileExtension();
|
||||
$inputFile = UploadedFile::fake()->create($fileName);
|
||||
|
||||
$path = Storage::disk('public')->putFile('testDir', $inputFile);
|
||||
$absolutePath = Storage::disk('public')->url($path);
|
||||
|
||||
Storage::disk('public')->assertExists($path);
|
||||
FileFacade::delete($absolutePath, url_is_absolute: true);
|
||||
Storage::disk('public')->assertMissing($path);
|
||||
}
|
||||
}
|
||||
180
tests/Feature/V3/Profile/ChangePasswordTest.php
Normal file
180
tests/Feature/V3/Profile/ChangePasswordTest.php
Normal file
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\V3\Profile;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Tests\TestCase;
|
||||
|
||||
class ChangePasswordTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, WithFaker;
|
||||
|
||||
public function test_current_password_is_required()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.changePassword'));
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'current_password' => __('validation.required', ['attribute' => 'رمز عبور فعلی'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_current_password_should_be_string()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.changePassword'), [
|
||||
'current_password' => $this->faker->numberBetween(1, 10)
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'current_password' => __('validation.string', ['attribute' => 'رمز عبور فعلی'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_current_password_should_match_the_regex()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.changePassword'), [
|
||||
'current_password' => $this->faker->numberBetween(10000000, 99999999)
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'current_password' => __('validation.regex', ['attribute' => 'رمز عبور فعلی'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_current_password_should_have_at_least_8_characters()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.changePassword'), [
|
||||
'current_password' => $this->faker->numerify()
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'current_password' => __('validation.min.string', ['attribute' => 'رمز عبور فعلی', 'min' => 8])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_new_password_is_required()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.changePassword'));
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'new_password' => __('validation.required', ['attribute' => 'رمز عبور جدید'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_new_password_should_be_string()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.changePassword'), [
|
||||
'new_password' => $this->faker->numberBetween(1, 10)
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'new_password' => __('validation.string', ['attribute' => 'رمز عبور جدید'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_new_password_should_match_the_regex()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.changePassword'), [
|
||||
'new_password' => $this->faker->numberBetween(10000000, 99999999)
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'new_password' => __('validation.regex', ['attribute' => 'رمز عبور جدید'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_new_password_should_have_at_least_8_characters()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.changePassword'), [
|
||||
'new_password' => $this->faker->numerify()
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'new_password' => __('validation.min.string', ['attribute' => 'رمز عبور جدید', 'min' => 8])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_can_not_change_the_password_of_the_user_with_wrong_current_password(): void
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$password = $this->faker->numerify('#a######');
|
||||
|
||||
$response = $this->post(route('v3.profile.changePassword'), [
|
||||
'current_password' => 'fake1234',
|
||||
'new_password' => $password,
|
||||
]);
|
||||
|
||||
$response->assertStatus(422);
|
||||
|
||||
$response->assertExactJson([
|
||||
'message' => __('messages.incorrect_current_password'),
|
||||
"type" => "logical_exception"
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_user_can_change_the_password(): void
|
||||
{
|
||||
$this->withoutExceptionHandling();
|
||||
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->post(route('v3.profile.changePassword'), [
|
||||
'current_password' => 'password1234',
|
||||
'new_password' => $this->faker->numerify('#a######'),
|
||||
]);
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$response->assertExactJson([
|
||||
'message' => __('messages.successful')
|
||||
]);
|
||||
}
|
||||
}
|
||||
239
tests/Feature/V3/Profile/EditTest.php
Normal file
239
tests/Feature/V3/Profile/EditTest.php
Normal file
@@ -0,0 +1,239 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\V3\Profile;
|
||||
|
||||
use App\Facades\File\FileFacade;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Illuminate\Http\UploadedFile;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use Tests\TestCase;
|
||||
|
||||
class EditTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, WithFaker;
|
||||
|
||||
public function test_first_name_is_required()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'));
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'first_name' => __('validation.required', ['attribute' => 'نام'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_first_name_should_be_string()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'), [
|
||||
'first_name' => $this->faker->numberBetween(0, 10)
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'first_name' => __('validation.string', ['attribute' => 'نام'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_last_name_is_required()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'));
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'last_name' => __('validation.required', ['attribute' => 'نام خانوادگی'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_last_name_should_be_string()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'), [
|
||||
'last_name' => $this->faker->numberBetween(0, 10)
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'last_name' => __('validation.string', ['attribute' => 'نام خانوادگی'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_degree_is_required()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'));
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'degree' => __('validation.required', ['attribute' => 'مدرک تحصیلی'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_major_is_required()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'));
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'major' => __('validation.required', ['attribute' => 'شغل'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_mobile_is_required()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'));
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'mobile' => __('validation.required', ['attribute' => 'تلفن همراه'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_mobile_should_match_the_regex()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'), [
|
||||
'mobile' => $this->faker->numberBetween(1000000, 9999999)
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'mobile' => __('validation.regex', ['attribute' => 'تلفن همراه'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_mobile_should_be_numeric()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'), [
|
||||
'mobile' => $this->faker->name()
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'mobile' => __('validation.numeric', ['attribute' => 'تلفن همراه'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_mobile_should_be_11_digits()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'), [
|
||||
'mobile' => $this->faker->numberBetween(10000, 99999)
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'mobile' => __('validation.digits', ['attribute' => 'تلفن همراه', 'digits' => 11])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_avatar_should_match_the_mimes()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$image = UploadedFile::fake()->create('image.txt', 40);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'), [
|
||||
'avatar' => $image
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'avatar' => __('validation.mimes', ['attribute' => 'آواتار', 'values' => 'png, jpg, jpeg'])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_avatar_should_be_less_than_2048kb()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$image = UploadedFile::fake()->create('image.jpg', 40000);
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'), [
|
||||
'avatar' => $image
|
||||
]);
|
||||
|
||||
$response->assertUnprocessable()
|
||||
->assertInvalid([
|
||||
'avatar' => __('validation.max.file', ['attribute' => 'آواتار', 'max' => 2048])
|
||||
]);
|
||||
}
|
||||
|
||||
public function test_user_can_edit_the_profile()
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$avatar = UploadedFile::fake()->create('image.jpg', 1024);
|
||||
|
||||
FileFacade::shouldReceive('save')
|
||||
->andReturn('image.jpg');
|
||||
|
||||
FileFacade::shouldReceive('delete');
|
||||
|
||||
$data = [
|
||||
'first_name' => $this->faker->firstName,
|
||||
'last_name' => $this->faker->lastName,
|
||||
'degree' => $this->faker->name,
|
||||
'major' => $this->faker->name,
|
||||
'mobile' => $this->faker->numerify('09#########'),
|
||||
'avatar' => $avatar
|
||||
];
|
||||
|
||||
$response = $this->postJson(route('v3.profile.edit'), $data);
|
||||
|
||||
$response->assertOk()
|
||||
->assertExactJson([
|
||||
'message' => __('messages.successful')
|
||||
]);
|
||||
|
||||
$this->assertDatabaseHas('users', [
|
||||
'first_name' => $data['first_name'],
|
||||
'last_name' => $data['last_name'],
|
||||
'mobile' => $data['mobile'],
|
||||
'degree' => $data['degree'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
38
tests/Feature/V3/Profile/InfoTest.php
Normal file
38
tests/Feature/V3/Profile/InfoTest.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature\V3\Profile;
|
||||
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Foundation\Testing\WithFaker;
|
||||
use Tests\TestCase;
|
||||
|
||||
class InfoTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase, WithFaker;
|
||||
|
||||
public function test_user_info_returns_successfully(): void
|
||||
{
|
||||
$user = User::factory()->create();
|
||||
|
||||
$this->actingAs($user);
|
||||
|
||||
$response = $this->get(route('v3.profile.info'));
|
||||
|
||||
$response->assertStatus(200);
|
||||
|
||||
$response->assertExactJson([
|
||||
'data' => [
|
||||
'username' => $user->username,
|
||||
'first_name' => $user->first_name,
|
||||
'last_name' => $user->last_name,
|
||||
'name' => $user->name,
|
||||
'last_login' => $user->last_login,
|
||||
'major' => $user->major,
|
||||
'degree' => $user->degree,
|
||||
'mobile' => $user->mobile,
|
||||
'avatar' => $user->avatar,
|
||||
]
|
||||
]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user