Skip to content
Merged
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
117 changes: 52 additions & 65 deletions call-profile/main.go
Original file line number Diff line number Diff line change
@@ -1,25 +1,14 @@
package main

import (
"context"
"fmt"
"identity-service/layer/utils"
"log"
"net/http"
"time"

"cloud.google.com/go/firestore"

"github.com/aws/aws-lambda-go/events"
"github.com/aws/aws-lambda-go/lambda"
)

type deps struct {
client *firestore.Client
ctx context.Context
}

func (d *deps) handler(request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
func handler(d *utils.Deps, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) {
var userId, sessionId string = utils.GetDataFromBody([]byte(request.Body))
if userId == "" {
return events.APIGatewayProxyResponse{
Expand All @@ -28,52 +17,63 @@ func (d *deps) handler(request events.APIGatewayProxyRequest) (events.APIGateway
}, nil
}

dsnap, err := d.client.Collection("users").Doc(userId).Get(d.ctx)

var userUrl string
var chaincode string
var discordId string
dsnap, err := d.Client.Collection("users").Doc(userId).Get(d.Ctx)
if err != nil {
return events.APIGatewayProxyResponse{
Body: fmt.Sprintf("Error retrieving user: %v", err),
StatusCode: 500,
}, nil
}

if str, ok := dsnap.Data()["discordId"].(string); ok {
discordId = str
} else {
discordId = ""
data := dsnap.Data()

var user utils.User
err = dsnap.DataTo(&user)
if err != nil {
utils.LogProfileSkipped(d.Client, d.Ctx, "UserData Type Error: "+fmt.Sprintln(err), userId, sessionId)
return events.APIGatewayProxyResponse{
Body: "Profile Skipped No User Data",
StatusCode: 200,
}, nil
}

if str, ok := dsnap.Data()["profileURL"].(string); ok {
userUrl = str
} else {
utils.LogProfileSkipped(d.client, d.ctx, userId, "Profile URL not available", sessionId)
utils.SetProfileStatusBlocked(d.client, d.ctx, userId, "Profile URL not available", sessionId, discordId)
discordId := user.DiscordID

if user.ProfileURL == "" {
utils.LogProfileSkipped(d.Client, d.Ctx, "Profile URL not available", userId, sessionId)
utils.SetProfileStatusBlocked(d.Client, d.Ctx, userId, "Profile URL not available", sessionId, discordId)
return events.APIGatewayProxyResponse{
Body: "Profile Skipped No Profile URL",
StatusCode: 200,
}, nil
}

if str, ok := dsnap.Data()["chaincode"].(string); ok {
if str == "" {
utils.LogProfileSkipped(d.client, d.ctx, userId, "Profile Service Blocked or Chaincode is empty", sessionId)
utils.SetProfileStatusBlocked(d.client, d.ctx, userId, "Profile Service Blocked or Chaincode is empty", sessionId, discordId)
return events.APIGatewayProxyResponse{
Body: "Profile Skipped Profile Service Blocked",
StatusCode: 200,
}, nil
}
chaincode = str
} else {
utils.LogProfileSkipped(d.client, d.ctx, userId, "Chaincode Not Found", sessionId)
utils.SetProfileStatusBlocked(d.client, d.ctx, userId, "Chaincode Not Found", sessionId, discordId)
_, chaincodeExists := data["chaincode"]
if !chaincodeExists {
utils.LogProfileSkipped(d.Client, d.Ctx, "Chaincode Not Found", userId, sessionId)
utils.SetProfileStatusBlocked(d.Client, d.Ctx, userId, "Chaincode Not Found", sessionId, discordId)
return events.APIGatewayProxyResponse{
Body: "Profile Skipped Chaincode Not Found",
StatusCode: 200,
}, nil
}

if user.Chaincode == "" {
utils.LogProfileSkipped(d.Client, d.Ctx, "Profile Service Blocked or Chaincode is empty", userId, sessionId)
utils.SetProfileStatusBlocked(d.Client, d.Ctx, userId, "Profile Service Blocked or Chaincode is empty", sessionId, discordId)
return events.APIGatewayProxyResponse{
Body: "Profile Skipped Profile Service Blocked",
StatusCode: 200,
}, nil
}

userUrl := user.ProfileURL
chaincode := user.Chaincode

var userData utils.Diff
err = dsnap.DataTo(&userData)
if err != nil {
utils.LogProfileSkipped(d.client, d.ctx, userId, "UserData Type Error: "+fmt.Sprintln(err), sessionId)
utils.LogProfileSkipped(d.Client, d.Ctx, "UserData Type Error: "+fmt.Sprintln(err), userId, sessionId)
return events.APIGatewayProxyResponse{
Body: "Profile Skipped No User Data",
StatusCode: 200,
Expand All @@ -83,33 +83,31 @@ func (d *deps) handler(request events.APIGatewayProxyRequest) (events.APIGateway
if userUrl[len(userUrl)-1] != '/' {
userUrl = userUrl + "/"
}

_, serviceErr := utils.GetWithContext(d.Ctx, userUrl+"health", 5*time.Second)
var isServiceRunning bool
c := &http.Client{
Timeout: 5 * time.Second,
}
_, serviceErr := c.Get(userUrl + "health")
if serviceErr != nil {
isServiceRunning = false
} else {
isServiceRunning = true
}

utils.LogHealth(d.client, d.ctx, userId, isServiceRunning, sessionId)
utils.LogHealth(d.Client, d.Ctx, userId, isServiceRunning, sessionId)
if !isServiceRunning {
utils.LogProfileSkipped(d.client, d.ctx, userId, "Profile Service Down", sessionId)
utils.SetProfileStatusBlocked(d.client, d.ctx, userId, "Profile Service Down", sessionId, discordId)
utils.LogProfileSkipped(d.Client, d.Ctx, "Profile Service Down", userId, sessionId)
utils.SetProfileStatusBlocked(d.Client, d.Ctx, userId, "Profile Service Down", sessionId, discordId)
return events.APIGatewayProxyResponse{
Body: "Profile Skipped Service Down",
StatusCode: 200,
}, nil
}

dataErr := utils.Getdata(d.client, d.ctx, userId, userUrl, chaincode, utils.DiffToRes(userData), sessionId, discordId)
if dataErr != "" {
return events.APIGatewayProxyResponse{
Body: "Profile Skipped " + dataErr,
StatusCode: 200,
}, nil
err = utils.Getdata(d.Client, d.Ctx, userId, userUrl, chaincode, utils.DiffToRes(userData), sessionId, discordId)
if err != nil {
if profileErr, ok := err.(*utils.ProfileError); ok {
return utils.HandleProfileSkippedError(profileErr.Message), nil
}
return utils.HandleProfileSkippedError(err.Error()), nil
}

return events.APIGatewayProxyResponse{
Expand All @@ -119,16 +117,5 @@ func (d *deps) handler(request events.APIGatewayProxyRequest) (events.APIGateway
}

func main() {
ctx := context.Background()
client, err := utils.InitializeFirestoreClient(ctx)
if err != nil {
log.Fatalf("Failed to initialize Firestore client: %v", err)
}

d := deps{
client: client,
ctx: ctx,
}

lambda.Start(d.handler)
utils.InitializeLambdaWithFirestore("call-profile", handler)
}
26 changes: 15 additions & 11 deletions call-profile/main_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ func TestHandlerIntegration(t *testing.T) {
"githubId": "johndoe",
"linkedin": "johndoe",
"website": "https://johndoe.com",
"dob": "1990-01-15",
},
mockServer: func() *httptest.Server {
return httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -337,7 +338,8 @@ func TestHandlerIntegration(t *testing.T) {
"designation": "Developer",
"github_id": "johndoe",
"linkedin_id": "johndoe",
"website": "https://johndoe.com"
"website": "https://johndoe.com",
"dob": "1990-01-15"
}`))
}
}))
Expand All @@ -364,8 +366,8 @@ func TestHandlerIntegration(t *testing.T) {
},
userData: nil,
mockServer: nil,
expectedBody: "Profile Skipped No Profile URL",
expectedStatus: 200,
expectedBody: "Error retrieving user: rpc error: code = NotFound desc = \"projects/test-project/databases/(default)/documents/users/non-existent-user\" not found",
expectedStatus: 500,
expectedError: false,
},
{
Expand Down Expand Up @@ -435,7 +437,7 @@ func TestHandlerIntegration(t *testing.T) {
w.Write([]byte("Service Unavailable"))
}))
},
expectedBody: "Profile Skipped error in getting profile data",
expectedBody: "Profile Skipped: error in getting profile data: status code 500",
expectedStatus: 200,
expectedError: false,
},
Expand Down Expand Up @@ -522,6 +524,7 @@ func TestHandlerWithRealFirestore(t *testing.T) {
"githubId": "integrationtest",
"linkedin": "integrationtest",
"website": "https://integrationtest.com",
"dob": "1992-05-20",
}

server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
Expand All @@ -540,7 +543,8 @@ func TestHandlerWithRealFirestore(t *testing.T) {
"designation": "Tester",
"github_id": "integrationtest",
"linkedin_id": "integrationtest",
"website": "https://integrationtest.com"
"website": "https://integrationtest.com",
"dob": "1992-05-20"
}`))
}
}))
Expand Down Expand Up @@ -590,7 +594,7 @@ func TestHandlerEdgeCases(t *testing.T) {
"firstName": 123, // Invalid type
"lastName": "Doe",
},
expectedBody: "Profile Skipped error in getting profile data",
expectedBody: "Profile Skipped: error in getting profile data: status code 404",
expectedStatus: 200,
},
{
Expand All @@ -604,7 +608,7 @@ func TestHandlerEdgeCases(t *testing.T) {
"chaincode": "TESTCHAIN",
"profileStatus": "PENDING",
},
expectedBody: "Profile Skipped error in getting profile data", // Will fail health check
expectedBody: "Profile Skipped: error in getting profile data: status code 404", // Will fail health check
expectedStatus: 200,
},
}
Expand Down Expand Up @@ -635,9 +639,9 @@ func newFirestoreMockClient(ctx context.Context) *firestore.Client {

func handlerWithClient(request events.APIGatewayProxyRequest, client *firestore.Client) (events.APIGatewayProxyResponse, error) {
ctx := context.Background()
d := deps{
client: client,
ctx: ctx,
d := &utils.Deps{
Client: client,
Ctx: ctx,
}
return d.handler(request)
return handler(d, request)
}
74 changes: 74 additions & 0 deletions call-profile/testdata.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ var ResValidationTests = []struct {
TwitterId: "johndoe",
InstagramId: "johndoe",
Website: "https://johndoe.com",
DOB: "1990-01-15",
},
IsValid: true,
Description: "Complete valid Res struct",
Expand Down Expand Up @@ -241,6 +242,78 @@ var ResValidationTests = []struct {
IsValid: false,
Description: "Invalid website URL should fail validation",
},
{
Name: "InvalidDOBFormat_Slash",
Res: utils.Res{
FirstName: "John",
LastName: "Doe",
Email: "john.doe@example.com",
Phone: "1234567890",
YOE: 5,
Company: "Tech Corp",
Designation: "Developer",
GithubId: "johndoe",
LinkedIn: "johndoe",
Website: "https://johndoe.com",
DOB: "01/15/1990",
},
IsValid: false,
Description: "DOB with slash separator should fail validation",
},
{
Name: "InvalidDOBFormat_WrongFormat",
Res: utils.Res{
FirstName: "John",
LastName: "Doe",
Email: "john.doe@example.com",
Phone: "1234567890",
YOE: 5,
Company: "Tech Corp",
Designation: "Developer",
GithubId: "johndoe",
LinkedIn: "johndoe",
Website: "https://johndoe.com",
DOB: "invalid-date",
},
IsValid: false,
Description: "Invalid date string should fail validation",
},
{
Name: "ValidDOB_EmptyString",
Res: utils.Res{
FirstName: "John",
LastName: "Doe",
Email: "john.doe@example.com",
Phone: "1234567890",
YOE: 5,
Company: "Tech Corp",
Designation: "Developer",
GithubId: "johndoe",
LinkedIn: "johndoe",
Website: "https://johndoe.com",
DOB: "",
},
IsValid: true,
Description: "Empty DOB string should be valid (optional field)",
},
{
Name: "ValidDOB_ValidFormat",
Res: utils.Res{
FirstName: "John",
LastName: "Doe",
Email: "john.doe@example.com",
Phone: "1234567890",
YOE: 5,
Company: "Tech Corp",
Designation: "Developer",
GithubId: "johndoe",
LinkedIn: "johndoe",
Website: "https://johndoe.com",
DOB: "1990-01-15",
},
IsValid: true,
Description: "Valid DOB in YYYY-MM-DD format should pass validation",
},
}

var MockResponses = struct {
Expand Down Expand Up @@ -293,3 +366,4 @@ var EmptyUserIdTests = []struct {
Description: "Null userId should return skip message",
},
}

Loading
Loading