diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 6cd4809..3137be0 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -20,9 +20,20 @@ - + + + + + + + + + + - + + + + + + + + + + @@ -262,13 +280,6 @@ - - - - - - - @@ -321,7 +332,7 @@ - + diff --git a/CHANGELOG.md b/CHANGELOG.md index 74c6947..efc398e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,3 +4,9 @@ - Fix Database migration - Fix Main Theme - Add Blocks Feature + +# v1.02 +- Add Auth APIs +- Add User CLI APIs +- User Activated By Email +- User Activated By Phone [MessageBird] diff --git a/app/Http/Controllers/API/AuthController.php b/app/Http/Controllers/API/AuthController.php new file mode 100644 index 0000000..0aae1be --- /dev/null +++ b/app/Http/Controllers/API/AuthController.php @@ -0,0 +1,473 @@ + 'required|string|max:255', + 'email' => 'required|string|email|max:255|unique:users', + 'phone' => 'nullable|string|max:20|unique:users', + 'password' => 'required|string|confirmed|min:8', + 'username' => 'nullable|string|max:120|unique:users', + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + $checkEx = User::where('email', $request->get('email'))->orWhere('phone', $request->get('phone'))->first(); + if($checkEx->email_verified_at){ + return response()->json([ + "success" => false, + "message" => $validator->messages() + ]); + } + else { + Mail::to($checkEx)->send(new EmailCode($checkEx->code)); + if(!empty($request->get('phone'))){ + send_sms('3U4hIoTFq6FZddMbJ9gZWFRw2','+201069706892', $checkEx->phone, 'Your Code IS: '. $checkEx->code);; + } + + return response()->json([ + "success" => false, + 'message' => __('your activated link has been send to your email') + ]); + } + + } + else{ + $user = User::create([ + 'name' => $request->get('name'), + 'phone' => $request->get('phone'), + 'username' => $request->get('username'), + 'email' => $request->get('email'), + 'password' => Hash::make($request->get('password')), + ]); + + if($user){ + $token = $user->createToken('auth_token')->plainTextToken; + + $user->api_key = $token; + $user->secret_key = Str::uuid(); + $user->code = substr(number_format(time() * rand(),0,'',''),0,6); + $user->save(); + + Mail::to($user)->send(new EmailCode($user->code)); + if(!empty($user->phone)){ + send_sms('3U4hIoTFq6FZddMbJ9gZWFRw2','+201069706892', $user->phone, 'Your Code IS: '. $user->code); + } + + return response()->json([ + 'success' => true, + 'message' => __('your activated link has been send to your email') + ]); + } + else { + return response()->json([ + 'success' => false, + 'message' => __('something going error!') + ], 401); + } + + + } + } + + public function resend(Request $request){ + $rules = [ + 'email' => 'nullable|string|email', + 'phone' => 'nullable|string' + ]; + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ]); + } + else { + $checkEx = User::where('email', $request->get('email'))->orWhere('phone', $request->get('phone'))->first(); + + if($checkEx){ + $checkEx->code = substr(number_format(time() * rand(),0,'',''),0,6); + $checkEx->save(); + + if(!empty($request->get('email'))){ + Mail::to($checkEx)->send(new EmailCode($checkEx->code)); + } + + if(!empty($request->get('phone'))){ + send_sms('3U4hIoTFq6FZddMbJ9gZWFRw2','+201069706892', $checkEx->phone, 'Your Code IS: '. $checkEx->code); + } + + return response()->json([ + 'success' => true, + 'message' => __('your activated link has been send to your email') + ]); + } + else { + return response()->json([ + 'success' => false, + 'message' => __('sorry user not exits!') + ], 401); + } + } + + } + + public function login(Request $request) + { + $rules = [ + 'email' => 'required|string|email', + 'password' => 'required|string|min:8', + ]; + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ]); + } + else { + if (!Auth::attempt($request->only('email', 'password'))) { + return response()->json([ + 'success' => false, + 'message' => __('Invalid login details') + ], 401); + } + else { + $user = User::where('email', $request['email'])->firstOrFail(); + + if($user->email_verified_at && !$user->code){ + if(!$user->api_key){ + $token = $user->createToken('auth_token')->plainTextToken; + $user->api_key = $token; + $user->secret_key = Str::uuid(); + $user->save(); + } + + return response()->json([ + 'success' => true, + 'message' => __('Login Success'), + 'data' => [ + 'login' => true, + 'api_key' => $user->api_key, + 'secret_key' => $user->secret_key, + 'token_type' => 'Bearer', + 'user' => [ + "name" => $user->name, + "email" => $user->email, + "phone" => $user->phone, + "username" => $user->username, + ] + ] + ]); + } + else { + return response()->json([ + 'success' => false, + 'message' => __('Sorry! your account not active please check your email or phone to get activated link') + ], 403); + } + + } + } + } + + public function user(Request $request){ + $rules = [ + 'secret_key' => 'required|string', + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ]); + } + else { + if(Auth::user()){ + if($request->user()->secret_key == $request->get('secret_key')){ + return response()->json([ + 'success' => true, + 'message' => __('User Data Has Been Loaded Success'), + 'data' => [ + 'api_key' => $request->user()->api_key, + 'secret_key' => $request->user()->secret_key, + 'token_type' => 'Bearer', + 'user' => [ + "id" => $request->user()->id, + "name" => $request->user()->name, + "email" => $request->user()->email, + "phone" => $request->user()->phone, + "username" => $request->user()->username, + ] + ] + ]); + } + else { + return response()->json([ + 'success' => false, + 'message' => __('Please Input a Valid Secret Key') + ], 401); + } + + } + else { + return response()->json([ + 'success' => false, + 'user' => __('Sorry Not Auth User!') + ], 403); + } + + } + + } + + public function update(Request $request){ + $user = User::find(auth()->user()->id); + if($user){ + $rules = [ + 'secret_key' => 'required|string', + 'name' => 'sometimes|string|max:255', + 'email' => 'sometimes|string|email|max:255|unique:users,email,'.$user->id, + 'phone' => 'sometimes|string|max:20|unique:users,phone,'.$user->id, + 'username' => 'sometimes|string|max:120|unique:users,username,'.$user->id, + 'roles' => 'sometimes|array', + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ]); + } + else { + if($request->has('name')){ + $user->name = $request->get('name'); + } + if($request->has('email')){ + $user->email = $request->get('email'); + } + if($request->has('phone')){ + $user->phone = $request->get('phone'); + } + if($request->has('username')){ + $user->username = $request->get('username'); + } + if($request->has('roles')){ + $user->roles()->sync($request->get('roles')); + } + + $user->save(); + + return response()->json([ + 'success' => true, + 'message' => __('Profile Has Been Update Success'), + 'data' => [ + 'user' => [ + "id" => $user->id, + "name" => $user->name, + "email" => $user->email, + "phone" => $user->phone, + "username" => $user->username, + "roles" => $user->load('roles') + ] + ] + ]); + } + } + else { + return response()->json([ + "success" => false, + "message" => __('Sorry You Are Not User') + ]); + } + + } + + public function password(Request $request){ + $user = User::find(auth()->user()->id); + if($user){ + $rules = [ + 'secret_key' => 'required|string', + 'password' => 'required|confirmed|string|min:8', + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ]); + } + else { + $user->password = bcrypt($request->get('password')); + $user->save(); + + return response()->json([ + "success" => true, + "message" => __('User Password Has Been Update Success') + ]); + + } + } + else { + return response()->json([ + "success" => false, + "message" => __('Sorry You Are Not User') + ]); + } + } + + public function verified(Request $request){ + $rules = [ + "email" => "required|email|string", + "code" => "required|digits:6|integer" + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ]); + } + else { + $user = User::where("email", $request->get('email'))->first(); + if($user){ + if (!empty($user->code) && $user->code === $request->get('code')) { + $user->email_verified_at = Carbon::now(); + $user->activated = true; + $user->code = null; + $user->save(); + Mail::to($user)->send(new EmailWelcome()); + + return response()->json([ + 'success' => true, + 'message' => __('your email has been activated, you can login') + ]); + } + else { + return response()->json([ + 'success' => false, + 'message' => __('sorry this code is not valid or expired') + ], 401); + } + } + else { + return response()->json([ + 'success' => false, + 'message' => __('no user exist with this email') + ], 401); + } + + + } + + + } + + public function forgot(Request $request) { + $rules = [ + 'email' => 'required|email', + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ]); + } + else { + $checkIfEx = User::where('email', $request->get('email'))->first(); + if($checkIfEx){ + + $checkIfEx->code = substr(number_format(time() * rand(),0,'',''),0,6); + $checkIfEx->save(); + + Mail::to($checkIfEx)->send(new EmailCode($checkIfEx->code)); + + return response()->json([ + 'success' => true, + 'message' => __('Reset password link sent on your email id.') + ]); + } + else { + return response()->json([ + 'success' => false, + 'message' => __('This Email Not Found In Database') + ], 400); + } + + } + } + + public function reset(Request $request) { + $rules = [ + 'email' => 'required|email', + 'code' => 'required|integer|digits:6', + 'password' => 'required|string|confirmed' + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ]); + } + else { + $isExUser = User::where('email', $request->get('email'))->first(); + if($isExUser){ + if($isExUser->code === $request->get('code')){ + $isExUser->password = Hash::make($request->get('password')); + $isExUser->save(); + + Mail::to($isExUser)->send(new EmailReset()); + + return response()->json([ + "success"=> true, + "message" => __("Password has been successfully changed") + ]); + } + else { + return response()->json([ + 'success' => false, + 'message' => __('sorry this code is not valid or expired') + ], 401); + } + } + else { + return response()->json([ + "success" => false, + "message" => __("User Not Found!") + ], 400); + } + + } + } +} diff --git a/app/Http/Controllers/API/PermissionsController.php b/app/Http/Controllers/API/PermissionsController.php new file mode 100644 index 0000000..d9310ca --- /dev/null +++ b/app/Http/Controllers/API/PermissionsController.php @@ -0,0 +1,166 @@ +json([ + 'success' => true, + 'message' => __('Permissions Load Success'), + 'data' => $permissions + ]); + } + else { + return response()->json([ + 'success' => false, + 'message' => __('UnAuth Action') + ], 403); + } + + } + + public function store(Request $request) + { + if(user_can('permissions.store')){ + $rules = [ + 'guard' => 'required|string', + 'group' => 'required|string', + 'key' => 'required|string|unique:permissions', + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ]); + } + else { + $permission = Permission::create($request->all()); + + return response()->json([ + 'success'=> true, + 'message' => __('Permission Added Success'), + 'data' => [ + 'permission' => $permission + ] + ]); + } + } + else { + return response()->json([ + 'success' => false, + 'message' => __('UnAuth Action') + ], 403); + } + + } + + public function show($permission) + { + if(user_can('permissions.show')){ + $permission = Permission::find($permission); + return response()->json([ + 'success' => true, + 'message' => __('Permission Loaded Success'), + 'data' => [ + 'permission' => $permission + ] + ]); + } + else { + return response()->json([ + 'success' => false, + 'message' => __('UnAuth Action') + ], 403); + } + + } + + public function update(Request $request, $permission) + { + if(user_can('permissions.update')){ + $permission = Permission::find($permission); + if($permission){ + $rules = [ + 'guard' => 'sometimes|string', + 'group' => 'sometimes|string', + 'key' => 'sometimes|string|unique:permissions,key,'.$permission->id, + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ], 401); + } + else { + $permission->update($request->all()); + + return response()->json([ + 'success'=> true, + 'message' => __('Permission Updated Success'), + 'data' => [ + 'permission' => $permission + ] + ]); + } + } + else { + return response()->json([ + 'success'=> false, + 'message' => __('Permission Not Found'), + ]); + } + } + else { + return response()->json([ + 'success' => false, + 'message' => __('UnAuth Action') + ], 403); + } + + } + + + public function destroy($permission) + { + if(user_can('permissions.delete')){ + $permission = Permission::find($permission); + if($permission){ + $permission->roles()->sync([]); + $permission->delete(); + + return response()->json([ + 'success'=> true, + 'message' => __('Permission Deleted Success'), + ]); + } + else { + return response()->json([ + 'success'=> false, + 'message' => __('Permission Not Found'), + ], 404); + } + } + else { + return response()->json([ + 'success' => false, + 'message' => __('UnAuth Action') + ], 403); + } + } +} diff --git a/app/Http/Controllers/API/RoleController.php b/app/Http/Controllers/API/RoleController.php new file mode 100644 index 0000000..53870f5 --- /dev/null +++ b/app/Http/Controllers/API/RoleController.php @@ -0,0 +1,183 @@ +load('permissions'); + } + + return response()->json([ + 'success' => true, + 'message' => __('Roles Load Success'), + 'data' => $role + ]); + } + else { + return response()->json([ + 'success' => false, + 'message' => __('UnAuth Action') + ], 403); + } + + } + + public function store(Request $request) + { + if(user_can('roles.create')){ + $rules = [ + 'guard' => 'required|string', + 'name' => 'required|string', + 'key' => 'required|string|unique:roles', + 'permissions' => 'required|array', + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ]); + } + else { + $role = Role::create($request->all()); + $role->permissions()->attach($request->get('permissions')); + $role->load('permissions'); + return response()->json([ + 'success'=> true, + 'message' => __('Role Added Success'), + 'data' => [ + 'role' => $role + ] + ]); + } + } + else { + return response()->json([ + 'success' => false, + 'message' => __('UnAuth Action') + ], 403); + } + + } + + public function show($role) + { + if(user_can('roles.show')){ + $role = Role::find($role); + if($role){ + $role->load('permissions'); + return response()->json([ + 'success' => true, + 'message' => __('Role Loaded Success'), + 'data' => [ + 'role' => $role + ] + ]); + } + else { + return response()->json([ + 'success'=> false, + 'message' => __('Role Not Found'), + ], 404); + } + } + else { + return response()->json([ + 'success' => false, + 'message' => __('UnAuth Action') + ], 403); + } + } + + public function update(Request $request, $role) + { + if(user_can('roles.update')){ + $role = Role::find($role); + if($role){ + $rules = [ + 'guard' => 'sometimes|string', + 'name' => 'sometimes|string', + 'key' => 'sometimes|string|unique:permissions,key,'.$role->id, + 'permissions' => 'sometimes|array', + ]; + + $validator = Validator::make($request->all(), $rules); + if ($validator->fails()) { + return response()->json([ + "success" => false, + "message" => $validator->messages() + ], 401); + } + else { + $role->update($request->all()); + if($request->has('permissions')){ + $role->permissions()->sync($request->get('permissions')); + } + $role->load('permissions'); + + return response()->json([ + 'success'=> true, + 'message' => __('Role Updated Success'), + 'data' => [ + 'role' => $role + ] + ]); + } + } + else { + return response()->json([ + 'success'=> false, + 'message' => __('Role Not Found'), + ], 404); + } + } + else { + return response()->json([ + 'success' => false, + 'message' => __('UnAuth Action') + ], 403); + } + + } + + public function destroy($role) + { + if(user_can('roles.delete')){ + $role = Role::find($role); + if($role){ + $role->permissions()->sync([]); + $role->delete(); + + return response()->json([ + 'success'=> true, + 'message' => __('Role Deleted Success'), + ]); + } + else { + return response()->json([ + 'success'=> false, + 'message' => __('Role Not Found'), + ], 404); + } + } + else { + return response()->json([ + 'success' => false, + 'message' => __('UnAuth Action') + ], 403); + } + } +} diff --git a/app/Http/Middleware/SecretMiddleware.php b/app/Http/Middleware/SecretMiddleware.php new file mode 100644 index 0000000..de8325d --- /dev/null +++ b/app/Http/Middleware/SecretMiddleware.php @@ -0,0 +1,31 @@ +user() && auth()->user()->secret_key == $request->secret_key){ + return $next($request); + } + else { + return response()->json([ + 'success' => false, + 'message' => __('Bad Secret Key'), + ]); + } + + } +} diff --git a/app/Mail/EmailCode.php b/app/Mail/EmailCode.php new file mode 100644 index 0000000..3675b42 --- /dev/null +++ b/app/Mail/EmailCode.php @@ -0,0 +1,33 @@ +code = $code; + } + + /** + * Build the message. + * + * @return $this + */ + public function build() + { + return $this + ->from('info@3x1.io') + ->view('emails.code'); + } +} diff --git a/app/Mail/EmailReset.php b/app/Mail/EmailReset.php new file mode 100644 index 0000000..9181cf6 --- /dev/null +++ b/app/Mail/EmailReset.php @@ -0,0 +1,33 @@ +view('emails.reset'); + } +} diff --git a/app/Mail/EmailWelcome.php b/app/Mail/EmailWelcome.php new file mode 100644 index 0000000..76094df --- /dev/null +++ b/app/Mail/EmailWelcome.php @@ -0,0 +1,33 @@ +view('emails.welcome'); + } +} diff --git a/app/helpers.php b/app/helpers.php index 8626051..b85993a 100644 --- a/app/helpers.php +++ b/app/helpers.php @@ -2,6 +2,8 @@ //Setting Helpers use App\Models\Block; +use MessageBird\Client; +use MessageBird\Objects\Message; if(!function_exists('setting')){ function setting($key){ @@ -170,6 +172,54 @@ function get_permissions($key, $label, $selected=[]){ ])->render(); } } +if(!function_exists('user_can')){ + function user_can($permission){ + if(auth()->user()){ + $roles = auth()->user()->roles; + if($roles->count()){ + foreach ($roles as $item){ + $getRole = \App\Models\Role::find($item->id); + if($getRole){ + $permissions = $getRole->permissions; + foreach ($permissions as $perm){ + if($perm->key === $permission){ + return true; + } + } + } + else { + return false; + } + + } + + return false; + } + else { + return false; + } + + } + else { + return false; + } + + } +} + +if(!function_exists('send_sms')){ + function send_sms($api, $from, $to, $message){ + $MessageBird = new Client($api); + $sms = new Message(); + $sms->originator = $from; + $sms->recipients = array($to); + $sms->body = $message; + $sms->type = 'sms'; + + $MessageBird->messages->create($sms); + } +} + //HTML if(!function_exists('input')){ diff --git a/resources/views/emails/code.blade.php b/resources/views/emails/code.blade.php new file mode 100644 index 0000000..2e80e03 --- /dev/null +++ b/resources/views/emails/code.blade.php @@ -0,0 +1,3 @@ +
+

