diff --git a/app/Http/Controllers/AuthController.php b/app/Http/Controllers/AuthController.php index 62548e5..c72067b 100644 --- a/app/Http/Controllers/AuthController.php +++ b/app/Http/Controllers/AuthController.php @@ -3,17 +3,22 @@ namespace App\Http\Controllers; use App\Http\Requests\LoginRequest; +use App\Http\Requests\UpdateUserRequest; +use App\Http\Resources\UserResource; use App\Models\User; +use App\Services\CreditCardService; +use App\Services\UserService; use Exception; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Hash; use Illuminate\Validation\ValidationException; -use Log; use Symfony\Component\HttpFoundation\Response; class AuthController extends Controller { + public function __construct(protected UserService $userService, protected CreditCardService $creditCardService) {} + public function register(Request $request): JsonResponse { $fields = $request->validate([ @@ -67,4 +72,15 @@ public function login(LoginRequest $request): JsonResponse 'message' => 'Login successful', ], Response::HTTP_OK); } + + public function show(User $user): UserResource + { + return new UserResource($this->userService->show($user)); + } + + public function update(UpdateUserRequest $request, User $user): UserResource + { + return new UserResource($this->userService->update($request->updateUser(), $user)); + + } } diff --git a/app/Http/Controllers/CreditCardController.php b/app/Http/Controllers/CreditCardController.php new file mode 100644 index 0000000..04aa94c --- /dev/null +++ b/app/Http/Controllers/CreditCardController.php @@ -0,0 +1,23 @@ +creditCardService->show($user)); + } + + public function update(UpdateCreditCardRequest $request, User $user): CreditCardResource + { + return new CreditCardResource($this->creditCardService->updateOrCreate($request->updateCard(), $user)); + } +} diff --git a/app/Http/Requests/UpdateCreditCardRequest.php b/app/Http/Requests/UpdateCreditCardRequest.php new file mode 100644 index 0000000..0ff2904 --- /dev/null +++ b/app/Http/Requests/UpdateCreditCardRequest.php @@ -0,0 +1,29 @@ + 'string|min:2|max:30|regex:/^[a-zA-ZÀ-ž\s\'-]+$/', + 'card_last_name' => 'string|min:2|max:30|regex:/^[a-zA-ZÀ-ž\s\'-]+$/', + 'card_number' => 'string|regex:/^\d{16}$/', + 'card_expiry_date' => 'string|regex:/^\d{2}\/\d{2}$/', + 'card_cvv' => 'string|regex:/^\d{3,4}$/', + ]; + } + + public function updateCard(): array + { + return $this->validated(); + } +} diff --git a/app/Http/Requests/UpdateUserRequest.php b/app/Http/Requests/UpdateUserRequest.php new file mode 100644 index 0000000..8fa2c60 --- /dev/null +++ b/app/Http/Requests/UpdateUserRequest.php @@ -0,0 +1,41 @@ +|string> + */ + public function rules(): array + { + return [ + 'name' => 'string|min:2|max:30|regex:/^[a-zA-ZÀ-ž\s\'-]+$/', + 'last_name' => 'string|min:2|max:30|regex:/^[a-zA-ZÀ-ž\s\'-]+$/', + 'email' => 'email|max:255|unique:users,email,'.$this->user->id, + 'phone_number' => 'string|regex:/^\+?\d{9,15}$/', + 'voivodship' => 'string|min:1|max:30', + 'city' => 'string|min:1|max:30', + 'zip_code' => 'string|regex:/^\d{2}-\d{3}$/', + 'street' => 'string|min:1|max:30', + 'house_number' => 'string|regex:/^\d+[a-zA-Z]?$/', + ]; + } + + public function updateUser(): array + { + return $this->validated(); + } +} diff --git a/app/Http/Resources/CreditCardResource.php b/app/Http/Resources/CreditCardResource.php new file mode 100644 index 0000000..da85cdc --- /dev/null +++ b/app/Http/Resources/CreditCardResource.php @@ -0,0 +1,36 @@ + + */ + public function toArray(Request $request): array + { + return [ + 'card_first_name' => $this->card_first_name, + 'card_last_name' => $this->card_last_name, + 'card_number' => $this->maskCardNumber($this->card_number), + 'card_expiry_date' => $this->card_expiry_date, + 'card_cvv' => $this->maskCvv($this->card_cvv), + ]; + } + + private function maskCardNumber(string $cardNumber): string + { + // ############1234 + return str_repeat('#', strlen($cardNumber) - 4).substr($cardNumber, -4); + } + + private function maskCvv(string $cvv): string + { + return str_repeat('*', strlen($cvv)); + } +} diff --git a/app/Http/Resources/UserResource.php b/app/Http/Resources/UserResource.php new file mode 100644 index 0000000..3b6b127 --- /dev/null +++ b/app/Http/Resources/UserResource.php @@ -0,0 +1,19 @@ + + */ + public function toArray(Request $request): array + { + return parent::toArray($request); + } +} diff --git a/app/Models/CreditCard.php b/app/Models/CreditCard.php new file mode 100644 index 0000000..4ff1488 --- /dev/null +++ b/app/Models/CreditCard.php @@ -0,0 +1,36 @@ + */ + use HasFactory; + + protected $fillable = [ + 'user_id', + 'card_first_name', + 'card_last_name', + 'card_number', + 'card_expiry_date', + 'card_cvv', + ]; + + protected function casts(): array + { + return [ + 'card_number' => 'hashed', + 'card_cvv' => 'hashed', + ]; + } + + public function user(): BelongsTo + { + return $this->belongsTo(User::class); + } +} diff --git a/app/Models/User.php b/app/Models/User.php index aea9947..0356cbe 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -5,6 +5,7 @@ // use Illuminate\Contracts\Auth\MustVerifyEmail; use Database\Factories\UserFactory; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Foundation\Auth\User as Authenticatable; use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; @@ -21,8 +22,16 @@ class User extends Authenticatable */ protected $fillable = [ 'name', + 'last_name', 'email', 'password', + 'phone_number', + 'voivodship', + 'city', + 'zip_code', + 'street', + 'house_number', + ]; /** @@ -47,4 +56,9 @@ protected function casts(): array 'password' => 'hashed', ]; } + + public function creditCard(): HasOne + { + return $this->hasOne(CreditCard::class); + } } diff --git a/app/Services/CreditCardService.php b/app/Services/CreditCardService.php new file mode 100644 index 0000000..a203363 --- /dev/null +++ b/app/Services/CreditCardService.php @@ -0,0 +1,21 @@ +creditCard; + } + + public function updateOrCreate(array $data, User $user): CreditCard + { + $creditCard = $user->creditCard(); + + return $creditCard->updateOrCreate(['user_id' => $user->id], $data); + } +} diff --git a/app/Services/UserService.php b/app/Services/UserService.php new file mode 100644 index 0000000..20f0383 --- /dev/null +++ b/app/Services/UserService.php @@ -0,0 +1,20 @@ +update($data); + + return $user; + } +} diff --git a/database/factories/CreditCardFactory.php b/database/factories/CreditCardFactory.php new file mode 100644 index 0000000..29d68d8 --- /dev/null +++ b/database/factories/CreditCardFactory.php @@ -0,0 +1,29 @@ + + */ +class CreditCardFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'user_id' => User::factory(), + 'card_first_name' => fake()->card_first_name, + 'card_last_name' => fake()->card_last_name, + 'card_number' => fake()->card_number, + 'card_expiry_date' => fake()->card_expiry_date, + 'card_cvv' => fake()->card_cvv, + ]; + } +} diff --git a/database/migrations/0001_01_01_000000_create_users_table.php b/database/migrations/0001_01_01_000000_create_users_table.php index 05fb5d9..2e43f5e 100644 --- a/database/migrations/0001_01_01_000000_create_users_table.php +++ b/database/migrations/0001_01_01_000000_create_users_table.php @@ -14,9 +14,18 @@ public function up(): void Schema::create('users', function (Blueprint $table) { $table->id(); $table->string('name'); + $table->string('last_name')->nullable(); $table->string('email')->unique(); + $table->string('role')->nullable(); + $table->string('phone_number')->nullable(); + $table->string('voivodship')->nullable(); + $table->string('city')->nullable(); + $table->string('zip_code')->nullable(); + $table->string('street')->nullable(); + $table->string('house_number')->nullable(); $table->timestamp('email_verified_at')->nullable(); $table->string('password'); + $table->rememberToken(); $table->timestamps(); }); diff --git a/database/migrations/2024_12_18_090401_create_credit_cards_table.php b/database/migrations/2024_12_18_090401_create_credit_cards_table.php new file mode 100644 index 0000000..50f1020 --- /dev/null +++ b/database/migrations/2024_12_18_090401_create_credit_cards_table.php @@ -0,0 +1,33 @@ +id(); + $table->foreignId('user_id')->constrained(); + $table->string('card_first_name')->nullable(); + $table->string('card_last_name')->nullable(); + $table->string('card_number')->nullable(); + $table->string('card_expiry_date')->nullable(); + $table->string('card_cvv')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('credit_cards'); + } +}; diff --git a/routes/api.php b/routes/api.php index 0bf52a2..623a665 100644 --- a/routes/api.php +++ b/routes/api.php @@ -2,10 +2,25 @@ use App\Http\Controllers\AuthController; use App\Http\Controllers\CourseController; +use App\Http\Controllers\CreditCardController; use App\Http\Controllers\GoogleAuthController; use Illuminate\Http\Request; use Illuminate\Support\Facades\Route; +Route::middleware('auth:sanctum')->group(function () { + Route::controller(AuthController::class)->group(function () { + Route::get('user/{user}', 'show'); + Route::put('user/{user}', 'update'); + }); +}); + +Route::middleware('auth:sanctum')->group(function () { + Route::controller(CreditCardController::class)->group(function () { + Route::get('user/{user}/credit-card', 'show'); + Route::put('user/{user}/credit-card', 'update'); + }); +}); + Route::get('/user', function (Request $request) { return $request->user(); })->middleware('auth:sanctum');