feature/ForgotPassword #29

Closed
faezeh wants to merge 91 commits from feature/ForgotPassword into main
30 changed files with 969 additions and 65 deletions
Showing only changes of commit b32ee444ca - Show all commits

View File

@@ -0,0 +1,23 @@
<?php
namespace App\Http\Resources;
use Illuminate\Http\Request;
use Illuminate\Http\Resources\Json\JsonResource;
class UserResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @return array<string, mixed>
*/
public function toArray(Request $request): array
{
return [
'id' => $this->id,
'username' => $this->username,
'email' => $this->email,
];
}
}

18
backend/app/Models/User.php Normal file → Executable file
View File

@@ -5,30 +5,18 @@ namespace App\Models;
// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
#[Fillable(['name', 'email', 'password'])]
#[Hidden(['password', 'remember_token'])]
#[Guarded(['id'])]
#[Hidden(['password'])]
class User extends Authenticatable
{
/** @use HasFactory<UserFactory> */
use HasFactory, Notifiable, HasApiTokens;
/**
* Get the attributes that should be cast.
*
* @return array<string, string>
*/
protected function casts(): array
{
return [
'email_verified_at' => 'datetime',
'password' => 'hashed',
];
}
protected $guarded = ['id'];
}

2
backend/app/Providers/AppServiceProvider.php Normal file → Executable file
View File

@@ -22,6 +22,6 @@ class AppServiceProvider extends ServiceProvider
public function boot(): void
{
Passport::enablePasswordGrant();
Passport::personalAccessTokensExpireIn(CarbonInterval::hour(2));
Passport::personalAccessTokensExpireIn(CarbonInterval::minutes(1));
}
}

0
backend/app/Traits/ApiResponse.php Normal file → Executable file
View File

44
backend/app/User/Controller/Auth/AuthController.php Normal file → Executable file
View File

@@ -3,12 +3,14 @@
namespace App\User\Controller\Auth;
use App\Http\Controllers\Controller;
use App\Http\Resources\UserResource;
use App\Models\User;
use App\Traits\ApiResponse;
use App\User\Requests\Auth\LoginRequest;
use App\User\Requests\Auth\RegisterRequest;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class AuthController extends Controller
@@ -17,42 +19,48 @@ class AuthController extends Controller
public function register(RegisterRequest $request): JsonResponse
{
$user = User::query()->create([
User::query()->create([
'username' => $request->username,
'email' => $request->email,
'password' => Hash::make($request->password),
]);
$token = $user->createToken('Register Token')->accessToken;
$request->session()->regenerate();
return $this->successResponse([
'token' => $token,
]);
return $this->successResponse();
}
public function login(LoginRequest $request): JsonResponse
{
$uniq_identifier = $request->input('login');
$user = User::query()
->where('email', $uniq_identifier)
->orWhere('username', $uniq_identifier)
->first();
$credentials = ['password' => $request->password,];
if (!$user || !Hash::check($request->password, $user->password)) {
return $this->errorResponse('');
if (filter_var($request->login, FILTER_VALIDATE_EMAIL)) {
$credentials['email'] = $request->login;
} else {
$credentials['username'] = $request->login;
}
$token = $user->createToken('Login Token')->accessToken;
if (Auth::attempt($credentials))
{
$request->session()->regenerate();
return $this->successResponse([
'token' => $token,
]);
$user = Auth::user();
return $this->successResponse([
'info' => new UserResource($user),
]);
}
return $this->errorResponse(__('messages.incorrect_or_username_password'));
}
public function logout(Request $request): JsonResponse
{
$request->user()->token()->revoke();
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return $this->successResponse();
}

View File

@@ -0,0 +1,61 @@
<?php
namespace App\User\Controller;
use App\Http\Controllers\Controller;
use App\Http\Resources\UserResource;
use App\Traits\ApiResponse;
use App\User\Requests\Profile\ChangePasswordRequest;
use App\User\Requests\Profile\EditRequest;
use Illuminate\Http\JsonResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
class ProfileController extends Controller
{
use ApiResponse;
public function info(): JsonResponse
{
$user = Auth::user();
return $this->successResponse([
'info' => new UserResource($user),
]);
}
public function edit(EditRequest $request): JsonResponse
{
$user = Auth::user();
$user->update([
'first_name' => $request->first_name,
'last_name' => $request->last_name,
'national_id' => $request->national_id,
'address' => $request->address,
'postal_code' => $request->postal_code,
'account_number' => $request->account_number,
'phone_number' => $request->phone_number,
'province_id' => $request->province_id,
'city_id' => $request->city_id,
]);
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();
}
}

3
backend/app/User/Requests/Auth/LoginRequest.php Normal file → Executable file
View File

@@ -22,8 +22,7 @@ class LoginRequest extends FormRequest
public function rules(): array
{
return [
'username' => 'required_without:email|string',
'email' => 'required_without:name|email',
'login' => 'required|string',
'password' => 'required|string',
];
}

6
backend/app/User/Requests/Auth/RegisterRequest.php Normal file → Executable file
View File

@@ -22,9 +22,9 @@ class RegisterRequest extends FormRequest
public function rules(): array
{
return [
'username' => 'required_without:email|unique:users,name',
'email' => 'required_without:name|email|unique:users,email',
'password' => 'required|string|regex:/^(?=.*[a-zA-Z])(?=.*\d).+$/|min:8',
'username' => 'required|unique:users,username',
'email' => 'required|email|unique:users,email',
'password' => 'required|string|regex:/^(?=.*[a-zA-Z])(?=.*\d).+$/|min:6',
];
}
}

View File

@@ -0,0 +1,30 @@
<?php
namespace App\User\Requests\Profile;
use Illuminate\Contracts\Validation\ValidationRule;
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, ValidationRule|array|string>
*/
public function rules(): array
{
return [
'current_password' => 'required|string|regex:/^(?=.*[a-zA-Z])(?=.*\d).+$/|min:6',
'new_password' => 'required|string|regex:/^(?=.*[a-zA-Z])(?=.*\d).+$/|min:6',
];
}
}

View File

@@ -0,0 +1,37 @@
<?php
namespace App\User\Requests\Profile;
use Illuminate\Contracts\Validation\ValidationRule;
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, ValidationRule|array|string>
*/
public function rules(): array
{
return [
'first_name' => 'required|string',
'last_name' => 'required|string',
'national_id' => 'required',
'address' => 'required',
'postal_code' => 'required',
'account_number' => 'required',
'phone_number' => 'required|regex:/^964\d{9}$/|numeric|digits:11',
'province_id' => 'required',
'city_id' => 'required',
];
}
}

