diff --git a/cmd/main/main b/cmd/main/main index 7069426..b9bef3d 100755 Binary files a/cmd/main/main and b/cmd/main/main differ diff --git a/pkg/controllers/gacha-controller.go b/pkg/controllers/gacha-controller.go index 4e9bcfb..69aa8c0 100644 --- a/pkg/controllers/gacha-controller.go +++ b/pkg/controllers/gacha-controller.go @@ -5,63 +5,33 @@ import ( "fmt" "io/ioutil" "net/http" - "strconv" - "github.com/gorilla/mux" "github.com/iamananya/ginco-task/pkg/models" "github.com/iamananya/ginco-task/pkg/utils" ) var NewUser models.User - -/* -TODO----(Task completed) - -[*] Handle case for empty name- return error (Error code 400), non exisiting user ID return error -[*] Autogenerate Token Don't take it from user -[*] For UpdateUser don't show response -[*] Check swagger yaml for responses. - -*/ +var NewCharacter models.Character func GetUser(w http.ResponseWriter, r *http.Request) { - newUsers := models.GetAllUsers() - res, _ := json.Marshal(newUsers) - w.Header().Set("Content-Type", "application/json") - w.WriteHeader(http.StatusOK) - w.Write(res) -} + // Authenticate user using x-token in headers to get user details----- + token := r.Header.Get("X-Token") + user := models.GetAllUsers(token) -func GetUserById(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - userId := vars["userId"] - ID, err := strconv.ParseInt(userId, 0, 0) - if err != nil { - fmt.Println("error while parsing") - w.WriteHeader(http.StatusBadRequest) - return - } - // Invalid ID error handling done here - - userDetails, db := models.GetUserById(ID) - if db.Error != nil { - if db.RecordNotFound() { - w.WriteHeader(http.StatusNotFound) - } else { - w.WriteHeader(http.StatusInternalServerError) - } + if user == nil { + w.WriteHeader(http.StatusNotFound) return } - res, err := json.Marshal(userDetails) + res, err := json.Marshal(user) if err != nil { w.WriteHeader(http.StatusInternalServerError) return } + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) w.Write(res) - } func CreateUser(w http.ResponseWriter, r *http.Request) { @@ -97,26 +67,107 @@ func CreateUser(w http.ResponseWriter, r *http.Request) { } -// UpdateUser does not show any reponse. - func UpdateUser(w http.ResponseWriter, r *http.Request) { - var updateUser = &models.User{} - utils.ParseBody(r, updateUser) - vars := mux.Vars(r) - userId := vars["userId"] - ID, err := strconv.ParseInt(userId, 0, 0) - if err != nil { - fmt.Println("error while parsing") + // Authenticate user using x-token in headers to get user details-------- + + var updateUser models.User + utils.ParseBody(r, &updateUser) + token := r.Header.Get("X-Token") + user := models.GetUserByToken(token) + fmt.Print(user) + + if user == nil { + w.WriteHeader(http.StatusNotFound) + return } - userDetails, db := models.GetUserById(ID) + if updateUser.Name != "" { - userDetails.Name = updateUser.Name + user[0].Name = updateUser.Name } if updateUser.Token != "" { - userDetails.Token = updateUser.Token + user[0].Token = updateUser.Token + } + + err := models.UpdateUser(&user[0]) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + return + } + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) +} + +func ListCharacters(w http.ResponseWriter, r *http.Request) { + + characters := models.GetAllCharacters() + + res, _ := json.Marshal(characters) + + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusOK) + w.Write(res) +} + +func HandleGachaDraw(w http.ResponseWriter, r *http.Request) { + + var reqBody models.GachaDrawRequest + err := json.NewDecoder(r.Body).Decode(&reqBody) + if err != nil { + http.Error(w, "Invalid request body", http.StatusBadRequest) + return } - db.Save(&userDetails) + fmt.Printf("Received request: %+v\n", reqBody) + characters := models.GetAllCharacters() + characterPool := generateCharacterPool(characters) + response := models.GachaDrawResponse{ + Results: []models.CharacterResponse{}, + } + // fmt.Println(reqBody.NumTrials) + for i := 0; i < reqBody.Times; i++ { + character := models.DrawCharacter(characters, characterPool) // Simulate drawing a character + fmt.Println(character) + response.Results = append(response.Results, models.CharacterResponse{ + CharacterID: fmt.Sprintf("Character-%d", character.ID), + Name: character.Name, + }) + + } + + respBody, err := json.Marshal(response) + if err != nil { + http.Error(w, "Error creating response", http.StatusInternalServerError) + return + } + w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) + w.Write(respBody) + +} +func generateCharacterPool(characters []models.Character) []models.Character { + var characterPool []models.Character + + for _, character := range characters { + rarity := character.Rarity + + // Assign the probability based on rarity + var probability int + switch rarity { + case "SSR": + probability = 5 + case "SR": + probability = 15 + case "R": + probability = 80 + } + + // Add the character to the pool multiple times based on its probability + poolSize := probability + for i := 0; i < poolSize; i++ { + characterPool = append(characterPool, character) + } + } + return characterPool } diff --git a/pkg/models/gacha.go b/pkg/models/gacha.go index b34d642..a0d06fb 100644 --- a/pkg/models/gacha.go +++ b/pkg/models/gacha.go @@ -1,8 +1,8 @@ package models import ( - "math/rand" - "time" + "crypto/rand" + "math/big" "github.com/iamananya/ginco-task/pkg/config" "github.com/jinzhu/gorm" @@ -12,8 +12,55 @@ var db *gorm.DB type User struct { gorm.Model - Name string `gorm:"type:varchar(30);size:30" json:"name"` - Token string `gorm:"type:char(30)" json:"token"` + Name string `gorm:"type:varchar(30);size:30" json:"name"` + Token string `gorm:"type:char(30)" json:"token"` + Characters []UserCharacter `gorm:"foreignKey:UserID" json:"characters"` +} +type Character struct { + gorm.Model + Name string `gorm:"type:varchar(30);size:30" json:"name"` + AttackPower int `gorm:"column:attack_power" json:"attack_power"` + Defense int `gorm:"column:defense" json:"defense"` + Speed int `json:"speed"` + HitPoints int `gorm:"column:hit_points" json:"hit_points"` + CriticalHitRate float64 `gorm:"column:critical_hit_rate" json:"critical_hit_rate"` + ElementalAffinity string `json:"elemental_affinity"` + Rarity string `json:"rarity"` + Synergy bool `json:"synergy"` + Evolution bool `json:"evolution"` + Users []UserCharacter `gorm:"foreignKey:CharacterID" json:"users"` +} + +type UserCharacter struct { + gorm.Model + UserID uint `gorm:"index" json:"user_id"` + CharacterID uint `gorm:"index" json:"character_id"` + AttackPower int `gorm:"column:attack_power" json:"attack_power"` + Defense int `gorm:"column:defense" json:"defense"` + Speed int `json:"speed"` + HitPoints int `gorm:"column:hit_points" json:"hit_points"` + CriticalHitRate float64 `gorm:"column:critical_hit_rate" json:"critical_hit_rate"` + ElementalAffinity string `json:"elemental_affinity"` + Rarity string `json:"rarity"` + Synergy bool `json:"synergy"` + Evolution bool `json:"evolution"` +} +type GachaResult struct { + gorm.Model + CharacterID uint `gorm:"index" json:"character_id"` + CharacterName string `json:"character_name"` +} + +type GachaDrawRequest struct { + Times int `json:"times"` +} + +type GachaDrawResponse struct { + Results []CharacterResponse `json:"results"` +} +type CharacterResponse struct { + CharacterID string `json:"characterID"` + Name string `json:"name"` } func init() { @@ -22,42 +69,87 @@ func init() { db.AutoMigrate(&User{}) db.Model(&User{}).ModifyColumn("name", "varchar(30)") db.Model(&User{}).ModifyColumn("token", "char(30)") + db.AutoMigrate(&Character{}) + db.Model(&Character{}).ModifyColumn("name", "varchar(30)") + db.AutoMigrate(&UserCharacter{}) + db.AutoMigrate(&GachaResult{}) } func (u *User) CreateUser() *User { - rand.Seed(time.Now().UnixNano()) - u.Token = generateRandomString(30) db.NewRecord(u) db.Create(&u) return u } -// Function defined to generate random string for token - +// Function defined to generate random string for token--- func generateRandomString(length int) string { const charset = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + charsetLength := big.NewInt(int64(len(charset))) b := make([]byte, length) - for i := range b { - b[i] = charset[rand.Intn(len(charset))] + for i := 0; i < length; i++ { + randomIndex, _ := rand.Int(rand.Reader, charsetLength) + b[i] = charset[randomIndex.Int64()] } return string(b) } -func GetAllUsers() []User { - var Users []User - db.Find(&Users) - return Users +// Function used to verify user token----- +func GetUserByToken(token string) []User { + var users []User + db.Where("token = ?", token).Find(&users) + return users } -func GetUserById(Id int64) (*User, *gorm.DB) { - var getUser User - db := db.Where("ID=?", Id).Find(&getUser) - return &getUser, db +func GetAllUsers(token string) []User { + + if token != "" { + return GetUserByToken(token) + } + return nil + + // If no token is provided, retrieve all users + // var users []User + // db.Find(&users) + // return users +} + +func UpdateUser(user *User) error { + + if err := db.Save(user).Error; err != nil { + return err + } + + return nil } -// func DeleteUser(Id int64) User { -// var user User -// db.Where("ID=?", Id).Delete(user) -// return user -// } +func GetAllCharacters() []Character { + var Characters []Character + db.Find(&Characters) + return Characters +} +func (uc *UserCharacter) CreateUserCharacter() *UserCharacter { + db.Create(&uc) + return uc +} + +func DrawCharacter(characters []Character, characterPool []Character) Character { + randIndex, _ := rand.Int(rand.Reader, big.NewInt(int64(len(characterPool)))) + + index := int(randIndex.Int64()) + selectedCharacter := characterPool[index] + + // Save the gacha result in the database + gachaResult := GachaResult{ + CharacterID: selectedCharacter.ID, + CharacterName: selectedCharacter.Name, + } + _ = gachaResult.SaveGachaResult() + + return selectedCharacter +} +func (gr *GachaResult) SaveGachaResult() error { + db := config.GetDB() + err := db.Create(gr).Error + return err +} diff --git a/pkg/routes/gacha-routes.go b/pkg/routes/gacha-routes.go index 525d147..7139379 100644 --- a/pkg/routes/gacha-routes.go +++ b/pkg/routes/gacha-routes.go @@ -8,8 +8,9 @@ import ( var RegisterUserRoute = func(router *mux.Router) { router.HandleFunc("/user/", controllers.CreateUser).Methods("POST") router.HandleFunc("/user/", controllers.GetUser).Methods("GET") - router.HandleFunc("/user/{userId}", controllers.GetUserById).Methods("GET") - router.HandleFunc("/user/{userId}", controllers.UpdateUser).Methods("PUT") - // router.HandleFunc("/user/{userId}", controllers.DeleteUser).Methods("DELETE") + router.HandleFunc("/user/", controllers.UpdateUser).Methods("PUT") + router.HandleFunc("/characters/list/", controllers.ListCharacters).Methods("GET") + router.HandleFunc("/gacha/draw/", controllers.HandleGachaDraw).Methods("POST") + // router.HandleFunc("/user/characters/", controllers.CreateUserCharacter).Methods("POST") }