Skip to content

Commit

Permalink
add email and user service
Browse files Browse the repository at this point in the history
  • Loading branch information
Lukmanern committed Jan 24, 2024
1 parent dfca9b1 commit 191895b
Show file tree
Hide file tree
Showing 8 changed files with 851 additions and 12 deletions.
27 changes: 26 additions & 1 deletion domain/model/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,19 @@ import (
"github.com/Lukmanern/gost/domain/entity"
)

type User struct {
ID int `gorm:"type:bigserial;primaryKey" json:"id"`
Name string `gorm:"type:varchar(100) not null" json:"name"`
Email string `gorm:"type:varchar(100) not null unique" json:"email"`
Password string `gorm:"type:varchar(255) not null" json:"password"`
ActivatedAt *time.Time `gorm:"type:timestamp null;default:null" json:"activated_at"`
}

type UserRegister struct {
Name string `validate:"required,min=2,max=60" json:"name"`
Email string `validate:"required,email,min=5,max=60" json:"email"`
Password string `validate:"required,min=8,max=30" json:"password"`
RoleID int `validate:"required,numeric,min=1" json:"role_id"`
RolesID []int `validate:"required" json:"role_id"`
}

type UserActivation struct {
Expand All @@ -24,6 +32,23 @@ type UserLogin struct {
IP string `validate:"required,min=4,max=20" json:"ip"`
}

// ID int `gorm:"type:bigserial;primaryKey" json:"id"`
// Name string `gorm:"type:varchar(100) not null" json:"name"`
// Email string `gorm:"type:varchar(100) not null unique" json:"email"`
// Password string `gorm:"type:varchar(255) not null" json:"password"`
// ActivatedAt *time.Time `gorm:"type:timestamp null;default:null" json:"activated_at"`
// Roles []Role `gorm:"many2many:user_has_roles" json:"roles"`

type UserUpdate struct {
ID int `gorm:"type:bigserial;primaryKey" json:"id"`
Name string `gorm:"type:varchar(100) not null" json:"name"`
}

type UserUpdateRoles struct {
ID int `gorm:"type:bigserial;primaryKey" json:"id"`
RolesID []int `validate:"required" json:"role_id"`
}

type UserForgetPassword struct {
Email string `validate:"required,email,min=5,max=60" json:"email"`
}
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/Lukmanern/gost
go 1.20

require (
github.com/XANi/loremipsum v1.1.0
github.com/go-redis/redis v6.15.9+incompatible
github.com/gofiber/fiber/v2 v2.50.0
github.com/golang-jwt/jwt/v5 v5.0.0
Expand All @@ -17,7 +18,6 @@ require (

require (
github.com/BurntSushi/toml v1.2.1 // indirect
github.com/XANi/loremipsum v1.1.0 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/uuid v1.3.1 // indirect
Expand Down
1 change: 1 addition & 0 deletions internal/consts/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const (
InvalidID = "invalid ID"
NilValue = "error nil value"
InvalidToken = "invalid token / JWT, please logout and try-login"
ErrHashing = "error while hashing password"
)

const (
Expand Down
18 changes: 10 additions & 8 deletions repository/user/user_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import (

type UserRepository interface {
// Create adds a new user to the repository with a specified role.
Create(ctx context.Context, user entity.User, roleID int) (id int, err error)
Create(ctx context.Context, user entity.User, roleIDs []int) (id int, err error)

// GetByID retrieves a user by their unique identifier.
GetByID(ctx context.Context, id int) (user *entity.User, err error)
Expand Down Expand Up @@ -57,20 +57,22 @@ func NewUserRepository() UserRepository {
return userRepositoryImpl
}

func (repo *UserRepositoryImpl) Create(ctx context.Context, user entity.User, roleID int) (id int, err error) {
func (repo *UserRepositoryImpl) Create(ctx context.Context, user entity.User, roleIDs []int) (id int, err error) {
err = repo.db.Transaction(func(tx *gorm.DB) error {
if res := tx.Create(&user); res.Error != nil {
tx.Rollback()
return res.Error
}
id = user.ID

if res := tx.Create(&entity.UserHasRoles{
UserID: id,
RoleID: roleID,
}); res.Error != nil {
tx.Rollback()
return res.Error
for _, roleID := range roleIDs {
if res := tx.Create(&entity.UserHasRoles{
UserID: id,
RoleID: roleID,
}); res.Error != nil {
tx.Rollback()
return res.Error
}
}
return nil
})
Expand Down
4 changes: 2 additions & 2 deletions repository/user/user_repository_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ func TestCreateDelete(t *testing.T) {
log.Println(tc.Name, headerTestName)

tc.Payload.SetCreateTime()
id, createErr := repository.Create(ctx, tc.Payload, 1)
id, createErr := repository.Create(ctx, tc.Payload, []int{1})
if tc.WantErr {
assert.Error(t, createErr, consts.ShouldErr, tc.Name, headerTestName)
continue
Expand Down Expand Up @@ -443,7 +443,7 @@ func createUser() entity.User {
ActivatedAt: &timeNow,
}
newUser.SetCreateTime()
userID, createErr := repository.Create(ctx, newUser, 1)
userID, createErr := repository.Create(ctx, newUser, []int{1})
if createErr != nil {
log.Fatal("error while create new user", headerTestName)
}
Expand Down
66 changes: 66 additions & 0 deletions service/email_service/email_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package service

import (
"fmt"
"net/smtp"
"strings"
"sync"

"github.com/Lukmanern/gost/internal/env"
"github.com/Lukmanern/gost/internal/helper"
)

type EmailService interface {
// SendMail func sends message with subject to some emails address.
SendMail(subject, message string, emails ...string) error
}

type EmailServiceImpl struct {
Server string
Port int
Email string
Password string
SmptAuth smtp.Auth
SmptMime string
SmptAddr string
}

var (
emailService *EmailServiceImpl
emailServiceOnce sync.Once
)

func NewEmailService() EmailService {
emailServiceOnce.Do(func() {
config := env.Configuration()
emailService = &EmailServiceImpl{
Server: config.SMTPServer,
Port: config.SMTPPort,
Email: config.SMTPEmail,
Password: config.SMTPPassword,
}

emailService.SmptAuth = smtp.PlainAuth("", emailService.Email, emailService.Password, emailService.Server)
emailService.SmptAddr = fmt.Sprintf("%s:%d", emailService.Server, emailService.Port)
emailService.SmptMime = "MIME-version: 1.0;\nContent-Type: text/html; charset=\"UTF-8\";\r\n"
})

return emailService
}

func (svc *EmailServiceImpl) SendMail(subject, message string, emails ...string) error {
validateErr := helper.ValidateEmails(emails...)
if validateErr != nil {
return validateErr
}
body := "From: " + "CONFIG_SENDER_NAME" + "\n" +
"To: " + strings.Join(emails, ",") + "\n" +
"Subject: " + subject + "\n" + svc.SmptMime + "\n\n" +
message

err := smtp.SendMail(svc.SmptAddr, svc.SmptAuth, svc.Email, emails, []byte(body))
if err != nil {
return err
}
return nil
}
Loading

0 comments on commit 191895b

Please sign in to comment.