2
backend/bootstrap/app.php Normal file → Executable file
View File

@@ -12,7 +12,7 @@ return Application::configure(basePath: dirname(__DIR__))
health: '/up',
)
->withMiddleware(function (Middleware $middleware): void {
//
$middleware->web()->validateCsrfTokens(['*']);
})
->withExceptions(function (Exceptions $exceptions): void {
//

0
backend/config/auth.php Normal file → Executable file
View File

34
backend/config/cors.php Executable file
View File

@@ -0,0 +1,34 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Cross-Origin Resource Sharing (CORS) Configuration
|--------------------------------------------------------------------------
|
| Here you may configure your settings for cross-origin resource sharing
| or "CORS". This determines what cross-origin operations may execute
| in web browsers. You are free to adjust these settings as needed.
|
| To learn more: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
|
*/
'paths' => ['*'],
'allowed_methods' => ['*'],
'allowed_origins' => ['*'],
'allowed_origins_patterns' => [],
'allowed_headers' => ['*'],
'exposed_headers' => [],
'max_age' => 0,
'supports_credentials' => true,
];

0
backend/config/session.php Normal file → Executable file
View File

2
backend/database/factories/UserFactory.php Normal file → Executable file
View File

@@ -25,7 +25,7 @@ class UserFactory extends Factory
public function definition(): array
{
return [
'name' => fake()->name(),
'username' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'email_verified_at' => now(),
'password' => static::$password ??= Hash::make('password'),

View File

@@ -13,18 +13,23 @@ return new class extends Migration
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('username');
$table->string('first_name')->nullable();
$table->string('last_name')->nullable();
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
$table->tinyInteger('status')->default(0);
$table->string('national_id')->nullable();
$table->string('address')->nullable();
$table->string('postal_code')->nullable();
$table->string('account_number')->nullable();
$table->string('phone_number')->nullable();
$table->string('province_id')->nullable();
$table->string('province_name')->nullable();
$table->string('city_id')->nullable();
$table->string('city_name')->nullable();
Schema::create('password_reset_tokens', function (Blueprint $table) {
$table->string('email')->primary();
$table->string('token');
$table->timestamp('created_at')->nullable();
$table->timestamps();
});
Schema::create('sessions', function (Blueprint $table) {
@@ -43,7 +48,6 @@ return new class extends Migration
public function down(): void
{
Schema::dropIfExists('users');
Schema::dropIfExists('password_reset_tokens');
Schema::dropIfExists('sessions');
}
};

3
backend/database/seeders/DatabaseSeeder.php Normal file → Executable file
View File

@@ -18,8 +18,9 @@ class DatabaseSeeder extends Seeder
// User::factory(10)->create();
User::factory()->create([
'name' => 'Test User',
'username' => 'Test User',
'email' => 'test@example.com',
'password' => 'password123@',
]);
}
}

View File

@@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'failed' => 'These credentials do not match our records.',
'throttle' => 'Too many login attempts. Please try again in :seconds seconds.',
];

View File

@@ -0,0 +1,7 @@
<?php
return [
'successful' => 'The Operation was successful',
'incorrect_current_password' => 'The current password is incorrect.',
'incorrect_or_username_password' => 'The username or password is incorrect.',
];

View File

@@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '&laquo; Previous',
'next' => 'Next &raquo;',
];

View File

@@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reset Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
'reset' => 'Your password has been reset!',
'sent' => 'We have e-mailed your password reset link!',
'throttled' => 'Please wait before retrying.',
'token' => 'This password reset token is invalid.',
'user' => "We can't find a user with that e-mail address.",
];

View File

