summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
authorBobby <[email protected]>2025-12-22 14:44:37 +0530
committerBobby <[email protected]>2025-12-22 14:44:37 +0530
commit318360a60aa52cf91ac80d547285f4d14c2c4517 (patch)
treeb5261424716c4ecbe4085dfe914e99223a1a610d /utils
parent32ee8047eba06c9f1c7575b66fc0f9195657ac04 (diff)
downloadlain-318360a60aa52cf91ac80d547285f4d14c2c4517.tar.xz
lain-318360a60aa52cf91ac80d547285f4d14c2c4517.zip
imap client, flash messages, imap login verification
Diffstat (limited to 'utils')
-rw-r--r--utils/email/imap.go39
-rw-r--r--utils/shortcuts/flash.go31
-rw-r--r--utils/shortcuts/helpers.go95
-rw-r--r--utils/shortcuts/redirect.go7
-rw-r--r--utils/shortcuts/render.go24
5 files changed, 162 insertions, 34 deletions
diff --git a/utils/email/imap.go b/utils/email/imap.go
new file mode 100644
index 0000000..69181b3
--- /dev/null
+++ b/utils/email/imap.go
@@ -0,0 +1,39 @@
+package email
+
+import (
+ "crypto/tls"
+ "fmt"
+ "lain/config"
+ "lain/types"
+
+ "github.com/emersion/go-imap/client"
+)
+
+func ConnectIMAP(email, password string) (*types.EmailClient, error) {
+ address := fmt.Sprintf("%s:%d", config.MailServer.IMAPHost, config.MailServer.IMAPPort)
+
+ var c *client.Client
+ var err error
+
+ if config.MailServer.IMAPTLS {
+ c, err = client.DialTLS(address, &tls.Config{
+ ServerName: config.MailServer.IMAPHost,
+ })
+ } else {
+ c, err = client.Dial(address)
+ }
+
+ if err != nil {
+ return nil, fmt.Errorf("failed to connect to IMAP server: %w", err)
+ }
+
+ if err := c.Login(email, password); err != nil {
+ return nil, fmt.Errorf("invalid credentials: %w", err)
+ }
+
+ return &types.EmailClient{Client: c}, nil
+}
+
+func DisconnectIMAP(c *types.EmailClient) error {
+ return c.Logout()
+}
diff --git a/utils/shortcuts/flash.go b/utils/shortcuts/flash.go
new file mode 100644
index 0000000..da1507a
--- /dev/null
+++ b/utils/shortcuts/flash.go
@@ -0,0 +1,31 @@
+package shortcuts
+
+import (
+ "lain/session"
+
+ "github.com/gofiber/fiber/v2"
+)
+
+const flashKey = "__flash__"
+
+func Flash(ctx *fiber.Ctx, data any) error {
+ normalized, err := normalizeBind(data)
+ if err != nil {
+ return err
+ }
+
+ return session.Set(ctx, flashKey, normalized)
+}
+
+func ConsumeFlash(ctx *fiber.Ctx) (any, error) {
+ value, err := session.Get(ctx, flashKey)
+ if err != nil || value == nil {
+ return nil, err
+ }
+
+ if err := session.Delete(ctx, flashKey); err != nil {
+ return nil, err
+ }
+
+ return value, nil
+}
diff --git a/utils/shortcuts/helpers.go b/utils/shortcuts/helpers.go
index 8503a2d..5ffd43e 100644
--- a/utils/shortcuts/helpers.go
+++ b/utils/shortcuts/helpers.go
@@ -2,8 +2,11 @@ package shortcuts
import (
"fmt"
+ "maps"
"reflect"
"strings"
+
+ "github.com/gofiber/fiber/v2"
)
func structValue(data any) (reflect.Value, error) {
@@ -13,10 +16,7 @@ func structValue(data any) (reflect.Value, error) {
}
if v.Kind() != reflect.Struct {
- return reflect.Value{}, fmt.Errorf(
- "Render: unsupported bind type %T; must be struct or *struct",
- data,
- )
+ return reflect.Value{}, fmt.Errorf("unsupported bind type %T; must be struct or *struct", data)
}
return v, nil
@@ -27,24 +27,85 @@ func mapStruct(v reflect.Value) map[string]any {
result := make(map[string]any, v.NumField())
for i := 0; i < v.NumField(); i++ {
- fieldType := t.Field(i)
- if !fieldType.IsExported() {
+ field := t.Field(i)
+ if !field.IsExported() {
continue
}
- key := fieldType.Name
- if tag := fieldType.Tag.Get("json"); tag != "" && tag != "-" {
- if idx := strings.IndexByte(tag, ','); idx >= 0 {
- if idx > 0 {
- key = tag[:idx]
- }
- } else {
- key = tag
- }
+ result[getFieldKey(field)] = v.Field(i).Interface()
+ }
+
+ return result
+}
+
+func getFieldKey(field reflect.StructField) string {
+ key := field.Name
+ tag := field.Tag.Get("json")
+
+ if tag == "" || tag == "-" {
+ return key
+ }
+
+ if idx := strings.IndexByte(tag, ','); idx >= 0 {
+ if idx > 0 {
+ return tag[:idx]
}
+ return key
+ }
+
+ return tag
+}
- result[key] = v.Field(i).Interface()
+func normalizeBind(data any) (fiber.Map, error) {
+ if data == nil {
+ return nil, nil
}
- return result
+ switch v := data.(type) {
+ case fiber.Map:
+ return v, nil
+ case map[string]any:
+ return fiber.Map(v), nil
+ default:
+ return structToMap(v)
+ }
+}
+
+func structToMap(data any) (fiber.Map, error) {
+ v, err := structValue(data)
+ if err != nil {
+ return nil, err
+ }
+ return fiber.Map(mapStruct(v)), nil
+}
+
+func mergeFlash(ctx *fiber.Ctx, bind fiber.Map) error {
+ flash, err := ConsumeFlash(ctx)
+ if err != nil || flash == nil {
+ return err
+ }
+
+ flashMap, err := normalizeBind(flash)
+ if err != nil {
+ return err
+ }
+
+ maps.Copy(bind, flashMap)
+ return nil
+}
+
+func mergeUserValues(ctx *fiber.Ctx, bind fiber.Map) {
+ ctx.Context().VisitUserValues(func(key []byte, value any) {
+ bind[string(key)] = value
+ })
+}
+
+func mergeData(bind fiber.Map, data any) error {
+ dataMap, err := normalizeBind(data)
+ if err != nil {
+ return err
+ }
+
+ maps.Copy(bind, dataMap)
+ return nil
}
diff --git a/utils/shortcuts/redirect.go b/utils/shortcuts/redirect.go
index 77e1959..1add12f 100644
--- a/utils/shortcuts/redirect.go
+++ b/utils/shortcuts/redirect.go
@@ -27,3 +27,10 @@ func RedirectTo(route string) fiber.Handler {
return Redirect(ctx, route)
}
}
+
+func RedirectWithFlash(context *fiber.Ctx, routeName string, data fiber.Map) error {
+ if err := Flash(context, data); err != nil {
+ return err
+ }
+ return Redirect(context, routeName)
+}
diff --git a/utils/shortcuts/render.go b/utils/shortcuts/render.go
index 1efeb61..7862b91 100644
--- a/utils/shortcuts/render.go
+++ b/utils/shortcuts/render.go
@@ -1,31 +1,21 @@
package shortcuts
import (
- "maps"
-
"github.com/gofiber/fiber/v2"
)
func Render(ctx *fiber.Ctx, template string, data any) error {
bind := make(fiber.Map)
- ctx.Context().VisitUserValues(func(key []byte, value any) {
- bind[string(key)] = value
- })
+ if err := mergeFlash(ctx, bind); err != nil {
+ return err
+ }
+
+ mergeUserValues(ctx, bind)
if data != nil {
- switch v := data.(type) {
- case map[string]any:
- maps.Copy(bind, v)
- case fiber.Map:
- maps.Copy(bind, v)
- default:
- rv, err := structValue(data)
- if err != nil {
- return err
- }
-
- maps.Copy(bind, mapStruct(rv))
+ if err := mergeData(bind, data); err != nil {
+ return err
}
}