diff --git a/main.go b/main.go index d72eb6a..e121ba0 100644 --- a/main.go +++ b/main.go @@ -2,18 +2,22 @@ package main import ( "crypto/rand" + "encoding/xml" "fmt" + "io/ioutil" "log" "math/big" "net/http" "net/mail" "os" + "strings" "time" "github.com/labstack/echo/v5" "github.com/pocketbase/pocketbase" "github.com/pocketbase/pocketbase/apis" "github.com/pocketbase/pocketbase/core" + "github.com/pocketbase/pocketbase/models" "github.com/pocketbase/pocketbase/tools/mailer" "github.com/pocketbase/pocketbase/tools/types" ) @@ -29,80 +33,99 @@ type EmailConfigurationResponse struct { } `json:"items"` } +type GenericData struct { + XMLName xml.Name `xml:"GenericData"` + DataSet []Obs `xml:"DataSet>Obs"` +} + +type Obs struct { + ObsKey []ObsKey `xml:"ObsKey>Value"` // Dynamic key-value pairs + ObsValue ObsValue `xml:"ObsValue"` +} + +type ObsKey struct { + ID string `xml:"id,attr"` // Attribute for 'id' + Value string `xml:"value,attr"` // Attribute for 'value' +} + +type ObsValue struct { + Value string `xml:"value,attr"` // Attribute for 'value' +} + +// Helper function to map ObsKey into a dictionary +func mapObsKey(keys []ObsKey) map[string]string { + result := map[string]string{} + for _, key := range keys { + result[key.ID] = key.Value + } + return result +} + +// Helper function to clean XML namespace prefixes +func removeNamespace(xmlBytes []byte) string { + return strings.ReplaceAll(string(xmlBytes), "generic:", "") +} + +// Function to fetch XML from an API and convert it to JSON +func fetchAndConvertXMLToJSON(apiURL string) ([]map[string]interface{}, error) { + // Call the API and get the XML response + resp, err := http.Get(apiURL) + if err != nil { + return nil, err + } + defer resp.Body.Close() + + // Read the response body + body, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + + // Clean the XML by removing namespace prefixes + cleanXML := []byte(removeNamespace(body)) + + // Parse the cleaned XML data + var data GenericData + err = xml.Unmarshal(cleanXML, &data) + if err != nil { + return nil, err + } + + // Transform the data for JSON output + response := []map[string]interface{}{} + for _, obs := range data.DataSet { + obsMap := map[string]interface{}{ + "ObsKey": mapObsKey(obs.ObsKey), + "ObsValue": obs.ObsValue, + } + response = append(response, obsMap) + } + + return response, nil +} + var app *pocketbase.PocketBase func main() { // app := pocketbase.New() app = pocketbase.New() + //send mail while status changed from app admin app.OnRecordBeforeUpdateRequest().Add(func(e *core.RecordUpdateEvent) error { if e.Collection.Name == "users" { - // Fetch the original record by ID originalRecord, err := app.Dao().FindRecordById("users", e.Record.GetString("id")) if err != nil { return fmt.Errorf("failed to fetch original record: %v", err) } - // Get the old status before the update oldStatus := originalRecord.GetString("status") newStatus := e.Record.GetString("status") - // If the status has changed, send an email - if newStatus != oldStatus { - userEmail := e.Record.GetString("email") - userName := e.Record.GetString("username") - if userEmail != "" { - - var subject string - var body string - - // Define the email content based on status - if newStatus == "Approved" { - subject = "Registration Approved – FCSC" - body = fmt.Sprintf(` -

Dear %s,

-

We are pleased to inform you that your registration with FCSC has been approved. You can now log in using the credentials that you had created.

-

Please access your account using the following link: Login.

-

If you have any questions, please feel free to contact us for further clarification.

- `, userName) - } else if newStatus == "Denied" { - subject = "Registration Update – FCSC" - body = fmt.Sprintf(` -

Dear %s,

-

Thank you for registering with FCSC. After careful review, we regret to inform you that your registration has not been approved at this time.

-

If you have any questions or believe this decision was made in error, please feel free to contact us for further clarification.

-

We appreciate your understanding and thank you for your interest.

-

Best regards,

- `, userName) - } else { - // If the status is neither "Approved" nor "Denied", skip sending an email - return nil - } - - // Create the email message - message := &mailer.Message{ - From: mail.Address{ - Name: "FCSC", - Address: app.Settings().Meta.SenderAddress, // Replace with your sender's email - }, - To: []mail.Address{ - { - Name: userName, - Address: userEmail, - }, - }, - Subject: subject, - HTML: body, - } - - // Send the email - err = app.NewMailClient().Send(message) - if err != nil { - log.Printf("Failed to send status change email: %v", err) - return err - } - - log.Println("Status change email sent successfully to:", userEmail) + // Check if the status has changed + if oldStatus != newStatus { + err := sendStatusChangeEmail(app, e.Record, newStatus) + if err != nil { + return err } } } @@ -169,7 +192,7 @@ func main() { app.OnBeforeServe().Add(func(e *core.ServeEvent) error { e.Router.GET("/api/custom/approve", func(c echo.Context) error { - userId := c.QueryParam("userId") // Get userId from query parameters + userId := c.QueryParam("userId") if userId == "" { return c.JSON(400, map[string]interface{}{ "code": 400, @@ -177,7 +200,7 @@ func main() { }) } - // Find the user record in PocketBase by userId + // Find the user record record, err := app.Dao().FindRecordById("users", userId) if err != nil { return c.JSON(500, map[string]interface{}{ @@ -186,8 +209,60 @@ func main() { }) } - // Set the verified status to true + // Check if the email is already verified + if record.GetBool("reviewed") { + return c.HTML(http.StatusOK, ` + + + + + +
+
+

Your Already Reviewed

+

You have already been reviewed. No further action is required.

+
+ + +`) + } + + // Update the status + newStatus := "Approved" record.Set("verified", true) + record.Set("status", newStatus) + record.Set("reviewed", true) if err := app.Dao().SaveRecord(record); err != nil { return c.JSON(500, map[string]interface{}{ "code": 500, @@ -195,39 +270,8 @@ func main() { }) } - // Prepare the email details - name := record.GetString("username") - email := record.GetString("email") - subject := "Registration Approved – FCSC" - body := fmt.Sprintf(` - - -

Dear %s,

-

We are pleased to inform you that your registration with FCSC has been approved. You can now log in using the credentials that you had created.

-

Please access your account using the following link: Login.

-

If you have any questions, please feel free to contact us for further clarification.

- - - `, name) - - // Create the email message - message := &mailer.Message{ - From: mail.Address{ - Name: "FCSC", - Address: app.Settings().Meta.SenderAddress, - }, - To: []mail.Address{ - { - Name: name, - Address: email, - }, - }, - Subject: subject, - HTML: body, - } - - // Send the approval email - err = app.NewMailClient().Send(message) + // Send the status change email + err = sendStatusChangeEmail(app, record, newStatus) if err != nil { return c.JSON(500, map[string]interface{}{ "code": 500, @@ -235,9 +279,8 @@ func main() { }) } - // Render a success message as an HTML response return c.HTML(http.StatusOK, ` - + + + +
+
+

Your Already Reviewed

+

You have already been reviewed. No further action is required.

+
+ + +`) + } + + // Check if the status is already "Denied" to avoid duplicate email + if record.GetString("status") == "Denied" { + return c.JSON(400, map[string]interface{}{ + "code": 400, + "message": "User is already rejected.", }) } - // Prepare the rejection email details - name := record.GetString("username") - email := record.GetString("email") - subject := "Registration Update – FCSC" - body := fmt.Sprintf(` - - -

Dear %s,

-

Thank you for registering with FCSC. After careful review, we regret to inform you that your registration has not been approved at this time.

-

If you have any questions or believe this decision was made in error, please feel free to contact us for further clarification.

-

We appreciate your understanding and thank you for your interest.

-

Best regards,

- - -`, name) - - // Create the rejection email message - message := &mailer.Message{ - From: mail.Address{ - Name: "FCSC", - Address: app.Settings().Meta.SenderAddress, - }, - To: []mail.Address{ - { - Name: name, - Address: email, - }, - }, - Subject: subject, - HTML: body, + // Update the status + newStatus := "Denied" + record.Set("verified", true) + record.Set("status", newStatus) + record.Set("reviewed", true) + if err := app.Dao().SaveRecord(record); err != nil { + return c.JSON(500, map[string]interface{}{ + "code": 500, + "message": "Failed to verify user.", + }) } - // Send the rejection email - err = app.NewMailClient().Send(message) + // Send the status change email + err = sendStatusChangeEmail(app, record, newStatus) if err != nil { return c.JSON(500, map[string]interface{}{ "code": 500, @@ -359,44 +430,44 @@ func main() { // Render a success message as an HTML response return c.HTML(http.StatusOK, ` - - - - - - User Rejected - - - -
- -

User Rejected

-

Rejection email sent successfully.

-
- - + + + + + + User Rejected + + + +
+ +

User Rejected

+

Rejection email sent successfully.

+
+ + `) }) @@ -410,6 +481,7 @@ func main() { return nil }) + //Feedback Mail Trigger app.OnRecordAfterCreateRequest().Add(func(e *core.RecordCreateEvent) error { if e.Record.Collection().Name == "feedback" { // Retrieve feedback details @@ -635,6 +707,55 @@ func verifyEmailHandler(c echo.Context) error { }) } + // Check if the email is already verified + if record.GetBool("user_mail_verify") { + return c.HTML(http.StatusOK, ` + + + + + +
+
+

Email Already Verified

+

Your email has already been verified. No further action is required.

+
+ + +`) + } + // Set the verified status to true record.Set("user_mail_verify", true) // log.Printf("Failed to verify user: %v", err) @@ -710,6 +831,7 @@ func verifyEmailHandler(c echo.Context) error { func sendAdminEmail(app *pocketbase.PocketBase, userID, username, userEmail string) error { adminName := "Admin" subject := "New User Registration Pending Review" + body := fmt.Sprintf(` @@ -755,3 +877,60 @@ func sendAdminEmail(app *pocketbase.PocketBase, userID, username, userEmail stri log.Println("Admin email sent successfully.") return nil } + +func sendStatusChangeEmail(app *pocketbase.PocketBase, record *models.Record, newStatus string) error { + userEmail := record.GetString("email") + userName := record.GetString("username") + + if userEmail == "" { + return fmt.Errorf("user email is empty") + } + + var subject, body string + + if newStatus == "Approved" { + subject = "Registration Approved – FCSC" + body = fmt.Sprintf(` +

Dear %s,

+

We are pleased to inform you that your registration with FCSC has been approved. You can now log in using the credentials that you had created.

+

Please access your account using the following link: Login.

+

If you have any questions, please feel free to contact us for further clarification.

+ `, userName) + } else if newStatus == "Denied" { + subject = "Registration Update – FCSC" + body = fmt.Sprintf(` +

Dear %s,

+

Thank you for registering with FCSC. After careful review, we regret to inform you that your registration has not been approved at this time.

+

If you have any questions or believe this decision was made in error, please feel free to contact us for further clarification.

+

We appreciate your understanding and thank you for your interest.

+

Best regards,

+ `, userName) + } else { + // If the status is neither "Approved" nor "Denied", skip sending an email + return nil + } + + // Create and send the email + message := &mailer.Message{ + From: mail.Address{ + Name: "FCSC", + Address: app.Settings().Meta.SenderAddress, + }, + To: []mail.Address{ + { + Name: userName, + Address: userEmail, + }, + }, + Subject: subject, + HTML: body, + } + + err := app.NewMailClient().Send(message) + if err != nil { + return fmt.Errorf("failed to send email: %v", err) + } + + log.Printf("Status change email sent successfully to: %s", userEmail) + return nil +}