@@ -0,0 +1,151 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'accepted' => 'The :attribute must be accepted.',
'active_url' => 'The :attribute is not a valid URL.',
'after' => 'The :attribute must be a date after :date.',
'after_or_equal' => 'The :attribute must be a date after or equal to :date.',
'alpha' => 'The :attribute may only contain letters.',
'alpha_dash' => 'The :attribute may only contain letters, numbers, dashes and underscores.',
'alpha_num' => 'The :attribute may only contain letters and numbers.',
'array' => 'The :attribute must be an array.',
'before' => 'The :attribute must be a date before :date.',
'before_or_equal' => 'The :attribute must be a date before or equal to :date.',
'between' => [
'numeric' => 'The :attribute must be between :min and :max.',
'file' => 'The :attribute must be between :min and :max kilobytes.',
'string' => 'The :attribute must be between :min and :max characters.',
'array' => 'The :attribute must have between :min and :max items.',
],
'boolean' => 'The :attribute field must be true or false.',
'confirmed' => 'The :attribute confirmation does not match.',
'date' => 'The :attribute is not a valid date.',
'date_equals' => 'The :attribute must be a date equal to :date.',
'date_format' => 'The :attribute does not match the format :format.',
'different' => 'The :attribute and :other must be different.',
'digits' => 'The :attribute must be :digits digits.',
'digits_between' => 'The :attribute must be between :min and :max digits.',
'dimensions' => 'The :attribute has invalid image dimensions.',
'distinct' => 'The :attribute field has a duplicate value.',
'email' => 'The :attribute must be a valid email address.',
'ends_with' => 'The :attribute must end with one of the following: :values.',
'exists' => 'The selected :attribute is invalid.',
'file' => 'The :attribute must be a file.',
'filled' => 'The :attribute field must have a value.',
'gt' => [
'numeric' => 'The :attribute must be greater than :value.',
'file' => 'The :attribute must be greater than :value kilobytes.',
'string' => 'The :attribute must be greater than :value characters.',
'array' => 'The :attribute must have more than :value items.',
],
'gte' => [
'numeric' => 'The :attribute must be greater than or equal :value.',
'file' => 'The :attribute must be greater than or equal :value kilobytes.',
'string' => 'The :attribute must be greater than or equal :value characters.',
'array' => 'The :attribute must have :value items or more.',
],
'image' => 'The :attribute must be an image.',
'in' => 'The selected :attribute is invalid.',
'in_array' => 'The :attribute field does not exist in :other.',
'integer' => 'The :attribute must be an integer.',
'ip' => 'The :attribute must be a valid IP address.',
'ipv4' => 'The :attribute must be a valid IPv4 address.',
'ipv6' => 'The :attribute must be a valid IPv6 address.',
'json' => 'The :attribute must be a valid JSON string.',
'lt' => [
'numeric' => 'The :attribute must be less than :value.',
'file' => 'The :attribute must be less than :value kilobytes.',
'string' => 'The :attribute must be less than :value characters.',
'array' => 'The :attribute must have less than :value items.',
],
'lte' => [
'numeric' => 'The :attribute must be less than or equal :value.',
'file' => 'The :attribute must be less than or equal :value kilobytes.',
'string' => 'The :attribute must be less than or equal :value characters.',
'array' => 'The :attribute must not have more than :value items.',
],
'max' => [
'numeric' => 'The :attribute may not be greater than :max.',
'file' => 'The :attribute may not be greater than :max kilobytes.',
'string' => 'The :attribute may not be greater than :max characters.',
'array' => 'The :attribute may not have more than :max items.',
],
'mimes' => 'The :attribute must be a file of type: :values.',
'mimetypes' => 'The :attribute must be a file of type: :values.',
'min' => [
'numeric' => 'The :attribute must be at least :min.',
'file' => 'The :attribute must be at least :min kilobytes.',
'string' => 'The :attribute must be at least :min characters.',
'array' => 'The :attribute must have at least :min items.',
],
'not_in' => 'The selected :attribute is invalid.',
'not_regex' => 'The :attribute format is invalid.',
'numeric' => 'The :attribute must be a number.',
'password' => 'The password is incorrect.',
'present' => 'The :attribute field must be present.',
'regex' => 'The :attribute format is invalid.',
'required' => 'The :attribute field is required.',
'required_if' => 'The :attribute field is required when :other is :value.',
'required_unless' => 'The :attribute field is required unless :other is in :values.',
'required_with' => 'The :attribute field is required when :values is present.',
'required_with_all' => 'The :attribute field is required when :values are present.',
'required_without' => 'The :attribute field is required when :values is not present.',
'required_without_all' => 'The :attribute field is required when none of :values are present.',
'same' => 'The :attribute and :other must match.',
'size' => [
'numeric' => 'The :attribute must be :size.',
'file' => 'The :attribute must be :size kilobytes.',
'string' => 'The :attribute must be :size characters.',
'array' => 'The :attribute must contain :size items.',
],
'starts_with' => 'The :attribute must start with one of the following: :values.',
'string' => 'The :attribute must be a string.',
'timezone' => 'The :attribute must be a valid zone.',
'unique' => 'The :attribute has already been taken.',
'uploaded' => 'The :attribute failed to upload.',
'url' => 'The :attribute format is invalid.',
'uuid' => 'The :attribute must be a valid UUID.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [
'attribute-name' => [
'rule-name' => 'custom-message',
],
],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap our attribute placeholder
| with something more reader friendly such as "E-Mail Address" instead
| of "email". This simply helps us make our message more expressive.
|
*/
'attributes' => [],
];

View File

