Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

wip: start refactoring using ddd #203

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 48 additions & 0 deletions pkg/domain/template/template.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package template

import (
"github.com/ludusrusso/kannon/pkg/values/fqdn"
"github.com/ludusrusso/kannon/pkg/values/meta"
"github.com/ludusrusso/kannon/pkg/values/ref"
)

type Type string

const (
TemplateTypeTransient Type = "transient"
TemplateTypeTemplate Type = "template"
)

type Template struct {
meta.Meta
ref.Ref
html string
tType Type
}

func NewTemplate(domain fqdn.FQDN, tType Type, title, description string) (Template, error) {
ref, err := ref.NewRef("template", domain)
if err != nil {
return Template{}, err
}

return Template{
Meta: meta.NewMeta(title, description),
Ref: ref,
tType: tType,
html: "",
}, nil
}

func (t Template) Type() Type {
return t.tType
}

func (t Template) HTML() string {
return t.html
}

func (t *Template) SetHTML(html string) {
t.html = html
t.Update()
}
35 changes: 35 additions & 0 deletions pkg/sendingpool/email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package sendingpool

import (
"time"

"github.com/ludusrusso/kannon/pkg/values/email"
"github.com/ludusrusso/kannon/pkg/values/id"
)

type CustomFields map[string]string

type SendingPoolEmailStatus string

const (
SendingPoolEmailStatusInitializing SendingPoolEmailStatus = "initializing"
SendingPoolEmailStatusToValidate SendingPoolEmailStatus = "to_validate"
SendingPoolEmailStatusValidating SendingPoolEmailStatus = "validating"
SendingPoolEmailStatusSending SendingPoolEmailStatus = "sending"
SendingPoolEmailStatusSent SendingPoolEmailStatus = "sent"
SendingPoolEmailStatusScheduled SendingPoolEmailStatus = "scheduled"
SendingPoolEmailStatusError SendingPoolEmailStatus = "error"
)

type PoolEmail struct {
ID int32
ScheduledTime time.Time
OriginalScheduledTime time.Time
SendAttemptsCnt int32
Email email.Email
MessageID id.ID
Fields CustomFields
Status SendingPoolEmailStatus
CreatedAt time.Time
Domain string
}
20 changes: 20 additions & 0 deletions pkg/sendingpool/sendingpool.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package sendingpool

import (
"github.com/ludusrusso/kannon/pkg/values/email"
"github.com/ludusrusso/kannon/pkg/values/fqdn"
"github.com/ludusrusso/kannon/pkg/values/id"
)

type Sender interface {
Email() email.Email
Alias() string
}

type PoolMessage struct {
MessageID id.ID
Subject string
Sender Sender
TemplateID id.ID
Domain fqdn.FQDN
}
67 changes: 67 additions & 0 deletions pkg/values/email/email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
package email

import (
"errors"
"fmt"
"regexp"
"strings"
)

var ErrInvalidEmail = errors.New("invalid email")

type Email string

func NewEmail(v string) (Email, error) {
if !isValidEmail(v) {
return "", fmt.Errorf("%w: %s", ErrInvalidEmail, v)
}
return Email(v), nil
}

func NewEmailFromPtr(v *string) (*Email, error) {
if v == nil {
return nil, nil
}

email, err := NewEmail(*v)
if err != nil {
return nil, err
}

return &email, nil
}

func (e Email) String() string {
return string(e)
}

func (e Email) Username() string {
return strings.Split(e.String(), "@")[0]
}

func (e Email) Domain() string {
return strings.Split(e.String(), "@")[1]
}

var reg = regexp.MustCompile(`^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$`)

func isValidEmail(email string) bool {
return reg.MatchString(email)
}

func SafeToString(e *Email) string {
if e == nil {
return ""
}

return e.String()
}

