diff --git a/app/Http/Controllers/APIS/AdminApi/UsersController.php b/app/Http/Controllers/APIS/AdminApi/UsersController.php index 307e718..9f60396 100644 --- a/app/Http/Controllers/APIS/AdminApi/UsersController.php +++ b/app/Http/Controllers/APIS/AdminApi/UsersController.php @@ -5,12 +5,19 @@ namespace App\Http\Controllers\APIS\AdminApi; use App\Http\Controllers\Controller; use Illuminate\Http\Request; use App\Http\Requests\CreateUserRequest; +use App\Mail\Admin\UserCreatedMail; use App\Models\User; use App\Services\AdminService; use Exception; use Illuminate\Database\QueryException; +use Illuminate\Support\Facades\Hash; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Mail; +use Illuminate\Support\Facades\URL; use Illuminate\Support\Str; +use Illuminate\Validation\ValidationException; +use Illuminate\Support\Facades\Auth; + class UsersController extends Controller { @@ -70,13 +77,32 @@ class UsersController extends Controller $user->last_login_ts = $request->last_login_ts; $user->save(); - return jsonResponseWithSuccessMessage(__('auth.data_fetched_successfully'), $response, 200); - } catch (QueryException $e) { + $randomToken = Str::random(64); + + $activationLink = url("/apia/activate/{$user->id}?token={$randomToken}"); + + $mail = Mail::to($user->email)->send(new UserCreatedMail($user, $activationLink)); + + + return response()->json([ + 'message' => __('auth.data_fetched_successfully'), + 'user_id' => $user->id, + 'activation_link' => $activationLink, + 'token' => $randomToken, + 'data' => $response + ], 200); + } catch (QueryException $e) { Log::error('Error in creating User ' . $e->getMessage()); return jsonResponseWithErrorMessageApi(__('auth.something went wrong'), 401); } } + + + + + + public function list() { try { @@ -131,5 +157,267 @@ class UsersController extends Controller } } + // public function activate(Request $request, $id) + // { + // Log::info('Full Request URL: ' . $request->fullUrl()); + + // try { + // $user = User::find($id); + + // if (!$user) { + // Log::error("User not found for ID: {$id}"); + // return response()->json([ + // 'status' => false, + // 'message' => 'User not found.' + // ], 404); + // } + + // $token = $request->query('token'); + // if (!$token) { + // Log::error("Token missing for User ID: {$id}"); + // return response()->json([ + // 'status' => false, + // 'message' => 'Invalid activation link.' + // ], 401); + // } + + // // Validate password input + // $validated = $request->validate([ + // 'password' => 'required|min:6|confirmed' + // ]); + + // // Update the user's password locally + // $user->password = Hash::make($validated['password']); + // $user->save(); + + // // Use the activateUser function to activate in ThingsBoard + // $this->adminService->activateUser($user, $validated['password'], $token); + + // Log::info("User ID: {$id} activated successfully."); + + // return response()->json([ + // 'status' => true, + // 'message' => 'User activated and password set successfully in Laravel and ThingsBoard!', + // 'user_id' => $user->id + // ], 200); + + // } catch (ValidationException $e) { + // Log::error("Validation error for User ID: {$id}. Exception: " . $e->getMessage()); + // return response()->json([ + // 'status' => false, + // 'message' => 'Validation error.', + // 'errors' => $e->errors() + // ], 422); + + // } catch (\Exception $e) { + // Log::error("Error activating user ID: {$id}. Exception: " . $e->getMessage()); + // return response()->json([ + // 'status' => false, + // 'message' => 'An error occurred. Please try again later.', + // 'error' => $e->getMessage() + // ], 500); + // } + // } + + public function activate(Request $request, $id) + { + Log::info('Full Request URL: ' . $request->fullUrl()); + + try { + $user = User::find($id); + + if (!$user) { + Log::error("User not found for ID: {$id}"); + return response()->json([ + 'status' => false, + 'message' => 'User not found.' + ], 404); + } + + $token = $request->query('token'); + if (!$token) { + Log::error("Token missing for User ID: {$id}"); + return response()->json([ + 'status' => false, + 'message' => 'Invalid activation link.' + ], 401); + } + + // ✅ Validate password input + $validated = $request->validate([ + 'password' => 'required|min:6|confirmed' + ]); + + // ✅ Update the user's password locally + $user->password = Hash::make($validated['password']); + $user->save(); + + Log::info("User ID: {$id} activated successfully in Laravel."); + + return response()->json([ + 'status' => true, + 'message' => 'User activated and password set successfully in Laravel!', + 'user_id' => $user->id + ], 200); + + } catch (ValidationException $e) { + Log::error("Validation error for User ID: {$id}. Exception: " . $e->getMessage()); + return response()->json([ + 'status' => false, + 'message' => 'Validation error.', + 'errors' => $e->errors() + ], 422); + + } catch (\Exception $e) { + Log::error("Error activating user ID: {$id}. Exception: " . $e->getMessage()); + return response()->json([ + 'status' => false, + 'message' => 'An error occurred. Please try again later.', + 'error' => $e->getMessage() + ], 500); + } + } + + + // public function autoLogin(Request $request) + // { + // $request->validate([ + // 'email' => 'required|email' + // ]); + + // $email = $request->email; + + // $user = User::where('email', $email)->first(); + + // if (!$user) { + // return response()->json([ + // 'status' => false, + // 'message' => 'User not found in Laravel. Please register or verify your email.' + // ], 404); + // } + + // Auth::login($user); + + // $thingsboardUser = $this->adminService->getUserByEmail($email); + + // if ($thingsboardUser) { + // $tbUserId = $thingsboardUser['id']['id']; + // $thingsboardDashboardUrl = "http://your-thingsboard-domain.com/dashboard/{$tbUserId}"; + // } else { + // $thingsboardDashboardUrl = null; + // } + + // return response()->json([ + // 'status' => true, + // 'message' => 'User found, redirecting to dashboards...', + // 'laravel_dashboard_url' => url("/dashboard/{$user->id}"), + // 'thingsboard_dashboard_url' => $thingsboardDashboardUrl + // ], 200); + // } + + + // public function loginUser(Request $request) + // { + // $email = $request->input('email'); + + // if (!$email) { + // return response()->json([ + // 'status' => false, + // 'message' => 'Email is required.' + // ], 400); + // } + + // $localResponse = null; + // $thingsboardResponse = null; + + // // ✅ Check in local database + // $user = User::where('email', $email)->first(); + + // if ($user) { + // $localResponse = [ + // 'status' => true, + // 'message' => 'Login successful (Local). Redirecting to Local dashboard...', + // 'user_id' => $user->id, + // 'email' => $email, + // 'dashboard_url' => url('/dashboard') // Local dashboard URL + // ]; + // } else { + // $localResponse = [ + // 'status' => false, + // 'message' => 'User not found in Local database.' + // ]; + // } + + // // ✅ Check in ThingsBoard + // $thingsboardResponse = $this->adminService->getUserByIdThingsBoard($email); + + // if ($thingsboardResponse['status']) { + // $thingsboardUser = $thingsboardResponse['user']; + // $thingsboardResponse = [ + // 'status' => true, + // 'message' => 'Login successful (ThingsBoard). Redirecting to ThingsBoard dashboard...', + // 'user_id' => $thingsboardUser['id']['id'], + // 'email' => $email, + // 'dashboard_url' => $thingsboardResponse['dashboard_url'] + // ]; + // } else { + // $thingsboardResponse = [ + // 'status' => false, + // 'message' => 'User not found in ThingsBoard.' + // ]; + // } + + // // ✅ Return both responses + // return response()->json([ + // 'local' => $localResponse, + // 'thingsboard' => $thingsboardResponse + // ], 200); + // } + + public function loginUser(Request $request) + { + $email = $request->input('email'); + + if (!$email) { + return response()->json([ + 'status' => false, + 'message' => 'Email is required.' + ], 400); + } + + $localResponse = null; + $thingsboardResponse = null; + + // ✅ Check in Local database + $user = User::where('email', $email)->first(); + + if ($user) { + $localResponse = [ + 'status' => true, + 'message' => 'Login successful (Local). Redirecting to Local dashboard...', + 'user_id' => $user->id, + 'email' => $email, + 'dashboard_url' => url('/dashboard') + ]; + } else { + $localResponse = [ + 'status' => false, + 'message' => 'User not found in Local database.' + ]; + } + + // ✅ Fetch ThingsBoard user by email, then by ID + $thingsboardResponse = $this->adminService->getUserByEmailThingsBoard($email); + + // ✅ Return both responses + return response()->json([ + 'local' => $localResponse, + 'thingsboard' => $thingsboardResponse + ], 200); + } + + + + } diff --git a/app/Mail/Admin/UserCreatedMail.php b/app/Mail/Admin/UserCreatedMail.php new file mode 100644 index 0000000..ae1fef8 --- /dev/null +++ b/app/Mail/Admin/UserCreatedMail.php @@ -0,0 +1,34 @@ +user = $user; + $this->activationLink = $activationLink; + } + + public function build() + { + return $this->subject('Activate Your Account') + ->view('Mails.user_created') + ->with([ + 'user' => $this->user, + 'activationLink' => $this->activationLink + ]); + } +} \ No newline at end of file diff --git a/app/Services/AdminService.php b/app/Services/AdminService.php index d165ad6..cbef161 100644 --- a/app/Services/AdminService.php +++ b/app/Services/AdminService.php @@ -2,10 +2,12 @@ namespace App\Services; +use App\Models\User; use Illuminate\Support\Facades\Http; use Illuminate\Support\Facades\Cache; use Exception; use Illuminate\Support\Facades\Log; +use Illuminate\Support\Str; class AdminService @@ -173,6 +175,78 @@ class AdminService throw new Exception('Failed to create user: ' . $response->body()); } + // public function createOrUpdateUser(array $data) + // { + // $token = $this->getToken(); + + // // First, check if the user exists in ThingsBoard by email + // $email = $data['email']; + + // // ✅ Fetch ThingsBoard ID by email + // $response = Http::withHeaders([ + // 'Authorization' => "Bearer $token", + // 'accept' => 'application/json' + // ])->get("{$this->baseUrl}/api/users?pageSize=1&page=0&textSearch=$email"); + + // $userExists = false; + // $thingsboardUserId = null; + + // if ($response->successful()) { + // $users = $response->json()['data'] ?? []; + + // if (!empty($users)) { + // $userExists = true; + // $thingsboardUserId = $users[0]['id']['id']; + // } + // } + + // // ✅ Prepare payload + // $payload = [ + // 'email' => $data['email'] ?? 'default@example.com', + // 'tenantId' => [ + // 'id' => $data['tenantId'] ?? '6e9b7fde-0ca0-4d19-9d2a-fba98e3e12a0', + // 'entityType' => 'TENANT' + // ], + // 'customerId' => [ + // 'id' => $data['customerId'], + // 'entityType' => 'CUSTOMER' + // ], + // 'authority' => $data['authority'] ?? 'TENANT_ADMIN', + // 'name' => $data['name'] ?? 'John Doe', + // 'phone' => $data['phone'] ?? '1234567890', + // 'additionalInfo' => [ + // 'description' => $data['description'] ?? 'User description' + // ] + // ]; + + // if ($userExists && $thingsboardUserId) { + // // ✅ Update existing user in ThingsBoard + // $response = Http::withHeaders([ + // 'Authorization' => "Bearer $token", + // 'accept' => 'application/json', + // 'Content-Type' => 'application/json', + // ])->withBody(json_encode($payload), 'application/json') + // ->post("{$this->baseUrl}/api/user/{$thingsboardUserId}"); + // } else { + // // ✅ Create new user in ThingsBoard + // $response = Http::withHeaders([ + // 'Authorization' => "Bearer $token", + // 'accept' => 'application/json', + // 'Content-Type' => 'application/json', + // ])->withBody(json_encode($payload), 'application/json') + // ->post("{$this->baseUrl}/api/user"); + // } + + // if ($response->successful()) { + // return $response->json(); + // } else { + // throw new Exception('Failed to create or update user: ' . $response->body()); + // } + // } + + + + public function listUsers() @@ -192,24 +266,133 @@ class AdminService } - public function deleteUser($userId) - { +public function deleteUser($userId) +{ + try { $token = $this->getToken(); + // ✅ Make the DELETE request to ThingsBoard $response = Http::withHeaders([ 'Authorization' => "Bearer $token", 'accept' => 'application/json', 'Content-Type' => 'application/json', ])->delete("{$this->baseUrl}/api/user/{$userId}"); - // Handle ThingsBoard API errors + // ✅ Handle API response if ($response->failed()) { Log::error('Failed to delete user: ' . $response->body()); - // Return the ThingsBoard error message - return $response->json(); + return response()->json([ + 'error' => true, + 'message' => 'Failed to delete user from ThingsBoard', + 'details' => $response->json() + ], $response->status()); } - return $response->json(); + // ✅ Return successful response + return response()->json([ + 'success' => true, + 'message' => 'User deleted successfully', + 'data' => $response->json() + ], 200); + + } catch (Exception $e) { + Log::error('Exception while deleting user: ' . $e->getMessage()); + + return response()->json([ + 'error' => true, + 'message' => 'An error occurred while deleting the user', + ], 500); } +} + + + +public function activateUser(User $user, string $password, string $activateToken) +{ + try { + // Prepare the payload with the token and password + $payload = [ + 'activateToken' => $activateToken, + 'password' => $password + ]; + + $activationUrl = "{$this->baseUrl}/api/noauth/activate"; + + // Send the activation request + $response = Http::withHeaders([ + 'Content-Type' => 'application/json', + ])->post($activationUrl, $payload); + + if (!$response->successful()) { + Log::error("Failed to activate user in ThingsBoard. Error: " . $response->body()); + throw new Exception('Failed to activate user: ' . $response->body()); + } + + Log::info("User activated successfully in ThingsBoard for User ID: {$user->id}"); + + } catch (\Exception $e) { + Log::error("Error activating user in ThingsBoard for User ID: {$user->id}. Exception: " . $e->getMessage()); + throw $e; + } +} + + +public function getUserByEmailThingsBoard(string $email) +{ + Log::info("Fetching ThingsBoard ID by email: $email"); + + $token = $this->getToken(); + + // First, fetch the ThingsBoard ID by email + $response = Http::withHeaders([ + 'Authorization' => "Bearer $token", + 'accept' => 'application/json' + ])->get("http://65.0.131.117:8080/api/users?pageSize=1&page=0&textSearch=$email"); + + if ($response->successful()) { + $data = $response->json()['data'] ?? []; + + if (!empty($data)) { + $thingsboardUserId = $data[0]['id']['id']; + Log::info("Found ThingsBoard ID: $thingsboardUserId"); + + // Now fetch user by ID + $userResponse = Http::withHeaders([ + 'Authorization' => "Bearer $token", + 'accept' => 'application/json' + ])->get("http://65.0.131.117:8080/api/user/$thingsboardUserId"); + + if ($userResponse->successful()) { + return [ + 'status' => true, + 'user' => $userResponse->json(), + 'dashboard_url' => 'http://65.0.131.117:8080/dashboard' + ]; + } else { + Log::error("Failed to fetch user by ID. Status: " . $userResponse->status()); + return [ + 'status' => false, + 'message' => 'User not found in ThingsBoard by ID.' + ]; + } + } + } + + Log::error("Failed to fetch ThingsBoard ID. Status: " . $response->status()); + return [ + 'status' => false, + 'message' => 'User not found in ThingsBoard by email.' + ]; +} + + + + + + + + + + } diff --git a/database/migrations/2025_03_19_134832_create_device_profile_master_table.php b/database/migrations/2025_03_19_134832_create_device_profile_master_table.php new file mode 100644 index 0000000..adc3dad --- /dev/null +++ b/database/migrations/2025_03_19_134832_create_device_profile_master_table.php @@ -0,0 +1,29 @@ +uuid('id')->primary(); + $table->string('name'); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('device_profile_master'); + } +}; \ No newline at end of file diff --git a/database/migrations/2025_03_19_135406_create_timeseries_key_master_table.php b/database/migrations/2025_03_19_135406_create_timeseries_key_master_table.php new file mode 100644 index 0000000..5348c57 --- /dev/null +++ b/database/migrations/2025_03_19_135406_create_timeseries_key_master_table.php @@ -0,0 +1,33 @@ +id(); + $table->uuid('device_profile_xid'); + $table->string('key_name'); + $table->string('display_name'); + $table->tinyInteger('display_on_dashboard')->default(0); + $table->tinyInteger('display_on_popup')->default(0); + $table->timestamps(); + $table->softDeletes(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('timeseries_key_master'); + } +}; diff --git a/resources/views/Mails/user_created.blade.php b/resources/views/Mails/user_created.blade.php new file mode 100644 index 0000000..db66ef6 --- /dev/null +++ b/resources/views/Mails/user_created.blade.php @@ -0,0 +1,27 @@ + + + + + Welcome Email + + +

Welcome, {{ $user['first_name'] }}!

+

You have successfully registered with the following details:

+ +

+ + Activate Account + +

+ +

This link will expire in 24 hours.

+ +

If you did not create this account, please ignore this email.

+

Thank you for joining us!

+ + diff --git a/routes/admin_api.php b/routes/admin_api.php index 034e0a4..86d3019 100644 --- a/routes/admin_api.php +++ b/routes/admin_api.php @@ -31,3 +31,5 @@ Route::delete('/users-delete/{userId}', [UsersController::class, 'delete']); //******************************************************* User API******************************************************** Route::post('/device/create-or-update', [DeviceController::class, 'createOrUpdateDevice'])->name('customer.create-or-update'); +Route::post('/activate/{id}', [UsersController::class, 'activate'])->name('activate.user'); +Route::post('/users-login', [UsersController::class, 'loginUser']);