@@ -0,0 +1,137 @@
{
"Reset Password Notification": "بازیابی رمز عبور",
"You are receiving this email because we received a password reset request for your account.": "شما این ایمیل را برای بازیابی رمز عبور از ما دریافت کرده اید.",
"Reset Password": "بازیابی رمز عبور",
"This password reset link will expire in :count minutes.": "این لینک بازیابی در :count دقیقه دیگر منقضی میشود.",
"If you did not request a password reset, no further action is required.": "اگر شما برای بازیابی رمز عبور درخواست نداده اید این ایمیل را نادیده بگیرید.",
"Verify Email Address": "تایید آدرس ایمیل",
"Please click the button below to verify your email address.": "برای تایید ایمیل لطفا بر ری دکمه زیر کلیک کنید",
"If you did not create an account, no further action is required.": "اگر شما برای تایید حساب درخواست نداده اید این ایمیل را نادیده بگیرید.",
"Login": "ورود",
"E-Mail Address": "ادرس ایمیل",
"Password": "رمز عبور",
"Remember Me": "مرا به خاطر بسپار",
"Forgot Your Password?": "رمز عبورتان را فراموش کرده اید؟",
"Register": "ثبت نام",
"Name": "ثبت نام",
"Confirm Password": "تایید رمز عبور",
"Verify Your Email Address": "ایمیل خود را تایید کنید",
"A fresh verification link has been sent to your email address.": "یک لینک فعال سازی جدید به ادرس ایمیل شما ارسال شد.",
"Before proceeding, please check your email for a verification link.": "قبل از ادامه دادن لطفا ایمیل خود را برای فعال سازی حسابتان برسی کنید.",
"If you did not receive the email": "اگه ایمیلی دریافت نکرده اید",
"click here to request another": "برای درخواست لینک جدید اینجا کلیک کنید",
"Please confirm your password before continuing.": "لطفا برای ادامه رمز عبور خود را تایید کنید",
"Send Password Reset Link": "ارسال لینک بازیابی رمز عبور",
"Logout": "خروج",
"Dashboard": "داشبورد",
"Manage Account": "مدیریت حساب کاربری",
"Profile": "پروفایل",
"API Tokens": "توکن های api",
"Manage Team": "مدیریت تیم",
"Team Settings": "تنظیمات تیم",
"Create New Team": "ساخت تیم جدید",
"Switch Teams": "تعویض تیم",
"Delete Account": "حذف حساب کاربری",
"Permanently delete your account.": ".حذف دائمی حساب کاربری",
"Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.": "زمانی که حساب کاربریتان حذف شد، همه اطلاعات به صورت دائم حذف خواهد شد. قبل از حذف همه اطلاعات مورد نیاز خودتان را دانلود کنید.",
"Are you sure you want to delete your account? Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.": "آیا مطمئن هستید میخواهید حساب کاربریتان را حذف کنید؟ زمانی که حساب کاربریتان حذف شد، همه اطلاعات به صورت دائم حذف میشود. لطفا رمز عبور خود را برای حذف دائمی حسابتان وارد کنین.",
"Nevermind": "بیخیال",
"Browser Sessions": "دستگاه های فعال",
"Manage and logout your active sessions on other browsers and devices.": "مدیریت و خروج از بقیه دستگاه ها و براورز های فعال.",
"If necessary, you may logout of all of your other browser sessions across all of your devices. If you feel your account has been compromised, you should also update your password.": "اگر نیاز میدونید، میتوانید تمام دستگاه ها و براوزر های فعال این حساب غیر فعال کنید. اگر احساس میکنید حسابتان ممکن است در خطر هست بهتر است رمز عبورتان را هم اپدیت کنید.",
"This device": "این دستگاه",
"Last active": "آخرین زمان فعالیت",
"Done": "انجام شد.",
"Please enter your password to confirm you would like to logout of your other browser sessions across all of your devices.": "برای خروج از بقیه دستگاه ها رمز عبور خود را وارد کنید.",
"Logout Other Browser Sessions": "خروج از بقیه دستگاه ها",
"Two Factor Authentication": "احراز هویت دو فاکتور",
"Add additional security to your account using two factor authentication.": "امنیت بیشتری به حساب خود با استفاده از احراز هویت دو فاکتور اضافه کنید.",
"You have enabled two factor authentication.": "احراز هویت دو فاکتور شما فعال است.",
"You have not enabled two factor authentication.": "شما احراز هویت دو فاکتور را فعال نکرده اید!",
"When two factor authentication is enabled, you will be prompted for a secure, random token during authentication. You may retrieve this token from your phone's Google Authenticator application.": "زمانی که احراز هویت دو فاکتور فعال باشد، در هنگام احراز هویت از شما یک رمز امن و تصادفی درخواست می شود. شما می توانید این رمز را از برنامه Google Authenticator تلفن خود دریافت کنید.",
"Two factor authentication is now enabled. Scan the following QR code using your phone's authenticator application.": "احراز هویت دو فاکتور اکنون فعال شده است. کد QR زیر را با استفاده از برنامه authenticator خود اسکن کنید.",
"Store these recovery codes in a secure password manager. They can be used to recover access to your account if your two factor authentication device is lost.": "این کدهای بازیابی را در یک برنامه مدیریت رمز عبور امن ذخیره کنید. اگر دستگاه تأیید اعتبار دو فاکتور شما از بین رفته باشد ، می توان از آنها برای بازیابی دسترسی به حساب شما استفاده کرد.",
"Enable": "فعال کردن",
"Regenerate Recovery Codes": "تولید دوباره کد های بازیابی",
"Show Recovery Codes": "نمایش کد های بازیابی",
"Disable": "غیر فعال کردن",
"Update Password": "اپدیت رمز عبور",
"Ensure your account is using a long, random password to stay secure.": "اطمینان حاصل کنید که حساب شما از یک رمز عبور تصادفی طولانی برای ایمن ماندن استفاده می کند.",
"Current Password": "رمز عبور فعلی",
"New Password": "رمز عبور جدید",
"Saved.": "ذخیره شد.",
"Save": "ذخیره",
"Profile Information": "اطلاعات پروفایل",
"Update your account's profile information and email address.": "اطلاعات حساب کاربری و ایمیل خود را اپدیت کنید",
"Photo": "عکس",
"Select A New Photo": "انتخاب عکس جدید",
"Remove Photo": "حذف عکس",
"Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.": "رمز عبور خود را فراموش کرده اید؟ مشکلی نیست فقط آدرس ایمیل خود را وارد کنید و ما یک ایمیل تنظیم مجدد رمز عبور را برای شما ارسال خواهیم کرد که به شما امکان می دهد رمز عبور جدیدی را انتخاب کنید.",
"Email Password Reset Link": "ایمیل بازیابی رمز عبور",
"Email": "ایمیل",
"Remember me": "مرا به خاطر داشته باش",
"Forgot your password?": "رمز عبور خود را فراموش کرده اید؟",
"Already registered?": "قبلا ثبت نام کرده اید؟",
"Please confirm access to your account by entering the authentication code provided by your authenticator application.": "لطفاً با وارد کردن کد احراز هویت ارائه شده توسط برنامه تایید اعتبار، دسترسی به حساب خود را تأیید کنید.",
"Please confirm access to your account by entering one of your emergency recovery codes.": "لطفاً با وارد کردن یکی از کدهای بازیابی اضطراری، دسترسی به حساب خود را تأیید کنید.",
"Code": "کد",
"Recovery Code": "کد بازیابی",
"Use a recovery code": "استفاده از کد بازیابی",
"Use an authentication code": "استفاده از کد احراز هویت",
"Thanks for signing up! Before getting started, could you verify your email address by clicking on the link we just emailed to you? If you didn't receive the email, we will gladly send you another.": "از ثبت نام شما سپاسگزاریم! قبل از شروع، آیا می توانید آدرس ایمیل خود را با کلیک بر روی لینکی که برای شما فرستادیم، تأیید کنید؟ اگر ایمیل را دریافت نکردید ، ما با کمال میل ایمیل دیگری را برای شما ارسال خواهیم کرد.",
"A new verification link has been sent to the email address you provided during registration.": "لینک تأیید جدید به آدرس ایمیلی که هنگام ثبت نام وارد کرده اید ارسال شده است.",
"Resend Verification Email": "ارسال دوباره تایید ایمیل",
"Create API Token": "ساخت یک توکن",
"API tokens allow third-party services to authenticate with our application on your behalf.": "توکن های API به سرویس های شخص ثالث اجازه می دهد تا از طریق شما با برنامه ما احراز هویت شوند",
"Token Name": "اسم توکن",
"Permissions": "دسترسی ها",
"Created.": "ساخته شد.",
"Create": "ساختن",
"Manage API Tokens": "مدیریت توکن ها",
"You may delete any of your existing tokens if they are no longer needed.": "میتوانید هر یک از توکن های موجود را پاک کنید اگه نیازی به انها ندارید.",
"Last used": "اخرین زمان مورد استفاده",
"Delete": "حذف",
"Please copy your new API token. For your security, it won't be shown again.": "لطفا توکن API خود را کپی کنید. برای امنیت شما ، دوباره نمایش داده نمی شود.",
"Close": "بستن",
"API Token Permissions": "دسترسی های توکن",
"Delete API Token": "حذف توکن",
"Are you sure you would like to delete this API token?": "آیا از حذف این توکن مطمئن هستید؟",
"The :attribute must be a valid role": "فیلد :attribute باید نقش درستی داشته باشد",
"The provided two factor authentication code was invalid.": "رمز دوم شما درست نیست.",
"The provided password does not match your current password.": "رمز عبور وارد شده با رمز عبور حسابتان یکی نیست!",
"The :attribute must be at least :length characters and contain at least one uppercase character.": "فیلد :attribute باید حداقل :length کاراکتر و شامل حداقل یک حرف بزرگ باشد.",
"The :attribute must be at least :length characters and contain at least one number.": "فیلد :attribute باید حداقل :length کاراکتر و شامل حداقل یک عدد باشد.",
"The :attribute must be at least :length characters and contain at least one uppercase character and number.": "فیلد :attribute باید حداقل :length کاراکتر و شامل حداقل یک حرف بزرگ و یک عدد باشد.",
"The :attribute must be at least :length characters.": "فیلد :attribute باید حداقل :length کاراکتر باشد.",
"Team Details": "جزئیات تیم",
"Create a new team to collaborate with others on projects.": "یک تیم جدید برای همکاری با دیگران در پروژه ها ایجاد کنید.",
"Team Owner": "مالک تیم",
"Team Name": "نام تیم",
"Delete Team": "حذف تیم",
"Permanently delete this team.": "حذف دائمی این تیم.",
"Once a team is deleted, all of its resources and data will be permanently deleted. Before deleting this team, please download any data or information regarding this team that you wish to retain.": "پس از حذف یک تیم ، تمام منابع و داده های آن برای همیشه حذف می شوند. قبل از حذف این تیم ، لطفاً هرگونه اطلاعات یا اطلاعات مربوط به این تیم را که می خواهید حفظ کنید دانلود کنید.",
"Are you sure you want to delete this team? Once a team is deleted, all of its resources and data will be permanently deleted.": "آیا مطمئن هستید که می خواهید این تیم را حذف کنید؟ پس از حذف یک تیم ، تمام منابع و داده های آن برای همیشه حذف می شوند.",
"Add Team Member": "افزودن عضو تیم",
"Add a new team member to your team, allowing them to collaborate with you.": "عضوی جدید از تیم را به تیم خود اضافه کنید و به وی اجازه دهید با شما همکاری کند.",
"Please provide the email address of the person you would like to add to this team. The email address must be associated with an existing account.": "لطفاً آدرس ایمیل شخصی را که می خواهید به این تیم اضافه کنید ، وارد کنید. آدرس ایمیل باید با یک حساب موجود مرتبط باشد.",
"Role": "نقش",
"Added.": "اضافه شد",
"Add": "اضافه",
"Team Members": "اعضای تیم",
"All of the people that are part of this team.": "همه افرادی که در این تیم عضو هستند.",
"Leave": "رفتن",
"Remove": "پاک کردن",
"Manage Role": "مدیریت نقش",
"Leave Team": "ترک کردن تیم",
"Are you sure you would like to leave this team?": "آیا مطمئن هستید که می خواهید این تیم را ترک کنید؟",
"Remove Team Member": "حذف عضو تیم",
"Are you sure you would like to remove this person from the team?": "آیا مطمئن هستید که می خواهید این شخص را از تیم حذف کنید؟",
"The team's name and owner information.": "نام تیم و اطلاعات مالک آن.",
"You may not leave a team that you created.": "نمیتوانید از تیم خودتان خارج شوید.",
"You may not delete your personal team.": "نمیتوانید تیم خودتان را حذف کنید.",
"This password does not match our records.": "این رمز عبور با اطلاعات ما مطابق نیست.",
"The :attribute must be a valid role.": "فیلد :attribute باید یک نقش درست باشد.",
"The :attribute must be at least :length characters and contain at least one special character.": "فیلد :attribute باید حداقل :length کاراکتر و شامل یک کاراکتر مخصوص باشد.",
"The :attribute must be at least :length characters and contain at least one uppercase character and one special character.": "فیلد :attribute باید حداقل :length کاراکتر و شامل یک کاراکتر مخصوص و یک حرف بزرگ باشد.",
"The :attribute must be at least :length characters and contain at least one uppercase character, one number, and one special character.": "فیلد :attribute باید حداقل :length کاراکتر، یک کاراکتر مخصوص، یک حرف بزرگ و یک عدد باشد."
}