func SafeToStringPtr(e *Email) *string {
if e == nil {
return nil
}

v := e.String()
return &v
}
68 changes: 68 additions & 0 deletions pkg/values/email/email_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package email

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestEmailVaidation(t *testing.T) {
tt := []struct {
email string
expectErr bool
}{
{
email: "",
expectErr: true,
},
{
email: "test",
expectErr: true,
},
{
email: "test@",
expectErr: true,
},
{
email: "test@test",
expectErr: true,
},
{
email: "test@test.",
expectErr: true,
},
{
email: "[email protected]",
expectErr: true,
},
{
email: "[email protected]",
expectErr: false,
},
}

for _, tc := range tt {
t.Run(tc.email, func(t *testing.T) {
_, err := NewEmail(tc.email)
if tc.expectErr {
if err == nil {
t.Errorf("expected error, got nil")
}
} else {
if err != nil {
t.Errorf("expected no error, got %v", err)
}
}
})
}
}

func TestUsername(t *testing.T) {
email, err := NewEmail("[email protected]")
if err != nil {
t.Fatalf("expected no error, got %v", err)
}

assert.Equal(t, email.Username(), "test")
assert.Equal(t, email.Domain(), "test.com")
}
32 changes: 32 additions & 0 deletions pkg/values/fqdn/fqdn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package fqdn

import (
"fmt"
"regexp"
)

type FQDN string

var ErrInvalidFQDN = fmt.Errorf("invalid FQDN")

// NewFQDN creates a new FQDN
func NewFQDN(fqdn string) (FQDN, error) {
res := FQDN(fqdn)
if !res.IsValid() {
return "", fmt.Errorf("%w: %s", ErrInvalidFQDN, fqdn)
}
return res, nil
}

// String returns the string representation of the FQDN
func (f FQDN) String() string {
return string(f)
}

// IsValid checks if the FQDN is valid using regex
var fqdnRegex = regexp.MustCompile(`^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$`)

// IsValid checks if the FQDN is valid
func (f FQDN) IsValid() bool {
return fqdnRegex.MatchString(f.String())
}
46 changes: 46 additions & 0 deletions pkg/values/fqdn/fqdn_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package fqdn

import "testing"

func TestValidateFQDN(t *testing.T) {
tt := []struct {
fqdn string
expectedErr error
}{
{
fqdn: "test",
expectedErr: ErrInvalidFQDN,
},
{
fqdn: "test.com",
expectedErr: nil,
},
{
fqdn: "test.com.",
expectedErr: ErrInvalidFQDN,
},
{
fqdn: "exp.test.com",
expectedErr: nil,
},
{
fqdn: "exp.test.com.",
expectedErr: ErrInvalidFQDN,
},
}

for _, tc := range tt {
t.Run(tc.fqdn, func(t *testing.T) {
_, err := NewFQDN(tc.fqdn)
if tc.expectedErr != nil {
if err == nil {
t.Errorf("expected error, got nil")
}
} else {
if err != nil {
t.Errorf("expected no error, got %v", err)
}
}
})
}
}
59 changes: 59 additions & 0 deletions pkg/values/id/id.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package id

import (
"crypto/rand"
"errors"
"fmt"

"github.com/lucsky/cuid"
"github.com/ludusrusso/kannon/pkg/values/fqdn"
)

type ID string

func (id ID) String() string {
return string(id)
}

func (id ID) IsEmpty() bool {
return id == ""
}

func (id ID) Validate() error {
if id.IsEmpty() {
return ErrEmptyID
}
return nil
}

var (
ErrCannotCreateID = errors.New("cannot create id")
ErrEmptyID = errors.New("empty id")
)

func FromString(id string) ID {
return ID(id)
}

func CreateID(prefix string) (ID, error) {
id, err := cuid.NewCrypto(rand.Reader)
if err != nil {
return "", fmt.Errorf("%w: %w", ErrCannotCreateID, err)
}

return ID(fmt.Sprintf("%s_%s", prefix, id)), nil
}

func CreateScopedID(prefix string, d fqdn.FQDN) (ID, error) {
id, err := CreateID(prefix)
if err != nil {
return "", err
}

return ID(fmt.Sprintf("%s@%s", id, d)), nil
}

func NewID(id string) (ID, error) {
i := ID(id)
return i, i.Validate()
}
Loading
Loading