User.php 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
  1. <?php
  2. namespace App\Http\Livewire;
  3. use Illuminate\Support\Facades\Log;
  4. use Illuminate\Support\Facades\DB;
  5. use Illuminate\Support\Facades\Mail;
  6. use Livewire\Component;
  7. use App\Http\Middleware\TenantMiddleware;
  8. use Illuminate\Support\Facades\Auth;
  9. class User extends Component
  10. {
  11. public function boot()
  12. {
  13. app(TenantMiddleware::class)->setupTenantConnection();
  14. $this->logCurrentDatabase('After tenant connection setup in boot()');
  15. }
  16. public $records, $name, $cognome, $email, $password, $oldPassword, $level, $enabled, $dataId, $update = false, $add = false, $oldEmail = null;
  17. public $userExists = false;
  18. protected $rules = [
  19. 'name' => 'required',
  20. 'cognome' => 'required',
  21. 'email' => 'required',
  22. 'password' => 'required'
  23. ];
  24. protected $messages = [
  25. 'name.required' => 'Il nome è obbligatorio',
  26. 'cognome.required' => 'Il cognome è obbligatorio',
  27. 'email.required' => 'La mail è obbligatoria',
  28. 'password.required' => 'La password è obbligatoria',
  29. ];
  30. /**
  31. * Helper method to log current database information
  32. */
  33. private function logCurrentDatabase($context = '')
  34. {
  35. try {
  36. $currentConnection = DB::getDefaultConnection();
  37. $currentDatabase = DB::connection()->getDatabaseName();
  38. $user = Auth::user();
  39. Log::info('Database Connection Info', [
  40. 'context' => $context,
  41. 'current_connection' => $currentConnection,
  42. 'current_database' => $currentDatabase,
  43. 'user_id' => $user ? $user->id : null,
  44. 'user_tenant_database' => $user ? $user->tenant_database : null,
  45. 'user_tenant_username' => $user ? $user->tenant_username : null,
  46. ]);
  47. } catch (\Exception $e) {
  48. Log::error('Failed to get database info', [
  49. 'context' => $context,
  50. 'error' => $e->getMessage()
  51. ]);
  52. }
  53. }
  54. /**
  55. * Create or update user in master database
  56. */
  57. private function syncUserToMasterDatabase($userData, $action = 'create', $oldEmail = null)
  58. {
  59. try {
  60. Log::info('Syncing user to master database', [
  61. 'action' => $action,
  62. 'email' => $userData['email'],
  63. 'old_email' => $oldEmail
  64. ]);
  65. $masterConfig = [
  66. 'driver' => 'mysql',
  67. 'host' => env('DB_HOST', '127.0.0.1'),
  68. 'port' => env('DB_PORT', '3306'),
  69. 'database' => env('DB_DATABASE'),
  70. 'username' => env('DB_USERNAME'),
  71. 'password' => env('DB_PASSWORD'),
  72. 'charset' => 'utf8mb4',
  73. 'collation' => 'utf8mb4_unicode_ci',
  74. 'prefix' => '',
  75. 'strict' => true,
  76. 'engine' => null,
  77. ];
  78. config(['database.connections.master_sync' => $masterConfig]);
  79. $currentUser = Auth::user();
  80. $masterData = [
  81. 'name' => $userData['name'],
  82. 'email' => $userData['email'],
  83. 'password' => $userData['password'],
  84. 'tenant_database' => $currentUser->tenant_database,
  85. 'tenant_username' => $currentUser->tenant_username,
  86. 'tenant_password' => $currentUser->tenant_password,
  87. 'tenant_host' => '127.0.0.1',
  88. 'created_at' => now(),
  89. 'updated_at' => now()
  90. ];
  91. if ($action === 'create') {
  92. $inserted = DB::connection('master_sync')
  93. ->table('users')
  94. ->insert($masterData);
  95. if ($inserted) {
  96. Log::info('Successfully created user in master database', [
  97. 'email' => $userData['email'],
  98. 'tenant_database' => $currentUser->tenant_database
  99. ]);
  100. return true;
  101. } else {
  102. Log::warning('Failed to create user in master database', [
  103. 'email' => $userData['email']
  104. ]);
  105. return false;
  106. }
  107. } elseif ($action === 'update') {
  108. $searchEmail = $oldEmail ?: $userData['email'];
  109. unset($masterData['created_at']);
  110. $updated = DB::connection('master_sync')
  111. ->table('users')
  112. ->where('email', $searchEmail)
  113. ->update($masterData);
  114. if ($updated) {
  115. Log::info('Successfully updated user in master database', [
  116. 'old_email' => $searchEmail,
  117. 'new_email' => $userData['email']
  118. ]);
  119. return true;
  120. } else {
  121. Log::warning('No user found in master database to update', [
  122. 'search_email' => $searchEmail
  123. ]);
  124. return false;
  125. }
  126. }
  127. } catch (\Exception $e) {
  128. Log::error('Failed to sync user to master database', [
  129. 'action' => $action,
  130. 'email' => $userData['email'],
  131. 'error' => $e->getMessage(),
  132. 'trace' => $e->getTraceAsString()
  133. ]);
  134. return false;
  135. } finally {
  136. // Clean up the temporary connection
  137. try {
  138. DB::purge('master_sync');
  139. } catch (\Exception $e) {
  140. // Ignore cleanup errors
  141. }
  142. }
  143. }
  144. /**
  145. * Delete user from master database
  146. */
  147. private function deleteUserFromMasterDatabase($email)
  148. {
  149. try {
  150. Log::info('Deleting user from master database', [
  151. 'email' => $email
  152. ]);
  153. $masterConfig = [
  154. 'driver' => 'mysql',
  155. 'host' => env('DB_HOST', '127.0.0.1'),
  156. 'port' => env('DB_PORT', '3306'),
  157. 'database' => env('DB_DATABASE'),
  158. 'username' => env('DB_USERNAME'),
  159. 'password' => env('DB_PASSWORD'),
  160. 'charset' => 'utf8mb4',
  161. 'collation' => 'utf8mb4_unicode_ci',
  162. 'prefix' => '',
  163. 'strict' => true,
  164. 'engine' => null,
  165. ];
  166. config(['database.connections.master_delete' => $masterConfig]);
  167. $deleted = DB::connection('master_delete')
  168. ->table('users')
  169. ->where('email', $email)
  170. ->delete();
  171. if ($deleted) {
  172. Log::info('Successfully deleted user from master database', [
  173. 'email' => $email,
  174. 'rows_affected' => $deleted
  175. ]);
  176. return true;
  177. } else {
  178. Log::warning('No user found in master database to delete', [
  179. 'email' => $email
  180. ]);
  181. return false;
  182. }
  183. } catch (\Exception $e) {
  184. Log::error('Failed to delete user from master database', [
  185. 'email' => $email,
  186. 'error' => $e->getMessage(),
  187. 'trace' => $e->getTraceAsString()
  188. ]);
  189. return false;
  190. } finally {
  191. try {
  192. DB::purge('master_delete');
  193. } catch (\Exception $e) {
  194. }
  195. }
  196. }
  197. /**
  198. * Send welcome email to new user
  199. */
  200. private function sendWelcomeEmail($userData, $plainPassword)
  201. {
  202. try {
  203. $currentUser = Auth::user();
  204. $companyName = 'Leezard';
  205. Log::info('Preparing to send welcome email', [
  206. 'recipient' => $userData['email'],
  207. 'company' => $companyName,
  208. 'mail_from' => config('mail.from.address'),
  209. 'mail_host' => config('mail.mailers.smtp.host'),
  210. 'mail_port' => config('mail.mailers.smtp.port')
  211. ]);
  212. $emailData = [
  213. 'name' => $userData['name'],
  214. 'cognome' => $userData['cognome'],
  215. 'email' => $userData['email'],
  216. 'password' => $plainPassword,
  217. 'level' => $userData['level'],
  218. 'company' => $companyName,
  219. 'login_url' => url('/'),
  220. 'created_by' => $currentUser->name
  221. ];
  222. try {
  223. $viewContent = view('emails.welcome-user', $emailData)->render();
  224. Log::info('Email template rendered successfully', ['template_length' => strlen($viewContent)]);
  225. } catch (\Exception $viewException) {
  226. Log::error('Email template rendering failed', ['error' => $viewException->getMessage()]);
  227. throw new \Exception('Email template error: ' . $viewException->getMessage());
  228. }
  229. Mail::send('emails.welcome-user', $emailData, function ($message) use ($userData, $companyName) {
  230. $message->to($userData['email'], $userData['name'] . ' ' . $userData['cognome'])
  231. ->subject('Benvenuto su Leezard - Account Creato')
  232. ->from(config('mail.from.address'), config('mail.from.name'));
  233. if (env('MAIL_CCN')) {
  234. $message->bcc(env('MAIL_CCN'));
  235. }
  236. });
  237. Log::info('Welcome email sent successfully', [
  238. 'recipient' => $userData['email'],
  239. 'company' => $companyName,
  240. 'subject' => 'Benvenuto in ' . $companyName . ' - Account Creato'
  241. ]);
  242. return true;
  243. } catch (\Exception $e) {
  244. Log::error('SMTP Transport error when sending welcome email', [
  245. 'recipient' => $userData['email'],
  246. 'error' => $e->getMessage(),
  247. 'mail_config' => [
  248. 'host' => config('mail.mailers.smtp.host'),
  249. 'port' => config('mail.mailers.smtp.port'),
  250. 'encryption' => config('mail.mailers.smtp.encryption'),
  251. 'username' => config('mail.mailers.smtp.username')
  252. ]
  253. ]);
  254. return false;
  255. } catch (\Exception $e) {
  256. Log::error('General error when sending welcome email', [
  257. 'recipient' => $userData['email'],
  258. 'error' => $e->getMessage(),
  259. 'trace' => $e->getTraceAsString()
  260. ]);
  261. return false;
  262. }
  263. }
  264. public function resetFields()
  265. {
  266. $this->name = '';
  267. $this->cognome = '';
  268. $this->email = '';
  269. $this->password = '';
  270. $this->oldPassword = '';
  271. $this->level = 0;
  272. $this->enabled = true;
  273. $this->emit('load-data-table');
  274. }
  275. public function render()
  276. {
  277. $this->logCurrentDatabase('Before fetching users in render()');
  278. $this->records = \App\Models\User::select('id', 'name', 'cognome', 'email', 'password', 'level', 'enabled')->get();
  279. $this->logCurrentDatabase('After fetching users in render()');
  280. return view('livewire.user');
  281. }
  282. public function add()
  283. {
  284. $this->logCurrentDatabase('In add() method');
  285. $this->resetFields();
  286. $this->add = true;
  287. $this->update = false;
  288. $this->enabled = true;
  289. $this->userExists = false;
  290. }
  291. public function store()
  292. {
  293. $this->logCurrentDatabase('Start of store() method');
  294. Log::info('User store', [
  295. 'name' => $this->name,
  296. 'cognome' => $this->cognome,
  297. 'email' => $this->email,
  298. 'level' => $this->level,
  299. 'enabled' => $this->enabled
  300. ]);
  301. $rules = [
  302. 'name' => 'required',
  303. 'cognome' => 'required',
  304. 'email' => 'required|email|unique:users,email',
  305. 'password' => 'required|min:6'
  306. ];
  307. $messages = [
  308. 'name.required' => 'Il nome è obbligatorio',
  309. 'cognome.required' => 'Il cognome è obbligatorio',
  310. 'email.required' => 'La mail è obbligatoria',
  311. 'email.email' => 'La mail deve essere un indirizzo valido',
  312. 'email.unique' => 'Questa mail è già stata utilizzata',
  313. 'password.required' => 'La password è obbligatoria',
  314. 'password.min' => 'La password deve essere di almeno 6 caratteri'
  315. ];
  316. $this->validate($rules, $messages);
  317. $this->logCurrentDatabase('Before creating user in store()');
  318. try {
  319. $plainPassword = $this->password;
  320. $hashedPassword = bcrypt($this->password);
  321. $user = \App\Models\User::create([
  322. 'name' => $this->name,
  323. 'cognome' => $this->cognome,
  324. 'email' => $this->email,
  325. 'password' => $hashedPassword,
  326. 'level' => $this->level,
  327. 'enabled' => $this->enabled
  328. ]);
  329. $this->logCurrentDatabase('After creating user in tenant database');
  330. Log::info('User created successfully in tenant database', [
  331. 'user_id' => $user->id,
  332. 'name' => $this->name,
  333. 'cognome' => $this->cognome,
  334. 'email' => $this->email,
  335. 'level' => $this->level,
  336. 'enabled' => $this->enabled,
  337. 'database' => DB::connection()->getDatabaseName()
  338. ]);
  339. $masterSyncSuccess = $this->syncUserToMasterDatabase([
  340. 'name' => $this->name,
  341. 'cognome' => $this->cognome,
  342. 'email' => $this->email,
  343. 'password' => $hashedPassword,
  344. 'level' => $this->level,
  345. 'enabled' => $this->enabled
  346. ], 'create');
  347. if ($masterSyncSuccess) {
  348. $emailSent = $this->sendWelcomeEmail([
  349. 'name' => $this->name,
  350. 'cognome' => $this->cognome,
  351. 'email' => $this->email,
  352. 'level' => $this->level
  353. ], $plainPassword);
  354. if ($emailSent) {
  355. session()->flash('success', 'Utente creato e email di benvenuto inviata');
  356. } else {
  357. session()->flash('success', 'Utente creato ma errore nell\'invio email');
  358. }
  359. } else {
  360. session()->flash('success', 'Utente creato nel database tenant ma errore nella sincronizzazione master');
  361. }
  362. $this->resetFields();
  363. $this->add = false;
  364. } catch (\Exception $ex) {
  365. $this->logCurrentDatabase('Error in store() method');
  366. Log::error('User creation failed', [
  367. 'error' => $ex->getMessage(),
  368. 'database' => DB::connection()->getDatabaseName(),
  369. 'user_data' => [
  370. 'name' => $this->name,
  371. 'cognome' => $this->cognome,
  372. 'email' => $this->email,
  373. 'level' => $this->level,
  374. 'enabled' => $this->enabled
  375. ]
  376. ]);
  377. session()->flash('error', 'Errore (' . $ex->getMessage() . ')');
  378. }
  379. }
  380. public function edit($id)
  381. {
  382. $this->logCurrentDatabase('Start of edit() method');
  383. try {
  384. $user = \App\Models\User::findOrFail($id);
  385. $this->logCurrentDatabase('After finding user in edit()');
  386. if (!$user) {
  387. session()->flash('error', 'Dato non trovato');
  388. } else {
  389. $this->name = $user->name;
  390. $this->cognome = $user->cognome;
  391. $this->email = $user->email;
  392. $this->level = $user->level;
  393. $this->dataId = $user->id;
  394. $this->update = true;
  395. $this->add = false;
  396. $this->enabled = $user->enabled;
  397. $this->userExists = true;
  398. $this->oldEmail = $user->email;
  399. }
  400. Log::info('User edit loaded', [
  401. 'user_id' => $id,
  402. 'name' => $this->name,
  403. 'cognome' => $this->cognome,
  404. 'email' => $this->email,
  405. 'level' => $this->level,
  406. 'database' => DB::connection()->getDatabaseName()
  407. ]);
  408. } catch (\Exception $ex) {
  409. $this->logCurrentDatabase('Error in edit() method');
  410. Log::error('User edit failed', [
  411. 'user_id' => $id,
  412. 'error' => $ex->getMessage(),
  413. 'database' => DB::connection()->getDatabaseName()
  414. ]);
  415. session()->flash('error', 'Errore (' . $ex->getMessage() . ')');
  416. }
  417. }
  418. public function update()
  419. {
  420. $this->logCurrentDatabase('Start of update() method');
  421. $rules = [
  422. 'name' => 'required',
  423. 'cognome' => 'required',
  424. 'email' => 'required|email',
  425. 'password' => 'nullable|min:6'
  426. ];
  427. $this->validate($rules, $this->messages);
  428. try {
  429. $currentUser = \App\Models\User::findOrFail($this->dataId);
  430. $oldEmail = $currentUser->email;
  431. $oldName = $currentUser->name;
  432. $updateData = [
  433. 'name' => $this->name,
  434. 'cognome' => $this->cognome,
  435. 'email' => $this->email,
  436. 'level' => $this->level,
  437. 'enabled' => $this->enabled
  438. ];
  439. $passwordChanged = !empty($this->password);
  440. if ($passwordChanged) {
  441. $hashedPassword = bcrypt($this->password);
  442. $updateData['password'] = $hashedPassword;
  443. }
  444. \App\Models\User::whereId($this->dataId)->update($updateData);
  445. $this->logCurrentDatabase('After updating user');
  446. Log::info('User updated successfully in tenant database', [
  447. 'user_id' => $this->dataId,
  448. 'name' => $this->name,
  449. 'cognome' => $this->cognome,
  450. 'email' => $this->email,
  451. 'level' => $this->level,
  452. 'enabled' => $this->enabled,
  453. 'password_changed' => $passwordChanged,
  454. 'database' => DB::connection()->getDatabaseName()
  455. ]);
  456. $emailChanged = $oldEmail !== $this->email;
  457. $nameChanged = $oldName !== $this->name;
  458. if ($emailChanged || $nameChanged || $passwordChanged) {
  459. $masterData = [
  460. 'name' => $this->name,
  461. 'email' => $this->email
  462. ];
  463. if ($passwordChanged) {
  464. $masterData['password'] = $hashedPassword;
  465. }
  466. $this->syncUserToMasterDatabase($masterData, 'update', $oldEmail);
  467. }
  468. session()->flash('success', 'Dato aggiornato');
  469. $this->resetFields();
  470. $this->update = false;
  471. } catch (\Exception $ex) {
  472. $this->logCurrentDatabase('Error in update() method');
  473. Log::error('User update failed', [
  474. 'user_id' => $this->dataId,
  475. 'error' => $ex->getMessage(),
  476. 'database' => DB::connection()->getDatabaseName()
  477. ]);
  478. session()->flash('error', 'Errore (' . $ex->getMessage() . ')');
  479. }
  480. }
  481. public function cancel()
  482. {
  483. $this->logCurrentDatabase('In cancel() method');
  484. $this->resetFields();
  485. $this->add = false;
  486. $this->update = false;
  487. $this->userExists = false;
  488. $this->enabled = false;
  489. }
  490. public function delete($id)
  491. {
  492. $this->logCurrentDatabase('Start of delete() method');
  493. try {
  494. $user = \App\Models\User::find($id);
  495. $userEmail = $user ? $user->email : null;
  496. $user->delete();
  497. $this->logCurrentDatabase('After deleting user');
  498. Log::info('User deleted successfully from tenant database', [
  499. 'user_id' => $id,
  500. 'user_email' => $userEmail,
  501. 'database' => DB::connection()->getDatabaseName()
  502. ]);
  503. if ($userEmail) {
  504. $this->deleteUserFromMasterDatabase($userEmail);
  505. }
  506. session()->flash('success', "Dato eliminato");
  507. } catch (\Exception $e) {
  508. $this->logCurrentDatabase('Error in delete() method');
  509. Log::error('User deletion failed', [
  510. 'user_id' => $id,
  511. 'error' => $e->getMessage(),
  512. 'database' => DB::connection()->getDatabaseName()
  513. ]);
  514. session()->flash('error', 'Errore (' . $e->getMessage() . ')');
  515. }
  516. }
  517. }