View File

@@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Authentication Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used during authentication for various
| messages that we need to display to the user. You are free to modify
| these language lines according to your application's requirements.
|
*/
'failed' => 'اطلاعات وارد شده صحیح نمی باشد.',
'throttle' => 'تعداد تلاش های ناموفق زیاد بود . لطفا بعد از :seconds ثانیه ی دیگر تلاش کنید .',
];

View File

@@ -0,0 +1,7 @@
<?php
return [
'successful' => 'عملیات موفق آمیز بود',
'incorrect_current_password' => 'رمز عبور فعلی اشتباه است',
'incorrect_or_username_password' => 'رمز عبور یا نام کاربری اشتباه است'
];

View File

@@ -0,0 +1,19 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Pagination Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are used by the paginator library to build
| the simple pagination links. You are free to change them to anything
| you want to customize your views to better match your application.
|
*/
'previous' => '&laquo; قبلی',
'next' => 'بعدی &raquo;',
];

View File

@@ -0,0 +1,22 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Password Reset Language Lines
|--------------------------------------------------------------------------
|
| The following language lines are the default lines which match reasons
| that are given by the password broker for a password update attempt
| has failed, such as for an invalid token or invalid new password.
|
*/
'reset' => 'رمز عبور شما با موفقیت تغییر یافت!',
'sent' => 'لینک تغییر رمز عبور برای شما فرستاده شد!',
'throttled' => 'لطفا قبل تلاش مجدد منتظر بمانید.',
'token' => 'token تغییر گذر واژه (لینک) نامعتبر است.',
'user' => "کاربری با این ایمیل یافت نشد.",
];

