@@ -39,7 +39,7 @@ type SignupData struct {
3939 Token string `json:"token" binding:"required"`
4040}
4141
42- type ActivateData struct {
42+ type ActivateOrResetData struct {
4343 Email string `json:"email" binding:"required,email"`
4444 Token string `json:"token" binding:"required"`
4545}
@@ -315,6 +315,97 @@ const activate_template = `
315315</body>
316316</html>`
317317
318+ const pwdreset_template = `
319+ <!DOCTYPE html>
320+ <html>
321+ <head>
322+ <style>
323+ body {
324+ font-family: Arial, sans-serif;
325+ line-height: 1.6;
326+ color: #333;
327+ max-width: 600px;
328+ margin: 0 auto;
329+ }
330+ .header {
331+ background-color: #f8f9fa;
332+ padding: 20px;
333+ border-bottom: 2px solid #007bff;
334+ text-align: center;
335+ }
336+ .logo {
337+ max-width: 200px;
338+ margin-bottom: 10px;
339+ }
340+ .content {
341+ padding: 0 20px 20px 20px;
342+ }
343+ .button {
344+ background-color: #007bff;
345+ color: white;
346+ padding: 12px 24px;
347+ text-decoration: none;
348+ border-radius: 4px;
349+ font-weight: bold;
350+ display: inline-block;
351+ margin: 20px 0;
352+ }
353+ .button:hover {
354+ background-color: #0069d9;
355+ }
356+ .important-note {
357+ background-color: #f8f9fa;
358+ border-left: 4px solid #ffc107;
359+ padding: 15px;
360+ margin: 15px 0;
361+ font-size: 0.9em;
362+ }
363+ .footer {
364+ margin-top: 30px;
365+ padding-top: 15px;
366+ border-top: 1px solid #eee;
367+ font-size: 0.9em;
368+ color: #777;
369+ text-align: center;
370+ }
371+ .contact-info {
372+ margin-top: 20px;
373+ }
374+ </style>
375+ </head>
376+ <body>
377+ <div class="header">
378+ <h2>Password Reset Request</h2>
379+ </div>
380+
381+ <div class="content">
382+
383+
384+ <p>Your password can be reset by clicking the button below. If you did not request a new password, please ignore this email.</p>
385+
386+ <a href="https://rent.ragodevs.com/admins/reset?token={{.Token}}" class="button">Reset Password</a>
387+
388+ <div class="important-note">
389+ <p>Please note that this reset link will expire 45 minutes and can only be used once.</p>
390+ </div>
391+
392+ <div class="contact-info">
393+ <p>If you have any questions or need assistance, please contact our support team:</p>
394+ <p>Email: <a href="mailto:[email protected] ">[email protected] </a><br> 395+ Phone: 0654051622</p>
396+ </div>
397+
398+ <p>Best regards,</p>
399+ <p>The Rent Management System Team</p>
400+
401+ <div class="footer">
402+ <p><a href="https://www.rent.ragodevs.com">www.rent.ragodevs.com</a></p>
403+ <p>© 2025 Rent Management System. All rights reserved.</p>
404+ </div>
405+ </div>
406+ </body>
407+ </html>`
408+
318409func enableCORS () gin.HandlerFunc {
319410
320411 corsConfig := cors .DefaultConfig ()
@@ -395,7 +486,7 @@ func (mc *MailConfig) sendWelcomeEmail(data SignupData) error {
395486 return nil
396487}
397488
398- func (mc * MailConfig ) sendActivateEmail (data ActivateData ) error {
489+ func (mc * MailConfig ) sendActivateEmail (data ActivateOrResetData ) error {
399490
400491 tmpl , err := template .New ("email" ).Parse (activate_template )
401492 if err != nil {
@@ -420,6 +511,33 @@ func (mc *MailConfig) sendActivateEmail(data ActivateData) error {
420511
421512 return nil
422513}
514+
515+ func (mc * MailConfig ) sendPasswordResetEmail (data ActivateOrResetData ) error {
516+
517+ tmpl , err := template .New ("email" ).Parse (pwdreset_template )
518+ if err != nil {
519+ return fmt .Errorf ("failed to parse email template: %v" , err )
520+ }
521+
522+ var emailBody bytes.Buffer
523+ if err := tmpl .Execute (& emailBody , data ); err != nil {
524+ return fmt .Errorf ("failed to execute email template: %v" , err )
525+ }
526+
527+ recipients := []string {data .Email }
528+
529+ subject := "Password Reset Request for Rent Management System"
530+ msg := fmt .Sprintf ("Subject: %s\n To: %s\n Content-Type: text/html\n \n %s" , subject , data .Email , emailBody .String ())
531+
532+ auth := smtp .PlainAuth ("" , mc .USER , mc .PWD , mc .HOST )
533+ err = smtp .SendMail (mc .HOST + ":" + mc .PORT , auth , mc .USER , recipients , []byte (msg ))
534+ if err != nil {
535+ return fmt .Errorf ("failed to send email: %v" , err )
536+ }
537+
538+ return nil
539+ }
540+
423541func main () {
424542
425543 mc := & MailConfig {}
@@ -473,7 +591,7 @@ func main() {
473591
474592 router .POST ("/rent-activate" , func (c * gin.Context ) {
475593
476- var data ActivateData
594+ var data ActivateOrResetData
477595 if err := c .ShouldBindJSON (& data ); err != nil {
478596 c .JSON (400 , gin.H {"error" : err .Error ()})
479597 return
@@ -488,6 +606,23 @@ func main() {
488606 c .JSON (200 , gin.H {"message" : "Email sent successfully!" })
489607 })
490608
609+ router .POST ("/rent-resetpwd" , func (c * gin.Context ) {
610+
611+ var data ActivateOrResetData
612+ if err := c .ShouldBindJSON (& data ); err != nil {
613+ c .JSON (400 , gin.H {"error" : err .Error ()})
614+ return
615+ }
616+
617+ if err := mc .sendPasswordResetEmail (data ); err != nil {
618+ log .Printf ("Error sending email: %v" , err )
619+ c .JSON (500 , gin.H {"error" : "Failed to send email" })
620+ return
621+ }
622+
623+ c .JSON (200 , gin.H {"message" : "Email sent successfully!" })
624+ })
625+
491626 port := os .Getenv ("PORT" )
492627 if port == "" {
493628 port = "8080"
0 commit comments