package handlers import ( "errors" "net/http" "otaupdate/services" "sort" "strconv" "github.com/fiskerinc/cloud-services/pkg/common" "github.com/fiskerinc/cloud-services/pkg/httphandlers" "github.com/fiskerinc/cloud-services/pkg/loggerdataresp" "github.com/fiskerinc/cloud-services/pkg/utils" "github.com/fiskerinc/cloud-services/pkg/utils/envtool" "github.com/fiskerinc/cloud-services/pkg/validator" ) var apiCreateToken string = envtool.GetEnv("MIGRATE_CREATE_TOKEN", "") // HandleFlashpackVersionAdd godoc // @Summary Add a flashpack version // @Description Add a flashpack version // @Accept json // @Produce json // @Param Authorization header string false "Bearer " // @Param Api-Key header string false "" // @Param data body common.CarFlashpackVersionAddRequest true "Mappings between ECU versions and a flashpack number" // @Success 200 {object} common.JSONDBQueryResult "Created flashpack ecu mapping result" // @Failure 400 {object} common.JSONError "Bad request" // @Failure 401 {object} common.JSONError "Unauthorized" // @Failure 503 {object} common.JSONError "Service unavailable" // @Router /flashpack_version [post] func HandleFlashpackVersionAdd(w http.ResponseWriter, r *http.Request) { var req common.CarFlashpackVersionAddRequest err := httphandlers.ParseRequest(r, &req) if loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest) { return } if len(req.ECUVersions) < 1 { loggerdataresp.BadDataErrorResp(w, errors.New("CarECUName and CarECUVersion required"), http.StatusBadRequest) return } // Include previous flashpack mappings previousMappings, err := services.GetDB().GetCars().GetCarFlashpackVersionMappingsByModelTrim(req.CarModel, req.CarTrim, nil) if loggerdataresp.BadDataErrorResp(w, err, http.StatusServiceUnavailable) { return } // the flashpacks are stored in the database as strings, so we have to sort them numerically // in descending order by year and flashpack sort.Slice(previousMappings, func(i, j int) bool { iFp, _ := strconv.ParseFloat(previousMappings[i].Flashpack, 64) // guaranteed numeric jFp, _ := strconv.ParseFloat(previousMappings[j].Flashpack, 64) // guaranteed numeric iYear := previousMappings[i].CarYear jYear := previousMappings[j].CarYear if iYear == jYear { return iFp > jFp } else { return iYear > jYear } }) // Put all the mappings into one array, still in descending order by flashpack number // only include the ones that are less than or equal to the new flashpack number being added mappings := []common.CarFlashpackVersion{} for _, v := range req.ECUVersions { mappings = append(mappings, common.CarFlashpackVersion{ CarECUName: v.CarECUName, CarECUVersion: v.CarECUVersion, Flashpack: req.Flashpack, CarModel: req.CarModel, CarTrim: req.CarTrim, CarYear: req.CarYear, }) } for _, m := range previousMappings { reqFp, _ := strconv.ParseFloat(req.Flashpack, 64) // already validated as numeric mFp, _ := strconv.ParseFloat(m.Flashpack, 64) // already validated as numeric if (m.CarYear < req.CarYear) || (m.CarYear == req.CarYear && mFp <= reqFp) { mappings = append(mappings, m) } } // Put the mappings in a map by ecu name // There can be more than one ECU version for an ECU for a flashpack var newMappings = make(map[string][]common.CarFlashpackVersion) for _, m := range mappings { // Only include the mapping if it is one of the latest latestVersionMappings, ok := newMappings[m.CarECUName] // Include multiple versions for the same ecu and flashpack number if (ok && m.Flashpack == latestVersionMappings[0].Flashpack) || !ok { newMappings[m.CarECUName] = append(newMappings[m.CarECUName], m) } } // Flatten the map into an array var newMappingsArray []common.CarFlashpackVersion for _, m := range newMappings { newMappingsArray = append(newMappingsArray, m...) } // Apply the new flashpack number to all the mappings to be inserted for i := range newMappingsArray { newMappingsArray[i].Flashpack = req.Flashpack newMappingsArray[i].CarYear = req.CarYear } err = services.GetDB().GetCars().AddCarFlashpackVersionMappings(newMappingsArray) if loggerdataresp.BadDataErrorResp(w, err, http.StatusServiceUnavailable) { return } // Also add to other environments, as required for _, targetURL := range targetURLS { if !validator.ValidateURL(targetURL) || apiCreateToken == "" { break // No URL in MANIFEST_MIGRATE_URLS } otaService := services.NewOtaService(targetURL, apiCreateToken) resp, err := otaService.FlashpackVersionAdd(req) if loggerdataresp.BadDataErrorResp(w, err, http.StatusBadRequest) { return } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { utils.ForwardResponse(w, resp) } } utils.RespJSON(w, http.StatusOK, common.JSONMessage{ Message: "Created", }) }