add: Login system
This commit is contained in:
@@ -6,7 +6,6 @@ import (
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
|
||||
"GoMembership/internal/config"
|
||||
"GoMembership/internal/models"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@@ -64,7 +63,6 @@ func validateSubscription(assert bool, wantDBData map[string]interface{}) error
|
||||
|
||||
func getBaseSubscription() MembershipData {
|
||||
return MembershipData{
|
||||
APIKey: config.Auth.APIKEY,
|
||||
Model: models.SubscriptionModel{
|
||||
Name: "Just a Subscription",
|
||||
Details: "A subscription detail",
|
||||
@@ -80,28 +78,6 @@ func customizeSubscription(customize func(MembershipData) MembershipData) Member
|
||||
|
||||
func getSubscriptionData() []RegisterSubscriptionTest {
|
||||
return []RegisterSubscriptionTest{
|
||||
{
|
||||
Name: "No API Key should fail",
|
||||
WantResponse: http.StatusUnauthorized,
|
||||
WantDBData: map[string]interface{}{"name": "Just a Subscription"},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.APIKey = ""
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
{
|
||||
Name: "Wrong API Key should fail",
|
||||
WantResponse: http.StatusUnauthorized,
|
||||
WantDBData: map[string]interface{}{"name": "Just a Subscription"},
|
||||
Assert: false,
|
||||
Input: GenerateInputJSON(
|
||||
customizeSubscription(func(subscription MembershipData) MembershipData {
|
||||
subscription.APIKey = "alskfdlkjsfjk23-dF"
|
||||
return subscription
|
||||
})),
|
||||
},
|
||||
{
|
||||
Name: "No Details should fail",
|
||||
WantResponse: http.StatusNotAcceptable,
|
||||
|
||||
@@ -3,6 +3,8 @@ package controllers
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"GoMembership/internal/constants"
|
||||
"GoMembership/internal/middlewares"
|
||||
"GoMembership/internal/models"
|
||||
"GoMembership/internal/services"
|
||||
|
||||
@@ -25,6 +27,51 @@ type RegistrationData struct {
|
||||
User models.User `json:"user"`
|
||||
}
|
||||
|
||||
func (uc *UserController) LoginUser(c *gin.Context) {
|
||||
var input struct {
|
||||
Email string `json:"email"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
if err := c.ShouldBindJSON(&input); err != nil {
|
||||
logger.Error.Printf("Couldn't decode input: %v", err.Error())
|
||||
c.JSON(http.StatusBadRequest, gin.H{"error": "Couldn't decode request data"})
|
||||
return
|
||||
}
|
||||
|
||||
user, err := uc.Service.GetUserByEmail(input.Email)
|
||||
if err != nil {
|
||||
logger.Error.Printf("Error during user(%v) retrieval: %v\n", input.Email, err)
|
||||
c.JSON(http.StatusNotFound, gin.H{"error": "Couldn't find user"})
|
||||
return
|
||||
}
|
||||
|
||||
ok, err := user.PasswordMatches(input.Password)
|
||||
if err != nil {
|
||||
|
||||
logger.Error.Printf("Error during Password comparison: %v", err.Error())
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "couldn't calculate match"})
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
|
||||
logger.Error.Printf("Wrong Password: %v %v", user.FirstName, user.LastName)
|
||||
c.JSON(http.StatusNotAcceptable, gin.H{"error": "Wrong Password"})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := middlewares.GenerateToken(user.ID)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate JWT token"})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"message": "Login successful",
|
||||
"token": token,
|
||||
})
|
||||
}
|
||||
|
||||
func (uc *UserController) RegisterUser(c *gin.Context) {
|
||||
|
||||
var regData RegistrationData
|
||||
@@ -48,6 +95,9 @@ func (uc *UserController) RegisterUser(c *gin.Context) {
|
||||
}
|
||||
regData.User.Membership.SubscriptionModel = *selectedModel
|
||||
// logger.Info.Printf("REGISTERING user: %#v", regData.User)
|
||||
|
||||
regData.User.RoleID = constants.Roles.Member
|
||||
|
||||
// Register User
|
||||
id, token, err := uc.Service.RegisterUser(®Data.User)
|
||||
if err != nil {
|
||||
@@ -93,8 +143,8 @@ func (uc *UserController) RegisterUser(c *gin.Context) {
|
||||
// Proceed without returning error since user registration is successful
|
||||
}
|
||||
c.JSON(http.StatusCreated, gin.H{
|
||||
"status": "success",
|
||||
"id": regData.User.ID,
|
||||
"message": "Registration successuful",
|
||||
"id": regData.User.ID,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"GoMembership/internal/config"
|
||||
"GoMembership/internal/constants"
|
||||
@@ -57,8 +59,74 @@ func TestUserController(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
testLoginUser(t)
|
||||
}
|
||||
|
||||
func testLoginUser(t *testing.T) {
|
||||
// This test should run after the user registration test
|
||||
t.Run("LoginUser", func(t *testing.T) {
|
||||
// Test cases
|
||||
tests := []struct {
|
||||
name string
|
||||
input string
|
||||
wantStatusCode int
|
||||
wantToken bool
|
||||
}{
|
||||
{
|
||||
name: "Valid login",
|
||||
input: `{
|
||||
"email": "john.doe@example.com",
|
||||
"password": "password123"
|
||||
}`,
|
||||
wantStatusCode: http.StatusOK,
|
||||
wantToken: true,
|
||||
},
|
||||
{
|
||||
name: "Invalid email",
|
||||
input: `{
|
||||
"email": "nonexistent@example.com",
|
||||
"password": "password123"
|
||||
}`,
|
||||
wantStatusCode: http.StatusNotFound,
|
||||
wantToken: false,
|
||||
},
|
||||
{
|
||||
name: "Invalid password",
|
||||
input: `{
|
||||
"email": "john.doe@example.com",
|
||||
"password": "wrongpassword"
|
||||
}`,
|
||||
wantStatusCode: http.StatusNotAcceptable,
|
||||
wantToken: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Setup
|
||||
c, w, _ := GetMockedJSONContext([]byte(tt.input), "/login")
|
||||
|
||||
// Execute
|
||||
Uc.LoginUser(c)
|
||||
|
||||
// Assert
|
||||
assert.Equal(t, tt.wantStatusCode, w.Code)
|
||||
|
||||
var response map[string]interface{}
|
||||
err := json.Unmarshal(w.Body.Bytes(), &response)
|
||||
assert.NoError(t, err)
|
||||
|
||||
if tt.wantToken {
|
||||
logger.Info.Printf("Response: %#v", response)
|
||||
assert.Contains(t, response, "token")
|
||||
assert.NotEmpty(t, response["token"])
|
||||
} else {
|
||||
assert.NotContains(t, response, "token")
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
func validateUser(assert bool, wantDBData map[string]interface{}) error {
|
||||
users, err := Uc.Service.GetUsers(wantDBData)
|
||||
if err != nil {
|
||||
@@ -223,7 +291,7 @@ func verifyMail(verificationURL string) error {
|
||||
router := gin.New()
|
||||
router.LoadHTMLGlob(filepath.Join(config.Templates.HTMLPath, "*"))
|
||||
|
||||
router.GET("/backend/verify", Uc.VerifyMailHandler)
|
||||
router.GET("/verify", Uc.VerifyMailHandler)
|
||||
wv := httptest.NewRecorder()
|
||||
cv, _ := gin.CreateTestContext(wv)
|
||||
var err error
|
||||
|
||||
Reference in New Issue
Block a user