Skip to content

Commit

Permalink
Refactor auth service (#32)
Browse files Browse the repository at this point in the history
  • Loading branch information
ripls56 authored Sep 12, 2024
2 parents f5a5e2c + ae1fb17 commit e7f2908
Show file tree
Hide file tree
Showing 12 changed files with 520 additions and 48 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ TOKEN_SECRET={w:ae2@:;'aE.VW@FP0g813Lo-J\exKAf(0f5pt"+@V,z\2k(jk{MX?F6WK3|;Z"a,B

GRPC_PORT=50051

HOST_DOMAIN=localhost
NO_REPLAY_EMAIL=[email protected]

RABBITMQ_PASSWORD=taskem
RABBITMQ_URL=amqp://taskem:${RABBITMQ_PASSWORD}@rabbitmq:5672

Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/codecov.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ jobs:
name: server
- module: ./apps/notification
name: notification
- module: ./libs/queue
name: queue
- module: ./libs/template
name: template

steps:
- uses: actions/checkout@v4
Expand Down
3 changes: 3 additions & 0 deletions .mockery.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
with-expecter: True
inpackage: True
all: True
5 changes: 5 additions & 0 deletions apps/server/internal/app/auth/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package auth

import (
authserver "github.com/taskemapp/server/apps/server/internal/grpc/auth"
"github.com/taskemapp/server/apps/server/internal/pkg/notifier"
"github.com/taskemapp/server/apps/server/internal/repositories/token"
"github.com/taskemapp/server/apps/server/internal/repositories/user"
authservice "github.com/taskemapp/server/apps/server/internal/service/auth"
Expand All @@ -17,6 +18,10 @@ var App = fx.Options(
fx.Annotate(token.NewClient, fx.As(new(token.Repository))),
),

fx.Provide(
fx.Annotate(notifier.NewEmailAccountNotifier, fx.As(new(notifier.AccountNotifier))),
),

fx.Provide(
fx.Annotate(authservice.New, fx.As(new(authservice.Service))),
),
Expand Down
4 changes: 4 additions & 0 deletions apps/server/internal/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ type Config struct {

RabbitMq queue.Config

NoReplayEmail string `envconfig:"NO_REPLAY_EMAIL"`

HostDomain string `envconfig:"HOST_DOMAIN"`

S3Host string `envconfig:"S3_HOST"`
S3AccessToken string `envconfig:"S3_ACCESS_TOKEN"`
S3SecretToken string `envconfig:"S3_SECRET_TOKEN"`
Expand Down
89 changes: 89 additions & 0 deletions apps/server/internal/pkg/notifier/account.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package notifier

import (
"github.com/go-faster/errors"
"github.com/google/uuid"
"github.com/taskemapp/server/apps/server/internal/config"
"github.com/taskemapp/server/apps/server/internal/repositories/user"
"github.com/taskemapp/server/libs/queue"
"github.com/taskemapp/server/libs/template"
"go.uber.org/fx"
"go.uber.org/multierr"
"strings"
)

type AccountNotifier interface {
VerifyEmail(username string, email string) error
}

type EmailAccountNotifier struct {
config config.Config
q queue.Queue
userRepo user.Repository
}

type OptsEmailAccNotifier struct {
fx.In
Config config.Config
Queue queue.Queue
UserRepo user.Repository
}

func NewEmailAccountNotifier(opts OptsEmailAccNotifier) *EmailAccountNotifier {
return &EmailAccountNotifier{
config: opts.Config,
q: opts.Queue,
userRepo: opts.UserRepo,
}
}

func (n *EmailAccountNotifier) VerifyEmail(username string, email string) error {
confirmID, err := uuid.NewUUID()
if err != nil {
return errors.Wrap(err, "verify to")
}

confirmLink, err := buildConfirmLink(n.config.HostDomain, confirmID.String())
if err != nil {
return errors.Wrap(err, "verify to")
}

temp, err := template.Get(template.VerifyEmailTemplate)
if err != nil {
return errors.Wrap(err, "verify to")
}

err = sendEmail(sendEmailOpts{
temp: temp,
data: template.VerifyEmail{
Name: username,
ConfirmationLink: confirmLink,
UnsubscribeLink: "unsubscribe-link",
},
q: n.q,
title: "Verify to",
to: email,
from: n.config.NoReplayEmail,
})
if err != nil {
return errors.Wrap(err, "verify to")
}

return nil
}

func buildConfirmLink(host string, confirmID string) (string, error) {
var sb strings.Builder
var err error

_, err = sb.WriteString(host)
err = multierr.Append(err, err)

_, err = sb.WriteString("/verify?id=")
err = multierr.Append(err, err)

_, err = sb.WriteString(confirmID)
err = multierr.Append(err, err)

return sb.String(), err
}
40 changes: 40 additions & 0 deletions apps/server/internal/pkg/notifier/account_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package notifier

import (
"github.com/google/uuid"
"testing"
)

func Test_buildConfirmLink(t *testing.T) {
type args struct {
host string
confirmID string
}
tt := struct {
name string
args args
want string
wantErr bool
}{

"Basic link",
args{
"localhost",
uuid.Nil.String(),
},
"localhost/verify?id=00000000-0000-0000-0000-000000000000",
false,
}

t.Run(tt.name, func(t *testing.T) {
t.Parallel()
got, err := buildConfirmLink(tt.args.host, tt.args.confirmID)
if (err != nil) != tt.wantErr {
t.Errorf("buildConfirmLink() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("buildConfirmLink() got = %v, want %v", got, tt.want)
}
})
}
49 changes: 49 additions & 0 deletions apps/server/internal/pkg/notifier/email.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package notifier

import (
"bytes"
"encoding/json"
"github.com/go-faster/errors"
"github.com/taskemapp/server/apps/notification/pkg/notifier"
"github.com/taskemapp/server/libs/queue"
"html/template"
)

type sendEmailOpts struct {
temp *template.Template
data any
q queue.Queue
title string
to string
from string
}

func sendEmail(opts sendEmailOpts) error {
var buff bytes.Buffer
err := opts.temp.Execute(&buff, opts.data)
if err != nil {
return errors.Wrap(err, "send email")
}

body, err := json.Marshal(notifier.EmailNotification{
Notification: notifier.Notification{
Title: "Verify email",
Message: buff.String(),
},
To: opts.to,
From: opts.from,
})
if err != nil {
return errors.Wrap(err, "send email")
}

err = opts.q.Publish(notifier.ChannelEmail, queue.Message{
ContentType: "application/json",
Body: body,
})
if err != nil {
return errors.Wrap(err, "send email")
}

return nil
}
73 changes: 73 additions & 0 deletions apps/server/internal/pkg/notifier/email_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package notifier

import (
"bytes"
"encoding/json"
"github.com/stretchr/testify/assert"
"github.com/taskemapp/server/apps/notification/pkg/notifier"
"github.com/taskemapp/server/libs/queue"
"github.com/taskemapp/server/libs/template"
"testing"
)

func Test_sendEmail(t *testing.T) {
type args struct {
name string
to string
title string
from string
}
tt := args{
name: "",
to: "",
title: "",
from: "",
}

//Setup mock
queueMock := queue.NewMockQueue(t)
defer queueMock.AssertExpectations(t)

temp, err := template.Get(template.VerifyEmailTemplate, template.WithDir("../../../../.."))
assert.NoError(t, err)

data := template.VerifyEmail{
Name: tt.name,
ConfirmationLink: "",
UnsubscribeLink: "",
}

var buff bytes.Buffer
err = temp.Execute(&buff, data)
assert.NoError(t, err)

body, err := json.Marshal(notifier.EmailNotification{
Notification: notifier.Notification{
Title: "Verify email",
Message: buff.String(),
},
To: tt.to,
From: tt.from,
})

message := queue.Message{
ContentType: "application/json",
Body: body,
}

queueMock.EXPECT().Publish(notifier.ChannelEmail, message).Return(nil)

//Test starting
err = queueMock.Publish(notifier.ChannelEmail, message)
assert.NoError(t, err)

err = sendEmail(sendEmailOpts{
temp: temp,
data: data,
q: queueMock,
title: tt.title,
to: tt.to,
from: tt.from,
})
assert.NoError(t, err)
}
Loading

0 comments on commit e7f2908

Please sign in to comment.