{{$code}}

+
diff --git a/resources/views/emails/reset.blade.php b/resources/views/emails/reset.blade.php new file mode 100644 index 0000000..3409af2 --- /dev/null +++ b/resources/views/emails/reset.blade.php @@ -0,0 +1,3 @@ +
+

Your Password Has Been Reset Success

+
diff --git a/resources/views/emails/welcome.blade.php b/resources/views/emails/welcome.blade.php new file mode 100644 index 0000000..e1e4f11 --- /dev/null +++ b/resources/views/emails/welcome.blade.php @@ -0,0 +1,3 @@ +
+

Welcome To Our App

+
diff --git a/routes/api.php b/routes/api.php index bcb8b18..ff26787 100644 --- a/routes/api.php +++ b/routes/api.php @@ -14,6 +14,43 @@ | */ -Route::middleware('auth:api')->get('/user', function (Request $request) { - return $request->user(); +Route::get('/', function () { + return response()->json([ + "success" => true, + "message" => __('Welcome to 3x1 APIs Framework V1.00'), + "version" => "1.00", + "author" => "3x1.io", + "by" => "Fady Mondy", + "email" => "info@3x1.io" + ]); +}); + +Route::post('/login', 'AuthController@login')->name('login'); +Route::post('/register', 'AuthController@register'); +Route::post('/forgot', 'AuthController@forgot'); +Route::post('/reset', 'AuthController@reset')->name('password.reset'); +Route::post('/resend', 'AuthController@resend')->name('verification.resend'); +Route::post('/email/verify', 'AuthController@verified')->name('verification.verify'); + +//User +Route::middleware(['auth:sanctum', 'secret'])->group(function (){ + Route::prefix('user')->name('user')->group(function (){ + Route::get('/','AuthController@user')->name('show'); + Route::post('/','AuthController@update')->name('update'); + Route::post('/password','AuthController@password')->name('password'); + }); + Route::prefix('permissions')->name('permissions')->group(function (){ + Route::get('/','PermissionsController@index')->name('index'); + Route::post('/','PermissionsController@store')->name('store'); + Route::get('/{permission}/show','PermissionsController@show')->name('show'); + Route::put('/{permission}','PermissionsController@update')->name('update'); + Route::delete('/{permission}','PermissionsController@destroy')->name('destroy'); + }); + Route::prefix('roles')->name('roles')->group(function (){ + Route::get('/','RoleController@index')->name('index'); + Route::post('/','RoleController@store')->name('store'); + Route::get('/{role}/show','RoleController@show')->name('show'); + Route::put('/{role}','RoleController@update')->name('update'); + Route::delete('/{role}','RoleController@destroy')->name('destroy'); + }); });