View File

@@ -0,0 +1,292 @@
<?php
return [
/*
|--------------------------------------------------------------------------
| Validation Language Lines
|--------------------------------------------------------------------------
|
| The following language lines contain the default error messages used by
| the validator class. Some of these rules have multiple versions such
| as the size rules. Feel free to tweak each of these messages here.
|
*/
'prohibited' => ':attribute در این حالت مجاز نیست.',
"accepted" => ":attribute باید پذیرفته شده باشد.",
"active_url" => "آدرس :attribute معتبر نیست",
"after" => ":attribute باید بعد از :date باشد.",
'after_or_equal' => ':attribute باید بعد از یا برابر تاریخ :date باشد.',
"alpha" => ":attribute باید شامل حروف الفبا باشد.",
"alpha_dash" => ":attribute باید شامل حروف الفبا و عدد و خظ تیره(-) باشد.",
"alpha_num" => ":attribute باید شامل حروف الفبا و عدد باشد.",
"array" => ":attribute باید شامل آرایه باشد.",
"before" => ":attribute باید تاریخی قبل از :date باشد.",
'before_or_equal' => ':attribute باید قبل از یا برابر تاریخ :date باشد.',
"between" => [
"numeric" => ":attribute باید بین :min و :max باشد.",
"file" => ":attribute باید بین :min و :max کیلوبایت باشد.",
"string" => ":attribute باید بین :min و :max کاراکتر باشد.",
"array" => ":attribute باید بین :min و :max آیتم باشد.",
],
"boolean" => "فیلد :attribute فقط میتواند صحیح و یا غلط باشد",
"confirmed" => ":attribute با تاییدیه مطابقت ندارد.",
"date" => ":attribute یک تاریخ معتبر نیست.",
'date_equals' => ':attribute باید برابر تاریخ :date باشد.',
"date_format" => ":attribute با الگوی :format مطاقبت ندارد.",
"different" => ":attribute و :other باید متفاوت باشند.",
"digits" => ":attribute باید :digits رقم باشد.",
"digits_between" => ":attribute باید بین :min و :max رقم باشد.",
'dimensions' => 'dimensions مربوط به فیلد :attribute اشتباه است.',
'distinct' => ':attribute مقدار تکراری دارد.',
"email" => "فرمت :attribute معتبر نیست.",
'ends_with' => ':attribute باید با این مقدار تمام شود: :values.',
"exists" => ":attribute انتخاب شده، معتبر نیست.",
'file' => 'فیلد :attribute باید فایل باشد.',
"filled" => "فیلد :attribute الزامی است",
'gt' => [
'numeric' => ':attribute باید بیشتر از :value باشد.',
'file' => ':attribute باید بیشتر از :value کیلوبایت باشد.',
'string' => ':attribute باید بیشتر از :value کاراکتر باشد.',
'array' => ':attribute باید بیشتر از :value ایتم باشد.',
],
'gte' => [
'numeric' => ':attribute باید بیشتر یا برابر :value باشد.',
'file' => ':attribute باید بیشتر یا برابر :value کیلوبایت باشد.',
'string' => ':attribute باید بیشتر یا برابر :value کاراکتر باشد.',
'array' => ':attribute باید :value ایتم یا بیشتر را داشته باشد.',
],
"image" => ":attribute باید تصویر باشد.",
"in" => ":attribute انتخاب شده، معتبر نیست.",
"integer" => ":attribute باید نوع داده ای عددی (integer) باشد.",
"ip" => ":attribute باید IP آدرس معتبر باشد.",
'ipv4' => ':attribute باید یک ادرس درست IPv4 باشد.',
'ipv6' => ':attribute باید یک ادرس درست IPv6 باشد.',
'json' => ':attribute یک مقدار درست JSON باشد.',
'lt' => [
'numeric' => ':attribute باید کمتر از :value باشد.',
'file' => ':attribute باید کمتر از :value کیلوبایت باشد.',
'string' => ':attribute باید کمتر از :value کاراکتر باشد.',
'array' => ':attribute باید :value ایتم یا کمتر را داشته باشد.',
],
'lte' => [
'numeric' => ':attribute باید کمتر یا برابر :value باشد.',
'file' => ':attribute باید کمتر یا برابر :value کیلوبایت باشد.',
'string' => ':attribute باید کمتر یا برابر :value کاراکتر باشد.',
'array' => ':attribute باید :value ایتم یا کمتر را داشته باشد.',
],
"max" => [
"numeric" => ":attribute نباید بزرگتر از :max باشد.",
"file" => ":attribute نباید بزرگتر از :max کیلوبایت باشد.",
"string" => ":attribute نباید بیشتر از :max کاراکتر باشد.",
"array" => ":attribute نباید بیشتر از :max آیتم باشد.",
],
"mimes" => ":attribute باید یکی از فرمت های :values باشد.",
'mimetypes' => ':attribute باید تایپ ان از نوع: :values باشد.',
"min" => [
"numeric" => ":attribute نباید کوچکتر از :min باشد.",
"file" => ":attribute نباید کوچکتر از :min کیلوبایت باشد.",
"string" => ":attribute نباید کمتر از :min کاراکتر باشد.",
"array" => ":attribute نباید کمتر از :min آیتم باشد.",
],
"not_in" => ":attribute انتخاب شده، معتبر نیست.",
'not_regex' => ':attribute فرمت معتبر نیست.',
"numeric" => ":attribute باید شامل عدد باشد.",
'password' => 'رمز عبور اشتباه است.',
'present' => ':attribute باید وجود داشته باشد.',
"regex" => ":attribute یک فرمت معتبر نیست",
"required" => "فیلد :attribute الزامی است",
"required_if" => "فیلد :attribute هنگامی که :other برابر با :value است، الزامیست.",
'required_unless' => 'قیلد :attribute الزامیست مگر این فیلد :other مقدارش :values باشد.',
"required_with" => ":attribute الزامی است زمانی که :values موجود است.",
"required_with_all" => ":attribute الزامی است زمانی که :values موجود است.",
"required_without" => ":attribute الزامی است زمانی که :values موجود نیست.",
"required_without_all" => ":attribute الزامی است زمانی که :values موجود نیست.",
"same" => ":attribute و :other باید مانند هم باشند.",
"size" => [
"numeric" => ":attribute باید برابر با :size باشد.",
"file" => ":attribute باید برابر با :size کیلوبایت باشد.",
"string" => ":attribute باید برابر با :size کاراکتر باشد.",
"array" => ":attribute باسد شامل :size آیتم باشد.",
],
'starts_with' => ':attribute باید با یکی از این مقادیر شروع شود: :values.',
"string" => ":attribute باید رشته باشد.",
"timezone" => "فیلد :attribute باید یک منطقه صحیح باشد.",
"unique" => ":attribute قبلا انتخاب شده است.",
'uploaded' => 'فیلد :attribute به درستی اپلود نشد.',
"url" => "فرمت آدرس :attribute اشتباه است.",
'uuid' => ':attribute باید یک فرمت درست UUID باشد.',
/*
|--------------------------------------------------------------------------
| Custom Validation Language Lines
|--------------------------------------------------------------------------
|
| Here you may specify custom validation messages for attributes using the
| convention "attribute.rule" to name the lines. This makes it quick to
| specify a specific custom language line for a given attribute rule.
|
*/
'custom' => [],
/*
|--------------------------------------------------------------------------
| Custom Validation Attributes
|--------------------------------------------------------------------------
|
| The following language lines are used to swap attribute place-holders
| with something more reader friendly such as E-Mail Address instead
| of "email". This simply helps us make messages a little cleaner.
|
*/
'attributes' => [
"name" => "نام",
"username" => "نام کاربری",
"national_code" => "کد ملی",
"email" => "پست الکترونیکی",
"first_name" => "نام",
"last_name" => "نام خانوادگی",
"family" => "نام خانوادگی",
"password" => "رمز عبور",
"password_confirmation" => "تاییدیه ی رمز عبور",
"city" => "شهر",
"country" => "کشور",
"address" => "نشانی",
"phone" => "تلفن",
"mobile" => "تلفن همراه",
"age" => "سن",
"sex" => "جنسیت",
"gender" => "جنسیت",
"day" => "روز",
"month" => "ماه",
"year" => "سال",
"hour" => "ساعت",
"minute" => "دقیقه",
"second" => "ثانیه",
"title" => "عنوان",
"text" => "متن",
"content" => "محتوا",
"description" => "توضیحات",
"excerpt" => "گلچین کردن",
"date" => "تاریخ",
"time" => "زمان",
"available" => "موجود",
"size" => "اندازه",
"file" => "فایل",
"fullname" => "نام کامل",
'current_password' => 'رمز عبور فعلی',
'new_password' => 'رمز عبور جدید',
'degree' => 'مدرک تحصیلی',
'major' => 'شغل',
'avatar' => 'آواتار',
'lat' => 'طول جغرافیایی',
'lng' => 'عرض جغرافیایی',
'azmayesh_type_id' => 'نوع آزمایش',
'request_date' => 'تاریخ درخواست',
'report_date' => 'تاریخ گزارش',
'request_number' => 'شماره درخواست',
'employer' => 'کارفرما',
'contractor' => 'پیمانکار',
'work_number' => 'شماره کار',
'project_name' => 'نام پروژه',
'consultant' => 'مشاور',
'applicant' => 'متقاضی',
'province_id' => 'استان',
'azmayesh_id' => 'آزمایش',
'data' => 'داده',
'fields' => 'فیلد ها',
'fields.*.name' => 'نام فیلد',
'fields.*.unit' => 'واحد فیلد',
'fields.*.type' => 'نوع فیلد',
'fields.*.option' => 'گزینه های فیلد',
'cmms_machine_id' => 'کد یکتا ماشین',
'contract_subitem_id' => 'کد یکتای پروژه',
'base_price' => 'قیمت پایه',
'unit' => 'واحد',
'phone_number'=> 'شماره تلفن',
'final_description' => 'توضیحات نهایی',
'point' => 'منطقه' ,
'info_id' => 'دسته بندی' ,
'activity_date' => 'تاریخ فعالیت',
'activity_time' => 'زمان فعالیت',
'recognize_picture' => 'عکس بازدید',
'recognize_picture_second' => 'عکس بازدید',
'axis_type_id' => 'نوع محور',
'supervisor_description' => 'توضیحات کارشناس',
'need_judiciary' => 'دستور قضایی' ,
'operator_description' => 'توضیحات ناظر',
'judiciary_document' => 'فایل دستور قضایی',
'action_picture' => 'عکس اقدامات',
'finish_picture' => 'عکس پایان کار',
'action_date' => 'زمان فالیت',
'evidence_picture' => 'تصویر مشاهده شده',
'deposit_insurance_image' => 'عکس مبلغ بیمه',
'deposit_insurance_amount' => ' مبلغ بیمه',
'deposit_daghi_image' => 'عکس مبلغ بیمه',
'deposit_daghi_amount' => 'مبلغ داغی',
'is_foreign' => 'ناوگان خارجی',
'axis_name' => 'نام محور',
'driver_name' => 'اسم راننده',
'plaque' => 'پلاک',
'driver_national_code' => 'کدملی راننده',
'driver_phone_number' => 'شماره موبایل راننده',
'accident_type' => 'نوع خسارت',
'accident_date' => 'تاریخ تصادف',
'accident_time' => 'زمان تصادف',
'report_base' => 'گزارش',
'police_file' => 'تصویر کروکی یا نامه پلیس راه',
'police_serial' => 'شماره کروکی یا نامه پلیس راه',
'police_file_date' => 'تاریخ کروکی یا نامه پلیس راه',
'damage_picture1' => 'عکس تصادف',
'damage_picture2' => 'عکس تصادف',
'damage_items' => 'ایتم های خسارت',
'damage_items.*.value' => 'میزان ایتم های خسارت',
'damage_items.*.amount' => 'هزینه خسارت',
'driver_rate' => 'سهم راننده',
'code' => 'کد',
'rahdaran' => 'افراد',
'machines' => 'خودرو',
'driver' => 'راننده',
'zone' => 'منطقه',
'start_date' => 'تاریخ شروع',
'end_date' => 'تاریخ پایان',
'end_point' => 'مقصد',
'area' => 'منطقه عملیاتی',
'area.type' => 'نوع محدوده' ,
'area.coordinates' => 'مختصات محدوده',
'category_id' => 'دسته بندی',
'explanation' => 'توضیحات',
'requested_machines' => 'ماشین های درخواستی',
'type' => 'نوع',
'road_observed_id' => 'کد واکنش سریع',
'city_id' => 'شهر',
'expert_description' => 'توضیح کارشناس',
'need_payment' => 'نیاز به پرداخت',
'request_id' => 'شناسه درخواست',
'access_road' => 'راه دسترسی',
'access_road.type' => 'نوع راه دسترسی',
'access_road.coordinates' => 'مختصات راه دسترسی',
'final_area' => 'محدوده نهایی',
'final_area.type' => 'نوع محدوده نهایی',
'final_area.coordinates' => 'مختصات محدوده نهایی',
'final_plan' => 'طرح نهایی',
'final_plan.type' => 'نوع طرح نهایی',
'final_plan.coordinate' => 'مختصات طرح نهایی',
'national_id' => 'کد ملی' ,
'requested_organization' => 'سازمان درخواست‌کننده',
'plan_group' => 'گروه طرح',
'plan_title' => 'موضوع طرح',
'worksheet' => 'شناسه کاربرگ',
'response_options' => 'گزینه های پاسخ',
'isic' => 'کد ISIC',
'primary_area' => 'محدوده اولیه',
'primary_area.type' => 'نوع محدوده اولیه',
'primary_area.coordinates' => 'مختصات محدوده اولیه',
'forbidden_area' => 'محدوده ممنوعه',
'forbidden_area.type' => 'نوع محدوده محدوده',
'forbidden_area.coordinates' => 'مختصات محدوده ممنوعه',
'edarate_ostani_id' => 'اداره استانی',
'edarate_shahri_id' => ' اداره شهری'
],
];

10
backend/routes/api.php Normal file → Executable file
View File

@@ -8,13 +8,3 @@ Route::get('/user', function (Request $request) {
return $request->user();
})->middleware('auth:api');
Route::prefix('user')->group(function () {
Route::prefix('Auth')
->name('Auth')
->controller(AuthController::class)
->group(function () {
Route::post('register', 'register')->name('register');
Route::post('login', 'login')->name('login');
Route::post('logout', 'logout')->middleware('auth:api')->name('logout');
});
});

21
backend/routes/web.php Normal file → Executable file
View File

@@ -1,7 +1,22 @@
<?php
use App\User\Controller\Auth\AuthController;
use App\User\Controller\ProfileController;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::prefix('auth')
->name('Auth.')
->controller(AuthController::class)
->group(function () {
Route::post('register', 'register')->name('register');
Route::post('login', 'login')->name('login');
Route::post('logout', 'logout')->name('logout');
});
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');
});