add: mockSMTP Server for testing; getUser func
This commit is contained in:
2
go.mod
2
go.mod
@@ -13,6 +13,8 @@ require (
|
||||
|
||||
require github.com/kelseyhightower/envconfig v1.4.0
|
||||
|
||||
require github.com/mocktools/go-smtp-mock/v2 v2.3.1 // indirect
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.11.9 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
|
||||
2
go.sum
2
go.sum
@@ -48,6 +48,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
|
||||
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
|
||||
github.com/mocktools/go-smtp-mock/v2 v2.3.1 h1:wq75NDSsOy5oHo/gEQQT0fRRaYKRqr1IdkjhIPXxagM=
|
||||
github.com/mocktools/go-smtp-mock/v2 v2.3.1/go.mod h1:h9AOf/IXLSU2m/1u4zsjtOM/WddPwdOUBz56dV9f81M=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
|
||||
@@ -34,20 +34,25 @@ func (uc *UserController) RegisterUser(c *gin.Context) {
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode userdata"})
|
||||
return
|
||||
}
|
||||
if regData.User.Membership.SubscriptionModel.Name == "" {
|
||||
logger.Error.Printf("No subscription model provided")
|
||||
c.JSON(http.StatusNotAcceptable, gin.H{"error": "No subscription model provided"})
|
||||
return
|
||||
}
|
||||
|
||||
selectedModel, err := uc.MembershipService.GetModelByName(®Data.User.Membership.SubscriptionModel.Name)
|
||||
if err != nil {
|
||||
logger.Error.Printf("No subscription model found: %#v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Not a valid subscription model"})
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Not a valid subscription model"})
|
||||
return
|
||||
}
|
||||
regData.User.Membership.SubscriptionModel = *selectedModel
|
||||
logger.Info.Printf("REGISTERING user: %#v", regData.User)
|
||||
// logger.Info.Printf("REGISTERING user: %#v", regData.User)
|
||||
// Register User
|
||||
id, token, err := uc.Service.RegisterUser(®Data.User)
|
||||
if err != nil {
|
||||
logger.Error.Printf("Couldn't register User: %v", err)
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": fmt.Sprintf("Couldn't register User: %v", err)})
|
||||
c.JSON(int(id), gin.H{"error": fmt.Sprintf("Couldn't register User: %v", err)})
|
||||
return
|
||||
}
|
||||
regData.User.ID = id
|
||||
|
||||
@@ -3,7 +3,9 @@ package controllers
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
// "io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"os"
|
||||
@@ -12,37 +14,64 @@ import (
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"gorm.io/gorm"
|
||||
"reflect"
|
||||
|
||||
"GoMembership/internal/config"
|
||||
"GoMembership/internal/database"
|
||||
"GoMembership/internal/models"
|
||||
"GoMembership/internal/repositories"
|
||||
"GoMembership/internal/services"
|
||||
"GoMembership/internal/utils"
|
||||
"GoMembership/pkg/logger"
|
||||
)
|
||||
|
||||
type keyValuePair struct {
|
||||
value interface{}
|
||||
key string
|
||||
}
|
||||
|
||||
type test struct {
|
||||
name string
|
||||
wantResponse uint16
|
||||
userEmail string
|
||||
wantDBData []keyValuePair
|
||||
assert bool
|
||||
input string
|
||||
wantDBData map[string]interface{}
|
||||
wantResponse uint16
|
||||
assert bool
|
||||
}
|
||||
|
||||
// type RegistrationData struct {
|
||||
// User models.User `json:"user"`
|
||||
// }
|
||||
|
||||
const (
|
||||
Host = "127.0.0.1"
|
||||
Port int = 2525
|
||||
User = "alex@mail.de"
|
||||
Pass = "secret"
|
||||
AdminMail = "admin@mail.de"
|
||||
)
|
||||
|
||||
var (
|
||||
uc UserController
|
||||
)
|
||||
|
||||
func TestUserController(t *testing.T) {
|
||||
err := database.InitDB("test.db")
|
||||
if err != nil {
|
||||
_ = deleteTestDB("test.db")
|
||||
|
||||
if err := database.InitDB("test.db"); err != nil {
|
||||
t.Errorf("Failed to create DB: %#v", err)
|
||||
}
|
||||
|
||||
if err := os.Setenv("SMTP_HOST", Host); err != nil {
|
||||
t.Errorf("Error setting environment variable: %v", err)
|
||||
}
|
||||
if err := os.Setenv("SMTP_PORT", strconv.Itoa(Port)); err != nil {
|
||||
t.Errorf("Error setting environment variable: %v", err)
|
||||
}
|
||||
if err := os.Setenv("ADMIN_MAIL", AdminMail); err != nil {
|
||||
t.Errorf("Error setting environment variable: %v", err)
|
||||
}
|
||||
if err := os.Setenv("SMTP_USER", User); err != nil {
|
||||
t.Errorf("Error setting environment variable: %v", err)
|
||||
}
|
||||
if err := os.Setenv("SMTP_PASS", Pass); err != nil {
|
||||
t.Errorf("Error setting environment variable: %v", err)
|
||||
}
|
||||
config.LoadConfig()
|
||||
utils.SMTPStart(Host, Port)
|
||||
emailService := services.NewEmailService(config.SMTP.Host, config.SMTP.Port, config.SMTP.User, config.SMTP.Password, config.SMTP.AdminEmail)
|
||||
var consentRepo repositories.ConsentRepositoryInterface = &repositories.ConsentRepository{}
|
||||
consentService := &services.ConsentService{Repo: consentRepo}
|
||||
@@ -57,44 +86,16 @@ func TestUserController(t *testing.T) {
|
||||
var userRepo repositories.UserRepositoryInterface = &repositories.UserRepository{}
|
||||
userService := &services.UserService{Repo: userRepo}
|
||||
|
||||
uc := UserController{Service: userService, EmailService: emailService, ConsentService: consentService, BankAccountService: bankAccountService, MembershipService: membershipService}
|
||||
uc = UserController{Service: userService, EmailService: emailService, ConsentService: consentService, BankAccountService: bankAccountService, MembershipService: membershipService}
|
||||
|
||||
if err := initSubscriptionPlans(); err != nil {
|
||||
t.Errorf("Failed to init Susbcription plans: %#v", err)
|
||||
}
|
||||
|
||||
tests := getTestUsers()
|
||||
|
||||
for _, tt := range tests {
|
||||
c, _ := getMockedContext([]byte(tt.input))
|
||||
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
uc.RegisterUser(c)
|
||||
user, err := userRepo.FindUserByEmail(tt.userEmail)
|
||||
if err == gorm.ErrRecordNotFound && !tt.assert {
|
||||
//pass
|
||||
} else if err == nil && tt.assert {
|
||||
// check value:
|
||||
if tt.wantDBData != nil {
|
||||
for _, kvp := range tt.wantDBData {
|
||||
/* dbValue, err := getFieldValue(*user, kvp.key)
|
||||
if err != nil {
|
||||
t.Errorf("getFieldValue failed: %#v", err)
|
||||
} */
|
||||
dbValue, err := getAttr(&user, kvp.key)
|
||||
if err != nil {
|
||||
t.Errorf("Couldn't get Attribute: %#v", err)
|
||||
}
|
||||
if kvp.value != dbValue {
|
||||
// fail
|
||||
t.Errorf("Value is not expected: %v != %v", kvp.value, dbValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// fail
|
||||
t.Errorf("FindUserByEmail failed: %#v", err)
|
||||
}
|
||||
runSingleTest(t, &tt)
|
||||
})
|
||||
}
|
||||
if err := deleteTestDB("test.db"); err != nil {
|
||||
@@ -102,9 +103,43 @@ func TestUserController(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func runSingleTest(t *testing.T, tt *test) {
|
||||
|
||||
c, w := getMockedContext([]byte(tt.input))
|
||||
uc.RegisterUser(c)
|
||||
|
||||
if w.Code != int(tt.wantResponse) {
|
||||
t.Errorf("Didn't get the expected response code: got: %v; expected: %v", w.Code, tt.wantResponse)
|
||||
}
|
||||
validateUser(t, tt.assert, tt.wantDBData)
|
||||
}
|
||||
|
||||
func handleError(t *testing.T, err error, assert bool) {
|
||||
if err == gorm.ErrRecordNotFound && !assert {
|
||||
return // Expected case: user not found and assertion is false
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
t.Errorf("Error during testing: %#v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func validateUser(t *testing.T, assert bool, wantDBData map[string]interface{}) {
|
||||
users, err := uc.Service.GetUsers(wantDBData)
|
||||
if err != nil {
|
||||
t.Errorf("Error in database ops: %#v", err)
|
||||
}
|
||||
if assert != (len(*users) != 0) {
|
||||
t.Errorf("User entry query didn't met expectation: %v != %#v", assert, *users)
|
||||
}
|
||||
}
|
||||
|
||||
func initSubscriptionPlans() error {
|
||||
subscription := models.SubscriptionModel{
|
||||
Name: "basic",
|
||||
Name: "Basic",
|
||||
Details: "Test Plan",
|
||||
MonthlyFee: 2,
|
||||
HourlyRate: 3,
|
||||
}
|
||||
result := database.DB.Create(&subscription)
|
||||
if result.Error != nil {
|
||||
@@ -117,39 +152,16 @@ func getMockedContext(jsonStr []byte) (*gin.Context, *httptest.ResponseRecorder)
|
||||
gin.SetMode(gin.TestMode)
|
||||
w := httptest.NewRecorder()
|
||||
c, _ := gin.CreateTestContext(w)
|
||||
c.Request, _ = http.NewRequest("POST", "/register", bytes.NewBuffer(jsonStr))
|
||||
var err error
|
||||
c.Request, err = http.NewRequest("POST", "/register", bytes.NewBuffer(jsonStr))
|
||||
if err != nil {
|
||||
logger.Error.Fatalf("Failed to create new Request: %#v", err)
|
||||
}
|
||||
c.Request.Header.Set("Content-Type", "application/json")
|
||||
|
||||
return c, w
|
||||
}
|
||||
|
||||
func getAttr(obj interface{}, fieldName string) (interface{}, error) {
|
||||
pointToStruct := reflect.ValueOf(obj) // addressable
|
||||
curStruct := pointToStruct.Elem()
|
||||
if curStruct.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("expected a struct, but got %v", curStruct.Kind())
|
||||
}
|
||||
curField := curStruct.FieldByName(fieldName) // type: reflect.Value
|
||||
if !curField.IsValid() {
|
||||
return nil, fmt.Errorf("no such field: %s in user", fieldName)
|
||||
}
|
||||
return curField.Interface(), nil
|
||||
}
|
||||
|
||||
/* func getFieldValue(user models.User, fieldName string) (interface{}, error) {
|
||||
v := reflect.ValueOf(user)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
}
|
||||
if v.Kind() != reflect.Struct {
|
||||
return nil, fmt.Errorf("expected a struct, but got %v", v.Kind())
|
||||
}
|
||||
fieldVal := v.FieldByName(fieldName)
|
||||
if !fieldVal.IsValid() {
|
||||
return nil, fmt.Errorf("no such field: %s in user", fieldName)
|
||||
}
|
||||
return fieldVal.Interface(), nil
|
||||
} */
|
||||
|
||||
func deleteTestDB(dbPath string) error {
|
||||
err := os.Remove(dbPath)
|
||||
if err != nil {
|
||||
@@ -159,13 +171,35 @@ func deleteTestDB(dbPath string) error {
|
||||
}
|
||||
|
||||
// TEST DATA:
|
||||
func generateUserJSON(user models.User) string {
|
||||
data, err := json.Marshal(user)
|
||||
func getBaseUser() models.User {
|
||||
return models.User{
|
||||
DateOfBirth: time.Date(2000, time.January, 1, 0, 0, 0, 0, time.UTC),
|
||||
FirstName: "John",
|
||||
LastName: "Doe",
|
||||
Email: "john.doe@example.com",
|
||||
Address: "Pablo Escobar Str. 4",
|
||||
ZipCode: "25474",
|
||||
City: "Hasloh",
|
||||
Phone: "01738484993",
|
||||
BankAccount: models.BankAccount{IBAN: "DE89370400440532013000"},
|
||||
Membership: models.Membership{SubscriptionModel: models.SubscriptionModel{Name: "Basic"}},
|
||||
ProfilePicture: "",
|
||||
Password: "password123",
|
||||
Company: "",
|
||||
}
|
||||
}
|
||||
|
||||
func generateInputJSON(customize func(models.User) models.User) string {
|
||||
user := getBaseUser()
|
||||
user = customize(user) // Apply the customization
|
||||
regData := RegistrationData{User: user}
|
||||
|
||||
jsonBytes, err := json.Marshal(regData)
|
||||
if err != nil {
|
||||
logger.Error.Printf("couldn't generate Json from Uer: %#v\nERROR: %#v", user, err)
|
||||
logger.Error.Printf("couldn't generate Json from User: %#v\nERROR: %#v", regData, err)
|
||||
return ""
|
||||
}
|
||||
return string(data)
|
||||
return string(jsonBytes)
|
||||
}
|
||||
|
||||
func getTestUsers() []test {
|
||||
@@ -173,105 +207,129 @@ func getTestUsers() []test {
|
||||
{
|
||||
name: "birthday < 18 should fail",
|
||||
wantResponse: http.StatusNotAcceptable,
|
||||
wantDBData: []keyValuePair{
|
||||
{
|
||||
key: "Email",
|
||||
value: "john.doe@example.com"},
|
||||
},
|
||||
wantDBData: map[string]interface{}{"email": "john.doe@example.com"},
|
||||
assert: false,
|
||||
input: generateUserJSON(
|
||||
models.User{
|
||||
DateOfBirth: time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC),
|
||||
FirstName: "John",
|
||||
LastName: "Doe",
|
||||
Email: "john.doe@example.com",
|
||||
Address: "123 Main St",
|
||||
ZipCode: "12345",
|
||||
City: "Cityville",
|
||||
Phone: "123-456-7890",
|
||||
BankAccount: models.BankAccount{IBAN: "DE89370400440532013000"},
|
||||
Membership: models.Membership{SubscriptionModel: models.SubscriptionModel{Name: "Basic"}},
|
||||
ProfilePicture: "http://example.com/profile.jpg",
|
||||
Company: nil,
|
||||
Notes: nil,
|
||||
Password: "password123",
|
||||
ID: 1,
|
||||
PaymentStatus: 1,
|
||||
Status: 1,
|
||||
RoleID: 1,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.DateOfBirth = time.Date(2020, time.January, 1, 0, 0, 0, 0, time.UTC)
|
||||
return user
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "FirstName empty, should fail",
|
||||
wantResponse: http.StatusNotAcceptable,
|
||||
wantDBData: []keyValuePair{
|
||||
{
|
||||
key: "Email",
|
||||
value: "john.doe@example.com"},
|
||||
},
|
||||
wantDBData: map[string]interface{}{"email": "john.doe@example.com"},
|
||||
assert: false,
|
||||
input: generateUserJSON(
|
||||
models.User{
|
||||
DateOfBirth: time.Date(1990, time.January, 1, 0, 0, 0, 0, time.UTC),
|
||||
FirstName: "",
|
||||
LastName: "Doe",
|
||||
Email: "john.doe@example.com",
|
||||
Address: "123 Main St",
|
||||
ZipCode: "12345",
|
||||
City: "Cityville",
|
||||
Phone: "123-456-7890",
|
||||
BankAccount: models.BankAccount{IBAN: "DE89370400440532013000"},
|
||||
Membership: models.Membership{SubscriptionModel: models.SubscriptionModel{Name: "Basic"}},
|
||||
ProfilePicture: "http://example.com/profile.jpg",
|
||||
Company: nil,
|
||||
Notes: nil,
|
||||
Password: "password123",
|
||||
ID: 1,
|
||||
PaymentStatus: 1,
|
||||
Status: 1,
|
||||
RoleID: 1,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.FirstName = ""
|
||||
return user
|
||||
}),
|
||||
},
|
||||
/* Vjjjjjjjj
|
||||
models.User {
|
||||
DateOfBirth: time.Date(1985, time.March, 15, 0, 0, 0, 0, time.UTC),
|
||||
FirstName: "Jane",
|
||||
LastName: "Smith",
|
||||
Email: "jane.smith@example.com",
|
||||
Address: "456 Oak St",
|
||||
ZipCode: "67890",
|
||||
City: "Townsville",
|
||||
Phone: "098-765-4321",
|
||||
BankAccount: models.BankAccount{IBAN: "FR7630006000011234567890189"},
|
||||
Membership: models.Membership{SubscriptionModel: SubscriptionModel{Name: "Premium", Details: "Premium Subscription", Conditions: "None", MonthlyFee: 19.99, HourlyRate: 25.00}},
|
||||
ProfilePicture: "http://example.com/profile2.jpg",
|
||||
Company: stringPtr("ExampleCorp"),
|
||||
Notes: stringPtr("Important client"),
|
||||
Password: "securepassword456",
|
||||
ID: 2,
|
||||
PaymentStatus: 0,
|
||||
Status: 2,
|
||||
RoleID: 2,
|
||||
{
|
||||
name: "LastName Empty should fail",
|
||||
wantResponse: http.StatusNotAcceptable,
|
||||
wantDBData: map[string]interface{}{"email": "john.doe@example.com"},
|
||||
assert: false,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.LastName = ""
|
||||
return user
|
||||
}),
|
||||
},
|
||||
{
|
||||
DateOfBirth: time.Date(2000, time.July, 30, 0, 0, 0, 0, time.UTC),
|
||||
FirstName: "Alice",
|
||||
LastName: "Brown",
|
||||
Email: "alice.brown@example.com",
|
||||
Address: "789 Pine St",
|
||||
ZipCode: "11223",
|
||||
City: "Villageville",
|
||||
Phone: "555-555-5555",
|
||||
BankAccount: models.BankAccount{IBAN: "GB29NWBK60161331926819"},
|
||||
Membership: models.Membership{SubscriptionModel: SubscriptionModel{Name: "Standard", Details: "Standard Subscription", Conditions: "None", MonthlyFee: 14.99, HourlyRate: 20.00}},
|
||||
ProfilePicture: "",
|
||||
Company: stringPtr("AnotherCorp"),
|
||||
Notes: nil,
|
||||
Password: "mypassword789",
|
||||
ID: 3,
|
||||
PaymentStatus: 1,
|
||||
Status: 1,
|
||||
RoleID: 3,
|
||||
}, */
|
||||
name: "EMail wrong format should fail",
|
||||
wantResponse: http.StatusNotAcceptable,
|
||||
wantDBData: map[string]interface{}{"email": "johnexample.com"},
|
||||
assert: false,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.Email = "johnexample.com"
|
||||
return user
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Missing Zip Code should fail",
|
||||
wantResponse: http.StatusNotAcceptable,
|
||||
wantDBData: map[string]interface{}{"email": "john.doe@example.com"},
|
||||
assert: false,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.ZipCode = ""
|
||||
return user
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Missing Address should fail",
|
||||
wantResponse: http.StatusNotAcceptable,
|
||||
wantDBData: map[string]interface{}{"email": "john.doe@example.com"},
|
||||
assert: false,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.Address = ""
|
||||
return user
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Missing City should fail",
|
||||
wantResponse: http.StatusNotAcceptable,
|
||||
wantDBData: map[string]interface{}{"email": "john.doe@example.com"},
|
||||
assert: false,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.City = ""
|
||||
return user
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Missing IBAN should fail",
|
||||
wantResponse: http.StatusNotAcceptable,
|
||||
wantDBData: map[string]interface{}{"email": "john.doe@example.com"},
|
||||
assert: false,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.BankAccount.IBAN = ""
|
||||
return user
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Invalid IBAN should fail",
|
||||
wantResponse: http.StatusNotAcceptable,
|
||||
wantDBData: map[string]interface{}{"email": "john.doe@example.com"},
|
||||
assert: false,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.BankAccount.IBAN = "DE1234234123134"
|
||||
return user
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Missing subscription plan should fail",
|
||||
wantResponse: http.StatusNotAcceptable,
|
||||
wantDBData: map[string]interface{}{"email": "john.doe@example.com"},
|
||||
assert: false,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.Membership.SubscriptionModel.Name = ""
|
||||
return user
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Invalid subscription plan should fail",
|
||||
wantResponse: http.StatusNotFound,
|
||||
wantDBData: map[string]interface{}{"email": "john.doe@example.com"},
|
||||
assert: false,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.Membership.SubscriptionModel.Name = "NOTEXISTENTPLAN"
|
||||
return user
|
||||
}),
|
||||
},
|
||||
{
|
||||
name: "Correct Entry should pass",
|
||||
wantResponse: http.StatusCreated,
|
||||
wantDBData: map[string]interface{}{"Email": "john.doe@example.com"},
|
||||
assert: true,
|
||||
input: generateInputJSON(func(user models.User) models.User { return user }),
|
||||
},
|
||||
{
|
||||
name: "Email duplicate should fail",
|
||||
wantResponse: http.StatusConflict,
|
||||
wantDBData: map[string]interface{}{"first_name": "Jane"},
|
||||
assert: false,
|
||||
input: generateInputJSON(func(user models.User) models.User {
|
||||
user.FirstName = "Jane"
|
||||
return user
|
||||
}),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,14 +11,14 @@ type User struct {
|
||||
DateOfBirth time.Time `gorm:"not null" json:"date_of_birth" validate:"required,age"`
|
||||
CreatedAt time.Time
|
||||
Salt *string `json:"-"`
|
||||
Company *string `json:"company" validate:"omitempty,omitnil"`
|
||||
Company string `json:"company" validate:"omitempty,omitnil"`
|
||||
Phone string `json:"phone" validate:"omitempty,omitnil"`
|
||||
Notes *string `json:"notes"`
|
||||
FirstName string `gorm:"not null" json:"first_name" validate:"required"`
|
||||
Password string `json:"password"`
|
||||
Email string `gorm:"unique;not null" json:"email" validate:"required,email"`
|
||||
LastName string `gorm:"not null" json:"last_name" validate:"required"`
|
||||
ProfilePicture string `json:"profile_picture" validate:"omitempty,image"`
|
||||
ProfilePicture string `json:"profile_picture" validate:"omitempty,omitnil,image"`
|
||||
Address string `gorm:"not null" json:"address" validate:"required"`
|
||||
ZipCode string `gorm:"not null" json:"zip_code" validate:"required,alphanum"`
|
||||
City string `form:"not null" json:"city" validate:"required,alphaunicode"`
|
||||
|
||||
@@ -17,6 +17,7 @@ import (
|
||||
type UserRepositoryInterface interface {
|
||||
CreateUser(user *models.User) (int64, error)
|
||||
UpdateUser(userID int64, user *models.User) error
|
||||
GetUsers(where map[string]interface{}) (*[]models.User, error)
|
||||
FindUserByID(id int64) (*models.User, error)
|
||||
FindUserByEmail(email string) (*models.User, error)
|
||||
SetVerificationToken(user *models.User, token *string) (int64, error)
|
||||
@@ -51,6 +52,24 @@ func (ur *UserRepository) UpdateUser(userID int64, user *models.User) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ur *UserRepository) GetUsers(where map[string]interface{}) (*[]models.User, error) {
|
||||
var users []models.User
|
||||
result := database.DB.
|
||||
Preload("Consents").
|
||||
Preload("BankAccount").
|
||||
Preload("Verification").
|
||||
Preload("Membership", func(db *gorm.DB) *gorm.DB {
|
||||
return db.Preload("SubscriptionModel")
|
||||
}).Where(where).Find(&users)
|
||||
if result.Error != nil {
|
||||
if result.Error == gorm.ErrRecordNotFound {
|
||||
return nil, gorm.ErrRecordNotFound
|
||||
}
|
||||
return nil, result.Error
|
||||
}
|
||||
return &users, nil
|
||||
}
|
||||
|
||||
func (ur *UserRepository) FindUserByID(id int64) (*models.User, error) {
|
||||
var user models.User
|
||||
result := database.DB.
|
||||
|
||||
@@ -86,7 +86,7 @@ func (s *EmailService) SendWelcomeEmail(user *models.User) error {
|
||||
MembershipFee float32
|
||||
RentalFee float32
|
||||
}{
|
||||
Company: *user.Company,
|
||||
Company: user.Company,
|
||||
FirstName: user.FirstName,
|
||||
MembershipModel: user.Membership.SubscriptionModel.Name,
|
||||
MembershipID: user.Membership.ID,
|
||||
@@ -121,7 +121,7 @@ func (s *EmailService) NotifyAdminOfNewUser(user *models.User) error {
|
||||
RentalFee float32
|
||||
MembershipFee float32
|
||||
}{
|
||||
Company: *user.Company,
|
||||
Company: user.Company,
|
||||
FirstName: user.FirstName,
|
||||
LastName: user.LastName,
|
||||
MembershipModel: user.Membership.SubscriptionModel.Name,
|
||||
|
||||
@@ -1,20 +1,24 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
|
||||
"GoMembership/internal/constants"
|
||||
"GoMembership/internal/models"
|
||||
"GoMembership/internal/repositories"
|
||||
"GoMembership/internal/utils"
|
||||
"GoMembership/pkg/logger"
|
||||
"github.com/go-playground/validator/v10"
|
||||
// "crypto/rand"
|
||||
// "encoding/base64"
|
||||
// "golang.org/x/crypto/bcrypt"
|
||||
|
||||
"time"
|
||||
)
|
||||
|
||||
type UserServiceInterface interface {
|
||||
RegisterUser(user *models.User) (int64, string, error)
|
||||
FindUserByEmail(email string) (*models.User, error)
|
||||
GetUsers(where map[string]interface{}) (*[]models.User, error)
|
||||
// AuthenticateUser(email, password string) (*models.User, error)A
|
||||
VerifyUser(token *string) (*models.User, error)
|
||||
}
|
||||
@@ -32,7 +36,7 @@ func (service *UserService) RegisterUser(user *models.User) (int64, string, erro
|
||||
*/
|
||||
err := validateRegistrationData(user)
|
||||
if err != nil {
|
||||
return -1, "", err
|
||||
return http.StatusNotAcceptable, "", err
|
||||
}
|
||||
|
||||
user.Status = constants.UnverifiedStatus
|
||||
@@ -40,27 +44,38 @@ func (service *UserService) RegisterUser(user *models.User) (int64, string, erro
|
||||
user.UpdatedAt = time.Now()
|
||||
|
||||
id, err := service.Repo.CreateUser(user)
|
||||
if err != nil {
|
||||
return -1, "", err
|
||||
|
||||
if err != nil && strings.Contains(err.Error(), "UNIQUE constraint failed") {
|
||||
return http.StatusConflict, "", err
|
||||
} else if err != nil {
|
||||
return http.StatusInternalServerError, "", err
|
||||
}
|
||||
|
||||
user.ID = id
|
||||
|
||||
token, err := utils.GenerateVerificationToken()
|
||||
if err != nil {
|
||||
return -1, "", err
|
||||
return http.StatusInternalServerError, "", err
|
||||
}
|
||||
|
||||
logger.Info.Printf("TOKEN: %v", token)
|
||||
|
||||
_, err = service.Repo.SetVerificationToken(user, &token)
|
||||
if err != nil {
|
||||
return -1, "", err
|
||||
return http.StatusInternalServerError, "", err
|
||||
}
|
||||
|
||||
return id, token, nil
|
||||
}
|
||||
|
||||
func (service *UserService) FindUserByEmail(email string) (*models.User, error) {
|
||||
return service.Repo.FindUserByEmail(email)
|
||||
}
|
||||
|
||||
func (service *UserService) GetUsers(where map[string]interface{}) (*[]models.User, error) {
|
||||
return service.Repo.GetUsers(where)
|
||||
}
|
||||
|
||||
func (service *UserService) VerifyUser(token *string) (*models.User, error) {
|
||||
user, err := service.Repo.VerifyUserOfToken(token)
|
||||
if err != nil {
|
||||
|
||||
33
internal/utils/mock_smtp.go
Normal file
33
internal/utils/mock_smtp.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
smtpmock "github.com/mocktools/go-smtp-mock/v2"
|
||||
)
|
||||
|
||||
var Server smtpmock.Server
|
||||
|
||||
// StartMockSMTPServer starts a mock SMTP server for testing
|
||||
func SMTPStart(host string, port int) error {
|
||||
Server = *smtpmock.New(smtpmock.ConfigurationAttr{
|
||||
HostAddress: host,
|
||||
PortNumber: port,
|
||||
LogToStdout: false,
|
||||
LogServerActivity: false,
|
||||
})
|
||||
if err := Server.Start(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func SMTPGetMessages() []smtpmock.Message {
|
||||
return Server.MessagesAndPurge()
|
||||
}
|
||||
|
||||
func SMTPStop() error {
|
||||
|
||||
if err := Server.Stop(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user