From 318360a60aa52cf91ac80d547285f4d14c2c4517 Mon Sep 17 00:00:00 2001 From: Bobby <30593201+luciferreeves@users.noreply.github.com> Date: Mon, 22 Dec 2025 14:44:37 +0530 Subject: imap client, flash messages, imap login verification --- utils/email/imap.go | 39 +++++++++++++++++++ utils/shortcuts/flash.go | 31 +++++++++++++++ utils/shortcuts/helpers.go | 95 +++++++++++++++++++++++++++++++++++++-------- utils/shortcuts/redirect.go | 7 ++++ utils/shortcuts/render.go | 24 ++++-------- 5 files changed, 162 insertions(+), 34 deletions(-) create mode 100644 utils/email/imap.go create mode 100644 utils/shortcuts/flash.go (limited to 'utils') 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 } } -- cgit v1.2.3