// EstimateFenceCostHandler POST /fences/estimateCost func EstimateFenceCostHandler(w http.ResponseWriter, r *http.Request) { user, err := auth.ValidateSession(r) if err != nil { http.Error(w, "Invalid Session token. "+err.Error(), http.StatusUnauthorized) return } decoder := json.NewDecoder(r.Body) var f fenceResponse err = decoder.Decode(&f) indexRadius := sort.SearchInts(models.UpgradeTypesRadius[:], f.Radius) if !(indexRadius < len(models.UpgradeTypesRadius) && models.UpgradeTypesRadius[indexRadius] == f.Radius) { http.Error(w, "Invalid Radius", http.StatusExpectationFailed) return } indexRent := sort.SearchFloat64s(models.UpgradeTypesRent[:], float64(f.RentMultiplier)) if !(indexRent < len(models.UpgradeTypesRent) && models.UpgradeTypesRent[indexRent] == f.RentMultiplier) { http.Error(w, "Invalid RentMultiplier", http.StatusExpectationFailed) return } if f.TTL <= 0 || f.TTL > models.FenceMaxTTL { http.Error(w, "Invalid TTL", http.StatusExpectationFailed) return } if err != nil { http.Error(w, err.Error(), http.StatusBadRequest) return } price, err := scores.GetGeoFencePrice(f.Lat, f.Lon, f.TTL, f.RentMultiplier, indexRadius) if err != nil { InternalServerError(err, w) return } overlap, err := checkFenceOverlapWithFenceResponse(&f) if err != nil { InternalServerError(err, w) return } if overlap { http.Error(w, "Fence does overlap.", http.StatusBadRequest) return } var response = costEstimateResponse{Cost: price, CanAfford: user.Balance >= price} bytes, err := json.Marshal(&response) if err != nil { InternalServerError(err, w) return } w.Write(bytes) }
// CreateFenceHandler POST /fences func CreateFenceHandler(w http.ResponseWriter, r *http.Request) { user, err := auth.ValidateSession(r) if err != nil { http.Error(w, "Invalid Session token. "+err.Error(), http.StatusUnauthorized) return } decoder := json.NewDecoder(r.Body) var requestFence fenceResponse err = decoder.Decode(&requestFence) if err != nil { InternalServerError(err, w) return } indexRadius := sort.SearchInts(models.UpgradeTypesRadius[:], requestFence.Radius) if !(indexRadius < len(models.UpgradeTypesRadius) && models.UpgradeTypesRadius[indexRadius] == requestFence.Radius) { http.Error(w, "Invalid Radius", http.StatusExpectationFailed) return } indexRent := sort.SearchFloat64s(models.UpgradeTypesRent[:], float64(requestFence.RentMultiplier)) if !(indexRent < len(models.UpgradeTypesRent) && models.UpgradeTypesRent[indexRent] == requestFence.RentMultiplier) { http.Error(w, "Invalid RentMultiplier", http.StatusExpectationFailed) return } if requestFence.TTL <= 0 || requestFence.TTL > models.FenceMaxTTL { http.Error(w, "Invalid TTL", http.StatusExpectationFailed) return } var f models.Fence f.Lat = requestFence.Lat f.Lon = requestFence.Lon f.Name = requestFence.Name f.Radius = requestFence.Radius f.RentMultiplier = requestFence.RentMultiplier f.TTL = requestFence.TTL f.DiesAt = time.Now().Add(time.Duration(f.TTL) * time.Second) f.UserID = user.ID overlap, err := checkFenceOverlap(&f) if err != nil { InternalServerError(err, w) return } if overlap { http.Error(w, "Fence does overlap.", http.StatusBadRequest) return } price, err := scores.GetGeoFencePrice(f.Lat, f.Lon, f.TTL, f.RentMultiplier, indexRadius) if price > user.Balance { http.Error(w, "You do not have enough money for this thing.", http.StatusPaymentRequired) return } f.Cost = price user.LastKnownGeoHash = geomodel.GeoCell(requestFence.Lat, requestFence.Lon, models.LastKnownGeoHashResolution) user.Balance = user.Balance - price user.ExpensesGeoFenceAllTime = user.ExpensesGeoFenceAllTime + price err = user.Save() if err != nil { log.Errorf("Error while saving user: %v", err) } redis.AddBalanceRecord(redis.GetBalanceRecordName(user.ID, redis.BalanceNameExpenseGeoFence), price) f.User = *user err = f.Save() if err != nil { InternalServerError(err, w) return } err = search.IndexGeoFence(f) if err != nil { InternalServerError(err, w) return } jobs.QueueNotifyUsersSyncRequest(f.Lat, f.Lon) jobs.QueueFenceExpireRequest(&f) bytes, err := json.Marshal(&f) if err != nil { InternalServerError(err, w) return } w.Write(bytes) }