22
33namespace Leaf \Auth ;
44
5- use Exception ;
65use Firebase \JWT \JWT ;
7- use Leaf \Db ;
6+ use Leaf \Date ;
7+ use Leaf \Helpers \Password ;
88use Leaf \Http \Session ;
9- use Throwable ;
109
1110/**
1211 * Auth User
@@ -23,7 +22,7 @@ class User
2322
2423 /**
2524 * Internal instance of Leaf database
26- * @var Db
25+ * @var \Leaf\DB
2726 */
2827 protected $ db ;
2928
@@ -43,6 +42,12 @@ class User
4342 */
4443 protected array $ tokens = [];
4544
45+ /**
46+ * All errors caught
47+ * @var array
48+ */
49+ protected $ errorsArray = [];
50+
4651 public function __construct ($ data , $ session = true )
4752 {
4853 $ this ->data = $ data ;
@@ -72,7 +77,7 @@ public function __construct($data, $session = true)
7277 $ sessionLifetime = strtotime ($ sessionLifetime );
7378
7479 if (!$ sessionLifetime ) {
75- throw new Exception ('Invalid session lifetime ' );
80+ throw new \ Exception ('Invalid session lifetime ' );
7681 }
7782 } else {
7883 $ sessionLifetime = time () + $ sessionLifetime ;
@@ -103,6 +108,170 @@ public function id()
103108 return $ this ->data [Config::get ('id.key ' )] ?? null ;
104109 }
105110
111+ /**
112+ * Update user data
113+ * ---
114+ * Update user data in the database
115+ *
116+ * @param array $userData User data
117+ * @return bool
118+ */
119+ public function update (array $ userData ): bool
120+ {
121+ $ user = $ this ->get ();
122+
123+ if (!$ user ) {
124+ return false ;
125+ }
126+
127+ $ idKey = Config::get ('id.key ' );
128+ $ table = Config::get ('db.table ' );
129+
130+ if (Config::get ('timestamps ' )) {
131+ $ userData ['updated_at ' ] = (new Date ())->tick ()->format (Config::get ('timestamps.format ' ));
132+ }
133+
134+ if (isset ($ userData ['email ' ])) {
135+ $ userData ['email ' ] = strtolower ($ userData ['email ' ]);
136+ }
137+
138+ if (\count (Config::get ('unique ' )) > 0 ) {
139+ foreach (Config::get ('unique ' ) as $ unique ) {
140+ if (!isset ($ userData [$ unique ])) {
141+ continue ;
142+ }
143+
144+ $ data = $ this ->db ->select ($ table , Config::get ('id.key ' ))->where ($ unique , $ userData [$ unique ])->first ();
145+
146+ if ($ data && $ data [Config::get ('id.key ' )] !== $ this ->id ()) {
147+ $ this ->errorsArray [$ unique ] = "$ unique already exists " ;
148+ }
149+ }
150+
151+ if (\count ($ this ->errorsArray ) > 0 ) {
152+ return false ;
153+ }
154+ }
155+
156+ try {
157+ $ query = $ this ->db ->update ($ table )->params ($ userData )->where ($ idKey , $ this ->id ())->execute ();
158+
159+ if (!$ query ) {
160+ $ this ->errorsArray = array_merge ($ this ->errorsArray , $ this ->db ->errors ());
161+ return false ;
162+ }
163+ } catch (\Throwable $ th ) {
164+ throw new \Exception ($ th ->getMessage ());
165+ }
166+
167+ if (Config::get ('session ' )) {
168+ session_regenerate_id ();
169+ }
170+
171+ foreach ($ userData as $ key => $ value ) {
172+ $ this ->data [$ key ] = $ value ;
173+ }
174+
175+ return true ;
176+ }
177+
178+ /**
179+ * Update user password
180+ * ---
181+ * Update user password in the database
182+ *
183+ * @param string $oldPassword Old password
184+ * @param string $newPassword New password
185+ * @return bool
186+ */
187+ public function updatePassword (string $ oldPassword , string $ newPassword ): bool
188+ {
189+ $ user = $ this ->get ();
190+
191+ if (!$ user ) {
192+ return false ;
193+ }
194+
195+ $ passwordKey = Config::get ('password.key ' );
196+
197+ if (Config::get ('password.verify ' ) !== false && isset ($ user [$ passwordKey ])) {
198+ $ passwordIsValid = (is_callable (Config::get ('password.verify ' )))
199+ ? call_user_func (Config::get ('password.verify ' ), $ oldPassword , $ user [$ passwordKey ])
200+ : Password::verify ($ oldPassword , $ user [$ passwordKey ]);
201+
202+ if (!$ passwordIsValid ) {
203+ $ this ->errorsArray ['password ' ] = Config::get ('messages.loginPasswordError ' );
204+ return false ;
205+ }
206+ }
207+
208+ $ newPassword = (Config::get ('password.encode ' ) !== false )
209+ ? ((is_callable (Config::get ('password.encode ' )))
210+ ? call_user_func (Config::get ('password.encode ' ), $ newPassword )
211+ : Password::hash ($ newPassword ))
212+ : $ newPassword ;
213+
214+ try {
215+ $ query = $ this ->db ->update (Config::get ('db.table ' ))
216+ ->params ([$ passwordKey => $ newPassword ])
217+ ->where (Config::get ('id.key ' ), $ this ->id ())
218+ ->execute ();
219+
220+ if (!$ query ) {
221+ $ this ->errorsArray = array_merge ($ this ->errorsArray , $ this ->db ->errors ());
222+ return false ;
223+ }
224+ } catch (\Throwable $ th ) {
225+ throw new \Exception ($ th ->getMessage ());
226+ }
227+
228+ $ this ->data [$ passwordKey ] = $ newPassword ;
229+
230+ return true ;
231+ }
232+
233+ /**
234+ * Reset user password
235+ * ---
236+ * Reset user password in the database
237+ *
238+ * @param string $newPassword New password
239+ * @return bool
240+ */
241+ public function resetPassword (string $ newPassword ): bool
242+ {
243+ $ user = $ this ->get ();
244+
245+ if (!$ user ) {
246+ return false ;
247+ }
248+
249+ $ passwordKey = Config::get ('password.key ' );
250+ $ newPassword = (Config::get ('password.encode ' ) !== false )
251+ ? ((is_callable (Config::get ('password.encode ' )))
252+ ? call_user_func (Config::get ('password.encode ' ), $ newPassword )
253+ : Password::hash ($ newPassword ))
254+ : $ newPassword ;
255+
256+ try {
257+ $ query = $ this ->db ->update (Config::get ('db.table ' ))
258+ ->params ([$ passwordKey => $ newPassword ])
259+ ->where (Config::get ('id.key ' ), $ this ->id ())
260+ ->execute ();
261+
262+ if (!$ query ) {
263+ $ this ->errorsArray = array_merge ($ this ->errorsArray , $ this ->db ->errors ());
264+ return false ;
265+ }
266+ } catch (\Throwable $ th ) {
267+ throw new \Exception ($ th ->getMessage ());
268+ }
269+
270+ $ this ->data [$ passwordKey ] = $ newPassword ;
271+
272+ return true ;
273+ }
274+
106275 /**
107276 * Get auth information to be sent to the client
108277 * @return object
@@ -212,7 +381,7 @@ public function verifyEmail(): bool
212381 ->execute ();
213382
214383 return true ;
215- } catch (Throwable $ th ) {
384+ } catch (\ Throwable $ th ) {
216385 return false ;
217386 }
218387 }
@@ -246,7 +415,7 @@ public function get()
246415
247416 /**
248417 * Set user db instance
249- * @param Db $db
418+ * @param \Leaf\ Db $db
250419 * @return User
251420 */
252421 public function setDb ($ db )
@@ -256,6 +425,15 @@ public function setDb($db)
256425 return $ this ;
257426 }
258427
428+ /**
429+ * Get user errors
430+ * @return array
431+ */
432+ public function errors ()
433+ {
434+ return $ this ->errorsArray ;
435+ }
436+
259437 public function __toString ()
260438 {
261439 return json_encode ($ this ->get ());
@@ -296,14 +474,14 @@ public function __unset($name)
296474 *
297475 * @param mixed $method The table to relate to
298476 * @param mixed $args
299- * @throws Exception
477+ * @throws \ Exception
300478 *
301479 * @return Model
302480 */
303481 public function __call ($ method , $ args )
304482 {
305483 if (!class_exists ('Leaf\App ' )) {
306- throw new Exception ('Relations are only available in Leaf apps. ' );
484+ throw new \ Exception ('Relations are only available in Leaf apps. ' );
307485 }
308486
309487 return (new Model ([
0 commit comments