diff --git a/.env.example b/.env.example deleted file mode 100644 index b7becba..0000000 --- a/.env.example +++ /dev/null @@ -1,52 +0,0 @@ -APP_NAME=Laravel -APP_ENV=local -APP_KEY= -APP_DEBUG=true -APP_URL=http://localhost - -LOG_CHANNEL=stack -LOG_DEPRECATIONS_CHANNEL=null -LOG_LEVEL=debug - -DB_CONNECTION=mysql -DB_HOST=127.0.0.1 -DB_PORT=3306 -DB_DATABASE=laravel -DB_USERNAME=root -DB_PASSWORD= - -BROADCAST_DRIVER=log -CACHE_DRIVER=file -FILESYSTEM_DRIVER=local -QUEUE_CONNECTION=sync -SESSION_DRIVER=file -SESSION_LIFETIME=120 - -MEMCACHED_HOST=127.0.0.1 - -REDIS_HOST=127.0.0.1 -REDIS_PASSWORD=null -REDIS_PORT=6379 - -MAIL_MAILER=smtp -MAIL_HOST=mailhog -MAIL_PORT=1025 -MAIL_USERNAME=null -MAIL_PASSWORD=null -MAIL_ENCRYPTION=null -MAIL_FROM_ADDRESS=null -MAIL_FROM_NAME="${APP_NAME}" - -AWS_ACCESS_KEY_ID= -AWS_SECRET_ACCESS_KEY= -AWS_DEFAULT_REGION=us-east-1 -AWS_BUCKET= -AWS_USE_PATH_STYLE_ENDPOINT=false - -PUSHER_APP_ID= -PUSHER_APP_KEY= -PUSHER_APP_SECRET= -PUSHER_APP_CLUSTER=mt1 - -MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}" -MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}" diff --git a/app/Http/Controllers/Api/V1/AuthController.php b/app/Http/Controllers/Api/V1/AuthController.php new file mode 100644 index 0000000..47ff909 --- /dev/null +++ b/app/Http/Controllers/Api/V1/AuthController.php @@ -0,0 +1,39 @@ +all(); + + $validator = Validator::make($data, [ + 'username' => 'required', + 'password' => 'required|min:6' + ]); + + if($validator->fails()){ + return $this->sendError('Validation Error.', $validator->errors()); + } + + if (!Auth::attempt($data)) { + return $this->sendError('Unauthorised.',array('error'=>'Invalid login details')); + } + $user = User::where('username', $request['username'])->firstOrFail(); + $success['access_token'] = auth('api')->user()->createToken('auth_token')->plainTextToken; + $success['token_type'] = 'Bearer'; + return $success; + } + + public function logout (Request $request) { + + auth('api')->user()->currentAccessToken()->delete(); + return response(['message' => 'You have been successfully logged out.'], 200); + } +} diff --git a/app/Http/Controllers/Api/V1/BaseController.php b/app/Http/Controllers/Api/V1/BaseController.php new file mode 100644 index 0000000..8847c2f --- /dev/null +++ b/app/Http/Controllers/Api/V1/BaseController.php @@ -0,0 +1,44 @@ + true, + 'data' => $result, + 'message' => $message, + ]; + return response()->json($response, 200); + } + + + /** + * return error response. + * + * @return \Illuminate\Http\Response + */ + public function sendError($error, $errorMessages = [], $code = 200) + { + $response = [ + 'success' => false, + 'message' => $error, + ]; + + if(!empty($errorMessages)){ + $response['data'] = $errorMessages; + } + + return response()->json($response, $code); + } +} diff --git a/app/Http/Controllers/Api/V1/ProjectController.php b/app/Http/Controllers/Api/V1/ProjectController.php new file mode 100644 index 0000000..85869e2 --- /dev/null +++ b/app/Http/Controllers/Api/V1/ProjectController.php @@ -0,0 +1,64 @@ +all(); + $validator = Validator::make($data, [ + 'name' => 'required|unique:projects,name', + ]); + $data['name'] = $data['name']; + if($validator->fails()){ + return $this->sendError('Validation Error.', $validator->errors()); + } + + $Project = Project::create($data); + return new ProjectResource($Project); + } + + public function update(Request $request, $id) + { + $project = Project::findOrFail($id); + $data = $request->all(); + + $validator = Validator::make($data, [ + 'name' => 'required|unique:projects,name,'.$id, + ]); + + if($validator->fails()){ + return $this->sendError('Validation Error.', $validator->errors()); + } + + $project->update($data); + return new ProjectResource($project); + } + + public function destroy(Request $request, $id) + { + $project = Project::findOrFail($id); + $project->delete(); + return response()->json([ + 'message' => 'Project deleted successfully' + ], 200); + } +} diff --git a/app/Http/Controllers/Api/V1/TaskController.php b/app/Http/Controllers/Api/V1/TaskController.php new file mode 100644 index 0000000..0d4ec83 --- /dev/null +++ b/app/Http/Controllers/Api/V1/TaskController.php @@ -0,0 +1,68 @@ +all(); + $validator = Validator::make($data, [ + 'title' => 'required', + 'status' => 'required', + 'project_id' => 'required', + 'user_id' => 'required', + ]); + + if($validator->fails()){ + return $this->sendError('Validation Error.', $validator->errors()); + } + + $Task = Task::create($data); + return new TaskResource($Task); + } + + public function update(Request $request, $id) + { + $task = Task::findOrFail($id); + $data = $request->all(); + + $validator = Validator::make($data, [ + 'title' => 'required', + 'status' => 'required', + ]); + + if($validator->fails()){ + return $this->sendError('Validation Error.', $validator->errors()); + } + + $task->update($data); + return new TaskResource($task); + } + + public function destroy(Request $request, $id) + { + $task = Task::findOrFail($id); + $task->delete(); + return response()->json([ + 'message' => 'Task deleted successfully' + ], 200); + } +} diff --git a/app/Http/Controllers/Api/V1/UserController.php b/app/Http/Controllers/Api/V1/UserController.php new file mode 100644 index 0000000..5c0168b --- /dev/null +++ b/app/Http/Controllers/Api/V1/UserController.php @@ -0,0 +1,73 @@ +middleware('CheckBlackList'); + $data = $request->all(); + $validator = Validator::make($data, [ + 'username' => 'required|unique:users,username', + 'password' => 'required|min:6', + ]); + + if($validator->fails()){ + return $this->sendError('Validation Error.', $validator->errors()); + } + + $data['username'] = $data['username']; + + $data['password'] = Hash::make($data['password']); + $User = User::create($data); + return new UserResource($User); + } + + public function update(Request $request, $id) + { + $user = User::findOrFail($id); + $data = $request->all(); + + $validator = Validator::make($data, [ + 'username' => 'required|unique:users,username,'.$id, + 'password' => 'required|min:6', + ]); + + + + if($validator->fails()){ + return $this->sendError('Validation Error.', $validator->errors()); + } + $data['password'] = Hash::make($data['password']); + + $user->update($data); + return new UserResource($user); + } + + public function destroy(Request $request, $id) + { + $user = User::findOrFail($id); + $user->delete(); + return response()->json([ + 'message' => 'User deleted successfully' + ], 200); + } +} diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index d3722c2..f0e38c7 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -40,7 +40,7 @@ class Kernel extends HttpKernel ], 'api' => [ - // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, + \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, 'throttle:api', \Illuminate\Routing\Middleware\SubstituteBindings::class, ], diff --git a/app/Http/Resources/ProjectResource.php b/app/Http/Resources/ProjectResource.php new file mode 100644 index 0000000..ba96ecf --- /dev/null +++ b/app/Http/Resources/ProjectResource.php @@ -0,0 +1,13 @@ +hasOne(User::class); + } + + public function projects() + { + return $this->hasOne(Project::class); + } + +} diff --git a/app/Models/User.php b/app/Models/User.php index 8996368..017ca8a 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -2,43 +2,18 @@ namespace App\Models; -use Illuminate\Contracts\Auth\MustVerifyEmail; use Illuminate\Database\Eloquent\Factories\HasFactory; -use Illuminate\Foundation\Auth\User as Authenticatable; -use Illuminate\Notifications\Notifiable; use Laravel\Sanctum\HasApiTokens; +use Illuminate\Notifications\Notifiable; +use Illuminate\Foundation\Auth\User as Authenticatable; class User extends Authenticatable { - use HasApiTokens, HasFactory, Notifiable; - - /** - * The attributes that are mass assignable. - * - * @var array - */ - protected $fillable = [ - 'name', - 'email', - 'password', - ]; - - /** - * The attributes that should be hidden for serialization. - * - * @var array - */ - protected $hidden = [ - 'password', - 'remember_token', - ]; - - /** - * The attributes that should be cast. - * - * @var array - */ - protected $casts = [ - 'email_verified_at' => 'datetime', - ]; + use HasFactory, HasApiTokens, Notifiable; + protected $fillable = ['username', 'password', 'role']; + + public function Task() + { + return $this->belongsTo(Task::class); + } } diff --git a/config/auth.php b/config/auth.php index d8c6cee..377e98a 100644 --- a/config/auth.php +++ b/config/auth.php @@ -40,6 +40,11 @@ 'driver' => 'session', 'provider' => 'users', ], + 'api' => [ + 'driver' => 'sanctum', + 'provider' => 'users', + 'hash' => false, + ], ], /* diff --git a/database/factories/ProjectFactory.php b/database/factories/ProjectFactory.php new file mode 100644 index 0000000..b9e09cd --- /dev/null +++ b/database/factories/ProjectFactory.php @@ -0,0 +1,21 @@ + $this->faker->unique()->name(), + ]; + } +} diff --git a/database/factories/TaskFactory.php b/database/factories/TaskFactory.php new file mode 100644 index 0000000..95780b0 --- /dev/null +++ b/database/factories/TaskFactory.php @@ -0,0 +1,26 @@ + $this->faker->text(25), + 'description' => $this->faker->sentence(2), + 'status'=>$this->faker->randomElement(['not_started']), + 'user_id'=> $this->faker->randomElement(User::all())['id'], + 'project_id'=> $this->faker->randomElement(Project::all())['id'], + ]; + } +} diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index a3eb239..9868738 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -3,7 +3,6 @@ namespace Database\Factories; use Illuminate\Database\Eloquent\Factories\Factory; -use Illuminate\Support\Str; class UserFactory extends Factory { @@ -15,25 +14,9 @@ class UserFactory extends Factory public function definition() { return [ - 'name' => $this->faker->name(), - 'email' => $this->faker->unique()->safeEmail(), - 'email_verified_at' => now(), - 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password - 'remember_token' => Str::random(10), + 'username' => $this->faker->unique()->userName(), + 'password' => '$2y$10$QY1v7OuVtqwOc7SE88wqbej7K35KYfyltM9Ag90LnVpL3lbcFaIrC', + 'role'=>$this->faker->randomElement(['admin','product_owner','team_member']), ]; } - - /** - * Indicate that the model's email address should be unverified. - * - * @return \Illuminate\Database\Eloquent\Factories\Factory - */ - public function unverified() - { - return $this->state(function (array $attributes) { - return [ - 'email_verified_at' => null, - ]; - }); - } } diff --git a/database/migrations/2014_10_12_000000_create_users_table.php b/database/migrations/2022_09_02_115349_create_users_table.php similarity index 76% rename from database/migrations/2014_10_12_000000_create_users_table.php rename to database/migrations/2022_09_02_115349_create_users_table.php index 621a24e..fb3f363 100644 --- a/database/migrations/2014_10_12_000000_create_users_table.php +++ b/database/migrations/2022_09_02_115349_create_users_table.php @@ -15,11 +15,9 @@ public function up() { Schema::create('users', function (Blueprint $table) { $table->id(); - $table->string('name'); - $table->string('email')->unique(); - $table->timestamp('email_verified_at')->nullable(); + $table->string('username')->unique(); $table->string('password'); - $table->rememberToken(); + $table->enum('role',array('admin','product_owner','team_member')); $table->timestamps(); }); } diff --git a/database/migrations/2022_09_02_120355_create_projects_table.php b/database/migrations/2022_09_02_120355_create_projects_table.php new file mode 100644 index 0000000..950d255 --- /dev/null +++ b/database/migrations/2022_09_02_120355_create_projects_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('name')->unique(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('projects'); + } +} diff --git a/database/migrations/2022_09_02_121145_create_tasks_table.php b/database/migrations/2022_09_02_121145_create_tasks_table.php new file mode 100644 index 0000000..a7fd0f9 --- /dev/null +++ b/database/migrations/2022_09_02_121145_create_tasks_table.php @@ -0,0 +1,47 @@ +id(); + $table->string('title'); + $table->text('description')->nullable(); + $table->enum('status',array('not_started','in_progress','ready_for_test','completed')); + $table->unsignedBigInteger('user_id'); + $table->unsignedBigInteger('project_id'); + $table->timestamps(); + + $table->foreign('user_id') + ->references('id') + ->on('users') + ->onDelete('cascade'); + $table->foreign('project_id') + ->references('id') + ->on('projects') + ->onDelete('cascade'); + + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('tasks'); + } +} diff --git a/routes/api.php b/routes/api.php index eb6fa48..f1321d8 100644 --- a/routes/api.php +++ b/routes/api.php @@ -14,6 +14,16 @@ | */ -Route::middleware('auth:sanctum')->get('/user', function (Request $request) { - return $request->user(); +// Route::middleware('auth:sanctum')->get('/user', function (Request $request) { +// return $request->user(); +// }); + +Route::name('login')->post('/v1/login', [AuthController::class,'login']); + +Route::group(['middleware' => ['auth:api']], function () { + Route::name('logout')->post('/v1/logout', [AuthController::class,'logout']); + Route::resource('/v1/users', UserController::class); + Route::resource('v1/projects', ProjectController::class); + Route::resource('v1/tasks', TaskController::class); }); +